From aa38f1d23a61910d006197597a12353f0894b98f Mon Sep 17 00:00:00 2001 From: Xiangfu Liu Date: Sun, 16 Aug 2009 14:31:14 +0800 Subject: [PATCH] try to add lb60 to 2.6.31 kernel this is not the work patch. just show some work progress. Signed-off-by: Xiangfu Liu --- .../patches-2.6.31/0002-qi_lb60_support_patch | 103429 +++++++++++++++ 1 file changed, 103429 insertions(+) create mode 100644 target/linux/xburst/patches-2.6.31/0002-qi_lb60_support_patch diff --git a/target/linux/xburst/patches-2.6.31/0002-qi_lb60_support_patch b/target/linux/xburst/patches-2.6.31/0002-qi_lb60_support_patch new file mode 100644 index 000000000..1eaa44267 --- /dev/null +++ b/target/linux/xburst/patches-2.6.31/0002-qi_lb60_support_patch @@ -0,0 +1,103429 @@ +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 3ca0fe1..a86cdd5 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -19,6 +19,98 @@ choice + prompt "System type" + default SGI_IP22 + ++config JZ4740_QI_LB60 ++ bool "Ingenic JZ4740 QI_LB60 board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ ++config JZ4730_PMP ++ bool "Ingenic JZ4730 PMP board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4730 ++ ++config JZ4740_PAVO ++ bool "Ingenic JZ4740 PAVO board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ ++config JZ4740_LEO ++ bool "Ingenic JZ4740 LEO board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ ++config JZ4740_LYRA ++ bool "Ingenic JZ4740 LYRA board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ ++config JZ4725_DIPPER ++ bool "Ingenic JZ4725 DIPPER board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ select SOC_JZ4725 ++ ++config JZ4720_VIRGO ++ bool "Ingenic JZ4720 VIRGO board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ select SOC_JZ4720 ++ ++config JZ4750_FUWA ++ bool "Ingenic JZ4750 FUWA board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4750 ++ select JZ_FPGA ++ ++config JZ4750D_FUWA1 ++ bool "Ingenic JZ4750d FUWA1 board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4750D ++ select JZ_FPGA ++ ++config JZ4750_APUS ++ bool "Ingenic JZ4750 APUS board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4750 ++ ++config JZ4750D_CETUS ++ bool "Ingenic JZ4750d CETUS board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4750D ++ + config MACH_ALCHEMY + bool "Alchemy processor based machines" + +@@ -671,6 +763,48 @@ source "arch/mips/cavium-octeon/Kconfig" + + endmenu + ++##################################################### ++# Ingenic SOC series ++##################################################### ++ ++config SOC_JZ4730 ++ bool ++ select JZSOC ++ ++config SOC_JZ4740 ++ bool ++ select JZSOC ++ ++config SOC_JZ4725 ++ bool ++ select JZSOC ++ ++config SOC_JZ4720 ++ bool ++ select JZSOC ++ ++config SOC_JZ4750 ++ bool ++ select JZSOC ++ ++config SOC_JZ4750D ++ bool ++ select JZSOC ++ ++config JZ_FPGA ++ bool ++ ++config JZSOC ++ bool ++ select JZRISC ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ ++config JZRISC ++ bool ++ ++#################################################### ++ + config RWSEM_GENERIC_SPINLOCK + bool + default y +@@ -2055,6 +2189,14 @@ config PCI_DOMAINS + + source "drivers/pci/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) ++ + # + # ISA support is now enabled via select. Too many systems still have the one + # or other ISA chip on the board that users don't know about so don't expect +@@ -2164,6 +2306,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..91f73c0 100644 +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -180,6 +180,37 @@ cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7 + load-$(CONFIG_AR7) += 0xffffffff94100000 + + # ++# Commond Ingenic JZ4730 series ++# ++core-$(CONFIG_SOC_JZ4730) += arch/mips/jz4730/ ++cflags-$(CONFIG_SOC_JZ4730) += -Iinclude/asm-mips/mach-jz4730 ++load-$(CONFIG_SOC_JZ4730) += 0xffffffff80010000 ++ ++# ++# Commond Ingenic JZ4740 series ++# ++ ++core-$(CONFIG_SOC_JZ4740) += arch/mips/jz4740/ ++cflags-$(CONFIG_SOC_JZ4740) += -Iinclude/asm-mips/mach-jz4740 ++load-$(CONFIG_SOC_JZ4740) += 0xffffffff80010000 ++ ++# ++# Commond Ingenic JZ4750 series ++# ++ ++core-$(CONFIG_SOC_JZ4750) += arch/mips/jz4750/ ++cflags-$(CONFIG_SOC_JZ4750) += -Iinclude/asm-mips/mach-jz4750 ++load-$(CONFIG_SOC_JZ4750) += 0xffffffff80010000 ++ ++# ++# Commond Ingenic JZ4750d series ++# ++ ++core-$(CONFIG_SOC_JZ4750D) += arch/mips/jz4750d/ ++cflags-$(CONFIG_SOC_JZ4750D) += -Iinclude/asm-mips/mach-jz4750d ++load-$(CONFIG_SOC_JZ4750D) += 0xffffffff80010000 ++ ++# + # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. + # + core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/ +@@ -711,6 +742,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 +777,7 @@ install: + + archclean: + @$(MAKE) $(clean)=arch/mips/boot ++ @$(MAKE) $(clean)=arch/mips/boot/compressed + @$(MAKE) $(clean)=arch/mips/lasat + + define archhelp +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/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile +new file mode 100644 +index 0000000..8c3ede2 +--- /dev/null ++++ b/arch/mips/boot/compressed/Makefile +@@ -0,0 +1,42 @@ ++# ++# linux/arch/mips/boot/compressed/Makefile ++# ++# create a compressed zImage from the original vmlinux ++# ++ ++targets := zImage vmlinuz vmlinux.bin.gz head.o misc.o piggy.o dummy.o ++ ++OBJS := $(obj)/head.o $(obj)/misc.o ++ ++LD_ARGS := -T $(obj)/ld.script -Ttext 0x80600000 -Bstatic ++OBJCOPY_ARGS := -O elf32-tradlittlemips ++ ++ENTRY := $(obj)/../tools/entry ++FILESIZE := $(obj)/../tools/filesize ++ ++drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options ++strip-flags = $(addprefix --remove-section=,$(drop-sections)) ++ ++ ++$(obj)/vmlinux.bin.gz: vmlinux ++ rm -f $(obj)/vmlinux.bin.gz ++ $(OBJCOPY) -O binary $(strip-flags) vmlinux $(obj)/vmlinux.bin ++ gzip -v9f $(obj)/vmlinux.bin ++ ++$(obj)/head.o: $(obj)/head.S $(obj)/vmlinux.bin.gz vmlinux ++ $(CC) $(KBUILD_AFLAGS) -Iinclude \ ++ -DIMAGESIZE=$(shell sh $(FILESIZE) $(obj)/vmlinux.bin.gz) \ ++ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) vmlinux ) \ ++ -DLOADADDR=$(loadaddr) \ ++ -c -o $(obj)/head.o $< ++ ++$(obj)/vmlinuz: $(OBJS) $(obj)/ld.script $(obj)/vmlinux.bin.gz $(obj)/dummy.o ++ $(OBJCOPY) \ ++ --add-section=.image=$(obj)/vmlinux.bin.gz \ ++ --set-section-flags=.image=contents,alloc,load,readonly,data \ ++ $(obj)/dummy.o $(obj)/piggy.o ++ $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/piggy.o ++ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap ++ ++zImage: $(obj)/vmlinuz ++ $(OBJCOPY) -O binary $(obj)/vmlinuz $(obj)/zImage +diff --git a/arch/mips/boot/compressed/dummy.c b/arch/mips/boot/compressed/dummy.c +new file mode 100644 +index 0000000..31dbf45 +--- /dev/null ++++ b/arch/mips/boot/compressed/dummy.c +@@ -0,0 +1,4 @@ ++int main(void) ++{ ++ return 0; ++} +diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S +new file mode 100644 +index 0000000..d9700eb +--- /dev/null ++++ b/arch/mips/boot/compressed/head.S +@@ -0,0 +1,85 @@ ++/* ++ * linux/arch/mips/boot/compressed/head.S ++ * ++ * Copyright (C) 2005-2008 Ingenic Semiconductor Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define IndexInvalidate_I 0x00 ++#define IndexWriteBack_D 0x01 ++ ++ .set noreorder ++ LEAF(startup) ++startup: ++ move s0, a0 /* Save the boot loader transfered args */ ++ move s1, a1 ++ move s2, a2 ++ move s3, a3 ++ ++ la a0, _edata ++ la a1, _end ++1: sw zero, 0(a0) /* Clear BSS section */ ++ bne a1, a0, 1b ++ addu a0, 4 ++ ++ la sp, (.stack + 8192) ++ ++ la a0, __image_begin ++ la a1, IMAGESIZE ++ la a2, LOADADDR ++ la ra, 1f ++ la k0, decompress_kernel ++ jr k0 ++ nop ++1: ++ ++ move a0, s0 ++ move a1, s1 ++ move a2, s2 ++ move a3, s3 ++ li k0, KERNEL_ENTRY ++ jr k0 ++ nop ++2: ++ b 32 ++ END(startup) ++ ++ ++ LEAF(flushcaches) ++ la t0, 1f ++ la t1, 0xa0000000 ++ or t0, t0, t1 ++ jr t0 ++ nop ++1: ++ li k0, 0x80000000 # start address ++ li k1, 0x80004000 # end address (16KB I-Cache) ++ subu k1, 128 ++ ++2: ++ .set mips3 ++ cache IndexWriteBack_D, 0(k0) ++ cache IndexWriteBack_D, 32(k0) ++ cache IndexWriteBack_D, 64(k0) ++ cache IndexWriteBack_D, 96(k0) ++ cache IndexInvalidate_I, 0(k0) ++ cache IndexInvalidate_I, 32(k0) ++ cache IndexInvalidate_I, 64(k0) ++ cache IndexInvalidate_I, 96(k0) ++ .set mips0 ++ ++ bne k0, k1, 2b ++ addu k0, k0, 128 ++ la t0, 3f ++ jr t0 ++ nop ++3: ++ jr ra ++ nop ++ END(flushcaches) ++ ++ .comm .stack,4096*2,4 +diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script +new file mode 100644 +index 0000000..fcf8ba0 +--- /dev/null ++++ b/arch/mips/boot/compressed/ld.script +@@ -0,0 +1,151 @@ ++OUTPUT_ARCH(mips) ++ENTRY(startup) ++SECTIONS ++{ ++ /* Read-only sections, merged into text segment: */ ++ ++ .init : { *(.init) } =0 ++ .text : ++ { ++ _ftext = . ; ++ *(.text) ++ *(.rodata) ++ *(.rodata1) ++ /* .gnu.warning sections are handled specially by elf32.em. */ ++ *(.gnu.warning) ++ } =0 ++ .kstrtab : { *(.kstrtab) } ++ ++ . = ALIGN(16); /* Exception table */ ++ __start___ex_table = .; ++ __ex_table : { *(__ex_table) } ++ __stop___ex_table = .; ++ ++ __start___dbe_table = .; /* Exception table for data bus errors */ ++ __dbe_table : { *(__dbe_table) } ++ __stop___dbe_table = .; ++ ++ __start___ksymtab = .; /* Kernel symbol table */ ++ __ksymtab : { *(__ksymtab) } ++ __stop___ksymtab = .; ++ ++ _etext = .; ++ ++ . = ALIGN(8192); ++ .data.init_task : { *(.data.init_task) } ++ ++ /* Startup code */ ++ . = ALIGN(4096); ++ __init_begin = .; ++ .text.init : { *(.text.init) } ++ .data.init : { *(.data.init) } ++ . = ALIGN(16); ++ __setup_start = .; ++ .setup.init : { *(.setup.init) } ++ __setup_end = .; ++ __initcall_start = .; ++ .initcall.init : { *(.initcall.init) } ++ __initcall_end = .; ++ . = ALIGN(4096); /* Align double page for init_task_union */ ++ __init_end = .; ++ ++ . = ALIGN(4096); ++ .data.page_aligned : { *(.data.idt) } ++ ++ . = ALIGN(32); ++ .data.cacheline_aligned : { *(.data.cacheline_aligned) } ++ ++ .fini : { *(.fini) } =0 ++ .reginfo : { *(.reginfo) } ++ /* Adjust the address for the data segment. We want to adjust up to ++ the same address within the page on the next page up. It would ++ be more correct to do this: ++ . = .; ++ The current expression does not correctly handle the case of a ++ text segment ending precisely at the end of a page; it causes the ++ data segment to skip a page. The above expression does not have ++ this problem, but it will currently (2/95) cause BFD to allocate ++ a single segment, combining both text and data, for this case. ++ This will prevent the text segment from being shared among ++ multiple executions of the program; I think that is more ++ important than losing a page of the virtual address space (note ++ that no actual memory is lost; the page which is skipped can not ++ be referenced). */ ++ . = .; ++ .data : ++ { ++ _fdata = . ; ++ *(.data) ++ ++ /* Put the compressed image here, so bss is on the end. */ ++ __image_begin = .; ++ *(.image) ++ __image_end = .; ++ /* Align the initial ramdisk image (INITRD) on page boundaries. */ ++ . = ALIGN(4096); ++ __ramdisk_begin = .; ++ *(.initrd) ++ __ramdisk_end = .; ++ . = ALIGN(4096); ++ ++ CONSTRUCTORS ++ } ++ .data1 : { *(.data1) } ++ _gp = . + 0x8000; ++ .lit8 : { *(.lit8) } ++ .lit4 : { *(.lit4) } ++ .ctors : { *(.ctors) } ++ .dtors : { *(.dtors) } ++ .got : { *(.got.plt) *(.got) } ++ .dynamic : { *(.dynamic) } ++ /* We want the small data sections together, so single-instruction offsets ++ can access them all, and initialized data all before uninitialized, so ++ we can shorten the on-disk segment size. */ ++ .sdata : { *(.sdata) } ++ . = ALIGN(4); ++ _edata = .; ++ PROVIDE (edata = .); ++ ++ __bss_start = .; ++ _fbss = .; ++ .sbss : { *(.sbss) *(.scommon) } ++ .bss : ++ { ++ *(.dynbss) ++ *(.bss) ++ *(COMMON) ++ . = ALIGN(4); ++ _end = . ; ++ PROVIDE (end = .); ++ } ++ ++ /* Sections to be discarded */ ++ /DISCARD/ : ++ { ++ *(.text.exit) ++ *(.data.exit) ++ *(.exitcall.exit) ++ } ++ ++ /* This is the MIPS specific mdebug section. */ ++ .mdebug : { *(.mdebug) } ++ /* These are needed for ELF backends which have not yet been ++ converted to the new style linker. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ /* DWARF debug sections. ++ Symbols in the .debug DWARF section are relative to the beginning of the ++ section so we begin .debug at 0. It's not clear yet what needs to happen ++ for the others. */ ++ .debug 0 : { *(.debug) } ++ .debug_srcinfo 0 : { *(.debug_srcinfo) } ++ .debug_aranges 0 : { *(.debug_aranges) } ++ .debug_pubnames 0 : { *(.debug_pubnames) } ++ .debug_sfnames 0 : { *(.debug_sfnames) } ++ .line 0 : { *(.line) } ++ /* These must appear regardless of . */ ++ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } ++ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } ++ .comment : { *(.comment) } ++ .note : { *(.note) } ++} +diff --git a/arch/mips/boot/compressed/misc.c b/arch/mips/boot/compressed/misc.c +new file mode 100644 +index 0000000..2309fee +--- /dev/null ++++ b/arch/mips/boot/compressed/misc.c +@@ -0,0 +1,242 @@ ++/* ++ * linux/arch/mips/boot/compressed/misc.c ++ * ++ * This is a collection of several routines from gzip-1.0.3 ++ * adapted for Linux. ++ * ++ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 ++ * ++ * Adapted for JZSOC by Peter Wei, 2008 ++ * ++ */ ++ ++#define size_t int ++#define NULL 0 ++ ++/* ++ * gzip declarations ++ */ ++ ++#define OF(args) args ++#define STATIC static ++ ++#undef memset ++#undef memcpy ++#define memzero(s, n) memset ((s), 0, (n)) ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++#define WSIZE 0x8000 /* Window size must be at least 32k, */ ++ /* and a power of two */ ++ ++static uch *inbuf; /* input buffer */ ++static uch window[WSIZE]; /* Sliding window buffer */ ++ ++static unsigned insize = 0; /* valid bytes in inbuf */ ++static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ ++static unsigned outcnt = 0; /* bytes in output buffer */ ++ ++/* gzip flag byte */ ++#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ ++#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ ++#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ ++#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ ++#define COMMENT 0x10 /* bit 4 set: file comment present */ ++#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ ++#define RESERVED 0xC0 /* bit 6,7: reserved */ ++ ++#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) ++ ++/* Diagnostic functions */ ++#ifdef DEBUG ++# define Assert(cond,msg) {if(!(cond)) error(msg);} ++# define Trace(x) fprintf x ++# define Tracev(x) {if (verbose) fprintf x ;} ++# define Tracevv(x) {if (verbose>1) fprintf x ;} ++# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} ++# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} ++#else ++# define Assert(cond,msg) ++# define Trace(x) ++# define Tracev(x) ++# define Tracevv(x) ++# define Tracec(c,x) ++# define Tracecv(c,x) ++#endif ++ ++static int fill_inbuf(void); ++static void flush_window(void); ++static void error(char *m); ++static void gzip_mark(void **); ++static void gzip_release(void **); ++ ++void* memset(void* s, int c, size_t n); ++void* memcpy(void* __dest, __const void* __src, size_t __n); ++ ++extern void flushcaches(void); /* defined in head.S */ ++ ++char *input_data; ++int input_len; ++ ++static long bytes_out = 0; ++static uch *output_data; ++static unsigned long output_ptr = 0; ++ ++ ++static void *malloc(int size); ++static void free(void *where); ++static void error(char *m); ++static void gzip_mark(void **); ++static void gzip_release(void **); ++ ++static void puts(const char *str) ++{ ++} ++ ++extern unsigned char _end[]; ++static unsigned long free_mem_ptr; ++static unsigned long free_mem_end_ptr; ++ ++#define HEAP_SIZE 0x10000 ++ ++#include "../../../../lib/inflate.c" ++ ++static void *malloc(int size) ++{ ++ void *p; ++ ++ if (size <0) error("Malloc error\n"); ++ if (free_mem_ptr == 0) error("Memory error\n"); ++ ++ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ ++ ++ p = (void *)free_mem_ptr; ++ free_mem_ptr += size; ++ ++ if (free_mem_ptr >= free_mem_end_ptr) ++ error("\nOut of memory\n"); ++ ++ return p; ++} ++ ++static void free(void *where) ++{ /* Don't care */ ++} ++ ++static void gzip_mark(void **ptr) ++{ ++ *ptr = (void *) free_mem_ptr; ++} ++ ++static void gzip_release(void **ptr) ++{ ++ free_mem_ptr = (long) *ptr; ++} ++ ++void* memset(void* s, int c, size_t n) ++{ ++ int i; ++ char *ss = (char*)s; ++ ++ for (i=0;i> 3; i > 0; i--) { ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ } ++ ++ if (__n & 1 << 2) { ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ *d++ = *s++; ++ } ++ ++ if (__n & 1 << 1) { ++ *d++ = *s++; ++ *d++ = *s++; ++ } ++ ++ if (__n & 1) ++ *d++ = *s++; ++ ++ return __dest; ++} ++ ++/* =========================================================================== ++ * Fill the input buffer. This is called only when the buffer is empty ++ * and at least one byte is really needed. ++ */ ++static int fill_inbuf(void) ++{ ++ if (insize != 0) { ++ error("ran out of input data\n"); ++ } ++ ++ inbuf = input_data; ++ insize = input_len; ++ inptr = 1; ++ return inbuf[0]; ++} ++ ++/* =========================================================================== ++ * Write the output window window[0..outcnt-1] and update crc and bytes_out. ++ * (Used for the decompressed data only.) ++ */ ++static void flush_window(void) ++{ ++ ulg c = crc; /* temporary variable */ ++ unsigned n; ++ uch *in, *out, ch; ++ ++ in = window; ++ out = &output_data[output_ptr]; ++ for (n = 0; n < outcnt; n++) { ++ ch = *out++ = *in++; ++ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); ++ } ++ crc = c; ++ bytes_out += (ulg)outcnt; ++ output_ptr += (ulg)outcnt; ++ outcnt = 0; ++} ++ ++static void error(char *x) ++{ ++ puts("\n\n"); ++ puts(x); ++ puts("\n\n -- System halted"); ++ ++ while(1); /* Halt */ ++} ++ ++void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr) ++{ ++ input_data = (char *)imageaddr; ++ input_len = imagesize; ++ output_ptr = 0; ++ output_data = (uch *)loadaddr; ++ free_mem_ptr = (unsigned long)_end; ++ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; ++ ++ makecrc(); ++ puts("Uncompressing Linux..."); ++ gunzip(); ++ flushcaches(); ++ puts("Ok, booting the kernel."); ++} +diff --git a/arch/mips/boot/tools/entry b/arch/mips/boot/tools/entry +new file mode 100644 +index 0000000..376e822 +--- /dev/null ++++ b/arch/mips/boot/tools/entry +@@ -0,0 +1,12 @@ ++#!/bin/sh ++ ++# grab the kernel_entry address from the vmlinux elf image ++entry=`$1 $2 | grep kernel_entry` ++ ++fs=`echo $entry | grep ffffffff` # check toolchain output ++ ++if [ -n "$fs" ]; then ++ echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'` ++else ++ echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'` ++fi +diff --git a/arch/mips/boot/tools/filesize b/arch/mips/boot/tools/filesize +new file mode 100644 +index 0000000..2142ad5 +--- /dev/null ++++ b/arch/mips/boot/tools/filesize +@@ -0,0 +1,7 @@ ++#!/bin/sh ++HOSTNAME=`uname` ++if [ "$HOSTNAME" = "Linux" ]; then ++echo `ls -l $1 | awk '{print $5}'` ++else ++echo `ls -l $1 | awk '{print $6}'` ++fi +diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h +index 610fe3a..8bcf713 100644 +--- a/arch/mips/include/asm/bootinfo.h ++++ b/arch/mips/include/asm/bootinfo.h +@@ -57,6 +57,14 @@ + #define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */ + #define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */ + ++/* ++ * Valid machtype for group INGENIC ++ */ ++#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */ ++#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */ ++#define MACH_INGENIC_JZ4750 2 /* JZ4750 SOC */ ++#define MACH_INGENIC_JZ4750D 3 /* JZ4750D SOC */ ++ + #define CL_SIZE COMMAND_LINE_SIZE + + extern char *system_type; +diff --git a/arch/mips/jz4730/Makefile b/arch/mips/jz4730/Makefile +new file mode 100644 +index 0000000..d84b6b6 +--- /dev/null ++++ b/arch/mips/jz4730/Makefile +@@ -0,0 +1,22 @@ ++# ++# Makefile for the Ingenic JZ4730. ++# ++ ++# Object file lists. ++ ++obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ ++ platform.o i2c.o ++ ++obj-$(CONFIG_PROC_FS) += proc.o ++ ++# board specific support ++ ++obj-$(CONFIG_JZ4730_PMP) += board-pmp.o ++ ++# CPU Frequency scaling support ++ ++obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o ++ ++# PM support ++ ++obj-$(CONFIG_PM_LEGACY) +=pm.o sleep.o +diff --git a/arch/mips/jz4730/board-pmp.c b/arch/mips/jz4730/board-pmp.c +new file mode 100644 +index 0000000..00860c1 +--- /dev/null ++++ b/arch/mips/jz4730/board-pmp.c +@@ -0,0 +1,109 @@ ++/* ++ * linux/arch/mips/jz4730/board-pmp.c ++ * ++ * JZ4730 PMP board setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned int count = 0; ++ ++ count ++; ++ count &= 1; ++ if (count) ++ __gpio_set_pin(GPIO_LED_EN); ++ else ++ __gpio_clear_pin(GPIO_LED_EN); ++} ++ ++static void pmp_timer_ack(void) ++{ ++ static unsigned int count = 0; ++ count ++; ++ if (count % 100 == 0) { ++ count = 0; ++ dancing(); ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ __cpm_start_all(); ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Most of the gpios have been setup in the bootloader. ++ */ ++ ++ __harb_usb0_uhc(); ++ __gpio_as_dma(); ++ __gpio_as_eth(); ++ __gpio_as_usb(); ++ __gpio_as_lcd_master(); ++#if defined(CONFIG_I2S_AK4642EN) ++ __gpio_as_scc1(); ++#endif ++#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23) ++ __gpio_as_ssi(); ++#endif ++ //__gpio_as_ac97(); ++#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23) || defined(CONFIG_I2S_CS42L51) ++ __gpio_as_i2s_slave(); ++#endif ++ __gpio_as_cim(); ++ __gpio_as_msc(); ++ ++ __gpio_as_output(GPIO_LED_EN); ++ __gpio_set_pin(GPIO_LED_EN); ++ ++ __gpio_as_output(GPIO_DISP_OFF_N); ++ __gpio_set_pin(GPIO_DISP_OFF_N); ++ __gpio_as_output(GPIO_PWM0); ++ __gpio_set_pin(GPIO_PWM0); ++ ++ __gpio_as_input(GPIO_RTC_IRQ); ++ __gpio_as_output(GPIO_USB_CLK_EN); ++ __gpio_set_pin(GPIO_USB_CLK_EN); ++ ++ __gpio_as_input(GPIO_CHARG_STAT); ++ __gpio_disable_pull(GPIO_CHARG_STAT); ++ ++ __gpio_as_input(GPIO_UDC_HOTPLUG); ++ __gpio_disable_pull(GPIO_UDC_HOTPLUG); ++ __gpio_disable_pull(54); /* fixed ic bug, the pull of gpio pin 86 is as pin 54 */ ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4730 PMP board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = pmp_timer_ack; ++} +diff --git a/arch/mips/jz4730/cpufreq.c b/arch/mips/jz4730/cpufreq.c +new file mode 100644 +index 0000000..1bf4713 +--- /dev/null ++++ b/arch/mips/jz4730/cpufreq.c +@@ -0,0 +1,596 @@ ++ ++/* ++ * linux/arch/mips/jz4730/cpufreq.c ++ * ++ * cpufreq driver for JZ4730 ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ ++ "cpufreq-jz4730", msg) ++ ++#undef CHANGE_PLL ++ ++#define PLL_UNCHANGED 0 ++#define PLL_GOES_UP 1 ++#define PLL_GOES_DOWN 2 ++ ++#define PLL_WAIT_500NS (500*(__cpm_get_iclk()/1000000000)) ++ ++/* Saved the boot-time parameters */ ++static struct { ++ /* SDRAM parameters */ ++ unsigned int mclk; /* memory clock, KHz */ ++ unsigned int tras; /* RAS pulse width, cycles of mclk */ ++ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ ++ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ ++ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ ++ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ ++ unsigned int rtcor; /* Refresh Time Constant */ ++ unsigned int sdram_initialized; ++ ++ /* LCD parameters */ ++ unsigned int lcd_clk; /* LCD clock, Hz */ ++ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ ++ unsigned int lcd_clks_initialized; ++} boot_config; ++ ++struct jz4730_freq_percpu_info { ++ struct cpufreq_frequency_table table[7]; ++}; ++ ++static struct jz4730_freq_percpu_info jz4730_freq_table; ++ ++/* ++ * This contains the registers value for an operating point. ++ * If only part of a register needs to change then there is ++ * a mask value for that register. ++ * When going to a new operating point the current register ++ * value is ANDed with the ~mask and ORed with the new value. ++ */ ++struct dpm_regs { ++ u32 cfcr; /* Clock Freq Control Register */ ++ u32 cfcr_mask; /* Clock Freq Control Register mask */ ++ u32 cfcr2; /* Clock Freq Control Register 2 */ ++ u32 cfcr2_mask; /* Clock Freq Control Register 2 mask */ ++ u32 plcr1; /* PLL1 Control Register */ ++ u32 plcr1_mask; /* PLL1 Control Register mask */ ++ u32 pll_up_flag; /* New PLL freq is higher than current or not */ ++}; ++ ++extern jz_clocks_t jz_clocks; ++ ++static void jz_update_clocks(void) ++{ ++ /* Next clocks must be updated if we have changed ++ * the PLL or divisors. ++ */ ++ jz_clocks.iclk = __cpm_get_iclk(); ++ jz_clocks.sclk = __cpm_get_sclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++} ++ ++static void ++jz_init_boot_config(void) ++{ ++ if (!boot_config.lcd_clks_initialized) { ++ /* the first time to scale pll */ ++ boot_config.lcd_clk = __cpm_get_lcdclk(); ++ boot_config.lcdpix_clk = __cpm_get_pixclk(); ++ boot_config.lcd_clks_initialized = 1; ++ } ++ ++ if (!boot_config.sdram_initialized) { ++ /* the first time to scale frequencies */ ++ unsigned int dmcr, rtcor; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ ++ dmcr = REG_EMC_DMCR; ++ rtcor = REG_EMC_RTCOR; ++ ++ tras = (dmcr >> 13) & 0x7; ++ rcd = (dmcr >> 11) & 0x3; ++ tpc = (dmcr >> 8) & 0x7; ++ trwl = (dmcr >> 5) & 0x3; ++ trc = (dmcr >> 2) & 0x7; ++ ++ boot_config.mclk = __cpm_get_mclk() / 1000; ++ boot_config.tras = tras + 4; ++ boot_config.rcd = rcd + 1; ++ boot_config.tpc = tpc + 1; ++ boot_config.trwl = trwl + 1; ++ boot_config.trc = trc * 2 + 1; ++ boot_config.rtcor = rtcor; ++ ++ boot_config.sdram_initialized = 1; ++ } ++} ++ ++static void jz_update_dram_rtcor(unsigned int new_mclk) ++{ ++ unsigned int rtcor; ++ ++ new_mclk /= 1000; ++ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; ++ rtcor--; ++ ++ if (rtcor < 1) rtcor = 1; ++ if (rtcor > 255) rtcor = 255; ++ ++ REG_EMC_RTCOR = rtcor; ++ REG_EMC_RTCNT = rtcor; ++} ++ ++static void jz_update_dram_dmcr(unsigned int new_mclk) ++{ ++ unsigned int dmcr; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ unsigned int valid_time, new_time; /* ns */ ++ ++ new_mclk /= 1000; ++ tras = boot_config.tras * new_mclk / boot_config.mclk; ++ rcd = boot_config.rcd * new_mclk / boot_config.mclk; ++ tpc = boot_config.tpc * new_mclk / boot_config.mclk; ++ trwl = boot_config.trwl * new_mclk / boot_config.mclk; ++ trc = boot_config.trc * new_mclk / boot_config.mclk; ++ ++ /* Validation checking */ ++ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; ++ new_time = (tras * 1000000) / new_mclk; ++ if (new_time < valid_time) tras += 1; ++ ++ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; ++ new_time = (rcd * 1000000) / new_mclk; ++ if (new_time < valid_time) rcd += 1; ++ ++ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; ++ new_time = (tpc * 1000000) / new_mclk; ++ if (new_time < valid_time) tpc += 1; ++ ++ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; ++ new_time = (trwl * 1000000) / new_mclk; ++ if (new_time < valid_time) trwl += 1; ++ ++ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; ++ new_time = (trc * 1000000) / new_mclk; ++ if (new_time < valid_time) trc += 2; ++ ++ tras = (tras < 4) ? 4: tras; ++ tras = (tras > 11) ? 11: tras; ++ tras -= 4; ++ ++ rcd = (rcd < 1) ? 1: rcd; ++ rcd = (rcd > 4) ? 4: rcd; ++ rcd -= 1; ++ ++ tpc = (tpc < 1) ? 1: tpc; ++ tpc = (tpc > 8) ? 8: tpc; ++ tpc -= 1; ++ ++ trwl = (trwl < 1) ? 1: trwl; ++ trwl = (trwl > 4) ? 4: trwl; ++ trwl -= 1; ++ ++ trc = (trc < 1) ? 1: trc; ++ trc = (trc > 15) ? 15: trc; ++ trc /= 2; ++ ++ dmcr = REG_EMC_DMCR; ++ ++ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); ++ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); ++ ++ REG_EMC_DMCR = dmcr; ++} ++ ++static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR before changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } else { ++ /* We're going SLOWER: first update RTCOR value ++ * before changing the frequency. ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } ++} ++ ++static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so update RTCOR ++ * after changing the frequency ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } else { ++ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR after changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } ++} ++ ++static void jz_scale_divisors(struct dpm_regs *regs) ++{ ++ unsigned int cfcr; ++ unsigned int cur_mclk, new_mclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ cfcr = REG_CPM_CFCR; ++ cfcr &= ~((unsigned long)regs->cfcr_mask); ++ cfcr |= regs->cfcr; ++ cfcr |= CPM_CFCR_UPE; /* update immediately */ ++ ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = __cpm_get_pllout() / div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT]; ++ ++ /* Update some DRAM parameters before changing frequency */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++ ++#ifdef CHANGE_PLL ++/* Maintain the LCD clock and pixel clock */ ++static void jz_scale_lcd_divisors(struct dpm_regs *regs) ++{ ++ unsigned int new_pll, new_lcd_div, new_lcdpix_div; ++ unsigned int cfcr; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ if (!boot_config.lcd_clks_initialized) return; ++ ++ new_pll = __cpm_get_pllout(); ++ new_lcd_div = new_pll / boot_config.lcd_clk; ++ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; ++ ++ if (new_lcd_div < 1) ++ new_lcd_div = 1; ++ if (new_lcd_div > 16) ++ new_lcd_div = 16; ++ ++ if (new_lcdpix_div < 1) ++ new_lcdpix_div = 1; ++ if (new_lcdpix_div > 512) ++ new_lcdpix_div = 512; ++ ++ REG_CPM_CFCR2 = new_lcdpix_div - 1; ++ ++ cfcr = REG_CPM_CFCR; ++ cfcr &= ~CPM_CFCR_LFR_MASK; ++ cfcr |= ((new_lcd_div - 1) << CPM_CFCR_LFR_BIT); ++ cfcr |= CPM_CFCR_UPE; /* update immediately */ ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp)); ++} ++ ++static void jz_scale_pll(struct dpm_regs *regs) ++{ ++ unsigned int plcr1; ++ unsigned int cur_mclk, new_mclk, new_pll; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ int od[] = {1, 2, 2, 4}; ++ ++ plcr1 = REG_CPM_PLCR1; ++ plcr1 &= ~(regs->plcr1_mask | CPM_PLCR1_PLL1S | CPM_PLCR1_PLL1EN | CPM_PLCR1_PLL1ST_MASK); ++ regs->plcr1 &= ~CPM_PLCR1_PLL1EN; ++ plcr1 |= (regs->plcr1 | 0xff); ++ ++ /* Update some DRAM parameters before changing frequency */ ++ new_pll = JZ_EXTAL * ((plcr1>>23)+2) / ((((plcr1>>18)&0x1f)+2) * od[(plcr1>>16)&0x03]); ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = new_pll / div[(REG_CPM_CFCR>>16) & 0xf]; ++ ++ /* ++ * Update some SDRAM parameters ++ */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* ++ * Update PLL, align code to cache line. ++ */ ++ plcr1 |= CPM_PLCR1_PLL1EN; ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_PLCR1), "r" (plcr1)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++#endif ++ ++static void jz4730_transition(struct dpm_regs *regs) ++{ ++ /* ++ * Get and save some boot-time conditions. ++ */ ++ jz_init_boot_config(); ++ ++#ifdef CHANGE_PLL ++ /* ++ * Disable LCD before scaling pll. ++ * LCD and LCD pixel clocks should not be changed even if the PLL ++ * output frequency has been changed. ++ */ ++ REG_LCD_CTRL &= ~LCD_CTRL_ENA; ++#endif ++ /* ++ * Stop module clocks before scaling PLL ++ */ ++ __cpm_stop_eth(); ++ __cpm_stop_aic_pclk(); ++ __cpm_stop_aic_bitclk(); ++ ++ /* ... add more as necessary */ ++ ++ if (regs->pll_up_flag == PLL_GOES_UP) { ++ /* the pll frequency is going up, so change dividors first */ ++ jz_scale_divisors(regs); ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ } ++ else if (regs->pll_up_flag == PLL_GOES_DOWN) { ++ /* the pll frequency is going down, so change pll first */ ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ jz_scale_divisors(regs); ++ } ++ else { ++ /* the pll frequency is unchanged, so change divisors only */ ++ jz_scale_divisors(regs); ++ } ++ ++ /* ++ * Restart module clocks before scaling PLL ++ */ ++ __cpm_start_eth(); ++ __cpm_start_aic_pclk(); ++ __cpm_start_aic_bitclk(); ++ ++ /* ... add more as necessary */ ++ ++#ifdef CHANGE_PLL ++ /* Scale the LCD divisors after scaling pll */ ++ if (regs->pll_up_flag != PLL_UNCHANGED) { ++ jz_scale_lcd_divisors(regs); ++ } ++ ++ /* Enable LCD controller */ ++ REG_LCD_CTRL &= ~LCD_CTRL_DIS; ++ REG_LCD_CTRL |= LCD_CTRL_ENA; ++#endif ++ ++ /* Update system clocks */ ++ jz_update_clocks(); ++} ++ ++extern unsigned int idle_times; ++static unsigned int jz4730_freq_get(unsigned int cpu) ++{ ++ return (__cpm_get_iclk() / 1000); ++} ++ ++static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) ++{ ++ int n2FR[33] = { ++ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, ++ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, ++ 9 ++ }; ++ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ ++ unsigned int div_of_cclk, new_freq, i; ++ ++ regs->pll_up_flag = PLL_UNCHANGED; ++ regs->cfcr_mask = CPM_CFCR_IFR_MASK | CPM_CFCR_SFR_MASK | CPM_CFCR_PFR_MASK | CPM_CFCR_MFR_MASK; ++ ++ new_freq = jz4730_freq_table.table[index].frequency; ++ ++ do { ++ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); ++ } while (div_of_cclk==0); ++ ++ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { ++ for(i = 1; i<4; i++) { ++ div[i] = 3; ++ } ++ } else { ++ for(i = 1; i<4; i++) { ++ div[i] = 2; ++ } ++ } ++ ++ for(i = 0; i<4; i++) { ++ div[i] *= div_of_cclk; ++ } ++ ++ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); ++ ++ regs->cfcr = (n2FR[div[0]] << CPM_CFCR_IFR_BIT) | ++ (n2FR[div[1]] << CPM_CFCR_SFR_BIT) | ++ (n2FR[div[2]] << CPM_CFCR_PFR_BIT) | ++ (n2FR[div[3]] << CPM_CFCR_MFR_BIT); ++ ++ return div_of_cclk; ++} ++ ++static void jz4730_set_cpu_divider_index(unsigned int cpu, unsigned int index) ++{ ++ unsigned long divisor, old_divisor; ++ struct cpufreq_freqs freqs; ++ struct dpm_regs regs; ++ ++ old_divisor = __cpm_get_pllout() / __cpm_get_iclk(); ++ divisor = index_to_divisor(index, ®s); ++ ++ freqs.old = __cpm_get_iclk() / 1000; ++ freqs.new = __cpm_get_pllout() / (1000 * divisor); ++ freqs.cpu = cpu; ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (old_divisor != divisor) ++ jz4730_transition(®s); ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++} ++ ++static int jz4730_freq_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ unsigned int new_index = 0; ++ ++ if (cpufreq_frequency_table_target(policy, ++ &jz4730_freq_table.table[0], ++ target_freq, relation, &new_index)) ++ return -EINVAL; ++ ++ jz4730_set_cpu_divider_index(policy->cpu, new_index); ++ ++ dprintk("new frequency is %d KHz (REG_CPM_CFCR:0x%x)\n", __cpm_get_iclk() / 1000, REG_CPM_CFCR); ++ ++ return 0; ++} ++ ++static int jz4730_freq_verify(struct cpufreq_policy *policy) ++{ ++ return cpufreq_frequency_table_verify(policy, ++ &jz4730_freq_table.table[0]); ++} ++ ++static int __init jz4730_cpufreq_driver_init(struct cpufreq_policy *policy) ++{ ++ ++ struct cpufreq_frequency_table *table = &jz4730_freq_table.table[0]; ++ unsigned int MAX_FREQ; ++ ++ dprintk(KERN_INFO "Jz4730 cpufreq driver\n"); ++ ++ if (policy->cpu != 0) ++ return -EINVAL; ++ ++ policy->cur = MAX_FREQ = __cpm_get_iclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ ++ policy->cpuinfo.min_freq = MAX_FREQ/8; ++ policy->cpuinfo.max_freq = MAX_FREQ; ++ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ ++ ++ table[0].index = 0; ++ table[0].frequency = MAX_FREQ/8; ++ table[1].index = 1; ++ table[1].frequency = MAX_FREQ/6; ++ table[2].index = 2; ++ table[2].frequency = MAX_FREQ/4; ++ table[3].index = 3; ++ table[3].frequency = MAX_FREQ/3; ++ table[4].index = 4; ++ table[4].frequency = MAX_FREQ/2; ++ table[5].index = 5; ++ table[5].frequency = MAX_FREQ; ++ table[6].index = 6; ++ table[6].frequency = CPUFREQ_TABLE_END; ++ ++ return cpufreq_frequency_table_cpuinfo(policy, table); ++} ++ ++static struct cpufreq_driver cpufreq_jz4730_driver = { ++// .flags = CPUFREQ_STICKY, ++ .init = jz4730_cpufreq_driver_init, ++ .verify = jz4730_freq_verify, ++ .target = jz4730_freq_target, ++ .get = jz4730_freq_get, ++ .name = "jz4730", ++}; ++ ++static int __init jz4730_cpufreq_init(void) ++{ ++ return cpufreq_register_driver(&cpufreq_jz4730_driver); ++} ++ ++static void __exit jz4730_cpufreq_exit(void) ++{ ++ cpufreq_unregister_driver(&cpufreq_jz4730_driver); ++} ++ ++module_init(jz4730_cpufreq_init); ++module_exit(jz4730_cpufreq_exit); ++ ++MODULE_AUTHOR("Regen "); ++MODULE_DESCRIPTION("cpufreq driver for Jz4730"); ++MODULE_LICENSE("GPL"); ++ +diff --git a/arch/mips/jz4730/dma.c b/arch/mips/jz4730/dma.c +new file mode 100644 +index 0000000..ca7d549 +--- /dev/null ++++ b/arch/mips/jz4730/dma.c +@@ -0,0 +1,509 @@ ++/* ++ * linux/arch/mips/jz4730/dma.c ++ * ++ * JZ4730 DMA PC-like APIs. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * A note on resource allocation: ++ * ++ * All drivers needing DMA channels, should allocate and release them ++ * through the public routines `jz_request_dma()' and `jz_free_dma()'. ++ * ++ * In order to avoid problems, all processes should allocate resources in ++ * the same sequence and release them in the reverse order. ++ * ++ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. ++ * When releasing them, first release the IRQ, then release the DMA. The ++ * main reason for this order is that, if you are requesting the DMA buffer ++ * done interrupt, you won't know the irq number until the DMA channel is ++ * returned from jz_request_dma(). ++ */ ++ ++struct jz_dma_chan jz_dma_table[NUM_DMA] = { ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++}; ++ ++ ++// Device FIFO addresses and default DMA modes ++static const struct { ++ unsigned int fifo_addr; ++ unsigned int dma_mode; ++ unsigned int dma_source; ++} dma_dev_table[NUM_DMA_DEV] = { ++ {CPHYSADDR(UART0_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, ++ {CPHYSADDR(UART0_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, ++ {CPHYSADDR(UART1_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT}, ++ {CPHYSADDR(UART1_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART1IN}, ++ {CPHYSADDR(UART2_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT}, ++ {CPHYSADDR(UART2_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART2IN}, ++ {CPHYSADDR(UART3_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT}, ++ {CPHYSADDR(UART3_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART3IN}, ++ {CPHYSADDR(SSI_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT}, ++ {CPHYSADDR(SSI_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_SSIIN}, ++ {CPHYSADDR(MSC_TXFIFO), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT}, ++ {CPHYSADDR(MSC_RXFIFO), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_MSCIN}, ++ {CPHYSADDR(AIC_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, ++ {CPHYSADDR(AIC_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, ++ {0, DMA_AUTOINIT, 0}, ++}; ++ ++ ++int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data) ++{ ++ int i, len = 0; ++ struct jz_dma_chan *chan; ++ ++ for (i = 0; i < NUM_DMA; i++) { ++ if ((chan = get_dma_chan(i)) != NULL) { ++ len += sprintf(buf + len, "%2d: %s\n", ++ i, chan->dev_str); ++ } ++ } ++ ++ if (fpos >= len) { ++ *start = buf; ++ *eof = 1; ++ return 0; ++ } ++ *start = buf + fpos; ++ if ((len -= fpos) > length) ++ return length; ++ *eof = 1; ++ return len; ++} ++ ++ ++void dump_jz_dma_channel(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > NUM_DMA) ++ return; ++ chan = &jz_dma_table[dmanr]; ++ ++ printk(KERN_INFO "DMA%d Register Dump:\n", dmanr); ++ printk(KERN_INFO " DMACR= 0x%08x\n", REG_DMAC_DMACR); ++ printk(KERN_INFO " DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); ++ printk(KERN_INFO " DDAR = 0x%08x\n", REG_DMAC_DDAR(dmanr)); ++ printk(KERN_INFO " DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); ++ printk(KERN_INFO " DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); ++ printk(KERN_INFO " DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); ++} ++ ++ ++/** ++ * jz_request_dma - dynamically allcate an idle DMA channel to return ++ * @dev_id: the specified dma device id or DMA_ID_RAW_REQ ++ * @dev_str: the specified dma device string name ++ * @irqhandler: the irq handler, or NULL ++ * @irqflags: the irq handler flags ++ * @irq_dev_id: the irq handler device id for shared irq ++ * ++ * Finds a free channel, and binds the requested device to it. ++ * Returns the allocated channel number, or negative on error. ++ * Requests the DMA done IRQ if irqhandler != NULL. ++ * ++*/ ++int jz_request_dma(int dev_id, const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++{ ++ struct jz_dma_chan *chan; ++ int i, ret; ++ ++ if (dev_id < 0 || dev_id >= NUM_DMA_DEV) ++ return -EINVAL; ++ ++ for (i = 0; i < NUM_DMA; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == NUM_DMA) ++ return -ENODEV; ++ ++ chan = &jz_dma_table[i]; ++ ++ if (irqhandler) { ++ chan->irq = IRQ_DMA_0 + i; // see intc.h ++ chan->irq_dev = irq_dev_id; ++ if ((ret = request_irq(chan->irq, irqhandler, irqflags, ++ dev_str, chan->irq_dev))) { ++ chan->irq = 0; ++ chan->irq_dev = NULL; ++ return ret; ++ } ++ } else { ++ chan->irq = 0; ++ chan->irq_dev = NULL; ++ } ++ ++ // fill it in ++ chan->io = i; ++ chan->dev_id = dev_id; ++ chan->dev_str = dev_str; ++ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; ++ chan->mode = dma_dev_table[dev_id].dma_mode; ++ chan->source = dma_dev_table[dev_id].dma_source; ++ ++ return i; ++} ++ ++void jz_free_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) { ++ printk("Trying to free DMA%d\n", dmanr); ++ return; ++ } ++ ++ disable_dma(dmanr); ++ if (chan->irq) ++ free_irq(chan->irq, chan->irq_dev); ++ ++ chan->irq = 0; ++ chan->irq_dev = NULL; ++ chan->dev_id = -1; ++} ++ ++void jz_set_dma_dest_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ chan->mode &= ~DMAC_DCCSR_DWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCCSR_DWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCCSR_DWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCCSR_DWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_src_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ chan->mode &= ~DMAC_DCCSR_SWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCCSR_SWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCCSR_SWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCCSR_SWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_block_size(int dmanr, int nbyte) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ chan->mode &= ~DMAC_DCCSR_DS_MASK; ++ switch (nbyte) { ++ case 1: ++ chan->mode |= DMAC_DCCSR_DS_8b; ++ break; ++ case 2: ++ chan->mode |= DMAC_DCCSR_DS_16b; ++ break; ++ case 4: ++ chan->mode |= DMAC_DCCSR_DS_32b; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCCSR_DS_16B; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCCSR_DS_32B; ++ break; ++ } ++} ++ ++/** ++ * jz_set_dma_mode - do the raw settings for the specified DMA channel ++ * @dmanr: the specified DMA channel ++ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE ++ * @dma_mode: dma raw mode ++ * @dma_source: dma raw request source ++ * @fifo_addr: dma raw device fifo address ++ * ++ * Ensure call jz_request_dma(DMA_ID_RAW_REQ, ...) first, then call ++ * jz_set_dma_mode() rather than set_dma_mode() if you work with ++ * and external request dma device. ++ * ++ * NOTE: Don not dynamically allocate dma channel if one external request ++ * dma device will occupy this channel. ++*/ ++int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, ++ unsigned int dma_mode, unsigned int dma_source, ++ unsigned int fifo_addr) ++{ ++ int dev_id, i; ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > NUM_DMA) ++ return -ENODEV; ++ for (i = 0; i < NUM_DMA; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == NUM_DMA) ++ return -ENODEV; ++ ++ chan = &jz_dma_table[dmanr]; ++ dev_id = chan->dev_id; ++ if (dev_id > 0) { ++ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", ++ __FUNCTION__, dmanr); ++ return -ENODEV; ++ } ++ ++ /* clone it from the dynamically allocated. */ ++ if (i != dmanr) { ++ chan->irq = jz_dma_table[i].irq; ++ chan->irq_dev = jz_dma_table[i].irq_dev; ++ chan->dev_str = jz_dma_table[i].dev_str; ++ jz_dma_table[i].irq = 0; ++ jz_dma_table[i].irq_dev = NULL; ++ jz_dma_table[i].dev_id = -1; ++ } ++ chan->dev_id = DMA_ID_RAW_SET; ++ chan->io = dmanr; ++ chan->fifo_addr = fifo_addr; ++ chan->mode = dma_mode; ++ chan->source = dma_source; ++ ++ set_dma_mode(dmanr, dma_mode); ++ ++ return dmanr; ++} ++ ++void enable_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ __dmac_enable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_enable_irq(dmanr); ++} ++ ++#define DMA_DISABLE_POLL 0x5000 ++ ++void disable_dma(unsigned int dmanr) ++{ ++ int i; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ if (!__dmac_channel_enabled(dmanr)) ++ return; ++ ++ for (i = 0; i < DMA_DISABLE_POLL; i++) ++ if (__dmac_channel_transmit_end_detected(dmanr)) ++ break; ++#if 0 ++ if (i == DMA_DISABLE_POLL) ++ printk(KERN_INFO "disable_dma: poll expired!\n"); ++#endif ++ ++ __dmac_disable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_disable_irq(dmanr); ++} ++ ++/* note: DMA_MODE_MASK is simulated by sw, DCCSR_MODE_MASK mask hw bits */ ++void set_dma_mode(unsigned int dmanr, unsigned int mode) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); ++ mode &= DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ chan->mode |= DMAC_DCCSR_DAM; ++ chan->mode &= ~DMAC_DCCSR_SAM; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM; ++ chan->mode &= ~DMAC_DCCSR_DAM; ++ } else { ++ printk(KERN_DEBUG "set_dma_mode() support DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ } ++ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++} ++ ++void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case AFMT_U8: ++ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ ++ break; ++ case AFMT_S16_LE: ++ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCCSR_DAM; ++ chan->mode &= ~DMAC_DCCSR_SAM; ++ } else if (mode == DMA_MODE_WRITE) { ++ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM |DMAC_DCCSR_DAM); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM; ++ chan->mode &= ~DMAC_DCCSR_DAM; ++ } else ++ printk("jz_set_oss_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case 8: ++ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ ++ break; ++ case 16: ++ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCCSR_DAM; ++ chan->mode &= ~DMAC_DCCSR_SAM; ++ } else if (mode == DMA_MODE_WRITE) { ++ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM; ++ chan->mode &= ~DMAC_DCCSR_DAM; ++ } else ++ printk("jz_set_alsa_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++void set_dma_addr(unsigned int dmanr, unsigned int a) ++{ ++ unsigned int mode; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ mode = chan->mode & DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; ++ REG_DMAC_DDAR(chan->io) = a; ++ } else if (mode == DMA_MODE_WRITE) { ++ REG_DMAC_DSAR(chan->io) = a; ++ REG_DMAC_DDAR(chan->io) = chan->fifo_addr; ++ } else ++ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); ++} ++ ++void set_dma_count(unsigned int dmanr, unsigned int count) ++{ ++ unsigned int mode; ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT; ++ count = count / dma_ds[mode]; ++ REG_DMAC_DTCR(chan->io) = count; ++} ++ ++int get_dma_residue(unsigned int dmanr) ++{ ++ int count; ++ unsigned int mode; ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ ++ mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT; ++ count = REG_DMAC_DTCR(chan->io); ++ count = count * dma_ds[mode]; ++ ++ return count; ++} ++ ++EXPORT_SYMBOL(jz_dma_table); ++EXPORT_SYMBOL(jz_request_dma); ++EXPORT_SYMBOL(jz_free_dma); ++EXPORT_SYMBOL(jz_set_dma_src_width); ++EXPORT_SYMBOL(jz_set_dma_dest_width); ++EXPORT_SYMBOL(jz_set_dma_block_size); ++EXPORT_SYMBOL(jz_set_dma_mode); ++EXPORT_SYMBOL(set_dma_mode); ++EXPORT_SYMBOL(jz_set_oss_dma); ++EXPORT_SYMBOL(jz_set_alsa_dma); ++EXPORT_SYMBOL(set_dma_addr); ++EXPORT_SYMBOL(set_dma_count); ++EXPORT_SYMBOL(get_dma_residue); ++EXPORT_SYMBOL(enable_dma); ++EXPORT_SYMBOL(disable_dma); ++EXPORT_SYMBOL(dump_jz_dma_channel); +diff --git a/arch/mips/jz4730/i2c.c b/arch/mips/jz4730/i2c.c +new file mode 100644 +index 0000000..91f55a7 +--- /dev/null ++++ b/arch/mips/jz4730/i2c.c +@@ -0,0 +1,214 @@ ++/* ++ * linux/arch/mips/jz4730/i2c.c ++ * ++ * JZ4730 I2C APIs. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* I2C protocol */ ++#define I2C_READ 1 ++#define I2C_WRITE 0 ++ ++#define TIMEOUT 1000 ++ ++/* ++ * I2C bus protocol basic routines ++ */ ++static int i2c_put_data(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT * 10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (!__i2c_received_ack() && timeout) ++ timeout--; ++ ++ if (timeout) ++ return 0; ++ else ++ return -ETIMEDOUT; ++} ++ ++static int i2c_get_data(unsigned char *data, int ack) ++{ ++ int timeout = TIMEOUT*10; ++ ++ if (!ack) ++ __i2c_send_nack(); ++ else ++ __i2c_send_ack(); ++ ++ while (__i2c_check_drf() == 0 && timeout) ++ timeout--; ++ ++ if (timeout) { ++ if (!ack) ++ __i2c_send_stop(); ++ *data = __i2c_read(); ++ __i2c_clear_drf(); ++ return 0; ++ } else ++ return -ETIMEDOUT; ++} ++ ++/* ++ * I2C interface ++ */ ++void i2c_open(void) ++{ ++ __i2c_set_clk(jz_clocks.devclk, 10000); /* default 10 KHz */ ++ __i2c_enable(); ++} ++ ++void i2c_close(void) ++{ ++ udelay(300); /* wait for STOP goes over. */ ++ __i2c_disable(); ++} ++ ++void i2c_setclk(unsigned int i2cclk) ++{ ++ __i2c_set_clk(jz_clocks.devclk, i2cclk); ++} ++ ++int i2c_lseek(unsigned char device, unsigned char offset) ++{ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++ if (i2c_put_data(offset) < 0) ++ goto address_err; ++ return 0; ++ device_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++ address_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); ++ __i2c_send_stop(); ++ return -EREMOTEIO; ++} ++ ++int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int timeout = 5; ++ ++L_try_again: ++ ++ if (timeout < 0) ++ goto L_timeout; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_werr; ++ if (i2c_put_data(address) < 0) ++ goto address_err; ++ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) ++ goto device_rerr; ++ __i2c_send_ack(); /* Master sends ACK for continue reading */ ++ while (cnt) { ++ if (cnt == 1) { ++ if (i2c_get_data(buf, 0) < 0) ++ break; ++ } else { ++ if (i2c_get_data(buf, 1) < 0) ++ break; ++ } ++ cnt--; ++ buf++; ++ } ++ ++ __i2c_send_stop(); ++ return count - cnt; ++ device_rerr: ++ device_werr: ++ address_err: ++ timeout --; ++ __i2c_send_stop(); ++ goto L_try_again; ++ ++L_timeout: ++ __i2c_send_stop(); ++ printk("Read I2C device 0x%2x failed.\n", device); ++ return -ENODEV; ++} ++ ++int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int cnt_in_pg; ++ int timeout = 5; ++ unsigned char *tmpbuf; ++ unsigned char tmpaddr; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ ++ W_try_again: ++ if (timeout < 0) ++ goto W_timeout; ++ ++ cnt = count; ++ tmpbuf = (unsigned char *)buf; ++ tmpaddr = address; ++ ++ start_write_page: ++ cnt_in_pg = 0; ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ __i2c_send_stop(); ++ return count - cnt; ++ device_err: ++ address_err: ++ timeout--; ++ __i2c_send_stop(); ++ goto W_try_again; ++ ++ W_timeout: ++ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++} ++ ++EXPORT_SYMBOL(i2c_open); ++EXPORT_SYMBOL(i2c_close); ++EXPORT_SYMBOL(i2c_setclk); ++EXPORT_SYMBOL(i2c_read); ++EXPORT_SYMBOL(i2c_write); +diff --git a/arch/mips/jz4730/irq.c b/arch/mips/jz4730/irq.c +new file mode 100644 +index 0000000..658596f +--- /dev/null ++++ b/arch/mips/jz4730/irq.c +@@ -0,0 +1,266 @@ ++/* ++ * linux/arch/mips/jz4730/irq.c ++ * ++ * JZ4730 interrupt routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * INTC irq type ++ */ ++ ++static void enable_intc_irq(unsigned int irq) ++{ ++ __intc_unmask_irq(irq); ++} ++ ++static void disable_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++} ++ ++static void mask_and_ack_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++ __intc_ack_irq(irq); ++} ++ ++static void end_intc_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_intc_irq(irq); ++ } ++} ++ ++static unsigned int startup_intc_irq(unsigned int irq) ++{ ++ enable_intc_irq(irq); ++ return 0; ++} ++ ++static void shutdown_intc_irq(unsigned int irq) ++{ ++ disable_intc_irq(irq); ++} ++ ++static struct irq_chip intc_irq_type = { ++ .typename = "INTC", ++ .startup = startup_intc_irq, ++ .shutdown = shutdown_intc_irq, ++ .enable = enable_intc_irq, ++ .disable = disable_intc_irq, ++ .ack = mask_and_ack_intc_irq, ++ .end = end_intc_irq, ++}; ++ ++/* ++ * GPIO irq type ++ */ ++ ++static void enable_gpio_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if (irq < (IRQ_GPIO_0 + 32)) { ++ intc_irq = IRQ_GPIO0; ++ } ++ else if (irq < (IRQ_GPIO_0 + 64)) { ++ intc_irq = IRQ_GPIO1; ++ } ++ else if (irq < (IRQ_GPIO_0 + 96)) { ++ intc_irq = IRQ_GPIO2; ++ } ++ else { ++ intc_irq = IRQ_GPIO3; ++ } ++ ++ enable_intc_irq(intc_irq); ++ __gpio_unmask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void disable_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void mask_and_ack_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++ __gpio_ack_irq(irq - IRQ_GPIO_0); ++} ++ ++static void end_gpio_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_gpio_irq(irq); ++ } ++} ++ ++static unsigned int startup_gpio_irq(unsigned int irq) ++{ ++ enable_gpio_irq(irq); ++ return 0; ++} ++ ++static void shutdown_gpio_irq(unsigned int irq) ++{ ++ disable_gpio_irq(irq); ++} ++ ++static struct irq_chip gpio_irq_type = { ++ .typename = "GPIO", ++ .startup = startup_gpio_irq, ++ .shutdown = shutdown_gpio_irq, ++ .enable = enable_gpio_irq, ++ .disable = disable_gpio_irq, ++ .ack = mask_and_ack_gpio_irq, ++ .end = end_gpio_irq, ++}; ++ ++/* ++ * DMA irq type ++ */ ++ ++static void enable_dma_irq(unsigned int irq) ++{ ++ __intc_unmask_irq(IRQ_DMAC); ++ __dmac_channel_enable_irq(irq - IRQ_DMA_0); ++} ++ ++static void disable_dma_irq(unsigned int irq) ++{ ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void mask_and_ack_dma_irq(unsigned int irq) ++{ ++ __intc_ack_irq(IRQ_DMAC); ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void end_dma_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_dma_irq(irq); ++ } ++} ++ ++static unsigned int startup_dma_irq(unsigned int irq) ++{ ++ enable_dma_irq(irq); ++ return 0; ++} ++ ++static void shutdown_dma_irq(unsigned int irq) ++{ ++ disable_dma_irq(irq); ++} ++ ++static struct irq_chip dma_irq_type = { ++ .typename = "DMA", ++ .startup = startup_dma_irq, ++ .shutdown = shutdown_dma_irq, ++ .enable = enable_dma_irq, ++ .disable = disable_dma_irq, ++ .ack = mask_and_ack_dma_irq, ++ .end = end_dma_irq, ++}; ++ ++//---------------------------------------------------------------------- ++ ++void __init arch_init_irq(void) ++{ ++ int i; ++ ++ clear_c0_status(0xff04); /* clear ERL */ ++ set_c0_status(0x0400); /* set IP2 */ ++ ++ /* Set up INTC irq ++ */ ++ for (i = 0; i < 32; i++) { ++ disable_intc_irq(i); ++ irq_desc[i].chip = &intc_irq_type; ++ } ++ ++ /* Set up DMAC irq ++ */ ++ for (i = 0; i < NUM_DMA; i++) { ++ disable_dma_irq(IRQ_DMA_0 + i); ++ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; ++ } ++ ++ /* Set up GPIO irq ++ */ ++ for (i = 0; i < NUM_GPIO; i++) { ++ disable_gpio_irq(IRQ_GPIO_0 + i); ++ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; ++ } ++} ++ ++static int plat_real_irq(int irq) ++{ ++ switch (irq) { ++ case IRQ_GPIO0: ++ irq = __gpio_group_irq(0) + IRQ_GPIO_0; ++ break; ++ case IRQ_GPIO1: ++ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; ++ break; ++ case IRQ_GPIO2: ++ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; ++ break; ++ case IRQ_GPIO3: ++ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; ++ break; ++ case IRQ_DMAC: ++ irq = __dmac_get_irq() + IRQ_DMA_0; ++ break; ++ } ++ ++ return irq; ++} ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ int irq = 0; ++ static unsigned long intc_ipr = 0; ++ ++ intc_ipr |= REG_INTC_IPR; ++ ++ if (!intc_ipr) return; ++ ++ irq = ffs(intc_ipr) - 1; ++ intc_ipr &= ~(1< ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* OHCI (USB full speed host controller) */ ++static struct resource jz_usb_ohci_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap ++ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UHC, ++ .end = IRQ_UHC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++/* The dmamask must be set for OHCI to work */ ++static u64 ohci_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_ohci_device = { ++ .name = "jz-ohci", ++ .id = 0, ++ .dev = { ++ .dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), ++ .resource = jz_usb_ohci_resources, ++}; ++ ++/*** LCD controller ***/ ++static struct resource jz_lcd_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(LCD_BASE), ++ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_LCD, ++ .end = IRQ_LCD, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_lcd_dmamask = ~(u32)0; ++ ++static struct platform_device jz_lcd_device = { ++ .name = "jz-lcd", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_lcd_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_lcd_resources), ++ .resource = jz_lcd_resources, ++}; ++ ++/* UDC (USB gadget controller) */ ++static struct resource jz_usb_gdt_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UDC_BASE), ++ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UDC, ++ .end = IRQ_UDC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static u64 udc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_gdt_device = { ++ .name = "jz-udc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &udc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), ++ .resource = jz_usb_gdt_resources, ++}; ++ ++/** MMC/SD controller **/ ++static struct resource jz_mmc_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(MSC_BASE), ++ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_MSC, ++ .end = IRQ_MSC, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_mmc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_mmc_device = { ++ .name = "jz-mmc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_mmc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_mmc_resources), ++ .resource = jz_mmc_resources, ++}; ++ ++/* All */ ++static struct platform_device *jz_platform_devices[] __initdata = { ++ &jz_usb_ohci_device, ++ &jz_lcd_device, ++ &jz_usb_gdt_device, ++ &jz_mmc_device, ++}; ++ ++static int __init jz_platform_init(void) ++{ ++ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); ++} ++ ++arch_initcall(jz_platform_init); +diff --git a/arch/mips/jz4730/pm.c b/arch/mips/jz4730/pm.c +new file mode 100644 +index 0000000..a46e9c3 +--- /dev/null ++++ b/arch/mips/jz4730/pm.c +@@ -0,0 +1,1098 @@ ++/* ++ * linux/arch/mips/jz4730/pm.c ++ * ++ * Jz4730 Power Management Routines ++ * ++ * Copyright 2005 Ingenic Semiconductor ++ * Wei Jianli ++ * Huang Lihong ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++extern void jz_cpu_suspend(void); ++extern void jz_cpu_resume(void); ++ ++static void jz_board_pm_suspend(void); ++ ++#define SAVE(x,s) sleep_save[SLEEP_SAVE_##x] = REG##s(x) ++#define RESTORE(x,s) REG##s(x) = sleep_save[SLEEP_SAVE_##x] ++ ++/* ++ * List of global jz4730 peripheral registers to preserve. ++ * More ones like core register and general purpose register values ++ * are preserved with the stack pointer in sleep.S. ++ */ ++enum { SLEEP_SAVE_START = 0, ++ ++ /* CPM */ ++ SLEEP_SAVE_CPM_MSCR, SLEEP_SAVE_CPM_PLCR1, ++ ++ /* WDT */ ++ SLEEP_SAVE_WDT_WTCNT, SLEEP_SAVE_WDT_WTCSR, ++ ++ /* OST */ ++ SLEEP_SAVE_OST_TER, ++ SLEEP_SAVE_OST_TCSR0, SLEEP_SAVE_OST_TCSR1, SLEEP_SAVE_OST_TCSR2, ++ SLEEP_SAVE_OST_TRDR0, SLEEP_SAVE_OST_TRDR1, SLEEP_SAVE_OST_TRDR2, ++ SLEEP_SAVE_OST_TCNT0, SLEEP_SAVE_OST_TCNT1, SLEEP_SAVE_OST_TCNT2, ++ ++ /* HARB */ ++ SLEEP_SAVE_HARB_HAPOR, SLEEP_SAVE_HARB_HMCTR, SLEEP_SAVE_HARB_HMLTR, ++ ++ /* EMC */ ++ SLEEP_SAVE_EMC_SMCR0, SLEEP_SAVE_EMC_SMCR1, SLEEP_SAVE_EMC_SMCR2, SLEEP_SAVE_EMC_SMCR3, ++ SLEEP_SAVE_EMC_SMCR4, SLEEP_SAVE_EMC_SMCR5, ++ ++ /* GPIO */ ++ SLEEP_SAVE_GPIO_GPDR0, SLEEP_SAVE_GPIO_GPDR1, SLEEP_SAVE_GPIO_GPDR2, SLEEP_SAVE_GPIO_GPDR3, ++ SLEEP_SAVE_GPIO_GPDIR0, SLEEP_SAVE_GPIO_GPDIR1, SLEEP_SAVE_GPIO_GPDIR2, SLEEP_SAVE_GPIO_GPDIR3, ++ SLEEP_SAVE_GPIO_GPODR0, SLEEP_SAVE_GPIO_GPODR1, SLEEP_SAVE_GPIO_GPODR2, SLEEP_SAVE_GPIO_GPODR3, ++ SLEEP_SAVE_GPIO_GPPUR0, SLEEP_SAVE_GPIO_GPPUR1, SLEEP_SAVE_GPIO_GPPUR2, SLEEP_SAVE_GPIO_GPPUR3, ++ SLEEP_SAVE_GPIO_GPALR0, SLEEP_SAVE_GPIO_GPALR1, SLEEP_SAVE_GPIO_GPALR2, SLEEP_SAVE_GPIO_GPALR3, ++ SLEEP_SAVE_GPIO_GPAUR0, SLEEP_SAVE_GPIO_GPAUR1, SLEEP_SAVE_GPIO_GPAUR2, SLEEP_SAVE_GPIO_GPAUR3, ++ SLEEP_SAVE_GPIO_GPIDLR0, SLEEP_SAVE_GPIO_GPIDLR1, SLEEP_SAVE_GPIO_GPIDLR2, SLEEP_SAVE_GPIO_GPIDLR3, ++ SLEEP_SAVE_GPIO_GPIDUR0, SLEEP_SAVE_GPIO_GPIDUR1, SLEEP_SAVE_GPIO_GPIDUR2, SLEEP_SAVE_GPIO_GPIDUR3, ++ SLEEP_SAVE_GPIO_GPIER0, SLEEP_SAVE_GPIO_GPIER1, SLEEP_SAVE_GPIO_GPIER2, SLEEP_SAVE_GPIO_GPIER3, ++ SLEEP_SAVE_GPIO_GPIMR0, SLEEP_SAVE_GPIO_GPIMR1, SLEEP_SAVE_GPIO_GPIMR2, SLEEP_SAVE_GPIO_GPIMR3, ++ SLEEP_SAVE_GPIO_GPFR0, SLEEP_SAVE_GPIO_GPFR1, SLEEP_SAVE_GPIO_GPFR2, SLEEP_SAVE_GPIO_GPFR3, ++ ++ /* UART(0-3) */ ++ SLEEP_SAVE_UART0_IER, SLEEP_SAVE_UART0_LCR, SLEEP_SAVE_UART0_MCR, SLEEP_SAVE_UART0_SPR, SLEEP_SAVE_UART0_DLLR, SLEEP_SAVE_UART0_DLHR, ++ SLEEP_SAVE_UART1_IER, SLEEP_SAVE_UART1_LCR, SLEEP_SAVE_UART1_MCR, SLEEP_SAVE_UART1_SPR, SLEEP_SAVE_UART1_DLLR, SLEEP_SAVE_UART1_DLHR, ++ SLEEP_SAVE_UART2_IER, SLEEP_SAVE_UART2_LCR, SLEEP_SAVE_UART2_MCR, SLEEP_SAVE_UART2_SPR, SLEEP_SAVE_UART2_DLLR, SLEEP_SAVE_UART2_DLHR, ++ SLEEP_SAVE_UART3_IER, SLEEP_SAVE_UART3_LCR, SLEEP_SAVE_UART3_MCR, SLEEP_SAVE_UART3_SPR, SLEEP_SAVE_UART3_DLLR, SLEEP_SAVE_UART3_DLHR, ++ ++ /* DMAC */ ++ SLEEP_SAVE_DMAC_DMACR, ++ SLEEP_SAVE_DMAC_DSAR0, SLEEP_SAVE_DMAC_DSAR1, SLEEP_SAVE_DMAC_DSAR2, SLEEP_SAVE_DMAC_DSAR3, SLEEP_SAVE_DMAC_DSAR4, SLEEP_SAVE_DMAC_DSAR5, SLEEP_SAVE_DMAC_DSAR6, SLEEP_SAVE_DMAC_DSAR7, ++ SLEEP_SAVE_DMAC_DDAR0, SLEEP_SAVE_DMAC_DDAR1, SLEEP_SAVE_DMAC_DDAR2, SLEEP_SAVE_DMAC_DDAR3, SLEEP_SAVE_DMAC_DDAR4, SLEEP_SAVE_DMAC_DDAR5, SLEEP_SAVE_DMAC_DDAR6, SLEEP_SAVE_DMAC_DDAR7, ++ SLEEP_SAVE_DMAC_DTCR0, SLEEP_SAVE_DMAC_DTCR1, SLEEP_SAVE_DMAC_DTCR2, SLEEP_SAVE_DMAC_DTCR3, SLEEP_SAVE_DMAC_DTCR4, SLEEP_SAVE_DMAC_DTCR5, SLEEP_SAVE_DMAC_DTCR6, SLEEP_SAVE_DMAC_DTCR7, ++ SLEEP_SAVE_DMAC_DRSR0, SLEEP_SAVE_DMAC_DRSR1, SLEEP_SAVE_DMAC_DRSR2, SLEEP_SAVE_DMAC_DRSR3, SLEEP_SAVE_DMAC_DRSR4, SLEEP_SAVE_DMAC_DRSR5, SLEEP_SAVE_DMAC_DRSR6, SLEEP_SAVE_DMAC_DRSR7, ++ SLEEP_SAVE_DMAC_DCCSR0, SLEEP_SAVE_DMAC_DCCSR1, SLEEP_SAVE_DMAC_DCCSR2, SLEEP_SAVE_DMAC_DCCSR3, SLEEP_SAVE_DMAC_DCCSR4, SLEEP_SAVE_DMAC_DCCSR5, SLEEP_SAVE_DMAC_DCCSR6, SLEEP_SAVE_DMAC_DCCSR7, ++ ++ /* INTC */ ++ SLEEP_SAVE_INTC_IPR, SLEEP_SAVE_INTC_ISR, SLEEP_SAVE_INTC_IMR, ++ ++ /* Checksum */ ++ SLEEP_SAVE_CKSUM, ++ ++ SLEEP_SAVE_SIZE ++}; ++ ++static unsigned long sleep_save[SLEEP_SAVE_SIZE]; ++ ++static int jz_pm_do_suspend(void) ++{ ++ unsigned long checksum = 0; ++ unsigned long imr = REG_INTC_IMR; ++ int i; ++ ++ printk("Put cpu into suspend mode.\n"); ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* Preserve current time */ ++ REG_RTC_RSR = xtime.tv_sec; ++ ++ REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY0; /* suspend USB PHY 0 */ ++ REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY1; /* suspend USB PHY 1 */ ++ REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* select the external RTC clock (32.768KHz) */ ++ ++ /* Disable NAND ctroller */ ++ REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE); ++ ++ /* ++ * Temporary solution. This won't be necessary once ++ * we move this support into the device drivers. ++ * Save the on-chip modules ++ */ ++ SAVE(UART0_LCR, 8); SAVE(UART0_MCR, 8); SAVE(UART0_SPR, 8); ++ REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ SAVE(UART0_DLLR, 8); SAVE(UART0_DLHR, 8); ++ REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ SAVE(UART0_IER, 8); ++ ++ SAVE(UART1_LCR, 8); SAVE(UART1_MCR, 8); SAVE(UART1_SPR, 8); ++ REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ SAVE(UART1_DLLR, 8); SAVE(UART1_DLHR, 8); ++ REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ SAVE(UART1_IER, 8); ++ ++ SAVE(UART2_LCR, 8); SAVE(UART2_MCR, 8); SAVE(UART2_SPR, 8); ++ REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ SAVE(UART2_DLLR, 8); SAVE(UART2_DLHR, 8); ++ REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ SAVE(UART2_IER, 8); ++ ++ SAVE(UART3_LCR, 8); SAVE(UART3_MCR, 8); SAVE(UART3_SPR, 8); ++ REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ SAVE(UART3_DLLR, 8); SAVE(UART3_DLHR, 8); ++ REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ SAVE(UART3_IER, 8); ++ ++ /* Save vital registers */ ++ ++ SAVE(OST_TER, 8); ++ SAVE(OST_TCSR0, 16); SAVE(OST_TCSR1, 16); SAVE(OST_TCSR2, 16); ++ SAVE(OST_TRDR0, 32); SAVE(OST_TRDR1, 32); SAVE(OST_TRDR2, 32); ++ SAVE(OST_TCNT0, 32); SAVE(OST_TCNT1, 32); SAVE(OST_TCNT2, 32); ++ ++ SAVE(HARB_HAPOR, 32); SAVE(HARB_HMCTR, 32); SAVE(HARB_HMLTR, 32); ++ ++ SAVE(EMC_SMCR0, 32); SAVE(EMC_SMCR1, 32); SAVE(EMC_SMCR2, 32); SAVE(EMC_SMCR3, 32); ++ SAVE(EMC_SMCR4, 32); SAVE(EMC_SMCR5, 32); ++ ++ SAVE(GPIO_GPDR0, 32); SAVE(GPIO_GPDR1, 32); SAVE(GPIO_GPDR2, 32); ++ SAVE(GPIO_GPDR3, 32); ++ SAVE(GPIO_GPDIR0, 32); SAVE(GPIO_GPDIR1, 32); SAVE(GPIO_GPDIR2, 32); ++ SAVE(GPIO_GPDIR3, 32); ++ SAVE(GPIO_GPODR0, 32); SAVE(GPIO_GPODR1, 32); SAVE(GPIO_GPODR2, 32); ++ SAVE(GPIO_GPODR3, 32); ++ SAVE(GPIO_GPPUR0, 32); SAVE(GPIO_GPPUR1, 32); SAVE(GPIO_GPPUR2, 32); ++ SAVE(GPIO_GPPUR3, 32); ++ SAVE(GPIO_GPALR0, 32); SAVE(GPIO_GPALR1, 32); SAVE(GPIO_GPALR2, 32); ++ SAVE(GPIO_GPALR3, 32); ++ SAVE(GPIO_GPAUR0, 32); SAVE(GPIO_GPAUR1, 32); SAVE(GPIO_GPAUR2, 32); ++ SAVE(GPIO_GPAUR3, 32); ++ SAVE(GPIO_GPIDLR0, 32); SAVE(GPIO_GPIDLR1, 32); SAVE(GPIO_GPIDLR2, 32); ++ SAVE(GPIO_GPIDLR3, 32); ++ SAVE(GPIO_GPIDUR0, 32); SAVE(GPIO_GPIDUR1, 32); SAVE(GPIO_GPIDUR2, 32); ++ SAVE(GPIO_GPIDUR3, 32); ++ SAVE(GPIO_GPIER0, 32); SAVE(GPIO_GPIER1, 32); SAVE(GPIO_GPIER2, 32); ++ SAVE(GPIO_GPIER3, 32); ++ SAVE(GPIO_GPIMR0, 32); SAVE(GPIO_GPIMR1, 32); SAVE(GPIO_GPIMR2, 32); ++ SAVE(GPIO_GPIMR3, 32); ++ SAVE(GPIO_GPFR0, 32); SAVE(GPIO_GPFR1, 32); SAVE(GPIO_GPFR2, 32); ++ SAVE(GPIO_GPFR3, 32); ++ ++ SAVE(DMAC_DMACR, 32); ++ SAVE(DMAC_DSAR0, 32); SAVE(DMAC_DSAR1, 32); SAVE(DMAC_DSAR2, 32); SAVE(DMAC_DSAR3, 32); SAVE(DMAC_DSAR4, 32); SAVE(DMAC_DSAR5, 32); SAVE(DMAC_DSAR6, 32); SAVE(DMAC_DSAR7, 32); ++ SAVE(DMAC_DDAR0, 32); SAVE(DMAC_DDAR1, 32); SAVE(DMAC_DDAR2, 32); SAVE(DMAC_DDAR3, 32); SAVE(DMAC_DDAR4, 32); SAVE(DMAC_DDAR5, 32); SAVE(DMAC_DDAR6, 32); SAVE(DMAC_DDAR7, 32); ++ SAVE(DMAC_DTCR0, 32); SAVE(DMAC_DTCR1, 32); SAVE(DMAC_DTCR2, 32); SAVE(DMAC_DTCR3, 32); SAVE(DMAC_DTCR4, 32); SAVE(DMAC_DTCR5, 32); SAVE(DMAC_DTCR6, 32); SAVE(DMAC_DTCR7, 32); ++ SAVE(DMAC_DRSR0, 32); SAVE(DMAC_DRSR1, 32); SAVE(DMAC_DRSR2, 32); SAVE(DMAC_DRSR3, 32); SAVE(DMAC_DRSR4, 32); SAVE(DMAC_DRSR5, 32); SAVE(DMAC_DRSR6, 32); SAVE(DMAC_DRSR7, 32); ++ SAVE(DMAC_DCCSR0, 32); SAVE(DMAC_DCCSR1, 32); SAVE(DMAC_DCCSR2, 32); SAVE(DMAC_DCCSR3, 32); SAVE(DMAC_DCCSR4, 32); SAVE(DMAC_DCCSR5, 32); SAVE(DMAC_DCCSR6, 32); SAVE(DMAC_DCCSR7, 32); ++ ++ SAVE(INTC_IPR, 32);SAVE(INTC_ISR, 32);SAVE(INTC_IMR, 32); ++ ++ SAVE(WDT_WTCNT, 32);SAVE(WDT_WTCSR, 8); ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* Save module clocks */ ++ SAVE(CPM_MSCR, 32); ++ ++ /* Save PLL */ ++ SAVE(CPM_PLCR1, 32); ++ ++ /* Stop module clocks */ ++ __cpm_stop_uart0(); ++ __cpm_stop_uart1(); ++ __cpm_stop_uart2(); ++ __cpm_stop_uart3(); ++ __cpm_stop_uhc(); ++ __cpm_stop_udc(); ++ __cpm_stop_eth(); ++ __cpm_stop_cim(); ++ __cpm_stop_kbc(); ++ __cpm_stop_scc(); ++ __cpm_stop_ssi(); ++ __cpm_stop_ost(); ++ ++ /* platform-specific pm routine */ ++ jz_board_pm_suspend(); ++ ++ /* Clear previous reset status */ ++ REG_CPM_RSTR &= ~(CPM_RSTR_HR | CPM_RSTR_WR | CPM_RSTR_SR); ++ ++ /* Set resume return address */ ++ REG_CPM_SPR = virt_to_phys(jz_cpu_resume); ++ ++ /* Before sleeping, calculate and save a checksum */ ++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) ++ checksum += sleep_save[i]; ++ sleep_save[SLEEP_SAVE_CKSUM] = checksum; ++ ++ /* *** go zzz *** */ ++ jz_cpu_suspend(); ++#if 0 ++ /* after sleeping, validate the checksum */ ++ checksum = 0; ++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) ++ checksum += sleep_save[i]; ++ ++ /* if invalid, display message and wait for a hardware reset */ ++ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { ++ /** Add platform-specific message display codes here **/ ++ while (1); ++ } ++#endif ++ /* Restore PLL */ ++ RESTORE(CPM_PLCR1, 32); ++ ++ /* Restore module clocks */ ++ RESTORE(CPM_MSCR, 32); ++ ++ /* Ensure not to come back here if it wasn't intended */ ++ REG_CPM_SPR = 0; ++ ++ /* Restore registers */ ++ ++ RESTORE(GPIO_GPDR0, 32); RESTORE(GPIO_GPDR1, 32); RESTORE(GPIO_GPDR2, 32); ++ RESTORE(GPIO_GPDR3, 32); ++ RESTORE(GPIO_GPDIR0, 32); RESTORE(GPIO_GPDIR1, 32); RESTORE(GPIO_GPDIR2, 32); ++ RESTORE(GPIO_GPDIR3, 32); ++ RESTORE(GPIO_GPODR0, 32); RESTORE(GPIO_GPODR1, 32); RESTORE(GPIO_GPODR2, 32); ++ RESTORE(GPIO_GPODR3, 32); ++ RESTORE(GPIO_GPPUR0, 32); RESTORE(GPIO_GPPUR1, 32); RESTORE(GPIO_GPPUR2, 32); ++ RESTORE(GPIO_GPPUR3, 32); ++ RESTORE(GPIO_GPALR0, 32); RESTORE(GPIO_GPALR1, 32); RESTORE(GPIO_GPALR2, 32); ++ RESTORE(GPIO_GPALR3, 32); ++ RESTORE(GPIO_GPAUR0, 32); RESTORE(GPIO_GPAUR1, 32); RESTORE(GPIO_GPAUR2, 32); ++ RESTORE(GPIO_GPAUR3, 32); ++ RESTORE(GPIO_GPIDLR0, 32);RESTORE(GPIO_GPIDLR1, 32);RESTORE(GPIO_GPIDLR2, 32); ++ RESTORE(GPIO_GPIDLR3, 32); ++ RESTORE(GPIO_GPIDUR0, 32);RESTORE(GPIO_GPIDUR1, 32);RESTORE(GPIO_GPIDUR2, 32); ++ RESTORE(GPIO_GPIDUR3, 32); ++ RESTORE(GPIO_GPIER0, 32); RESTORE(GPIO_GPIER1, 32); RESTORE(GPIO_GPIER2, 32); ++ RESTORE(GPIO_GPIER3, 32); ++ RESTORE(GPIO_GPIMR0, 32); RESTORE(GPIO_GPIMR1, 32); RESTORE(GPIO_GPIMR2, 32); ++ RESTORE(GPIO_GPIMR3, 32); ++ RESTORE(GPIO_GPFR0, 32); RESTORE(GPIO_GPFR1, 32); RESTORE(GPIO_GPFR2, 32); ++ RESTORE(GPIO_GPFR3, 32); ++ ++ RESTORE(EMC_SMCR0, 32); RESTORE(EMC_SMCR1, 32); RESTORE(EMC_SMCR2, 32); RESTORE(EMC_SMCR3, 32); ++ RESTORE(EMC_SMCR4, 32); RESTORE(EMC_SMCR5, 32); ++ ++ RESTORE(HARB_HAPOR, 32); RESTORE(HARB_HMCTR, 32); RESTORE(HARB_HMLTR, 32); ++ ++ RESTORE(OST_TCNT0, 32); RESTORE(OST_TCNT1, 32); RESTORE(OST_TCNT2, 32); ++ RESTORE(OST_TRDR0, 32); RESTORE(OST_TRDR1, 32); RESTORE(OST_TRDR2, 32); ++ RESTORE(OST_TCSR0, 16); RESTORE(OST_TCSR1, 16); RESTORE(OST_TCSR2, 16); ++ RESTORE(OST_TER, 8); ++ ++ RESTORE(DMAC_DMACR, 32); ++ RESTORE(DMAC_DSAR0, 32); RESTORE(DMAC_DSAR1, 32); RESTORE(DMAC_DSAR2, 32); RESTORE(DMAC_DSAR3, 32); RESTORE(DMAC_DSAR4, 32); RESTORE(DMAC_DSAR5, 32); RESTORE(DMAC_DSAR6, 32); RESTORE(DMAC_DSAR7, 32); ++ RESTORE(DMAC_DDAR0, 32); RESTORE(DMAC_DDAR1, 32); RESTORE(DMAC_DDAR2, 32); RESTORE(DMAC_DDAR3, 32); RESTORE(DMAC_DDAR4, 32); RESTORE(DMAC_DDAR5, 32); RESTORE(DMAC_DDAR6, 32); RESTORE(DMAC_DDAR7, 32); ++ RESTORE(DMAC_DTCR0, 32); RESTORE(DMAC_DTCR1, 32); RESTORE(DMAC_DTCR2, 32); RESTORE(DMAC_DTCR3, 32); RESTORE(DMAC_DTCR4, 32); RESTORE(DMAC_DTCR5, 32); RESTORE(DMAC_DTCR6, 32); RESTORE(DMAC_DTCR7, 32); ++ RESTORE(DMAC_DRSR0, 32); RESTORE(DMAC_DRSR1, 32); RESTORE(DMAC_DRSR2, 32); RESTORE(DMAC_DRSR3, 32); RESTORE(DMAC_DRSR4, 32); RESTORE(DMAC_DRSR5, 32); RESTORE(DMAC_DRSR6, 32); RESTORE(DMAC_DRSR7, 32); ++ RESTORE(DMAC_DCCSR0, 32); RESTORE(DMAC_DCCSR1, 32); RESTORE(DMAC_DCCSR2, 32); RESTORE(DMAC_DCCSR3, 32); RESTORE(DMAC_DCCSR4, 32); RESTORE(DMAC_DCCSR5, 32); RESTORE(DMAC_DCCSR6, 32); RESTORE(DMAC_DCCSR7, 32); ++ ++ RESTORE(INTC_IPR, 32);RESTORE(INTC_ISR, 32);RESTORE(INTC_IMR, 32); ++ ++ REG_WDT_WTCNT = 0; RESTORE(WDT_WTCSR, 8); ++ ++ /* ++ * Temporary solution. This won't be necessary once ++ * we move this support into the device drivers. ++ * Restore the on-chip modules. ++ */ ++ ++ /* FIFO control reg, write-only */ ++ REG8(UART0_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; ++ REG8(UART1_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; ++ REG8(UART2_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; ++ REG8(UART3_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; ++ ++ REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ RESTORE(UART0_DLLR, 8); RESTORE(UART0_DLHR, 8); ++ REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ RESTORE(UART0_IER, 8); ++ RESTORE(UART0_MCR, 8); RESTORE(UART0_SPR, 8); RESTORE(UART0_LCR, 8); ++ ++ REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ RESTORE(UART1_DLLR, 8); RESTORE(UART1_DLHR, 8); ++ REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ RESTORE(UART1_IER, 8); ++ RESTORE(UART1_MCR, 8); RESTORE(UART1_SPR, 8); RESTORE(UART1_LCR, 8); ++ ++ REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ RESTORE(UART2_DLLR, 8); RESTORE(UART2_DLHR, 8); ++ REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ RESTORE(UART2_IER, 8); ++ RESTORE(UART2_MCR, 8); RESTORE(UART2_SPR, 8); RESTORE(UART2_LCR, 8); ++ ++ REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ ++ RESTORE(UART3_DLLR, 8); RESTORE(UART3_DLHR, 8); ++ REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ ++ RESTORE(UART3_IER, 8); ++ RESTORE(UART3_MCR, 8); RESTORE(UART3_SPR, 8); RESTORE(UART3_LCR, 8); ++ ++ REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY0; /* resume USB PHY 0 */ ++ REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY1; /* resume USB PHY 1 */ ++#if 0 ++ REG_CPM_OCR &= ~CPM_OCR_EXT_RTC_CLK; /* use internal RTC clock (JZ_EXTAL/128 Hz) */ ++#else ++ REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* use external RTC clock (32.768 KHz) */ ++#endif ++ ++ /* Enable NAND ctroller */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE; ++ ++ /* Restore current time */ ++ xtime.tv_sec = REG_RTC_RSR; ++ ++ /* Restore interrupts */ ++ REG_INTC_IMSR = imr; ++ REG_INTC_IMCR = ~imr; ++ ++ return 0; ++} ++ ++/* NOTES: ++ * 1: Pins that are floated (NC) should be set as input and pull-enable. ++ * 2: Pins that are pull-up or pull-down by outside should be set as input ++ * and pull-disable. ++ * 3: Pins that are connected to a chipset should be set as pull-disable. ++ */ ++static void jz_board_pm_gpio_setup(void) ++{ ++ /* CIM_D0(IN)/PULL-UP/GP0 */ ++ __gpio_as_input(0); ++ __gpio_enable_pull(0); ++ ++ /* CIM_D1(IN)/PULL-UP/GP1 */ ++ __gpio_as_input(1); ++ __gpio_enable_pull(1); ++ ++ /* CIM_D2(IN)/PULL-UP/GP2 */ ++ __gpio_as_input(2); ++ __gpio_enable_pull(2); ++ ++ /* CIM_D3(IN)/PULL-UP/GP3 */ ++ __gpio_as_input(3); ++ __gpio_enable_pull(3); ++ ++ /* CIM_D4(IN)/PULL-DOWN/GP4 */ ++ __gpio_as_input(4); ++ __gpio_enable_pull(4); ++ ++ /* CIM_D5(IN)/PULL-DOWN/GP5 */ ++ __gpio_as_input(5); ++ __gpio_enable_pull(5); ++ ++ /* CIM_D6(IN)/PULL-DOWN/GP6 */ ++ __gpio_as_input(6); ++ __gpio_enable_pull(6); ++ ++ /* CIM_D7(IN)/PULL-DOWN/GP7 */ ++ __gpio_as_input(7); ++ __gpio_enable_pull(7); ++ ++ /* CIM_VSYNC(IN)/PULL-DOWN/GP8 */ ++ __gpio_as_input(8); ++ __gpio_enable_pull(8); ++ ++ /* CIM_HSYNC(IN)/PULL-UP/GP9 */ ++ __gpio_as_input(9); ++ __gpio_enable_pull(9); ++ ++ /* CIM_PCLK(IN)/PULL-DOWN/GP10 */ ++ __gpio_as_input(10); ++ __gpio_enable_pull(10); ++ ++ /* CIM_MCLK(OUT)/PULL-DOWN/GP11 */ ++ __gpio_as_input(11); ++ __gpio_enable_pull(11); ++ ++ /* DMA_DREQ0(IN)/CHIP_MODE/PULL-UP/GP12 */ ++ __gpio_as_input(12); ++ __gpio_enable_pull(12); ++ ++ /* DMA_DACK0(OUT)/PULL-UP/GP13 */ /* GPIO13 */ ++ __gpio_as_input(13); ++ __gpio_disable_pull(13); ++ ++ /* GP14 */ ++ /* GP15 */ ++ ++ /* RXD3(IN)/PULL-UP/GP16 */ ++ __gpio_as_input(16); ++ __gpio_enable_pull(16); ++ ++ /* CTS3(IN)/PULL-UP/GP17 */ ++ __gpio_as_input(17); ++ __gpio_enable_pull(17); ++ ++ /* GP18 */ ++ /* GP19 */ ++ /* GP20 */ ++ ++ /* TXD3(OUT)/PULL-UP/GP21 */ ++ __gpio_as_input(21); ++ __gpio_enable_pull(21); ++ ++ /* GP22 */ ++ ++ /* RTS3(OUT)/PULL-UP/GP23 */ ++ __gpio_as_input(23); ++ __gpio_enable_pull(23); ++ ++ /* RXD1(IN)/PULL-UP/GP24 */ /* IR_RXD */ ++ __gpio_as_input(24); ++ __gpio_enable_pull(24); ++ ++ /* TXD1(OUT)/PULL-UP/GP25 */ /* IR_TXD */ ++ __gpio_disable_pull(25); ++ __gpio_as_output(25); ++ __cpm_set_pin(25); ++ ++ /* DMA_AEN(OUT)/PULL-UP/GP26 */ /* CIM_PWD_N */ ++ __gpio_as_input(26); ++ __gpio_disable_pull(26); ++ ++ /* DMA_EOP(OUT)/PULL-UP/GP27 */ /* SW4 */ ++ __gpio_as_input(27); ++ __gpio_disable_pull(27); ++ ++ /* USB_CLK(IN)/PULL-UP/GP28 */ ++ __gpio_as_input(28); ++ __gpio_disable_pull(28); ++ ++ /* USB_PPWR0(OUT)/PULL-UP/GP29 */ /* USB_CLK_EN */ ++ __gpio_disable_pull(29); ++ __gpio_as_output(29); ++ __cpm_clear_pin(29); /* disable USB 48MHz clock */ ++ ++ /* GP30 */ ++ /* GP31 */ ++ ++ /* PS2_KCLK(IO)/PULL-UP/GP32 */ ++ __gpio_as_input(32); ++ __gpio_enable_pull(32); ++ ++ /* PS2_KDATA(IO)/PULL-UP/GP33 */ /* CIM_RST */ ++ __gpio_as_input(33); ++ __gpio_enable_pull(33); ++ ++ /* MSC_D0(IO)/PULL-UP/GP34 */ ++ __gpio_as_input(34); ++ __gpio_disable_pull(34); ++ ++ /* MSC_D1(IO)/PULL-UP/GP35 */ ++ __gpio_as_input(35); ++ __gpio_disable_pull(35); ++ ++ /* MSC_D2(IO)/PULL-UP/GP36 */ ++ __gpio_as_input(36); ++ __gpio_disable_pull(36); ++ ++ /* MSC_D3(IO)/PULL-UP/GP37 */ ++ __gpio_as_input(37); ++ __gpio_disable_pull(37); ++ ++ /* MSC_CMD(IO)/PULL-UP/GP38 */ ++ __gpio_as_input(38); ++ __gpio_disable_pull(38); ++ ++ /* MSC_CLK(OUT)/PULL-UP/GP39 */ ++ __gpio_as_input(39); ++ __gpio_enable_pull(39); ++ ++ /* LCD_D0(OUT)/PULL-UP/GP40 */ ++ __gpio_as_input(40); ++ __gpio_enable_pull(40); ++ ++ /* LCD_D1(OUT)/PULL-UP/GP41 */ ++ __gpio_as_input(41); ++ __gpio_enable_pull(41); ++ ++ /* LCD_D2(OUT)/PULL-UP/GP42 */ ++ __gpio_as_input(42); ++ __gpio_enable_pull(42); ++ ++ /* LCD_D3(OUT)/PULL-UP/GP43 */ ++ __gpio_as_input(43); ++ __gpio_enable_pull(43); ++ ++ /* LCD_D4(OUT)/PULL-UP/GP44 */ ++ __gpio_as_input(44); ++ __gpio_enable_pull(44); ++ ++ /* LCD_D5(OUT)/PULL-UP/GP45 */ ++ __gpio_as_input(45); ++ __gpio_enable_pull(45); ++ ++ /* LCD_D6(OUT)/PULL-UP/GP46 */ ++ __gpio_as_input(46); ++ __gpio_enable_pull(46); ++ ++ /* LCD_D7(OUT)/PULL-UP/GP47 */ ++ __gpio_as_input(47); ++ __gpio_enable_pull(47); ++ ++ /* LCD_D8(OUT)/PULL-DOWN/GP48 */ ++ __gpio_as_input(48); ++ __gpio_enable_pull(48); ++ ++ /* LCD_D9(OUT)/PULL-DOWN/GP49 */ ++ __gpio_as_input(49); ++ __gpio_enable_pull(49); ++ ++ /* LCD_D10(OUT)/PULL-DOWN/GP50 */ ++ __gpio_as_input(50); ++ __gpio_enable_pull(50); ++ ++ /* LCD_D11(OUT)/PULL-DOWN/GP51 */ ++ __gpio_as_input(51); ++ __gpio_enable_pull(51); ++ ++ /* LCD_D12(OUT)/PULL-DOWN/GP52 */ ++ __gpio_as_input(52); ++ __gpio_enable_pull(52); ++ ++ /* LCD_D13(OUT)/PULL-DOWN/GP53 */ ++ __gpio_as_input(53); ++ __gpio_enable_pull(53); ++ ++ /* LCD_D14(OUT)/PULL-DOWN/GP54 */ ++ __gpio_as_input(54); ++ __gpio_enable_pull(54); ++ ++ /* LCD_D15(OUT)/PULL-DOWN/GP55 */ ++ __gpio_as_input(55); ++ __gpio_enable_pull(55); ++ ++ /* LCD_VSYNC(IN)/PULL-DOWN/GP56 */ ++ __gpio_as_input(56); ++ __gpio_enable_pull(56); ++ ++ /* LCD_HSYNC(IN)/PULL-UP/GP57 */ ++ __gpio_as_input(57); ++ __gpio_enable_pull(57); ++ ++ /* LCD_PCLK(IN)/PULL-DOWN/GP58 */ ++ __gpio_as_input(58); ++ __gpio_enable_pull(58); ++ ++ /* LCD_DE(OUT)/PULL-DOWN/GP59 */ ++ __gpio_as_input(59); ++ __gpio_enable_pull(59); ++ ++ /* LCD_SPL(OUT)/PULL-UP/GP60 */ ++ __gpio_as_input(60); ++ __gpio_disable_pull(60); ++ ++ /* LCD_CLS(OUT)/PULL-UP/GP61 */ ++ __gpio_as_input(61); ++ __gpio_disable_pull(61); ++ ++ /* LCD_PS(OUT)/PULL-UP/GP62 */ ++ __gpio_as_input(62); ++ __gpio_disable_pull(62); ++ ++ /* LCD_REV(OUT)/PULL-UP/GP63 */ ++ __gpio_as_input(63); ++ __gpio_enable_pull(63); ++ ++ /* SCC0_DAT(IO)/PULL-UP/GP64 */ /* Keypad */ ++ __gpio_as_input(64); ++ __gpio_enable_pull(64); ++ ++ /* SCC1_DAT(IO)/PULL-UP/GP65 */ /* SW5 */ ++ __gpio_as_input(65); ++ __gpio_disable_pull(65); ++ ++ /* SCC0_CLK(OUT)/PULL-UP/GP66 */ /* PW_O */ ++ __gpio_disable_pull(66); ++ __gpio_as_output(66); ++ __cpm_set_pin(66); ++ ++ /* SCC1_CLK(OUT)/PULL-UP/GP67 */ /* SW6 */ ++ __gpio_as_input(67); ++ __gpio_disable_pull(67); ++ ++ /* SYS_CLK(OUT)/PULL-UP/GP68 */ /* I2S_CLK */ ++ __gpio_disable_pull(68); ++ ++ /* ACRESET_N(OUT)/PULL-UP/GP69 */ /* AK4642 PDN */ ++ __gpio_disable_pull(69); ++ __gpio_as_output(69); ++ __cpm_clear_pin(69); ++ ++ /* SDATA_OUT(OUT)/PULL-UP/GP70 */ /* I2S_DIN */ ++ __gpio_disable_pull(70); ++ ++ /* SDATA_IN(IN)/PULL-UP/GP71 */ /* I2S_DOUT */ ++ __gpio_disable_pull(71); ++ ++ /* SSI_CLK(OUT)/PULL-UP/GP72 */ /* SSI_CLK */ ++ __gpio_as_input(72); ++ __gpio_enable_pull(72); ++ ++ /* SSI_CE1_N(OUT)/PULL-UP/GP73 */ /* SSI_CE1_N */ ++ __gpio_as_input(73); ++ __gpio_enable_pull(73); ++ ++ /* SSI_DT(OUT)/PULL-UP/GP74 */ /* SSI_DT */ ++ __gpio_as_input(74); ++ __gpio_enable_pull(74); ++ ++ /* SSI_DR(IN)/PULL-UP/GP75 */ /* SSI_DR */ ++ __gpio_as_input(75); ++ __gpio_enable_pull(75); ++ ++ /* SSI_CE2_N(OUT)/SSI_GPC/PULL-UP/GP76 */ ++ __gpio_as_input(76); ++ __gpio_enable_pull(76); ++ ++ /* BITCLK_IN(IN)/PULL-UP/GP77 */ /* I2S_BITCLK */ ++ __gpio_disable_pull(77); ++ ++ /* SYNC_IN(IN)/PULL-UP/GP78 */ /* I2S_LRCIN */ ++ __gpio_disable_pull(78); ++ ++ /* FRE_N(OUT)/PULL-UP/GP79 */ ++ __gpio_enable_pull(79); ++ __gpio_as_input(79); ++ ++ /* FWE_N(OUT)/PULL-UP/GP80 */ ++ __gpio_enable_pull(80); ++ __gpio_as_input(80); ++ ++ /* FRB_N(IN)/PULL-UP/GP81 */ ++ __gpio_enable_pull(81); ++ __gpio_as_input(81); ++ ++ /* DCS1_N(OUT)/PULL-UP/GP82 */ /* SD_WP */ ++ __gpio_as_input(82); ++ __gpio_enable_pull(82); ++ ++ /* CS1_N(OUT)/PULL-UP/GP83 */ /* JACK_PLUG */ ++ __gpio_as_input(83); ++ __gpio_disable_pull(83); ++ ++ /* CS2_N(OUT)/PULL-UP/GP84 */ /* DC_DETE */ ++ __gpio_as_input(84); ++ __gpio_disable_pull(84); ++ ++ /* CS3_N(OUT)/PULL-UP/GP85 */ /* NAND CS# */ ++ __gpio_enable_pull(85); ++ __gpio_as_input(85); ++ ++ /* CS4_N/(OUT)PULL-UP/GP86 */ /* PULL_OFF */ ++ __gpio_disable_pull(86); ++ __gpio_as_output(86); ++// __cpm_set_pin(86); ++ __cpm_clear_pin(86); ++ ++ /* CS5_N(OUT)/PULL-UP/GP87 */ /* IR_SD */ ++ __gpio_as_input(87); ++ __gpio_disable_pull(87); ++ ++ /* INPACK_N(IN)/PULL-UP/GP88 */ /* SW7 */ ++ __gpio_as_input(88); ++ __gpio_disable_pull(88); ++ ++ /* BVD2(IN)/PULL-UP/GP89 */ /* SW8 */ ++ __gpio_as_input(89); ++ __gpio_disable_pull(89); ++ ++ /* PCE1_N(OUT)/PULL-UP/GP90 */ /* SD_CD_N */ ++ __gpio_as_input(90); ++ __gpio_enable_pull(90); ++ ++ /* PSKTSEL_N(OUT)/PULL-UP/GP91 */ /* SD_VCC_3V_EN_N */ ++ __gpio_disable_pull(91); ++ __gpio_as_output(91); ++ __cpm_clear_pin(91); ++ ++ /* IOIS16_N(IN)/PULL-UP/GP92 */ /* LED_EN */ ++ __gpio_disable_pull(92); ++ __gpio_as_output(92); ++ __cpm_clear_pin(92); ++ ++ /* PCE2_N(OUT)/PULL-UP/GP93 */ /* LCD_DISP_OFF_N */ ++ __gpio_disable_pull(93); ++ __gpio_as_input(93); ++ ++ /* PWM0(OUT)/PULL-UP/GP94 */ /* LCD backlight off */ ++ __gpio_disable_pull(94); ++ __gpio_as_output(94); ++ __cpm_clear_pin(94); ++ ++ /* PWM1(OUT)/PULL-UP/GP95 */ ++ __gpio_disable_pull(95); ++ __gpio_as_output(95); ++ __cpm_clear_pin(95); ++ ++ /* PRT(OUT)/PULL-UP/GP96 */ /* RTC_IRQ */ ++ __gpio_as_input(96); ++ __gpio_disable_pull(96); ++ ++ /* PRT(OUT)/PULL-UP/GP97 */ /* PW_I */ ++ __gpio_as_input(97); ++ __gpio_disable_pull(97); ++ ++ /* PRT(OUT)/PULL-UP/GP98 */ /* Keypad */ ++ __gpio_as_input(98); ++ __gpio_disable_pull(98); ++ ++ /* PRT(OUT)/PULL-UP/GP99 */ /* Keypad */ ++ __gpio_as_input(99); ++ __gpio_disable_pull(99); ++ ++ /* PRT(OUT)/PULL-UP/GP100 */ /* Keypad */ ++ __gpio_as_input(100); ++ __gpio_disable_pull(100); ++ ++ /* PRT(OUT)/PULL-UP/GP101 */ /* Keypad */ ++ __gpio_as_input(101); ++ __gpio_disable_pull(101); ++ ++ /* PRT(OUT)/PULL-UP/GP102 */ /* Keypad */ ++ __gpio_as_input(102); ++ __gpio_disable_pull(102); ++ ++ /* PRT(OUT)/PULL-UP/GP103 */ /* Keypad */ ++ __gpio_as_input(103); ++ __gpio_enable_pull(103); ++ ++ /* PRT(OUT)/PULL-UP/GP104 */ /* Keypad */ ++ __gpio_as_input(104); ++ __gpio_enable_pull(104); ++ ++ /* PRT(OUT)/PULL-UP/GP105 */ /* Keypad */ ++ __gpio_as_input(105); ++ __gpio_enable_pull(105); ++ ++ /* PRT(OUT)/PULL-UP/GP106 */ /* 5V_ON */ ++ __gpio_disable_pull(106); ++ __gpio_as_output(106); ++ __cpm_clear_pin(106); ++ ++ /* PRT(IN)/PULL-UP/GP107 */ /* GSM_BOOT */ ++ __gpio_as_input(107); ++ __gpio_enable_pull(107); ++ ++ /* PRT(IN)/PULL-UP/GP108 */ /* GSM_RESET */ ++ __gpio_as_input(108); ++ __gpio_enable_pull(108); ++ ++ /* PRT(IN)/PULL-UP/GP109 */ /* GSM_EN */ ++ __gpio_as_input(109); ++ __gpio_enable_pull(109); ++ ++ /* PRT(IN)/PULL-UP/GP110 */ /* GSM_RING */ ++ __gpio_as_input(110); ++ __gpio_enable_pull(110); ++ ++ /* PRT(IN)/UART2_RXD/PULL-UP/GP111 */ /* Keypad */ ++ __gpio_as_input(111); ++ __gpio_enable_pull(111); ++ ++ /* MII_TX_EN(OUT)/PULL-UP/GP112 */ ++ __gpio_as_input(112); ++ __gpio_enable_pull(112); ++ ++ /* MII_RX_DV(IN)/PULL-UP/GP113 */ ++ __gpio_as_input(113); ++ __gpio_enable_pull(113); ++ ++ /* MII_RX_ER(IN)/PULL-UP/GP114 */ ++ __gpio_as_input(114); ++ __gpio_enable_pull(114); ++ ++ /* MII_COL(IN)/PULL-UP/GP115 */ ++ __gpio_as_input(115); ++ __gpio_enable_pull(115); ++ ++ /* MII_CRS(IN)/PULL-UP/GP116 */ ++ __gpio_as_input(116); ++ __gpio_enable_pull(116); ++ ++ /* MII_TXD0(OUT)/PULL-UP/GP117 */ ++ __gpio_as_input(117); ++ __gpio_enable_pull(117); ++ ++ /* MII_TXD1(OUT)/PULL-UP/GP118 */ ++ __gpio_as_input(118); ++ __gpio_enable_pull(118); ++ ++ /* MII_TXD2(OUT)/PULL-UP/GP119 */ ++ __gpio_as_input(119); ++ __gpio_enable_pull(119); ++ ++ /* MII_TXD3(OUT)/PULL-UP/GP120 */ ++ __gpio_as_input(120); ++ __gpio_enable_pull(120); ++ ++ /* MII_RXD0(IN)/PULL-UP/GP121 */ ++ __gpio_as_input(121); ++ __gpio_enable_pull(121); ++ ++ /* MII_RXD1(IN)/PULL-UP/GP122 */ ++ __gpio_as_input(122); ++ __gpio_enable_pull(122); ++ ++ /* MII_RXD2(IN)/PULL-UP/GP123 */ ++ __gpio_as_input(123); ++ __gpio_enable_pull(123); ++ ++ /* MII_RXD3(IN)/PULL-UP/GP124 */ ++ __gpio_as_input(124); ++ __gpio_enable_pull(124); ++ ++ /* UART2_TXD(OUT)/PULL-UP/GP125 */ /* CHARG_STAT */ ++ __gpio_as_output(125); ++ __gpio_disable_pull(125); ++ __cpm_clear_pin(125); ++ ++ /* UART0_RXD(IN)/PULL-UP/GP126 */ ++ __gpio_as_input(126); ++ __gpio_enable_pull(126); ++ ++ /* UART0_TXD(OUT)/PULL-UP/GP127 */ ++ __gpio_as_input(127); ++ __gpio_enable_pull(127); ++} ++ ++/* ++ * In order to save power most, all gpio pins should be put to their ++ * proper states during low power mode. ++ */ ++static void jz_board_pm_suspend(void) ++{ ++ /* Setup the state of all the GPIO pins during low-power mode */ ++ jz_board_pm_gpio_setup(); ++ ++ /* Allow next interrupts to wakeup the system. ++ */ ++ REG_CPM_WER = 0; /* Clear all first */ ++ ++ /* RTC alarm */ ++ REG_CPM_WER |= 1 << 0; ++ REG_CPM_WRER |= 1 << 0; ++ REG_CPM_WFER |= 1 << 0; ++ __gpio_as_irq_rise_edge(96); ++ ++ /* Power_I key */ ++ REG_CPM_WER |= 1 << 1; ++ REG_CPM_WRER |= 1 << 1; ++ REG_CPM_WFER |= 1 << 1; ++ __gpio_as_irq_rise_edge(97); ++ ++ /* enable INTC irq */ ++ __intc_unmask_irq(IRQ_GPIO3); ++ ++#if 0 ++ /* Enable RTC alarm */ ++ REG_CPM_WER |= CPM_WER_WERTC; ++ REG_RTC_RGR = 32767; ++ REG_RTC_RCR &= ~RTC_RCR_AE; ++ REG_RTC_RSR = 0; ++ REG_RTC_RSAR = 30; ++ REG_RTC_RCR = RTC_RCR_AE | RTC_RCR_AIE | RTC_RCR_START; ++#endif ++} ++ ++/* ++ * We don't use sleep mode of jz4730 for it has bug, the suspend mode ++ * implemented by hibernate mode is used instead of it. ++ */ ++static int jz_pm_do_sleep(void) ++{ ++ printk("It was deprecated, please use /proc/sys/pm/suspend.\n"); ++#if 0 ++ unsigned long imr = REG_INTC_IMR; ++ ++ /* Preserve current time */ ++ REG_RTC_RSR = xtime.tv_sec; ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* Just allow next interrupts to wakeup the system. ++ * Note: modify this according to your system. ++ */ ++ /* RTC alarm */ ++ __gpio_as_irq_fall_edge(96); /* GPIO 96 */ ++ ++ /* POWER_I key */ ++ __gpio_as_irq_rise_edge(97); /* GPIO 97 */ ++ ++ /* Enable INTC */ ++ __intc_unmask_irq(IRQ_GPIO3); ++ ++ /* Disable modules e.g. LCD backlight */ ++ ++ /* Stop module clocks */ ++ __cpm_stop_uhc(); ++ ++ /* Enter SLEEP mode ++ * Put SDRAM into self-refresh mode. ++ */ ++ REG_CPM_LPCR &= ~CPM_LPCR_LPM_MASK; ++ REG_CPM_LPCR |= CPM_LPCR_LPM_SLEEP; ++ ++ __asm__(".set\tmips3\n\t" ++ ".set noreorder\n\t" ++ ".align 5\n\t" ++ "wait\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ ".set\tmips0"); ++ ++ /* Restore to IDLE mode */ ++ REG_CPM_LPCR &= ~CPM_LPCR_LPM_MASK; ++ REG_CPM_LPCR |= CPM_LPCR_LPM_IDLE; ++ ++ /* Restore clock of usb host */ ++ __cpm_start_uhc(); ++ ++ /* Restore interrupts */ ++ REG_INTC_IMSR = imr; ++ REG_INTC_IMCR = ~imr; ++ ++ /* Restore current time */ ++ xtime.tv_sec = REG_RTC_RSR; ++#endif ++ return 0; ++} ++ ++#define K0BASE KSEG0 ++void jz_flush_cache_all(void) ++{ ++ unsigned long addr; ++ ++ /* Clear CP0 TagLo */ ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++ for (addr = K0BASE; addr < (K0BASE + 0x4000); addr += 32) { ++ asm volatile ( ++ ".set mips3\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips2\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ ++ asm volatile ( ++ ".set mips3\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips2\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t"::); ++ ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set mips32\n\t" ++ " mfc0 %0, $16, 7\n\t" ++ " nop\n\t" ++ " ori $0, 2\n\t" ++ " mtc0 %0, $16, 7\n\t" ++ " nop\n\t" ++ ".set mips2\n\t" ++ : ++ : "r"(addr)); ++} ++ ++/* Put CPU to HIBERNATE mode */ ++int jz_pm_suspend(void) ++{ ++ int retval; ++ ++ pm_send_all(PM_SUSPEND, (void *)3); ++ ++ retval = jz_pm_do_suspend(); ++ ++ pm_send_all(PM_RESUME, (void *)0); ++ ++ return retval; ++} ++ ++#if 0 ++/* Put CPU to SLEEP mode */ ++int jz_pm_sleep(void) ++{ ++ return jz_pm_do_sleep(); ++} ++ ++/* Put CPU to IDLE mode, used for dpm in linux 2.4 */ ++void jz_pm_idle(void) ++{ ++ local_irq_disable(); ++ if (!need_resched()) { ++ local_irq_enable(); ++ cpu_wait(); ++ } ++} ++#endif ++ ++#ifdef CONFIG_SYSCTL ++ ++/* ++ * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 ++ * when all the PM interfaces exist nicely. ++ */ ++#define CTL_PM_SUSPEND 1 ++#define CTL_PM_HIBERNATE 2 ++ ++/*---------------------------------------------------------------------------- ++ * Power Management sleep sysctl proc interface ++ * ++ * A write to /proc/sys/pm/suspend invokes this function ++ * which initiates a sleep. ++ *--------------------------------------------------------------------------*/ ++static int sysctl_jz_pm_sleep(void) ++{ ++ return jz_pm_suspend(); ++} ++ ++static struct ctl_table pm_table[] = ++{ ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "suspend", ++ .data = NULL, ++ .maxlen = 0, ++ .mode = 0600, ++ .proc_handler = &sysctl_jz_pm_sleep, ++ }, ++ { .ctl_name = 0} ++}; ++ ++static struct ctl_table pm_dir_table[] = ++{ ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "pm", ++ .mode = 0555, ++ .child = pm_table, ++ }, ++ { .ctl_name = 0} ++}; ++ ++#endif /* CONFIG_SYSCTL */ ++ ++/* ++ * Initialize power interface ++ */ ++static int __init jz_pm_init(void) ++{ ++ printk("Power Management for JZ\n"); ++ ++#ifdef CONFIG_SYSCTL ++ register_sysctl_table(pm_dir_table); ++#endif ++ ++ return 0; ++} ++ ++module_init(jz_pm_init); +diff --git a/arch/mips/jz4730/proc.c b/arch/mips/jz4730/proc.c +new file mode 100644 +index 0000000..49585bc +--- /dev/null ++++ b/arch/mips/jz4730/proc.c +@@ -0,0 +1,292 @@ ++/* ++ * linux/arch/mips/jz4730/proc.c ++ * ++ * /proc/jz/ procfs for on-chip peripherals. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct proc_dir_entry *proc_jz_root; ++ ++/* ++ * EMC Module ++ */ ++static int emc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += sprintf (page+len, "BCR: 0x%08x\n", REG_EMC_BCR); ++ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4, REG_EMC_SMCR5); ++ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4, REG_EMC_SACR5); ++ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); ++ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); ++ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); ++ len += sprintf (page+len, "DMAR(0-1): 0x%08x 0x%08x\n", REG_EMC_DMAR1, REG_EMC_DMAR2); ++ return len; ++} ++ ++/* ++ * Power Manager Module ++ */ ++static int pmc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned long lpcr = REG_CPM_LPCR; ++ unsigned long mscr = REG_CPM_MSCR; ++ ++ len += sprintf (page+len, "LPCR : 0x%08lx\n", lpcr); ++ len += sprintf (page+len, "Low Power Mode : %s\n", ++ ((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_IDLE)) ? ++ "idle" : (((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_SLEEP)) ? "sleep" : "hibernate")); ++ len += sprintf (page+len, "Doze Mode : %s\n", ++ (lpcr & CPM_LPCR_DOZE) ? "on" : "off"); ++ if (lpcr & CPM_LPCR_DOZE) ++ len += sprintf (page+len, " duty : %d\n", (int)((lpcr & CPM_LPCR_DUTY_MASK) >> CPM_LPCR_DUTY_BIT)); ++ len += sprintf (page+len, "CKO1 : %s\n", ++ (REG_CPM_CFCR & CPM_CFCR_CKOEN1) ? "enable" : "disable"); ++ len += sprintf (page+len, "UART0 : %s\n", ++ (mscr & CPM_MSCR_MSTP_UART0) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART1 : %s\n", ++ (mscr & CPM_MSCR_MSTP_UART1) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART2 : %s\n", ++ (mscr & CPM_MSCR_MSTP_UART2) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART3 : %s\n", ++ (mscr & CPM_MSCR_MSTP_UART3) ? "stopped" : "running"); ++ len += sprintf (page+len, "OST : %s\n", ++ (mscr & CPM_MSCR_MSTP_OST) ? "stopped" : "running"); ++ len += sprintf (page+len, "DMAC : %s\n", ++ (mscr & CPM_MSCR_MSTP_DMAC) ? "stopped" : "running"); ++ len += sprintf (page+len, "ETH : %s\n", ++ (mscr & CPM_MSCR_MSTP_ETH) ? "stopped" : "running"); ++ len += sprintf (page+len, "UHC/UDC : %s\n", ++ (mscr & CPM_MSCR_MSTP_UHC) ? "stopped" : "running"); ++ len += sprintf (page+len, "PWM0 : %s\n", ++ (mscr & CPM_MSCR_MSTP_PWM0) ? "stopped" : "running"); ++ len += sprintf (page+len, "PWM1 : %s\n", ++ (mscr & CPM_MSCR_MSTP_PWM1) ? "stopped" : "running"); ++ len += sprintf (page+len, "I2C : %s\n", ++ (mscr & CPM_MSCR_MSTP_I2C) ? "stopped" : "running"); ++ len += sprintf (page+len, "SSI : %s\n", ++ (mscr & CPM_MSCR_MSTP_SSI) ? "stopped" : "running"); ++ len += sprintf (page+len, "SCC : %s\n", ++ (mscr & CPM_MSCR_MSTP_SCC) ? "stopped" : "running"); ++ return len; ++} ++ ++static int pmc_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_MSCR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++/* ++ * Clock Generation Module ++ */ ++static int cgm_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned int cfcr = REG_CPM_CFCR; ++ unsigned int plcr1 = REG_CPM_PLCR1; ++ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int od[4] = {1, 2, 2, 4}; ++ ++ ++ len += sprintf (page+len, "PLCR1 : 0x%08x\n", plcr1); ++ len += sprintf (page+len, "CFCR : 0x%08x\n", cfcr); ++ len += sprintf (page+len, "PLL : %s\n", ++ (plcr1 & CPM_PLCR1_PLL1EN) ? "ON" : "OFF"); ++ len += sprintf (page+len, "NF:NR:NO : %d:%d:%d\n", ++ __cpm_plcr1_fd() + 2, ++ __cpm_plcr1_rd() + 2, ++ od[__cpm_plcr1_od()] ++ ); ++ len += sprintf (page+len, "I:S:M:P : %d:%d:%d:%d\n", ++ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT], ++ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT], ++ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT], ++ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT] ++ ); ++ len += sprintf (page+len, "PLL Freq : %d MHz\n", __cpm_get_pllout()/1000000); ++ len += sprintf (page+len, "ICLK : %d MHz\n", __cpm_get_iclk()/1000000); ++ len += sprintf (page+len, "SCLK : %d MHz\n", __cpm_get_sclk()/1000000); ++ len += sprintf (page+len, "MCLK : %d MHz\n", __cpm_get_mclk()/1000000); ++ len += sprintf (page+len, "PCLK : %d MHz\n", __cpm_get_pclk()/1000000); ++ len += sprintf (page+len, "DEVCLK : %d MHz\n", __cpm_get_devclk()/1000000); ++ len += sprintf (page+len, "RTCCLK : %d KHz\n", __cpm_get_rtcclk()/1000); ++ len += sprintf (page+len, "USBCLK : %d MHz\n", __cpm_get_usbclk()/1000000); ++#if defined(CONFIG_FB_JZ) ++ len += sprintf (page+len, "LCDCLK : %d MHz\n", __cpm_get_lcdclk()/1000000); ++ len += sprintf (page+len, "PIXCLK : %d MHz\n", __cpm_get_pixclk()/1000000); ++#endif ++ return len; ++} ++ ++static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CFCR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++/* ++ * WDT ++ */ ++static int wdt_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += sprintf (page+len, "WDT_WTCSR : 0x%08x\n", REG_WDT_WTCSR); ++ len += sprintf (page+len, "WDT_WTCNT : 0x%08x\n", REG_WDT_WTCNT); ++ ++ return len; ++} ++ ++static int wdt_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ unsigned long cnt = simple_strtoul(buffer, 0, 16); ++ ++ REG_WDT_WTCNT = cnt; ++ REG_WDT_WTCSR = WDT_WTCSR_START; ++ ++ return count; ++} ++ ++/* ++ * PWM ++ */ ++ ++static int proc_jz_pwm_read_byte(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ return sprintf (page, "0x%02x\n", REG8(data)); ++} ++ ++static int proc_jz_pwm_read_word(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ return sprintf (page, "0x%04x\n", REG16(data)); ++} ++ ++static int proc_jz_pwm_write_byte(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG8(data) = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++static int proc_jz_pwm_write_word(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG16(data) = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++#define PWM_NUM 2 ++ ++static int jz_pwm_proc_init(void) ++{ ++ struct proc_dir_entry *proc_jz_pwm, *res; ++ char name[16]; ++ unsigned char i; ++ ++ for (i = 0; i < PWM_NUM; i++) { ++ sprintf(name, "pwm%d", i); ++ proc_jz_pwm = proc_mkdir(name, proc_jz_root); ++ res = create_proc_entry("control", 0600, proc_jz_pwm); ++ if ( res) { ++ res->read_proc = proc_jz_pwm_read_byte; ++ res->write_proc = proc_jz_pwm_write_byte; ++ if (i) ++ res->data = (void * )PWM_CTR(1); ++ else ++ res->data = (void * )PWM_CTR(0); ++ } ++ res = create_proc_entry("period", 0600, proc_jz_pwm); ++ if ( res) { ++ res->read_proc = proc_jz_pwm_read_word; ++ res->write_proc = proc_jz_pwm_write_word; ++ if (i) ++ res->data = (void *)PWM_PER(1); ++ else ++ res->data = (void *)PWM_PER(0); ++ } ++ res = create_proc_entry("duty", 0600, proc_jz_pwm); ++ if ( res) { ++ res->read_proc = proc_jz_pwm_read_word; ++ res->write_proc = proc_jz_pwm_write_word; ++ if (i) ++ res->data = (void * )PWM_DUT(1); ++ else ++ res->data = (void * )PWM_DUT(0); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * /proc/jz/xxx entry ++ * ++ */ ++static int __init jz_proc_init(void) ++{ ++ struct proc_dir_entry *entry; ++ ++ /* create /proc/jz */ ++ proc_jz_root = proc_mkdir("jz", 0); ++ ++ /* create /proc/jz/emc */ ++ entry = create_proc_entry("emc", 0644, proc_jz_root); ++ if (entry) { ++ entry->read_proc = emc_read_proc; ++ entry->write_proc = NULL; ++ entry->data = NULL; ++ } ++ ++ /* create /proc/jz/pmc */ ++ entry = create_proc_entry("pmc", 0644, proc_jz_root); ++ if (entry) { ++ entry->read_proc = pmc_read_proc; ++ entry->write_proc = pmc_write_proc; ++ entry->data = NULL; ++ } ++ ++ /* create /proc/jz/cgm */ ++ entry = create_proc_entry("cgm", 0644, proc_jz_root); ++ if (entry) { ++ entry->read_proc = cgm_read_proc; ++ entry->write_proc = cgm_write_proc; ++ entry->data = NULL; ++ } ++ ++ /* create /proc/jz/wdt */ ++ entry = create_proc_entry("wdt", 0644, proc_jz_root); ++ if (entry) { ++ entry->read_proc = wdt_read_proc; ++ entry->write_proc = wdt_write_proc; ++ entry->data = NULL; ++ } ++ ++ /* PWM */ ++ jz_pwm_proc_init(); ++ ++ return 0; ++} ++ ++__initcall(jz_proc_init); +diff --git a/arch/mips/jz4730/prom.c b/arch/mips/jz4730/prom.c +new file mode 100644 +index 0000000..5a5f6b8 +--- /dev/null ++++ b/arch/mips/jz4730/prom.c +@@ -0,0 +1,198 @@ ++/* ++ * ++ * BRIEF MODULE DESCRIPTION ++ * PROM library initialisation code, supports YAMON and U-Boot. ++ * ++ * Copyright 2000, 2001, 2006 MontaVista Software Inc. ++ * Author: MontaVista Software, Inc. ++ * ppopov@mvista.com or source@mvista.com ++ * ++ * This file was derived from Carsten Langgaard's ++ * arch/mips/mips-boards/xx files. ++ * ++ * Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* #define DEBUG_CMDLINE */ ++ ++int prom_argc; ++char **prom_argv, **prom_envp; ++ ++char * prom_getcmdline(void) ++{ ++ return &(arcs_cmdline[0]); ++} ++ ++void prom_init_cmdline(void) ++{ ++ char *cp; ++ int actr; ++ ++ actr = 1; /* Always ignore argv[0] */ ++ ++ cp = &(arcs_cmdline[0]); ++ while(actr < prom_argc) { ++ strcpy(cp, prom_argv[actr]); ++ cp += strlen(prom_argv[actr]); ++ *cp++ = ' '; ++ actr++; ++ } ++ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ ++ --cp; ++ if (prom_argc > 1) ++ *cp = '\0'; ++ ++} ++ ++ ++char *prom_getenv(char *envname) ++{ ++#if 0 ++ /* ++ * Return a pointer to the given environment variable. ++ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". ++ */ ++ ++ char **env = prom_envp; ++ int i = strlen(envname); ++ int yamon = (*env && strchr(*env, '=') == NULL); ++ ++ while (*env) { ++ if (yamon) { ++ if (strcmp(envname, *env++) == 0) ++ return *env; ++ } else { ++ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') ++ return *env + i + 1; ++ } ++ env++; ++ } ++#endif ++ return NULL; ++} ++ ++inline unsigned char str2hexnum(unsigned char c) ++{ ++ if(c >= '0' && c <= '9') ++ return c - '0'; ++ if(c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if(c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return 0; /* foo */ ++} ++ ++inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for(i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= (str2hexnum(*str++)); ++ ea[i] = num; ++ } ++} ++ ++int get_ethernet_addr(char *ethernet_addr) ++{ ++ char *ethaddr_str; ++ ++ ethaddr_str = prom_getenv("ethaddr"); ++ if (!ethaddr_str) { ++ printk("ethaddr not set in boot prom\n"); ++ return -1; ++ } ++ str2eaddr(ethernet_addr, ethaddr_str); ++ ++#if 0 ++ { ++ int i; ++ ++ printk("get_ethernet_addr: "); ++ for (i=0; i<5; i++) ++ printk("%02x:", (unsigned char)*(ethernet_addr+i)); ++ printk("%02x\n", *(ethernet_addr+i)); ++ } ++#endif ++ ++ return 0; ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++void __init prom_init(void) ++{ ++ unsigned char *memsize_str; ++ unsigned long memsize; ++ ++ prom_argc = (int) fw_arg0; ++ prom_argv = (char **) fw_arg1; ++ prom_envp = (char **) fw_arg2; ++ ++ mips_machtype = MACH_INGENIC_JZ4730; ++ ++ prom_init_cmdline(); ++ memsize_str = prom_getenv("memsize"); ++ if (!memsize_str) { ++ memsize = 0x04000000; ++ } else { ++ memsize = simple_strtol(memsize_str, NULL, 0); ++ } ++ add_memory_region(0, memsize, BOOT_MEM_RAM); ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ volatile u8 *uart_lsr = (volatile u8 *)(UART3_BASE + OFF_LSR); ++ volatile u8 *uart_tdr = (volatile u8 *)(UART3_BASE + OFF_TDR); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); ++ ++ *uart_tdr = (u8)c; ++} ++ ++const char *get_system_type(void) ++{ ++ return "JZ4730"; ++} ++ ++EXPORT_SYMBOL(prom_getcmdline); ++EXPORT_SYMBOL(get_ethernet_addr); ++EXPORT_SYMBOL(str2eaddr); +diff --git a/arch/mips/jz4730/reset.c b/arch/mips/jz4730/reset.c +new file mode 100644 +index 0000000..4c9e20c +--- /dev/null ++++ b/arch/mips/jz4730/reset.c +@@ -0,0 +1,40 @@ ++/* ++ * linux/arch/mips/jz4730/reset.c ++ * ++ * JZ4730 reset routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void jz_restart(char *command) ++{ ++ __wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */ ++ __wdt_start(); ++ while (1); ++} ++ ++void jz_halt(void) ++{ ++ __wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */ ++ __wdt_start(); ++ while (1); ++} ++ ++void jz_power_off(void) ++{ ++ jz_halt(); ++} +diff --git a/arch/mips/jz4730/setup.c b/arch/mips/jz4730/setup.c +new file mode 100644 +index 0000000..4594b56 +--- /dev/null ++++ b/arch/mips/jz4730/setup.c +@@ -0,0 +1,182 @@ ++/* ++ * linux/arch/mips/jz4730/setup.c ++ * ++ * JZ4730 CPU common setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PC_KEYB ++#include ++#endif ++ ++jz_clocks_t jz_clocks; ++ ++extern char * __init prom_getcmdline(void); ++extern void __init jz_board_setup(void); ++extern void jz_restart(char *); ++extern void jz_halt(void); ++extern void jz_power_off(void); ++extern void jz_time_init(void); ++ ++static void __init sysclocks_setup(void) ++{ ++#ifndef CONFIG_JZ4730_URANUS ++ jz_clocks.iclk = __cpm_get_iclk(); ++ jz_clocks.sclk = __cpm_get_sclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.devclk = __cpm_get_devclk(); ++ jz_clocks.rtcclk = __cpm_get_rtcclk(); ++ jz_clocks.uartclk = __cpm_get_uartclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.usbclk = __cpm_get_usbclk(); ++ jz_clocks.i2sclk = __cpm_get_i2sclk(); ++ jz_clocks.mscclk = __cpm_get_mscclk(); ++#else /* URANUS FPGA */ ++ ++#define FPGACLK 8000000 ++ ++ jz_clocks.iclk = FPGACLK; ++ jz_clocks.sclk = FPGACLK; ++ jz_clocks.mclk = FPGACLK; ++ jz_clocks.devclk = FPGACLK; ++ jz_clocks.rtcclk = FPGACLK; ++ jz_clocks.uartclk = FPGACLK; ++ jz_clocks.pixclk = FPGACLK; ++ jz_clocks.lcdclk = FPGACLK; ++ jz_clocks.usbclk = FPGACLK; ++ jz_clocks.i2sclk = FPGACLK; ++ jz_clocks.mscclk = FPGACLK; ++#endif ++ ++ printk("CPU clock: %dMHz, System clock: %dMHz, Memory clock: %dMHz, Peripheral clock: %dMHz\n", ++ (jz_clocks.iclk + 500000) / 1000000, ++ (jz_clocks.sclk + 500000) / 1000000, ++ (jz_clocks.mclk + 500000) / 1000000, ++ (jz_clocks.pclk + 500000) / 1000000); ++} ++ ++static void __init soc_cpm_setup(void) ++{ ++ __cpm_idle_mode(); ++ __cpm_enable_cko1(); ++ __cpm_start_all(); ++ ++ /* get system clocks */ ++ sysclocks_setup(); ++} ++ ++static void __init soc_harb_setup(void) ++{ ++// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ ++// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ ++ __harb_set_priority(0x08); /* DMAC>LCD>CIM>ETH>USB>CIM */ ++// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ ++} ++ ++static void __init soc_emc_setup(void) ++{ ++} ++ ++static void __init soc_dmac_setup(void) ++{ ++ __dmac_enable_all_channels(); ++} ++ ++static void __init jz_soc_setup(void) ++{ ++ soc_cpm_setup(); ++ soc_harb_setup(); ++ soc_emc_setup(); ++ soc_dmac_setup(); ++} ++ ++static void __init jz_serial_setup(void) ++{ ++#ifdef CONFIG_SERIAL_8250 ++ struct uart_port s; ++ ++ memset(&s, 0, sizeof(s)); ++ ++ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; ++ s.iotype = UPIO_MEM; ++ s.regshift = 2; ++ s.uartclk = jz_clocks.uartclk; ++ ++ s.line = 0; ++ s.membase = (u8 *)UART0_BASE; ++ s.irq = IRQ_UART0; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); ++ } ++ ++ s.line = 1; ++ s.membase = (u8 *)UART1_BASE; ++ s.irq = IRQ_UART1; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); ++ } ++ ++ s.line = 2; ++ s.membase = (u8 *)UART2_BASE; ++ s.irq = IRQ_UART2; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS2 setup failed!\n"); ++ } ++ ++ s.line = 3; ++ s.membase = (u8 *)UART3_BASE; ++ s.irq = IRQ_UART3; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS3 setup failed!\n"); ++ } ++#endif ++} ++ ++void __init plat_mem_setup(void) ++{ ++ char *argptr; ++ ++ argptr = prom_getcmdline(); ++ ++ /* IO/MEM resources. */ ++ set_io_port_base(0); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ ++ _machine_restart = jz_restart; ++ _machine_halt = jz_halt; ++ pm_power_off = jz_power_off; ++ ++ jz_soc_setup(); /* soc specific setup */ ++ jz_serial_setup(); /* serial port setup */ ++ jz_board_setup(); /* board specific setup */ ++} +diff --git a/arch/mips/jz4730/sleep.S b/arch/mips/jz4730/sleep.S +new file mode 100644 +index 0000000..9ee9e70 +--- /dev/null ++++ b/arch/mips/jz4730/sleep.S +@@ -0,0 +1,307 @@ ++/* ++ * linux/arch/mips/jz4730/sleep.S ++ * ++ * jz4730 Assembler Sleep/WakeUp Management Routines ++ * ++ * Copyright (C) 2005 Ingenic Semiconductor ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++ ++ .text ++ .set noreorder ++ .set noat ++ ++ .extern jz_flush_cache_all ++ ++/* ++ * jz_cpu_suspend() ++ * ++ * Forces CPU into hibernate mode ++ */ ++ ++ .globl jz_cpu_suspend ++jz_cpu_suspend: ++ ++ /* save hi, lo and general registers except k0($26) and k1($27) (total 32) */ ++ move k0, sp ++ addiu k0, k0, -(32*4) ++ mfhi k1 ++ sw $0, 0(k0) ++ sw $1, 4(k0) ++ sw k1, 120(k0) /* hi */ ++ mflo k1 ++ sw $2, 8(k0) ++ sw $3, 12(k0) ++ sw k1, 124(k0) /* lo */ ++ sw $4, 16(k0) ++ sw $5, 20(k0) ++ sw $6, 24(k0) ++ sw $7, 28(k0) ++ sw $8, 32(k0) ++ sw $9, 36(k0) ++ sw $10, 40(k0) ++ sw $11, 44(k0) ++ sw $12, 48(k0) ++ sw $13, 52(k0) ++ sw $14, 56(k0) ++ sw $15, 60(k0) ++ sw $16, 64(k0) ++ sw $17, 68(k0) ++ sw $18, 72(k0) ++ sw $19, 76(k0) ++ sw $20, 80(k0) ++ sw $21, 84(k0) ++ sw $22, 88(k0) ++ sw $23, 92(k0) ++ sw $24, 96(k0) ++ sw $25, 100(k0) ++ sw $28, 104(k0) ++ sw $29, 108(k0) /* saved sp */ ++ sw $30, 112(k0) ++ sw $31, 116(k0) /* saved ra */ ++ move sp, k0 ++ ++ /* save CP0 registers and sp (total 26) */ ++ move k0, sp ++ addiu k0, k0, -(26*4) ++ ++ mfc0 $1, CP0_INDEX ++ mfc0 $2, CP0_RANDOM ++ mfc0 $3, CP0_ENTRYLO0 ++ mfc0 $4, CP0_ENTRYLO1 ++ mfc0 $5, CP0_CONTEXT ++ mfc0 $6, CP0_PAGEMASK ++ mfc0 $7, CP0_WIRED ++ mfc0 $8, CP0_BADVADDR ++ mfc0 $9, CP0_ENTRYHI ++ mfc0 $10, CP0_STATUS ++/* mfc0 $11, $12, 1*/ /* IntCtl */ ++ mfc0 $12, CP0_CAUSE ++ mfc0 $13, CP0_EPC ++/* mfc0 $14, $15, 1*/ /* EBase */ ++ mfc0 $15, CP0_CONFIG ++/* mfc0 $16, CP0_CONFIG, 7*/ /* Config 7 */ ++ mfc0 $17, CP0_LLADDR ++ mfc0 $18, CP0_WATCHLO ++ mfc0 $19, CP0_WATCHHI ++ mfc0 $20, CP0_DEBUG ++ mfc0 $21, CP0_DEPC ++ mfc0 $22, CP0_ECC ++ mfc0 $23, CP0_TAGLO ++ mfc0 $24, CP0_ERROREPC ++ mfc0 $25, CP0_DESAVE ++ ++ sw $1, 0(k0) ++ sw $2, 4(k0) ++ sw $3, 8(k0) ++ sw $4, 12(k0) ++ sw $5, 16(k0) ++ sw $6, 20(k0) ++ sw $7, 24(k0) ++ sw $8, 28(k0) ++ sw $9, 32(k0) ++ sw $10, 36(k0) ++ sw $11, 40(k0) ++ sw $12, 44(k0) ++ sw $13, 48(k0) ++ sw $14, 52(k0) ++ sw $15, 56(k0) ++ sw $16, 60(k0) ++ sw $17, 64(k0) ++ sw $18, 68(k0) ++ sw $19, 72(k0) ++ sw $20, 76(k0) ++ sw $21, 80(k0) ++ sw $22, 84(k0) ++ sw $23, 88(k0) ++ sw $24, 92(k0) ++ sw $25, 96(k0) ++ sw $29, 100(k0) /* saved sp */ ++ move sp, k0 ++ ++ /* preserve virtual address of stack */ ++ la k0, suspend_save_sp ++ sw sp, 0(k0) ++ ++ /* flush caches and write buffers */ ++ jal jz_flush_cache_all ++ nop ++ ++ /* set new sdram refresh constant */ ++ li t0, 1 ++ la t1, EMC_RTCOR ++ sh t0, 0(t1) ++ ++ /* disable PLL */ ++ la t0, CPM_PLCR1 ++ sw $0, 0(t0) ++ ++ /* put CPU to hibernate mode */ ++ la t0, CPM_LPCR ++ lw t1, 0(t0) ++ li t2, ~CPM_LPCR_LPM_MASK ++ and t1, t2 ++ ori t1, CPM_LPCR_LPM_HIBERNATE ++ ++ .align 5 ++ /* align execution to a cache line */ ++ j 1f ++ ++ .align 5 ++1: ++ /* all needed values are now in registers. ++ * These last instructions should be in cache ++ */ ++ nop ++ nop ++ ++ /* set hibernate mode */ ++ sw t1, 0(t0) ++ nop ++ ++ /* enter hibernate mode */ ++ .set mips3 ++ wait ++ nop ++ .set mips2 ++ ++2: j 2b /* loop waiting for suspended */ ++ nop ++ ++/* ++ * jz_cpu_resume() ++ * ++ * entry point from bootloader into kernel during resume ++ */ ++ ++ .align 5 ++ .globl jz_cpu_resume ++jz_cpu_resume: ++ /* clear SCR.HGP */ ++ la t0, CPM_SCR ++ lw t1, 0(t0) ++ li t2, ~CPM_SCR_HGP ++ and t1, t2 ++ sw t1, 0(t0) ++ ++ /* restore LPCR.LPM to IDLE mode */ ++ la t0, CPM_LPCR ++ lw t1, 0(t0) ++ li t2, ~CPM_LPCR_LPM_MASK ++ and t1, t2 ++ ori t1, CPM_LPCR_LPM_IDLE ++ sw t1, 0(t0) ++ ++ /* restore saved sp */ ++ la t0, suspend_save_sp ++ lw sp, 0(t0) ++ ++ /* restore CP0 registers */ ++ move k0, sp ++ lw $1, 0(k0) ++ lw $2, 4(k0) ++ lw $3, 8(k0) ++ lw $4, 12(k0) ++ lw $5, 16(k0) ++ lw $6, 20(k0) ++ lw $7, 24(k0) ++ lw $8, 28(k0) ++ lw $9, 32(k0) ++ lw $10, 36(k0) ++ lw $11, 40(k0) ++ lw $12, 44(k0) ++ lw $13, 48(k0) ++ lw $14, 52(k0) ++ lw $15, 56(k0) ++ lw $16, 60(k0) ++ lw $17, 64(k0) ++ lw $18, 68(k0) ++ lw $19, 72(k0) ++ lw $20, 76(k0) ++ lw $21, 80(k0) ++ lw $22, 84(k0) ++ lw $23, 88(k0) ++ lw $24, 92(k0) ++ lw $25, 96(k0) ++ lw $29, 100(k0) /* saved sp */ ++ ++ mtc0 $1, CP0_INDEX ++ mtc0 $2, CP0_RANDOM ++ mtc0 $3, CP0_ENTRYLO0 ++ mtc0 $4, CP0_ENTRYLO1 ++ mtc0 $5, CP0_CONTEXT ++ mtc0 $6, CP0_PAGEMASK ++ mtc0 $7, CP0_WIRED ++ mtc0 $8, CP0_BADVADDR ++ mtc0 $9, CP0_ENTRYHI ++ mtc0 $10, CP0_STATUS ++/* mtc0 $11, $12, 1*/ /* IntCtl */ ++ mtc0 $12, CP0_CAUSE ++ mtc0 $13, CP0_EPC ++/* mtc0 $14, $15, 1*/ /* EBase */ ++ mtc0 $15, CP0_CONFIG ++/* mtc0 $16, CP0_CONFIG, 7*/ /* Config 7 */ ++ mtc0 $17, CP0_LLADDR ++ mtc0 $18, CP0_WATCHLO ++ mtc0 $19, CP0_WATCHHI ++ mtc0 $20, CP0_DEBUG ++ mtc0 $21, CP0_DEPC ++ mtc0 $22, CP0_ECC ++ mtc0 $23, CP0_TAGLO ++ mtc0 $24, CP0_ERROREPC ++ mtc0 $25, CP0_DESAVE ++ ++ /* restore general registers */ ++ move k0, sp ++ lw k1, 120(k0) /* hi */ ++ lw $0, 0(k0) ++ lw $1, 4(k0) ++ mthi k1 ++ lw k1, 124(k0) /* lo */ ++ lw $2, 8(k0) ++ lw $3, 12(k0) ++ mtlo k1 ++ lw $4, 16(k0) ++ lw $5, 20(k0) ++ lw $6, 24(k0) ++ lw $7, 28(k0) ++ lw $8, 32(k0) ++ lw $9, 36(k0) ++ lw $10, 40(k0) ++ lw $11, 44(k0) ++ lw $12, 48(k0) ++ lw $13, 52(k0) ++ lw $14, 56(k0) ++ lw $15, 60(k0) ++ lw $16, 64(k0) ++ lw $17, 68(k0) ++ lw $18, 72(k0) ++ lw $19, 76(k0) ++ lw $20, 80(k0) ++ lw $21, 84(k0) ++ lw $22, 88(k0) ++ lw $23, 92(k0) ++ lw $24, 96(k0) ++ lw $25, 100(k0) ++ lw $28, 104(k0) ++ lw $29, 108(k0) /* saved sp */ ++ lw $30, 112(k0) ++ lw $31, 116(k0) /* saved ra */ ++ ++ /* return to caller */ ++ jr ra ++ nop ++ ++suspend_save_sp: ++ .word 0 /* preserve sp here */ ++ ++ .set reorder +diff --git a/arch/mips/jz4730/time.c b/arch/mips/jz4730/time.c +new file mode 100644 +index 0000000..806c7fe +--- /dev/null ++++ b/arch/mips/jz4730/time.c +@@ -0,0 +1,129 @@ ++/* ++ * linux/arch/mips/jz4730/time.c ++ * ++ * Setting up the clock on the JZ4730 boards. ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define JZ_TIMER_CHAN 0 ++#define JZ_TIMER_IRQ IRQ_OST0 ++#define JZ_TIMER_CLOCK JZ_EXTAL ++ ++static unsigned int timer_latch; ++ ++void (*jz_timer_callback)(void); ++ ++static void jz_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ break; ++ } ++} ++ ++static struct clock_event_device jz_clockevent_device = { ++ .name = "jz-timer", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++ ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ ++ .rating = 300, ++ .irq = JZ_TIMER_IRQ, ++ .set_mode = jz_set_mode, ++}; ++ ++static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ ++ __ost_clear_uf(JZ_TIMER_CHAN); /* ACK timer */ ++ ++ if (jz_timer_callback) ++ jz_timer_callback(); ++ ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction jz_irqaction = { ++ .handler = jz_timer_interrupt, ++ .flags = IRQF_DISABLED | IRQF_PERCPU, ++ .name = "jz-timer", ++}; ++ ++cycle_t jz_get_cycles(void) ++{ ++ unsigned int jz_timer_cnt; ++#if 0 /* clock source use pll, read directly */ ++ jz_timer_cnt = timer_latch - REG_OST_TCNT(JZ_TIMER_CHAN); ++#else /* clock source use RTCClock or Extall Clock, wait read ready */ ++ jz_timer_cnt = REG_OST_TCNT(JZ_TIMER_CHAN); /* dummy read */ ++ while ( __ost_is_busy(JZ_TIMER_CHAN) ) ; /* wait read ready */ ++ jz_timer_cnt = timer_latch - REG_OST_TCRB(JZ_TIMER_CHAN); ++#endif ++ ++ /* convert jiffes to jz timer cycles */ ++ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + jz_timer_cnt); ++} ++ ++static struct clocksource clocksource_jz = { ++ .name = "jz_clocksource", ++ .rating = 300, ++ .read = jz_get_cycles, ++ .mask = 0xFFFFFFFF, ++ .shift = 10, /* control clocksource.mult's accuracy */ ++ .flags = CLOCK_SOURCE_WATCHDOG, ++}; ++ ++static int __init jz_clocksource_init(void) ++{ ++ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); ++ clocksource_register(&clocksource_jz); ++ return 0; ++} ++ ++static void __init jz_timer_setup(void) ++{ ++ struct clock_event_device *cd = &jz_clockevent_device; ++ struct irqaction *action = &jz_irqaction; ++ unsigned int cpu = smp_processor_id(); ++ ++ jz_clocksource_init(); ++ cd->cpumask = cpumask_of_cpu(cpu); ++ clockevents_register_device(cd); ++ action->dev_id = cd; ++ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); ++} ++ ++void __init plat_time_init(void) ++{ ++ /* Init timer, timer clock soure use extal clock */ ++ timer_latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ; ++ __ost_set_mode(JZ_TIMER_CHAN, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL); ++ __ost_set_reload(JZ_TIMER_CHAN, timer_latch); ++ __ost_set_count(JZ_TIMER_CHAN, timer_latch); ++ __ost_enable_channel(JZ_TIMER_CHAN); ++ ++ jz_timer_setup(); ++} +diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile +new file mode 100644 +index 0000000..d32e7d0 +--- /dev/null ++++ b/arch/mips/jz4740/Makefile +@@ -0,0 +1,27 @@ ++# ++# 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 ++obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o ++ ++# PM support ++ ++obj-$(CONFIG_PM_LEGACY) +=pm.o ++ ++# CPU Frequency scaling support ++ ++obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o +diff --git a/arch/mips/jz4740/board-dipper.c b/arch/mips/jz4740/board-dipper.c +new file mode 100644 +index 0000000..ca30225 +--- /dev/null ++++ b/arch/mips/jz4740/board-dipper.c +@@ -0,0 +1,117 @@ ++/* ++ * linux/arch/mips/jz4740/board-dipper.c ++ * ++ * JZ4725 Dipper board setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++#if 0 ++static void dancing(void) ++{ ++ static unsigned int count = 0; ++ ++ count ++; ++ count &= 1; ++ ++ if (count) ++ __gpio_set_pin(GPIO_LED_EN); ++ else ++ __gpio_clear_pin(GPIO_LED_EN); ++} ++#endif ++ ++static void dipper_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++// dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4740/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Most of the GPIO pins should have been initialized by the boot-loader ++ */ ++ ++ /* ++ * Initialize MSC pins ++ */ ++ __gpio_as_msc(); ++ ++ /* ++ * Initialize Smart LCD pins ++ */ ++// __gpio_as_slcd_18bit(); ++ ++ /* ++ * Initialize SSI pins ++ */ ++ __gpio_as_ssi(); ++ ++ /* ++ * Initialize I2C pins ++ */ ++ __gpio_as_i2c(); ++ ++ /* ++ * Initialize Other pins ++ */ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); ++ ++ __gpio_as_input(GPIO_SD_CD_N); ++ __gpio_disable_pull(GPIO_SD_CD_N); ++ ++ __gpio_as_input(GPIO_SD_WP); ++ __gpio_disable_pull(GPIO_SD_WP); ++ ++ __gpio_as_input(GPIO_DC_DETE_N); ++ __gpio_as_input(GPIO_CHARG_STAT_N); ++ __gpio_as_input(GPIO_USB_DETE); ++ ++ __gpio_as_output(GPIO_DISP_OFF_N); ++ ++// __gpio_as_output(GPIO_LED_EN); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4725 DIPPER board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = dipper_timer_callback; ++} +diff --git a/arch/mips/jz4740/board-leo.c b/arch/mips/jz4740/board-leo.c +new file mode 100644 +index 0000000..912636a +--- /dev/null ++++ b/arch/mips/jz4740/board-leo.c +@@ -0,0 +1,67 @@ ++/* ++ * linux/arch/mips/jz4740/board-leo.c ++ * ++ * JZ4740 LEO board setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned char slash[] = "\\|/-"; ++ static volatile unsigned char *p = (unsigned char *)0xb6000016; ++ static unsigned int count = 0; ++ *p = slash[count++]; ++ count &= 3; ++} ++ ++static void leo_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 10 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4740/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* All GPIO pins should have been initialized by the boot-loader */ ++} ++ ++void __init jz_board_setup(void) ++{ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ printk(" BOARD SETUP"); ++ jz_timer_callback = leo_timer_callback; ++} +diff --git a/arch/mips/jz4740/board-lyra.c b/arch/mips/jz4740/board-lyra.c +new file mode 100644 +index 0000000..ea56626 +--- /dev/null ++++ b/arch/mips/jz4740/board-lyra.c +@@ -0,0 +1,114 @@ ++/* ++ * linux/arch/mips/jz4740/board-lyra.c ++ * ++ * JZ4740 LYRA board setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned int count = 0; ++ ++ count ++; ++ count &= 1; ++ if (count) ++ __gpio_set_pin(GPIO_LED_EN); ++ else ++ __gpio_clear_pin(GPIO_LED_EN); ++} ++ ++static void lyra_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4740/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Most of the GPIO pins should have been initialized by the boot-loader ++ */ ++ ++ /* ++ * Initialize MSC pins ++ */ ++ __gpio_as_msc(); ++ ++ /* ++ * Initialize LCD pins ++ */ ++ __gpio_as_lcd_18bit(); ++ ++ /* ++ * Initialize SSI pins ++ */ ++ __gpio_as_ssi(); ++ ++ /* ++ * Initialize I2C pins ++ */ ++ __gpio_as_i2c(); ++ ++ /* ++ * Initialize Other pins ++ */ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); ++ ++ __gpio_as_input(GPIO_SD_CD_N); ++ __gpio_disable_pull(GPIO_SD_CD_N); ++ ++ __gpio_as_input(GPIO_SD_WP); ++ __gpio_disable_pull(GPIO_SD_WP); ++ ++ __gpio_as_input(GPIO_DC_DETE_N); ++ __gpio_as_input(GPIO_CHARG_STAT_N); ++ __gpio_as_input(GPIO_USB_DETE); ++ ++ __gpio_as_output(GPIO_DISP_OFF_N); ++ ++ __gpio_as_output(GPIO_LED_EN); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4740 LYRA board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = lyra_timer_callback; ++} +diff --git a/arch/mips/jz4740/board-pavo.c b/arch/mips/jz4740/board-pavo.c +new file mode 100644 +index 0000000..e2a5509 +--- /dev/null ++++ b/arch/mips/jz4740/board-pavo.c +@@ -0,0 +1,114 @@ ++/* ++ * linux/arch/mips/jz4740/board-pavo.c ++ * ++ * JZ4740 PAVO board setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned int count = 0; ++ ++ count ++; ++ count &= 1; ++ if (count) ++ __gpio_set_pin(GPIO_LED_EN); ++ else ++ __gpio_clear_pin(GPIO_LED_EN); ++} ++ ++static void pavo_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4740/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Most of the GPIO pins should have been initialized by the boot-loader ++ */ ++ ++ /* ++ * Initialize MSC pins ++ */ ++ __gpio_as_msc(); ++ ++ /* ++ * Initialize LCD pins ++ */ ++ __gpio_as_lcd_18bit(); ++ ++ /* ++ * Initialize SSI pins ++ */ ++ __gpio_as_ssi(); ++ ++ /* ++ * Initialize I2C pins ++ */ ++ __gpio_as_i2c(); ++ ++ /* ++ * Initialize Other pins ++ */ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); ++ ++ __gpio_as_input(GPIO_SD_CD_N); ++ __gpio_disable_pull(GPIO_SD_CD_N); ++ ++ __gpio_as_input(GPIO_SD_WP); ++ __gpio_disable_pull(GPIO_SD_WP); ++ ++ __gpio_as_input(GPIO_DC_DETE_N); ++ __gpio_as_input(GPIO_CHARG_STAT_N); ++ __gpio_as_input(GPIO_USB_DETE); ++ ++ __gpio_as_output(GPIO_DISP_OFF_N); ++ ++ __gpio_as_output(GPIO_LED_EN); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4740 PAVO board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = pavo_timer_callback; ++} +diff --git a/arch/mips/jz4740/board-virgo.c b/arch/mips/jz4740/board-virgo.c +new file mode 100644 +index 0000000..1429877 +--- /dev/null ++++ b/arch/mips/jz4740/board-virgo.c +@@ -0,0 +1,114 @@ ++/* ++ * linux/arch/mips/jz4740/board-virgo.c ++ * ++ * JZ4720 VIRGO board setup routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned int count = 0; ++ ++ count ++; ++ count &= 1; ++ if (count) ++ __gpio_set_pin(GPIO_LED_EN); ++ else ++ __gpio_clear_pin(GPIO_LED_EN); ++} ++ ++static void virgo_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4740/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Most of the GPIO pins should have been initialized by the boot-loader ++ */ ++ ++ /* ++ * Initialize MSC pins ++ */ ++ __gpio_as_msc(); ++ ++ /* ++ * Initialize LCD pins ++ */ ++// __gpio_as_lcd_18bit(); ++ ++ /* ++ * Initialize SSI pins ++ */ ++ __gpio_as_ssi(); ++ ++ /* ++ * Initialize I2C pins ++ */ ++ __gpio_as_i2c(); ++ ++ /* ++ * Initialize Other pins ++ */ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); ++ ++ __gpio_as_input(GPIO_SD_CD_N); ++ __gpio_disable_pull(GPIO_SD_CD_N); ++ ++// __gpio_as_input(GPIO_SD_WP); ++// __gpio_disable_pull(GPIO_SD_WP); ++ ++ __gpio_as_input(GPIO_DC_DETE_N); ++// __gpio_as_input(GPIO_CHARG_STAT_N); ++ __gpio_as_input(GPIO_USB_DETE); ++ ++ __gpio_as_output(GPIO_DISP_OFF_N); ++ ++// __gpio_as_output(GPIO_LED_EN); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4720 VIRGO board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = virgo_timer_callback; ++} +diff --git a/arch/mips/jz4740/cpufreq.c b/arch/mips/jz4740/cpufreq.c +new file mode 100644 +index 0000000..d646a1e +--- /dev/null ++++ b/arch/mips/jz4740/cpufreq.c +@@ -0,0 +1,602 @@ ++/* ++ * linux/arch/mips/jz4740/cpufreq.c ++ * ++ * cpufreq driver for JZ4740 ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ ++ "cpufreq-jz4740", msg) ++ ++#undef CHANGE_PLL ++ ++#define PLL_UNCHANGED 0 ++#define PLL_GOES_UP 1 ++#define PLL_GOES_DOWN 2 ++ ++#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) ++ ++/* Saved the boot-time parameters */ ++static struct { ++ /* SDRAM parameters */ ++ unsigned int mclk; /* memory clock, KHz */ ++ unsigned int tras; /* RAS pulse width, cycles of mclk */ ++ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ ++ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ ++ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ ++ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ ++ unsigned int rtcor; /* Refresh Time Constant */ ++ unsigned int sdram_initialized; ++ ++ /* LCD parameters */ ++ unsigned int lcd_clk; /* LCD clock, Hz */ ++ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ ++ unsigned int lcd_clks_initialized; ++} boot_config; ++ ++struct jz4740_freq_percpu_info { ++ struct cpufreq_frequency_table table[7]; ++}; ++ ++static struct jz4740_freq_percpu_info jz4740_freq_table; ++ ++/* ++ * This contains the registers value for an operating point. ++ * If only part of a register needs to change then there is ++ * a mask value for that register. ++ * When going to a new operating point the current register ++ * value is ANDed with the ~mask and ORed with the new value. ++ */ ++struct dpm_regs { ++ u32 cpccr; /* Clock Freq Control Register */ ++ u32 cpccr_mask; /* Clock Freq Control Register mask */ ++ u32 cppcr; /* PLL1 Control Register */ ++ u32 cppcr_mask; /* PLL1 Control Register mask */ ++ u32 pll_up_flag; /* New PLL freq is higher than current or not */ ++}; ++ ++extern jz_clocks_t jz_clocks; ++ ++static void jz_update_clocks(void) ++{ ++ /* Next clocks must be updated if we have changed ++ * the PLL or divisors. ++ */ ++ jz_clocks.cclk = __cpm_get_cclk(); ++ jz_clocks.hclk = __cpm_get_hclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.i2sclk = __cpm_get_i2sclk(); ++ jz_clocks.usbclk = __cpm_get_usbclk(); ++ jz_clocks.mscclk = __cpm_get_mscclk(); ++} ++ ++static void ++jz_init_boot_config(void) ++{ ++ if (!boot_config.lcd_clks_initialized) { ++ /* the first time to scale pll */ ++ boot_config.lcd_clk = __cpm_get_lcdclk(); ++ boot_config.lcdpix_clk = __cpm_get_pixclk(); ++ boot_config.lcd_clks_initialized = 1; ++ } ++ ++ if (!boot_config.sdram_initialized) { ++ /* the first time to scale frequencies */ ++ unsigned int dmcr, rtcor; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ ++ dmcr = REG_EMC_DMCR; ++ rtcor = REG_EMC_RTCOR; ++ ++ tras = (dmcr >> 13) & 0x7; ++ rcd = (dmcr >> 11) & 0x3; ++ tpc = (dmcr >> 8) & 0x7; ++ trwl = (dmcr >> 5) & 0x3; ++ trc = (dmcr >> 2) & 0x7; ++ ++ boot_config.mclk = __cpm_get_mclk() / 1000; ++ boot_config.tras = tras + 4; ++ boot_config.rcd = rcd + 1; ++ boot_config.tpc = tpc + 1; ++ boot_config.trwl = trwl + 1; ++ boot_config.trc = trc * 2 + 1; ++ boot_config.rtcor = rtcor; ++ ++ boot_config.sdram_initialized = 1; ++ } ++} ++ ++static void jz_update_dram_rtcor(unsigned int new_mclk) ++{ ++ unsigned int rtcor; ++ ++ new_mclk /= 1000; ++ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; ++ rtcor--; ++ ++ if (rtcor < 1) rtcor = 1; ++ if (rtcor > 255) rtcor = 255; ++ ++ REG_EMC_RTCOR = rtcor; ++ REG_EMC_RTCNT = rtcor; ++} ++ ++static void jz_update_dram_dmcr(unsigned int new_mclk) ++{ ++ unsigned int dmcr; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ unsigned int valid_time, new_time; /* ns */ ++ ++ new_mclk /= 1000; ++ tras = boot_config.tras * new_mclk / boot_config.mclk; ++ rcd = boot_config.rcd * new_mclk / boot_config.mclk; ++ tpc = boot_config.tpc * new_mclk / boot_config.mclk; ++ trwl = boot_config.trwl * new_mclk / boot_config.mclk; ++ trc = boot_config.trc * new_mclk / boot_config.mclk; ++ ++ /* Validation checking */ ++ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; ++ new_time = (tras * 1000000) / new_mclk; ++ if (new_time < valid_time) tras += 1; ++ ++ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; ++ new_time = (rcd * 1000000) / new_mclk; ++ if (new_time < valid_time) rcd += 1; ++ ++ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; ++ new_time = (tpc * 1000000) / new_mclk; ++ if (new_time < valid_time) tpc += 1; ++ ++ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; ++ new_time = (trwl * 1000000) / new_mclk; ++ if (new_time < valid_time) trwl += 1; ++ ++ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; ++ new_time = (trc * 1000000) / new_mclk; ++ if (new_time < valid_time) trc += 2; ++ ++ tras = (tras < 4) ? 4: tras; ++ tras = (tras > 11) ? 11: tras; ++ tras -= 4; ++ ++ rcd = (rcd < 1) ? 1: rcd; ++ rcd = (rcd > 4) ? 4: rcd; ++ rcd -= 1; ++ ++ tpc = (tpc < 1) ? 1: tpc; ++ tpc = (tpc > 8) ? 8: tpc; ++ tpc -= 1; ++ ++ trwl = (trwl < 1) ? 1: trwl; ++ trwl = (trwl > 4) ? 4: trwl; ++ trwl -= 1; ++ ++ trc = (trc < 1) ? 1: trc; ++ trc = (trc > 15) ? 15: trc; ++ trc /= 2; ++ ++ dmcr = REG_EMC_DMCR; ++ ++ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); ++ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); ++ ++ REG_EMC_DMCR = dmcr; ++} ++ ++static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR before changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } else { ++ /* We're going SLOWER: first update RTCOR value ++ * before changing the frequency. ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } ++} ++ ++static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so update RTCOR ++ * after changing the frequency ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } else { ++ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR after changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } ++} ++ ++static void jz_scale_divisors(struct dpm_regs *regs) ++{ ++ unsigned int cpccr; ++ unsigned int cur_mclk, new_mclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ cpccr = REG_CPM_CPCCR; ++ cpccr &= ~((unsigned long)regs->cpccr_mask); ++ cpccr |= regs->cpccr; ++ cpccr |= CPM_CPCCR_CE; /* update immediately */ ++ ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; ++ ++ /* Update some DRAM parameters before changing frequency */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++ ++#ifdef CHANGE_PLL ++/* Maintain the LCD clock and pixel clock */ ++static void jz_scale_lcd_divisors(struct dpm_regs *regs) ++{ ++ unsigned int new_pll, new_lcd_div, new_lcdpix_div; ++ unsigned int cpccr; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ if (!boot_config.lcd_clks_initialized) return; ++ ++ new_pll = __cpm_get_pllout(); ++ new_lcd_div = new_pll / boot_config.lcd_clk; ++ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; ++ ++ if (new_lcd_div < 1) ++ new_lcd_div = 1; ++ if (new_lcd_div > 16) ++ new_lcd_div = 16; ++ ++ if (new_lcdpix_div < 1) ++ new_lcdpix_div = 1; ++ if (new_lcdpix_div > 512) ++ new_lcdpix_div = 512; ++ ++// REG_CPM_CPCCR2 = new_lcdpix_div - 1; ++ ++ cpccr = REG_CPM_CPCCR; ++ cpccr &= ~CPM_CPCCR_LDIV_MASK; ++ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); ++ cpccr |= CPM_CPCCR_CE; /* update immediately */ ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); ++} ++ ++static void jz_scale_pll(struct dpm_regs *regs) ++{ ++ unsigned int cppcr; ++ unsigned int cur_mclk, new_mclk, new_pll; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ int od[] = {1, 2, 2, 4}; ++ ++ cppcr = REG_CPM_CPPCR; ++ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); ++ regs->cppcr &= ~CPM_CPPCR_PLLEN; ++ cppcr |= (regs->cppcr | 0xff); ++ ++ /* Update some DRAM parameters before changing frequency */ ++ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = new_pll / div[(REG_CPM_CPCCR>>CPM_CPCCR_MDIV_BIT) & 0xf]; ++ ++ /* ++ * Update some SDRAM parameters ++ */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* ++ * Update PLL, align code to cache line. ++ */ ++ cppcr |= CPM_CPPCR_PLLEN; ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPPCR), "r" (cppcr)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++#endif ++ ++static void jz4740_transition(struct dpm_regs *regs) ++{ ++ /* ++ * Get and save some boot-time conditions. ++ */ ++ jz_init_boot_config(); ++ ++#ifdef CHANGE_PLL ++ /* ++ * Disable LCD before scaling pll. ++ * LCD and LCD pixel clocks should not be changed even if the PLL ++ * output frequency has been changed. ++ */ ++ REG_LCD_CTRL &= ~LCD_CTRL_ENA; ++ ++ /* ++ * Stop module clocks before scaling PLL ++ */ ++ __cpm_stop_eth(); ++ __cpm_stop_aic(1); ++ __cpm_stop_aic(2); ++#endif ++ ++ /* ... add more as necessary */ ++ ++ if (regs->pll_up_flag == PLL_GOES_UP) { ++ /* the pll frequency is going up, so change dividors first */ ++ jz_scale_divisors(regs); ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ } ++ else if (regs->pll_up_flag == PLL_GOES_DOWN) { ++ /* the pll frequency is going down, so change pll first */ ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ jz_scale_divisors(regs); ++ } ++ else { ++ /* the pll frequency is unchanged, so change divisors only */ ++ jz_scale_divisors(regs); ++ } ++ ++#ifdef CHANGE_PLL ++ /* ++ * Restart module clocks before scaling PLL ++ */ ++ __cpm_start_eth(); ++ __cpm_start_aic(1); ++ __cpm_start_aic(2); ++ ++ /* ... add more as necessary */ ++ ++ /* Scale the LCD divisors after scaling pll */ ++ if (regs->pll_up_flag != PLL_UNCHANGED) { ++ jz_scale_lcd_divisors(regs); ++ } ++ ++ /* Enable LCD controller */ ++ REG_LCD_CTRL &= ~LCD_CTRL_DIS; ++ REG_LCD_CTRL |= LCD_CTRL_ENA; ++#endif ++ ++ /* Update system clocks */ ++ jz_update_clocks(); ++} ++ ++extern unsigned int idle_times; ++static unsigned int jz4740_freq_get(unsigned int cpu) ++{ ++ return (__cpm_get_cclk() / 1000); ++} ++ ++static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) ++{ ++ int n2FR[33] = { ++ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, ++ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, ++ 9 ++ }; ++ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ ++ unsigned int div_of_cclk, new_freq, i; ++ ++ regs->pll_up_flag = PLL_UNCHANGED; ++ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; ++ ++ new_freq = jz4740_freq_table.table[index].frequency; ++ ++ do { ++ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); ++ } while (div_of_cclk==0); ++ ++ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { ++ for(i = 1; i<4; i++) { ++ div[i] = 3; ++ } ++ } else { ++ for(i = 1; i<4; i++) { ++ div[i] = 2; ++ } ++ } ++ ++ for(i = 0; i<4; i++) { ++ div[i] *= div_of_cclk; ++ } ++ ++ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); ++ ++ regs->cpccr = ++ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | ++ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | ++ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | ++ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); ++ ++ return div_of_cclk; ++} ++ ++static void jz4740_set_cpu_divider_index(unsigned int cpu, unsigned int index) ++{ ++ unsigned long divisor, old_divisor; ++ struct cpufreq_freqs freqs; ++ struct dpm_regs regs; ++ ++ old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); ++ divisor = index_to_divisor(index, ®s); ++ ++ freqs.old = __cpm_get_cclk() / 1000; ++ freqs.new = __cpm_get_pllout() / (1000 * divisor); ++ freqs.cpu = cpu; ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (old_divisor != divisor) ++ jz4740_transition(®s); ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++} ++ ++static int jz4740_freq_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ unsigned int new_index = 0; ++ ++ if (cpufreq_frequency_table_target(policy, ++ &jz4740_freq_table.table[0], ++ target_freq, relation, &new_index)) ++ return -EINVAL; ++ ++ jz4740_set_cpu_divider_index(policy->cpu, new_index); ++ ++ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); ++ ++ return 0; ++} ++ ++static int jz4740_freq_verify(struct cpufreq_policy *policy) ++{ ++ return cpufreq_frequency_table_verify(policy, ++ &jz4740_freq_table.table[0]); ++} ++ ++static int __init jz4740_cpufreq_driver_init(struct cpufreq_policy *policy) ++{ ++ ++ struct cpufreq_frequency_table *table = &jz4740_freq_table.table[0]; ++ unsigned int MAX_FREQ; ++ ++ dprintk(KERN_INFO "Jz4740 cpufreq driver\n"); ++ ++ if (policy->cpu != 0) ++ return -EINVAL; ++ ++ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ ++ policy->cpuinfo.min_freq = MAX_FREQ/8; ++ policy->cpuinfo.max_freq = MAX_FREQ; ++ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ ++ ++ table[0].index = 0; ++ table[0].frequency = MAX_FREQ/8; ++ table[1].index = 1; ++ table[1].frequency = MAX_FREQ/6; ++ table[2].index = 2; ++ table[2].frequency = MAX_FREQ/4; ++ table[3].index = 3; ++ table[3].frequency = MAX_FREQ/3; ++ table[4].index = 4; ++ table[4].frequency = MAX_FREQ/2; ++ table[5].index = 5; ++ table[5].frequency = MAX_FREQ; ++ table[6].index = 6; ++ table[6].frequency = CPUFREQ_TABLE_END; ++ ++#ifdef CONFIG_CPU_FREQ_STAT_DETAILS ++ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ ++#endif ++ ++ return cpufreq_frequency_table_cpuinfo(policy, table); ++} ++ ++static struct cpufreq_driver cpufreq_jz4740_driver = { ++// .flags = CPUFREQ_STICKY, ++ .init = jz4740_cpufreq_driver_init, ++ .verify = jz4740_freq_verify, ++ .target = jz4740_freq_target, ++ .get = jz4740_freq_get, ++ .name = "jz4740", ++}; ++ ++static int __init jz4740_cpufreq_init(void) ++{ ++ return cpufreq_register_driver(&cpufreq_jz4740_driver); ++} ++ ++static void __exit jz4740_cpufreq_exit(void) ++{ ++ cpufreq_unregister_driver(&cpufreq_jz4740_driver); ++} ++ ++module_init(jz4740_cpufreq_init); ++module_exit(jz4740_cpufreq_exit); ++ ++MODULE_AUTHOR("Regen "); ++MODULE_DESCRIPTION("cpufreq driver for Jz4740"); ++MODULE_LICENSE("GPL"); ++ +diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c +new file mode 100644 +index 0000000..dd5055e +--- /dev/null ++++ b/arch/mips/jz4740/dma.c +@@ -0,0 +1,768 @@ ++/* ++ * linux/arch/mips/jz4740/dma.c ++ * ++ * Support functions for the JZ4740 internal DMA channels. ++ * No-descriptor transfer only. ++ * Descriptor transfer should also call jz_request_dma() to get a free ++ * channel and call jz_free_dma() to free the channel. And driver should ++ * build the DMA descriptor and setup the DMA channel by itself. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * A note on resource allocation: ++ * ++ * All drivers needing DMA channels, should allocate and release them ++ * through the public routines `jz_request_dma()' and `jz_free_dma()'. ++ * ++ * In order to avoid problems, all processes should allocate resources in ++ * the same sequence and release them in the reverse order. ++ * ++ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. ++ * When releasing them, first release the IRQ, then release the DMA. The ++ * main reason for this order is that, if you are requesting the DMA buffer ++ * done interrupt, you won't know the irq number until the DMA channel is ++ * returned from jz_request_dma(). ++ */ ++ ++struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++ {dev_id:-1,}, ++}; ++ ++// Device FIFO addresses and default DMA modes ++static const struct { ++ unsigned int fifo_addr; ++ unsigned int dma_mode; ++ unsigned int dma_source; ++} dma_dev_table[DMA_ID_MAX] = { ++ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, ++ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, ++ {CPHYSADDR(SSI_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT}, ++ {CPHYSADDR(SSI_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSIIN}, ++ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, ++ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, ++ {CPHYSADDR(MSC_TXFIFO), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT}, ++ {CPHYSADDR(MSC_RXFIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSCIN}, ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, ++ {}, ++}; ++ ++ ++int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data) ++{ ++ int i, len = 0; ++ struct jz_dma_chan *chan; ++ ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if ((chan = get_dma_chan(i)) != NULL) { ++ len += sprintf(buf + len, "%2d: %s\n", ++ i, chan->dev_str); ++ } ++ } ++ ++ if (fpos >= len) { ++ *start = buf; ++ *eof = 1; ++ return 0; ++ } ++ *start = buf + fpos; ++ if ((len -= fpos) > length) ++ return length; ++ *eof = 1; ++ return len; ++} ++ ++ ++void dump_jz_dma_channel(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > MAX_DMA_NUM) ++ return; ++ chan = &jz_dma_table[dmanr]; ++ ++ printk("DMA%d Registers:\n", dmanr); ++ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR); ++ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); ++ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); ++ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); ++ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); ++ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); ++ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); ++ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); ++ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR); ++} ++ ++ ++/** ++ * jz_request_dma - dynamically allcate an idle DMA channel to return ++ * @dev_id: the specified dma device id or DMA_ID_RAW_SET ++ * @dev_str: the specified dma device string name ++ * @irqhandler: the irq handler, or NULL ++ * @irqflags: the irq handler flags ++ * @irq_dev_id: the irq handler device id for shared irq ++ * ++ * Finds a free channel, and binds the requested device to it. ++ * Returns the allocated channel number, or negative on error. ++ * Requests the DMA done IRQ if irqhandler != NULL. ++ * ++*/ ++/*int jz_request_dma(int dev_id, const char *dev_str, ++ void (*irqhandler)(int, void *, struct pt_regs *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++*/ ++ ++int jz_request_dma(int dev_id, const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++{ ++ struct jz_dma_chan *chan; ++ int i, ret; ++ ++ if (dev_id < 0 || dev_id >= DMA_ID_MAX) ++ return -EINVAL; ++ ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == MAX_DMA_NUM) /* no free channel */ ++ return -ENODEV; ++ ++ /* we got a free channel */ ++ chan = &jz_dma_table[i]; ++ ++ if (irqhandler) { ++ chan->irq = IRQ_DMA_0 + i; // allocate irq number ++ chan->irq_dev = irq_dev_id; ++ if ((ret = request_irq(chan->irq, irqhandler, irqflags, ++ dev_str, chan->irq_dev))) { ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ return ret; ++ } ++ } else { ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ } ++ ++ // fill it in ++ chan->io = i; ++ chan->dev_id = dev_id; ++ chan->dev_str = dev_str; ++ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; ++ chan->mode = dma_dev_table[dev_id].dma_mode; ++ chan->source = dma_dev_table[dev_id].dma_source; ++ ++ return i; ++} ++ ++void jz_free_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) { ++ printk("Trying to free DMA%d\n", dmanr); ++ return; ++ } ++ ++ disable_dma(dmanr); ++ if (chan->irq) ++ free_irq(chan->irq, chan->irq_dev); ++ ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ chan->dev_id = -1; ++} ++ ++void jz_set_dma_dest_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_DWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCMD_DWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_DWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_DWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_src_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_SWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCMD_SWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_SWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_SWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_block_size(int dmanr, int nbyte) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_DS_MASK; ++ switch (nbyte) { ++ case 1: ++ chan->mode |= DMAC_DCMD_DS_8BIT; ++ break; ++ case 2: ++ chan->mode |= DMAC_DCMD_DS_16BIT; ++ break; ++ case 4: ++ chan->mode |= DMAC_DCMD_DS_32BIT; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_DS_16BYTE; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_DS_32BYTE; ++ break; ++ } ++} ++ ++unsigned int jz_get_dma_command(int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ return chan->mode; ++} ++ ++/** ++ * jz_set_dma_mode - do the raw settings for the specified DMA channel ++ * @dmanr: the specified DMA channel ++ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE ++ * @dma_mode: dma raw mode ++ * @dma_source: dma raw request source ++ * @fifo_addr: dma raw device fifo address ++ * ++ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call ++ * jz_set_dma_mode() rather than set_dma_mode() if you work with ++ * and external request dma device. ++ * ++ * NOTE: Don not dynamically allocate dma channel if one external request ++ * dma device will occupy this channel. ++*/ ++int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, ++ unsigned int dma_mode, unsigned int dma_source, ++ unsigned int fifo_addr) ++{ ++ int dev_id, i; ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > MAX_DMA_NUM) ++ return -ENODEV; ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == MAX_DMA_NUM) ++ return -ENODEV; ++ ++ chan = &jz_dma_table[dmanr]; ++ dev_id = chan->dev_id; ++ if (dev_id > 0) { ++ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", ++ __FUNCTION__, dmanr); ++ return -ENODEV; ++ } ++ ++ /* clone it from the dynamically allocated. */ ++ if (i != dmanr) { ++ chan->irq = jz_dma_table[i].irq; ++ chan->irq_dev = jz_dma_table[i].irq_dev; ++ chan->dev_str = jz_dma_table[i].dev_str; ++ jz_dma_table[i].irq = 0; ++ jz_dma_table[i].irq_dev = NULL; ++ jz_dma_table[i].dev_id = -1; ++ } ++ chan->dev_id = DMA_ID_RAW_SET; ++ chan->io = dmanr; ++ chan->fifo_addr = fifo_addr; ++ chan->mode = dma_mode; ++ chan->source = dma_source; ++ ++ set_dma_mode(dmanr, dma_mode); ++ ++ return dmanr; ++} ++ ++void enable_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ ++ __dmac_enable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_enable_irq(dmanr); ++} ++ ++#define DMA_DISABLE_POLL 0x10000 ++ ++void disable_dma(unsigned int dmanr) ++{ ++ int i; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ if (!__dmac_channel_enabled(dmanr)) ++ return; ++ ++ for (i = 0; i < DMA_DISABLE_POLL; i++) ++ if (__dmac_channel_transmit_end_detected(dmanr)) ++ break; ++#if 0 ++ if (i == DMA_DISABLE_POLL) ++ printk(KERN_INFO "disable_dma: poll expired!\n"); ++#endif ++ ++ __dmac_disable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_disable_irq(dmanr); ++} ++ ++/* Note: DMA_MODE_MASK is simulated by sw */ ++void set_dma_mode(unsigned int dmanr, unsigned int mode) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else { ++ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ } ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++} ++ ++void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) ++{ ++ unsigned int mode; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ mode = chan->mode & DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; ++ REG_DMAC_DTAR(chan->io) = phyaddr; ++ } else if (mode == DMA_MODE_WRITE) { ++ REG_DMAC_DSAR(chan->io) = phyaddr; ++ REG_DMAC_DTAR(chan->io) = chan->fifo_addr; ++ } else ++ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); ++} ++ ++void set_dma_count(unsigned int dmanr, unsigned int bytecnt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ unsigned int ds; ++ ++ if (!chan) ++ return; ++ ++ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; ++ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count ++} ++ ++unsigned int get_dma_residue(unsigned int dmanr) ++{ ++ unsigned int count, ds; ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ ++ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; ++ count = REG_DMAC_DTCR(chan->io); ++ count = count * dma_ds[ds]; ++ ++ return count; ++} ++ ++void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case AFMT_U8: ++ /* burst mode : 32BIT */ ++ break; ++ case AFMT_S16_LE: ++ /* burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else ++ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case 8: ++ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ ++ break; ++ case 16: ++ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else ++ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++#undef JZ4740_DMAC_TEST_ENABLE ++ ++#ifdef JZ4740_DMAC_TEST_ENABLE ++ ++/* ++ * DMA test: external address <--> external address ++ */ ++#define TEST_DMA_SIZE 16*1024 ++ ++static jz_dma_desc *dma_desc; ++ ++static int dma_chan; ++static dma_addr_t dma_desc_phys_addr; ++static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; ++ ++static int dma_check_result(void *src, void *dst, int size) ++{ ++ unsigned int addr1, addr2, i, err = 0; ++ ++ addr1 = (unsigned int)src; ++ addr2 = (unsigned int)dst; ++ ++ for (i = 0; i < size; i += 4) { ++ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { ++ err++; ++ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); ++ } ++ addr1 += 4; ++ addr2 += 4; ++ } ++ printk("check DMA result err=%d\n", err); ++ return err; ++} ++ ++static void jz4740_dma_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ printk("jz4740_dma_irq %d\n", irq); ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ ++ if (__dmac_channel_transmit_halt_detected(dma_chan)) { ++ printk("DMA HALT\n"); ++ __dmac_channel_clear_transmit_halt(dma_chan); ++ } ++ ++ if (__dmac_channel_address_error_detected(dma_chan)) { ++ printk("DMA ADDR ERROR\n"); ++ __dmac_channel_clear_address_error(dma_chan); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { ++ printk("DMA DESC INVALID\n"); ++ __dmac_channel_clear_descriptor_invalid(dma_chan); ++ } ++ ++ if (__dmac_channel_count_terminated_detected(dma_chan)) { ++ printk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(dma_chan); ++ } ++ ++ if (__dmac_channel_transmit_end_detected(dma_chan)) { ++ printk("DMA TT\n"); ++ __dmac_channel_clear_transmit_end(dma_chan); ++ dump_jz_dma_channel(dma_chan); ++ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); ++ } ++ ++ /* free buffers */ ++ printk("free DMA buffers\n"); ++ free_pages(dma_src_addr, 2); ++ free_pages(dma_dst_addr, 2); ++ ++ if (dma_desc) ++ free_pages((unsigned int)dma_desc, 0); ++ ++ /* free dma */ ++ jz_free_dma(dma_chan); ++} ++ ++void dma_nodesc_test(void) ++{ ++ unsigned int addr, i; ++ ++ printk("dma_nodesc_test\n"); ++ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq, ++ SA_INTERRUPT, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq failed\n"); ++ return; ++ } ++ ++ printk("Requested DMA channel = %d\n", dma_chan); ++ ++ /* Allocate DMA buffers */ ++ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ ++ dma_src_phys_addr = CPHYSADDR(dma_src_addr); ++ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); ++ ++ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); ++ ++ /* Prepare data for source buffer */ ++ addr = (unsigned int)dma_src_addr; ++ for (i = 0; i < TEST_DMA_SIZE; i += 4) { ++ *(volatile unsigned int *)addr = addr; ++ addr += 4; ++ } ++ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); ++ ++ /* Init target buffer */ ++ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); ++ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); ++ ++ /* Init DMA module */ ++ printk("Starting DMA\n"); ++ REG_DMAC_DMACR = 0; ++ REG_DMAC_DCCSR(dma_chan) = 0; ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = 512; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); ++} ++ ++void dma_desc_test(void) ++{ ++ unsigned int next, addr, i; ++ static jz_dma_desc *desc; ++ ++ printk("dma_desc_test\n"); ++ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq, ++ SA_INTERRUPT, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq failed\n"); ++ return; ++ } ++ ++ printk("Requested DMA channel = %d\n", dma_chan); ++ ++ /* Allocate DMA buffers */ ++ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ ++ dma_src_phys_addr = CPHYSADDR(dma_src_addr); ++ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); ++ ++ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); ++ ++ /* Prepare data for source buffer */ ++ addr = (unsigned int)dma_src_addr; ++ for (i = 0; i < TEST_DMA_SIZE; i += 4) { ++ *(volatile unsigned int *)addr = addr; ++ addr += 4; ++ } ++ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); ++ ++ /* Init target buffer */ ++ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); ++ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); ++ ++ /* Allocate DMA descriptors */ ++ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); ++ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); ++ ++ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); ++ ++ /* Setup DMA descriptors */ ++ desc = dma_desc; ++ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr; /* DMA target address */ ++ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ ++ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ ++ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; ++ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ ++ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ ++ ++ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; ++ ++ /* DMA doorbell set -- start DMA now ... */ ++ REG_DMAC_DMADBSR = 1 << dma_chan; ++ ++ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); ++} ++ ++#endif ++ ++//EXPORT_SYMBOL_NOVERS(jz_dma_table); ++EXPORT_SYMBOL(jz_dma_table); ++EXPORT_SYMBOL(jz_request_dma); ++EXPORT_SYMBOL(jz_free_dma); ++EXPORT_SYMBOL(jz_set_dma_src_width); ++EXPORT_SYMBOL(jz_set_dma_dest_width); ++EXPORT_SYMBOL(jz_set_dma_block_size); ++EXPORT_SYMBOL(jz_set_dma_mode); ++EXPORT_SYMBOL(set_dma_mode); ++EXPORT_SYMBOL(jz_set_oss_dma); ++EXPORT_SYMBOL(jz_set_alsa_dma); ++EXPORT_SYMBOL(set_dma_addr); ++EXPORT_SYMBOL(set_dma_count); ++EXPORT_SYMBOL(get_dma_residue); ++EXPORT_SYMBOL(enable_dma); ++EXPORT_SYMBOL(disable_dma); ++EXPORT_SYMBOL(dump_jz_dma_channel); +diff --git a/arch/mips/jz4740/i2c.c b/arch/mips/jz4740/i2c.c +new file mode 100644 +index 0000000..3080fdf +--- /dev/null ++++ b/arch/mips/jz4740/i2c.c +@@ -0,0 +1,273 @@ ++/* ++ * linux/arch/mips/jz4740/i2c.c ++ * ++ * Jz4740 I2C routines. ++ * ++ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* I2C protocol */ ++#define I2C_READ 1 ++#define I2C_WRITE 0 ++ ++#define TIMEOUT 1000 ++ ++/* ++ * I2C bus protocol basic routines ++ */ ++static int i2c_put_data(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (!__i2c_received_ack() && timeout) ++ timeout--; ++ ++ if (timeout) ++ return 0; ++ else ++ return -ETIMEDOUT; ++} ++ ++#ifdef CONFIG_JZ_TPANEL_ATA2508 ++static int i2c_put_data_nack(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (timeout--); ++ return 0; ++} ++#endif ++ ++static int i2c_get_data(unsigned char *data, int ack) ++{ ++ int timeout = TIMEOUT*10; ++ ++ if (!ack) ++ __i2c_send_nack(); ++ else ++ __i2c_send_ack(); ++ ++ while (__i2c_check_drf() == 0 && timeout) ++ timeout--; ++ ++ if (timeout) { ++ if (!ack) ++ __i2c_send_stop(); ++ *data = __i2c_read(); ++ __i2c_clear_drf(); ++ return 0; ++ } else ++ return -ETIMEDOUT; ++} ++ ++/* ++ * I2C interface ++ */ ++void i2c_open(void) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ ++ __i2c_enable(); ++} ++ ++void i2c_close(void) ++{ ++ udelay(300); /* wait for STOP goes over. */ ++ __i2c_disable(); ++} ++ ++void i2c_setclk(unsigned int i2cclk) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, i2cclk); ++} ++ ++int i2c_lseek(unsigned char device, unsigned char offset) ++{ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++ if (i2c_put_data(offset) < 0) ++ goto address_err; ++ return 0; ++ device_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++ address_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); ++ __i2c_send_stop(); ++ return -EREMOTEIO; ++} ++ ++int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int timeout = 5; ++ ++L_try_again: ++ ++ if (timeout < 0) ++ goto L_timeout; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_werr; ++ if (i2c_put_data(address) < 0) ++ goto address_err; ++ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) ++ goto device_rerr; ++ __i2c_send_ack(); /* Master sends ACK for continue reading */ ++ while (cnt) { ++ if (cnt == 1) { ++ if (i2c_get_data(buf, 0) < 0) ++ break; ++ } else { ++ if (i2c_get_data(buf, 1) < 0) ++ break; ++ } ++ cnt--; ++ buf++; ++ } ++ ++ __i2c_send_stop(); ++ return count - cnt; ++ device_rerr: ++ device_werr: ++ address_err: ++ timeout --; ++ __i2c_send_stop(); ++ goto L_try_again; ++ ++L_timeout: ++ __i2c_send_stop(); ++ printk("Read I2C device 0x%2x failed.\n", device); ++ return -ENODEV; ++} ++ ++int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int cnt_in_pg; ++ int timeout = 5; ++ unsigned char *tmpbuf; ++ unsigned char tmpaddr; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ ++ W_try_again: ++ if (timeout < 0) ++ goto W_timeout; ++ ++ cnt = count; ++ tmpbuf = (unsigned char *)buf; ++ tmpaddr = address; ++ ++ start_write_page: ++ cnt_in_pg = 0; ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++#ifdef CONFIG_JZ_TPANEL_ATA2508 ++ if (address == 0xff) { ++ if (i2c_put_data_nack(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data_nack(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ } ++ else { ++ ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ } ++#else ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++#endif ++ __i2c_send_stop(); ++ return count - cnt; ++ device_err: ++ address_err: ++ timeout--; ++ __i2c_send_stop(); ++ goto W_try_again; ++ ++ W_timeout: ++ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++} ++ ++EXPORT_SYMBOL(i2c_open); ++EXPORT_SYMBOL(i2c_close); ++EXPORT_SYMBOL(i2c_setclk); ++EXPORT_SYMBOL(i2c_read); ++EXPORT_SYMBOL(i2c_write); +diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c +new file mode 100644 +index 0000000..98543c2 +--- /dev/null ++++ b/arch/mips/jz4740/irq.c +@@ -0,0 +1,265 @@ ++/* ++ * linux/arch/mips/jz4740/irq.c ++ * ++ * JZ4740 interrupt routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * INTC irq type ++ */ ++ ++static void enable_intc_irq(unsigned int irq) ++{ ++ __intc_unmask_irq(irq); ++} ++ ++static void disable_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++} ++ ++static void mask_and_ack_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++ __intc_ack_irq(irq); ++} ++ ++static void end_intc_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_intc_irq(irq); ++ } ++} ++ ++static unsigned int startup_intc_irq(unsigned int irq) ++{ ++ enable_intc_irq(irq); ++ return 0; ++} ++ ++static void shutdown_intc_irq(unsigned int irq) ++{ ++ disable_intc_irq(irq); ++} ++ ++static struct irq_chip intc_irq_type = { ++ .typename = "INTC", ++ .startup = startup_intc_irq, ++ .shutdown = shutdown_intc_irq, ++ .enable = enable_intc_irq, ++ .disable = disable_intc_irq, ++ .ack = mask_and_ack_intc_irq, ++ .end = end_intc_irq, ++}; ++ ++/* ++ * GPIO irq type ++ */ ++ ++static void enable_gpio_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if (irq < (IRQ_GPIO_0 + 32)) { ++ intc_irq = IRQ_GPIO0; ++ } ++ else if (irq < (IRQ_GPIO_0 + 64)) { ++ intc_irq = IRQ_GPIO1; ++ } ++ else if (irq < (IRQ_GPIO_0 + 96)) { ++ intc_irq = IRQ_GPIO2; ++ } ++ else { ++ intc_irq = IRQ_GPIO3; ++ } ++ ++ enable_intc_irq(intc_irq); ++ __gpio_unmask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void disable_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void mask_and_ack_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++ __gpio_ack_irq(irq - IRQ_GPIO_0); ++} ++ ++static void end_gpio_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_gpio_irq(irq); ++ } ++} ++ ++static unsigned int startup_gpio_irq(unsigned int irq) ++{ ++ enable_gpio_irq(irq); ++ return 0; ++} ++ ++static void shutdown_gpio_irq(unsigned int irq) ++{ ++ disable_gpio_irq(irq); ++} ++ ++static struct irq_chip gpio_irq_type = { ++ .typename = "GPIO", ++ .startup = startup_gpio_irq, ++ .shutdown = shutdown_gpio_irq, ++ .enable = enable_gpio_irq, ++ .disable = disable_gpio_irq, ++ .ack = mask_and_ack_gpio_irq, ++ .end = end_gpio_irq, ++}; ++ ++/* ++ * DMA irq type ++ */ ++ ++static void enable_dma_irq(unsigned int irq) ++{ ++ __intc_unmask_irq(IRQ_DMAC); ++ __dmac_channel_enable_irq(irq - IRQ_DMA_0); ++} ++ ++static void disable_dma_irq(unsigned int irq) ++{ ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void mask_and_ack_dma_irq(unsigned int irq) ++{ ++ __intc_ack_irq(IRQ_DMAC); ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void end_dma_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_dma_irq(irq); ++ } ++} ++ ++static unsigned int startup_dma_irq(unsigned int irq) ++{ ++ enable_dma_irq(irq); ++ return 0; ++} ++ ++static void shutdown_dma_irq(unsigned int irq) ++{ ++ disable_dma_irq(irq); ++} ++ ++static struct irq_chip dma_irq_type = { ++ .typename = "DMA", ++ .startup = startup_dma_irq, ++ .shutdown = shutdown_dma_irq, ++ .enable = enable_dma_irq, ++ .disable = disable_dma_irq, ++ .ack = mask_and_ack_dma_irq, ++ .end = end_dma_irq, ++}; ++ ++//---------------------------------------------------------------------- ++ ++void __init arch_init_irq(void) ++{ ++ int i; ++ ++ clear_c0_status(0xff04); /* clear ERL */ ++ set_c0_status(0x0400); /* set IP2 */ ++ ++ /* Set up INTC irq ++ */ ++ for (i = 0; i < 32; i++) { ++ disable_intc_irq(i); ++ irq_desc[i].chip = &intc_irq_type; ++ } ++ ++ /* Set up DMAC irq ++ */ ++ for (i = 0; i < NUM_DMA; i++) { ++ disable_dma_irq(IRQ_DMA_0 + i); ++ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; ++ } ++ ++ /* Set up GPIO irq ++ */ ++ for (i = 0; i < NUM_GPIO; i++) { ++ disable_gpio_irq(IRQ_GPIO_0 + i); ++ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; ++ } ++} ++ ++static int plat_real_irq(int irq) ++{ ++ switch (irq) { ++ case IRQ_GPIO0: ++ irq = __gpio_group_irq(0) + IRQ_GPIO_0; ++ break; ++ case IRQ_GPIO1: ++ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; ++ break; ++ case IRQ_GPIO2: ++ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; ++ break; ++ case IRQ_GPIO3: ++ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; ++ break; ++ case IRQ_DMAC: ++ irq = __dmac_get_irq() + IRQ_DMA_0; ++ break; ++ } ++ ++ return irq; ++} ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ int irq = 0; ++ static unsigned long intc_ipr = 0; ++ ++ intc_ipr |= REG_INTC_IPR; ++ ++ if (!intc_ipr) return; ++ ++ irq = ffs(intc_ipr) - 1; ++ intc_ipr &= ~(1< ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* OHCI (USB full speed host controller) */ ++static struct resource jz_usb_ohci_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap ++ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UHC, ++ .end = IRQ_UHC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++/* The dmamask must be set for OHCI to work */ ++static u64 ohci_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_ohci_device = { ++ .name = "jz-ohci", ++ .id = 0, ++ .dev = { ++ .dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), ++ .resource = jz_usb_ohci_resources, ++}; ++ ++/*** LCD controller ***/ ++static struct resource jz_lcd_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(LCD_BASE), ++ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_LCD, ++ .end = IRQ_LCD, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_lcd_dmamask = ~(u32)0; ++ ++static struct platform_device jz_lcd_device = { ++ .name = "jz-lcd", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_lcd_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_lcd_resources), ++ .resource = jz_lcd_resources, ++}; ++ ++/* UDC (USB gadget controller) */ ++static struct resource jz_usb_gdt_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UDC_BASE), ++ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UDC, ++ .end = IRQ_UDC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static u64 udc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_gdt_device = { ++ .name = "jz-udc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &udc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), ++ .resource = jz_usb_gdt_resources, ++}; ++ ++/** MMC/SD controller **/ ++static struct resource jz_mmc_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(MSC_BASE), ++ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_MSC, ++ .end = IRQ_MSC, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_mmc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_mmc_device = { ++ .name = "jz-mmc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_mmc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_mmc_resources), ++ .resource = jz_mmc_resources, ++}; ++ ++/** I2C controller **/ ++static struct resource jz_i2c_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(I2C_BASE), ++ .end = CPHYSADDR(I2C_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_I2C, ++ .end = IRQ_I2C, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_i2c_dmamask = ~(u32)0; ++ ++static struct platform_device jz_i2c_device = { ++ .name = "jz_i2c", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_i2c_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_i2c_resources), ++ .resource = jz_i2c_resources, ++}; ++ ++/* All */ ++static struct platform_device *jz_platform_devices[] __initdata = { ++ &jz_usb_ohci_device, ++ &jz_lcd_device, ++ &jz_usb_gdt_device, ++ &jz_mmc_device, ++ &jz_i2c_device, ++}; ++ ++static int __init jz_platform_init(void) ++{ ++ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); ++} ++ ++arch_initcall(jz_platform_init); +diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c +new file mode 100644 +index 0000000..2c6cd83 +--- /dev/null ++++ b/arch/mips/jz4740/pm.c +@@ -0,0 +1,462 @@ ++/* ++ * linux/arch/mips/jz4740/common/pm.c ++ * ++ * JZ4740 Power Management Routines ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++ ++#define GPIO_WAKEUP 125 /* set SW7(GPIO 125) as WAKEUP key */ ++ ++/* ++ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input ++ * except sdram, nand flash pins and the pins which can be used as CS1_N ++ * to CS4_N for chip select. ++ */ ++#define __gpio_as_sleep() \ ++do { \ ++ REG_GPIO_PXFUNC(1) = ~0x9ff9ffff; \ ++ REG_GPIO_PXSELC(1) = ~0x9ff9ffff; \ ++ REG_GPIO_PXDIRC(1) = ~0x9ff9ffff; \ ++ REG_GPIO_PXPES(1) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(2) = ~0x37000000; \ ++ REG_GPIO_PXSELC(2) = ~0x37000000; \ ++ REG_GPIO_PXDIRC(2) = ~0x37000000; \ ++ REG_GPIO_PXPES(2) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(3) = 0xffffffff; \ ++ REG_GPIO_PXSELC(3) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(3) = 0xffffffff; \ ++ REG_GPIO_PXPES(3) = 0xffffffff; \ ++} while (0) ++ ++static int jz_pm_do_hibernate(void) ++{ ++ printk("Put CPU into hibernate mode.\n"); ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* ++ * RTC Wakeup or 1Hz interrupt can be enabled or disabled ++ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c). ++ */ ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */ ++ ++ /* Scratch pad register to be reserved */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HSPR = 0x12345678; ++ ++ /* clear wakeup status register */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HWRSR = 0x0; ++ ++ /* Put CPU to power down mode */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HCR = RTC_HCR_PD; ++ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ while(1); ++ ++ /* We can't get here */ ++ return 0; ++} ++ ++/* NOTES: ++ * 1: Pins that are floated (NC) should be set as input and pull-enable. ++ * 2: Pins that are pull-up or pull-down by outside should be set as input ++ * and pull-disable. ++ * 3: Pins that are connected to a chip except sdram and nand flash ++ * should be set as input and pull-disable, too. ++ */ ++static void jz_board_do_sleep(unsigned long *ptr) ++{ ++ unsigned char i; ++ ++ /* Print messages of GPIO registers for debug */ ++ for(i=0;i<4;i++) { ++ dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \ ++ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \ ++ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i)); ++ } ++ ++ /* Save GPIO registers */ ++ for(i = 1; i < 4; i++) { ++ *ptr++ = REG_GPIO_PXFUN(i); ++ *ptr++ = REG_GPIO_PXSEL(i); ++ *ptr++ = REG_GPIO_PXDIR(i); ++ *ptr++ = REG_GPIO_PXPE(i); ++ *ptr++ = REG_GPIO_PXIM(i); ++ *ptr++ = REG_GPIO_PXDAT(i); ++ *ptr++ = REG_GPIO_PXTRG(i); ++ } ++ ++ /* ++ * Set all pins to pull-disable, and set all pins as input except ++ * sdram, nand flash pins and the pins which can be used as CS1_N ++ * to CS4_N for chip select. ++ */ ++ __gpio_as_sleep(); ++ ++ /* ++ * Set proper status for GPB25 to GPB28 which can be used as CS1_N to CS4_N. ++ * Keep the pins' function used for chip select(CS) here according to your ++ * system to avoid chip select crashing with sdram when resuming from sleep mode. ++ */ ++ ++#if defined(CONFIG_JZ4740_PAVO) ++ /* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */ ++ ++ /* GPB26/CS2_N is connected to nand flash, needn't be changed. */ ++ ++ /* GPB27/CS3_N is used as EXT_INT for CS8900 on debug board, it should be set as input.*/ ++ __gpio_as_input(32+27); ++ ++ /* GPB28/CS4_N is used as cs8900's chip select, shouldn't be changed. */ ++#endif ++ ++ /* ++ * Enable pull for NC pins here according to your system ++ */ ++ ++#if defined(CONFIG_JZ4740_PAVO) ++ /* GPB30-27 <-> J1: WE_N RD_N CS4_N EXT_INT */ ++ for(i=27;i<31;i++) { ++ __gpio_enable_pull(32+i); ++ } ++ ++ /* GPC27<-> WAIT_N */ ++ __gpio_enable_pull(32*2+27); ++ ++ /* GPD16<->SD_WP; GPD13-10<->MSC_D0-3; GPD9<->MSC_CMD; GPD8<->MSC_CLK */ ++ __gpio_enable_pull(32*3+16); ++ for(i=8;i<14;i++) { ++ __gpio_enable_pull(32*3+i); ++ } ++#endif ++ ++ /* ++ * If you must set some GPIOs as output to high level or low level, ++ * you can set them here, using: ++ * __gpio_as_output(n); ++ * __gpio_set_pin(n); or __gpio_clear_pin(n); ++ */ ++ ++#if defined(CONFIG_JZ4740_PAVO) ++ /* GPD16 which is used as AMPEN_N should be set to high to disable audio amplifier */ ++ __gpio_set_pin(32*3+4); ++#endif ++ ++#ifdef DEBUG ++ /* Keep uart0 function for printing debug message */ ++ __gpio_as_uart0(); ++ ++ /* Print messages of GPIO registers for debug */ ++ for(i=0;i<4;i++) { ++ dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \ ++ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \ ++ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i)); ++ } ++#endif ++} ++ ++static void jz_board_do_resume(unsigned long *ptr) ++{ ++ unsigned char i; ++ ++ /* Restore GPIO registers */ ++ for(i = 1; i < 4; i++) { ++ REG_GPIO_PXFUNS(i) = *ptr; ++ REG_GPIO_PXFUNC(i) = ~(*ptr++); ++ ++ REG_GPIO_PXSELS(i) = *ptr; ++ REG_GPIO_PXSELC(i) = ~(*ptr++); ++ ++ REG_GPIO_PXDIRS(i) = *ptr; ++ REG_GPIO_PXDIRC(i) = ~(*ptr++); ++ ++ REG_GPIO_PXPES(i) = *ptr; ++ REG_GPIO_PXPEC(i) = ~(*ptr++); ++ ++ REG_GPIO_PXIMS(i)=*ptr; ++ REG_GPIO_PXIMC(i)=~(*ptr++); ++ ++ REG_GPIO_PXDATS(i)=*ptr; ++ REG_GPIO_PXDATC(i)=~(*ptr++); ++ ++ REG_GPIO_PXTRGS(i)=*ptr; ++ REG_GPIO_PXTRGC(i)=~(*ptr++); ++ } ++ ++ /* Print messages of GPIO registers for debug */ ++ for(i=0;i<4;i++) { ++ dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \ ++ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \ ++ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i)); ++ } ++} ++ ++ ++ ++static int jz_pm_do_sleep(void) ++{ ++ unsigned long delta; ++ unsigned long nfcsr = REG_EMC_NFCSR; ++ unsigned long scr = REG_CPM_SCR; ++ unsigned long imr = REG_INTC_IMR; ++ unsigned long sadc = REG_SADC_ENA; ++ unsigned long sleep_gpio_save[7*3]; ++ ++ printk("Put CPU into sleep mode.\n"); ++ ++ /* Preserve current time */ ++ delta = xtime.tv_sec - REG_RTC_RSR; ++ ++ /* Disable nand flash */ ++ REG_EMC_NFCSR = ~0xff; ++ ++ /* stop sadc */ ++ REG_SADC_ENA &= ~0x7; ++ while((REG_SADC_ENA & 0x7) != 0); ++ udelay(100); ++ ++ /*stop udc and usb*/ ++ REG_CPM_SCR &= ~( 1<<6 | 1<<7); ++ REG_CPM_SCR |= 0<<6 | 1<<7; ++ ++ /* Sleep on-board modules */ ++ jz_board_do_sleep(sleep_gpio_save); ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* Just allow following interrupts to wakeup the system. ++ * Note: modify this according to your system. ++ */ ++ ++ /* enable RTC alarm */ ++ __intc_unmask_irq(IRQ_RTC); ++#if 0 ++ /* make system wake up after n seconds by RTC alarm */ ++ unsigned int v, n; ++ n = 10; ++ while (!__rtc_write_ready()); ++ __rtc_enable_alarm(); ++ while (!__rtc_write_ready()); ++ __rtc_enable_alarm_irq(); ++ while (!__rtc_write_ready()); ++ v = __rtc_get_second(); ++ while (!__rtc_write_ready()); ++ __rtc_set_alarm_second(v+n); ++#endif ++ ++ /* WAKEUP key */ ++ __gpio_as_irq_rise_edge(GPIO_WAKEUP); ++ __gpio_unmask_irq(GPIO_WAKEUP); ++ __intc_unmask_irq(IRQ_GPIO3); /* IRQ_GPIOn depends on GPIO_WAKEUP */ ++ ++ /* Enter SLEEP mode */ ++ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; ++ REG_CPM_LCR |= CPM_LCR_LPM_SLEEP; ++ __asm__(".set\tmips3\n\t" ++ "wait\n\t" ++ ".set\tmips0"); ++ ++ /* Restore to IDLE mode */ ++ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; ++ REG_CPM_LCR |= CPM_LCR_LPM_IDLE; ++ ++ /* Restore nand flash control register */ ++ REG_EMC_NFCSR = nfcsr; ++ ++ /* Restore interrupts */ ++ REG_INTC_IMSR = imr; ++ REG_INTC_IMCR = ~imr; ++ ++ /* Restore sadc */ ++ REG_SADC_ENA = sadc; ++ ++ /* Resume on-board modules */ ++ jz_board_do_resume(sleep_gpio_save); ++ ++ /* Restore sleep control register */ ++ REG_CPM_SCR = scr; ++ ++ /* Restore current time */ ++ xtime.tv_sec = REG_RTC_RSR + delta; ++ ++ return 0; ++} ++ ++/* Put CPU to HIBERNATE mode */ ++int jz_pm_hibernate(void) ++{ ++ return jz_pm_do_hibernate(); ++} ++ ++#ifndef CONFIG_JZ_POWEROFF ++static irqreturn_t pm_irq_handler (int irq, void *dev_id) ++{ ++ return IRQ_HANDLED; ++} ++#endif ++ ++/* Put CPU to SLEEP mode */ ++int jz_pm_sleep(void) ++{ ++ int retval; ++ ++#ifndef CONFIG_JZ_POWEROFF ++ if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED, ++ "PM", NULL))) { ++ printk ("PM could not get IRQ for GPIO_WAKEUP\n"); ++ return retval; ++ } ++#endif ++ ++ pm_send_all(PM_SUSPEND, (void *)3); ++ retval = jz_pm_do_sleep(); ++ pm_send_all(PM_RESUME, (void *)0); ++ ++#ifndef CONFIG_JZ_POWEROFF ++ free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL); ++#endif ++ ++ return retval; ++} ++ ++#if 0 ++/* Deprecated ,was used by dpm */ ++void jz_pm_idle(void) ++{ ++ local_irq_disable(); ++ if (!need_resched()) { ++ local_irq_enable(); ++ cpu_wait(); ++ } ++} ++#endif ++ ++#ifdef CONFIG_SYSCTL ++ ++/* ++ * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 ++ * when all the PM interfaces exist nicely. ++ */ ++#define CTL_PM_SUSPEND 1 ++#define CTL_PM_HIBERNATE 2 ++ ++/*---------------------------------------------------------------------------- ++ * Power Management sleep sysctl proc interface ++ * ++ * A write to /proc/sys/pm/suspend invokes this function ++ * which initiates a sleep. ++ *--------------------------------------------------------------------------*/ ++static int sysctl_jz_pm_sleep(struct ctl_table *ctl, int write, struct file * filp, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ return jz_pm_sleep(); ++} ++ ++/*---------------------------------------------------------------------------- ++ * Power Management sleep sysctl proc interface ++ * ++ * A write to /proc/sys/pm/hibernate invokes this function ++ * which initiates a poweroff. ++ *--------------------------------------------------------------------------*/ ++static int sysctl_jz_pm_hibernate(struct ctl_table *ctl, int write, struct file * filp, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ return jz_pm_hibernate(); ++} ++ ++static struct ctl_table pm_table[] = ++{ ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "suspend", ++ .data = NULL, ++ .maxlen = 0, ++ .mode = 0600, ++ .proc_handler = &sysctl_jz_pm_sleep, ++ }, ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "hibernate", ++ .data = NULL, ++ .maxlen = 0, ++ .mode = 0600, ++ .proc_handler = &sysctl_jz_pm_hibernate, ++ }, ++ { .ctl_name = 0} ++}; ++ ++static struct ctl_table pm_dir_table[] = ++{ ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "pm", ++ .mode = 0555, ++ .child = pm_table, ++ }, ++ { .ctl_name = 0} ++}; ++ ++#endif /* CONFIG_SYSCTL */ ++ ++/* ++ * Initialize power interface ++ */ ++static int __init jz_pm_init(void) ++{ ++ printk("Power Management for JZ\n"); ++ ++#ifdef CONFIG_SYSCTL ++ register_sysctl_table(pm_dir_table); ++#endif ++ ++ return 0; ++} ++ ++module_init(jz_pm_init); ++ +diff --git a/arch/mips/jz4740/proc.c b/arch/mips/jz4740/proc.c +new file mode 100644 +index 0000000..af48bee +--- /dev/null ++++ b/arch/mips/jz4740/proc.c +@@ -0,0 +1,887 @@ ++/* ++ * linux/arch/mips/jz4740/proc.c ++ * ++ * /proc/jz/ procfs for jz4740 on-chip modules. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#define DEBUG 1 ++#undef DEBUG ++ ++/* Define this to reserve total 4MB contineous physical memory for IPU. ++ * MPlayer will use IPU to optimize the decoding process. ++ * ++ * If you do not want to run the MPlayer, you can comment it. ++ */ ++#define CONFIG_RESERVE_IPU_MEM 1 ++ ++struct proc_dir_entry *proc_jz_root; ++ ++ ++/* ++ * EMC Modules ++ */ ++static int emc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); ++ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); ++ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); ++ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); ++ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); ++ return len; ++} ++ ++/* ++ * Power Manager Module ++ */ ++static int pmc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned long lcr = REG_CPM_LCR; ++ unsigned long clkgr = REG_CPM_CLKGR; ++ ++ len += sprintf (page+len, "Low Power Mode : %s\n", ++ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? ++ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? ++ "SLEEP" : "HIBERNATE")); ++ len += sprintf (page+len, "Doze Mode : %s\n", ++ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); ++ if (lcr & CPM_LCR_DOZE_ON) ++ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); ++ len += sprintf (page+len, "IPU : %s\n", ++ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); ++ len += sprintf (page+len, "DMAC : %s\n", ++ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); ++ len += sprintf (page+len, "UHC : %s\n", ++ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running"); ++ len += sprintf (page+len, "UDC : %s\n", ++ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); ++ len += sprintf (page+len, "LCD : %s\n", ++ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); ++ len += sprintf (page+len, "CIM : %s\n", ++ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); ++ len += sprintf (page+len, "SADC : %s\n", ++ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); ++ len += sprintf (page+len, "MSC : %s\n", ++ (clkgr & CPM_CLKGR_MSC) ? "stopped" : "running"); ++ len += sprintf (page+len, "AIC1 : %s\n", ++ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running"); ++ len += sprintf (page+len, "AIC2 : %s\n", ++ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running"); ++ len += sprintf (page+len, "SSI : %s\n", ++ (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running"); ++ len += sprintf (page+len, "I2C : %s\n", ++ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); ++ len += sprintf (page+len, "RTC : %s\n", ++ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); ++ len += sprintf (page+len, "TCU : %s\n", ++ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART1 : %s\n", ++ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART0 : %s\n", ++ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); ++ return len; ++} ++ ++static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++/* ++ * Clock Generation Module ++ */ ++#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 ++#define TO_KHZ(x) (x/1000),(x%1000)/10 ++ ++static int cgm_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ ++ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ ++ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int od[4] = {1, 2, 2, 4}; ++ ++ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); ++ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); ++ len += sprintf (page+len, "PLL : %s\n", ++ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); ++ len += sprintf (page+len, "m:n:o : %d:%d:%d\n", ++ __cpm_get_pllm() + 2, ++ __cpm_get_plln() + 2, ++ od[__cpm_get_pllod()] ++ ); ++ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", ++ div[__cpm_get_cdiv()], ++ div[__cpm_get_hdiv()], ++ div[__cpm_get_mdiv()], ++ div[__cpm_get_pdiv()] ++ ); ++ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); ++ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); ++ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); ++ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); ++ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); ++ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk())); ++ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); ++ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); ++ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); ++ len += sprintf (page+len, "MSCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk())); ++ len += sprintf (page+len, "EXTALCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); ++ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); ++ ++ return len; ++} ++ ++static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++ ++/* ++ * 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; ++} ++ ++#ifdef CONFIG_RESERVE_IPU_MEM ++ ++/* USAGE: ++ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages. ++ * echo FF > /proc/jz/ipu // 255, free all buffer ++ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx ++ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l) ++ * echo 0 > /proc/jz/ipu // debug, print ipu_buf ++ * od -X /proc/jz/ipu // read mem addr ++ */ ++ ++typedef struct _ipu_buf { ++ unsigned int addr; /* phys addr */ ++ unsigned int page_shift; ++} ipu_buf_t; ++ ++#define IPU_BUF_MAX 4 /* 4 buffers */ ++ ++static struct _ipu_buf ipu_buf[IPU_BUF_MAX]; ++static int ipu_buf_cnt = 0; ++static unsigned char g_asid=0; ++ ++extern void local_flush_tlb_all(void); ++ ++/* CP0 hazard avoidance. */ ++#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ ++ "nop; nop; nop; nop; nop; nop;\n\t" \ ++ ".set reorder\n\t") ++void show_tlb(void) ++{ ++#define ASID_MASK 0xFF ++ ++ unsigned long flags; ++ unsigned int old_ctx; ++ unsigned int entry; ++ unsigned int entrylo0, entrylo1, entryhi; ++ unsigned int pagemask; ++ ++ local_irq_save(flags); ++ ++ /* Save old context */ ++ old_ctx = (read_c0_entryhi() & 0xff); ++ ++ printk("TLB content:\n"); ++ entry = 0; ++ while(entry < 32) { ++ write_c0_index(entry); ++ BARRIER; ++ tlb_read(); ++ BARRIER; ++ entryhi = read_c0_entryhi(); ++ entrylo0 = read_c0_entrylo0(); ++ entrylo1 = read_c0_entrylo1(); ++ pagemask = read_c0_pagemask(); ++ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); ++ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); ++ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); ++ ++ printk("\t\tpagemask=0x%08x", pagemask); ++ printk("\tentryhi=0x%08x\n", entryhi); ++ printk("\t\tentrylo0=0x%08x", entrylo0); ++ printk("\tentrylo1=0x%08x\n", entrylo1); ++ ++ entry++; ++ } ++ BARRIER; ++ write_c0_entryhi(old_ctx); ++ ++ local_irq_restore(flags); ++} ++ ++static void ipu_add_wired_entry(unsigned long pid, ++ unsigned long entrylo0, unsigned long entrylo1, ++ unsigned long entryhi, unsigned long pagemask) ++{ ++ unsigned long flags; ++ unsigned long wired; ++ unsigned long old_pagemask; ++ unsigned long old_ctx; ++ struct task_struct *g, *p; ++ ++ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ ++ wired = read_c0_wired(); ++ if (wired) return; ++ ++ do_each_thread(g, p) { ++ if (p->pid == pid ) ++ g_asid = p->mm->context[0]; ++ } while_each_thread(g, p); ++ ++ local_irq_save(flags); ++ ++ entrylo0 = entrylo0 >> 6; /* PFN */ ++ entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */ ++ ++ /* Save old context and create impossible VPN2 value */ ++ old_ctx = read_c0_entryhi() & 0xff; ++ old_pagemask = read_c0_pagemask(); ++ write_c0_wired(wired + 1); ++ write_c0_index(wired); ++ BARRIER; ++ entryhi &= ~0xff; /* new add, 20070906 */ ++ entryhi |= g_asid; /* new add, 20070906 */ ++// entryhi |= old_ctx; /* new add, 20070906 */ ++ write_c0_pagemask(pagemask); ++ write_c0_entryhi(entryhi); ++ write_c0_entrylo0(entrylo0); ++ write_c0_entrylo1(entrylo1); ++ BARRIER; ++ tlb_write_indexed(); ++ BARRIER; ++ ++ write_c0_entryhi(old_ctx); ++ BARRIER; ++ write_c0_pagemask(old_pagemask); ++ local_flush_tlb_all(); ++ local_irq_restore(flags); ++#if defined(DEBUG) ++ printk("\nold_ctx=%03d\n", old_ctx); ++ ++ show_tlb(); ++#endif ++} ++ ++static void ipu_del_wired_entry( void ) ++{ ++ unsigned long flags; ++ unsigned long wired; ++ ++ /* Free all lock entry */ ++ local_irq_save(flags); ++ wired = read_c0_wired(); ++ if (wired) ++ write_c0_wired(0); ++ local_irq_restore(flags); ++} ++ ++static inline void ipu_buf_get( unsigned int page_shift ) ++{ ++ unsigned char * virt_addr; ++ int i; ++ for ( i=0; i< IPU_BUF_MAX; ++i ) { ++ if ( ipu_buf[i].addr == 0 ) { ++ break; ++ } ++ } ++ ++ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) { ++ printk("Error, no free ipu buffer.\n"); ++ return ; ++ } ++ ++ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ ++ if ( virt_addr ) { ++ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr); ++ ipu_buf[ipu_buf_cnt].page_shift = page_shift; ++ ++ for (i = 0; i < (1<= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */ ++ printk("no free buffer.\n"); ++ *pint = 0; ++ } ++ else ++ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */ ++ len += sizeof(unsigned int); ++ ++#if defined(DEBUG) ++ show_tlb(); ++#endif ++ return len; ++ ++} ++ ++static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ unsigned int val ; ++ int cnt,i; ++ char buf[12]; ++ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask; ++#if defined(DEBUG) ++ printk("ipu write count=%u\n", count); ++#endif ++ if (count == (8*5+1)) { ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*0, 8); ++ pid = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*1, 8); ++ entrylo0 = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*2, 8); ++ entrylo1 = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*3, 8); ++ entryhi = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*4, 8); ++ pagemask = simple_strtoul(buf, 0, 16); ++ ++#if defined(DEBUG) ++ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n", ++ pid, entrylo0, entrylo1, entryhi, pagemask); ++#endif ++ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask); ++ return 41; ++ } else if ( count <= 8+1 ) { ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer, 8); ++ val = simple_strtoul(buf, 0, 16); ++ } else if (count == 44) { ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer, 10); ++ pid = simple_strtoul(buf, 0, 16); ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 11, 10); ++ entryhi = simple_strtoul(buf, 0, 16);//vaddr ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 22, 10); ++ entrylo0 = simple_strtoul(buf, 0, 16);//paddr ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 33, 10); ++ pagemask = simple_strtoul(buf, 0, 16); ++ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */ ++ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask); ++ return 44; ++ } else { ++ printk("ipu write count error, count=%d\n.", (unsigned int)count); ++ return -1; ++ } ++ ++ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */ ++ if ( val == 0 ) { /* debug, print ipu_buf info */ ++ for ( cnt=0; cnt /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages ++ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx ++ * echo FF > /proc/jz/ipu // FF, free all buffers ++ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer ++ */ ++ ++//#define DEBUG_IMEM 1 ++ ++#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */ ++ ++static unsigned int jz_imem_base; /* physical base address of ipu memory */ ++ ++static unsigned int allocated_phys_addr = 0; ++ ++/* ++ * Allocated buffer list ++ */ ++typedef struct imem_list { ++ unsigned int phys_start; /* physical start addr */ ++ unsigned int phys_end; /* physical end addr */ ++ struct imem_list *next; ++} imem_list_t; ++ ++static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */ ++ ++#ifdef DEBUG_IMEM ++static void dump_imem_list(void) ++{ ++ struct imem_list *imem; ++ ++ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head); ++ imem = imem_list_head; ++ while (imem) { ++ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next); ++ imem = imem->next; ++ } ++} ++#endif ++ ++/* allocate 2^order pages inside the 4MB memory */ ++static int imem_alloc(unsigned int order) ++{ ++ int alloc_ok = 0; ++ unsigned int start, end; ++ unsigned int size = (1 << order) * PAGE_SIZE; ++ struct imem_list *imem, *imemn, *imemp; ++ ++ allocated_phys_addr = 0; ++ ++ start = jz_imem_base; ++ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; ++ ++ imem = imem_list_head; ++ while (imem) { ++ if ((imem->phys_start - start) >= size) { ++ /* we got a valid address range */ ++ alloc_ok = 1; ++ break; ++ } ++ ++ start = imem->phys_end + 1; ++ imem = imem->next; ++ } ++ ++ if (!alloc_ok) { ++ if ((end - start) >= size) ++ alloc_ok = 1; ++ } ++ ++ if (alloc_ok) { ++ end = start + size - 1; ++ allocated_phys_addr = start; ++ ++ /* add to imem_list, up sorted by phys_start */ ++ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL); ++ if (!imemn) { ++ return -ENOMEM; ++ } ++ imemn->phys_start = start; ++ imemn->phys_end = end; ++ imemn->next = NULL; ++ ++ if (!imem_list_head) ++ imem_list_head = imemn; ++ else { ++ imem = imemp = imem_list_head; ++ while (imem) { ++ if (start < imem->phys_start) { ++ break; ++ } ++ ++ imemp = imem; ++ imem = imem->next; ++ } ++ ++ if (imem == imem_list_head) { ++ imem_list_head = imemn; ++ imemn->next = imem; ++ } ++ else { ++ imemn->next = imemp->next; ++ imemp->next = imemn; ++ } ++ } ++ } ++ ++#ifdef DEBUG_IMEM ++ dump_imem_list(); ++#endif ++ return 0; ++} ++ ++static void imem_free(unsigned int phys_addr) ++{ ++ struct imem_list *imem, *imemp; ++ ++ imem = imemp = imem_list_head; ++ while (imem) { ++ if (phys_addr == imem->phys_start) { ++ if (imem == imem_list_head) { ++ imem_list_head = imem->next; ++ } ++ else { ++ imemp->next = imem->next; ++ } ++ ++ kfree(imem); ++ break; ++ } ++ ++ imemp = imem; ++ imem = imem->next; ++ } ++ ++#ifdef DEBUG_IMEM ++ dump_imem_list(); ++#endif ++} ++ ++static void imem_free_all(void) ++{ ++ struct imem_list *imem; ++ ++ imem = imem_list_head; ++ while (imem) { ++ kfree(imem); ++ imem = imem->next; ++ } ++ ++ imem_list_head = NULL; ++ ++ allocated_phys_addr = 0; ++ ++#ifdef DEBUG_IMEM ++ dump_imem_list(); ++#endif ++} ++ ++/* ++ * Return the allocated buffer address and the max order of free buffer ++ */ ++static int imem_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned int start_addr, end_addr, max_order, max_size; ++ struct imem_list *imem; ++ ++ unsigned int *tmp = (unsigned int *)(page + len); ++ ++ start_addr = jz_imem_base; ++ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; ++ ++ if (!imem_list_head) ++ max_size = end_addr - start_addr; ++ else { ++ max_size = 0; ++ imem = imem_list_head; ++ while (imem) { ++ if (max_size < (imem->phys_start - start_addr)) ++ max_size = imem->phys_start - start_addr; ++ ++ start_addr = imem->phys_end + 1; ++ imem = imem->next; ++ } ++ ++ if (max_size < (end_addr - start_addr)) ++ max_size = end_addr - start_addr; ++ } ++ ++ if (max_size > 0) { ++ max_order = get_order(max_size); ++ if (((1 << max_order) * PAGE_SIZE) > max_size) ++ max_order--; ++ } ++ else { ++ max_order = 0xffffffff; /* No any free buffer */ ++ } ++ ++ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */ ++ *tmp = max_order; /* max order of current free buffers */ ++ ++ len += 2 * sizeof(unsigned int); ++ ++ return len; ++} ++ ++static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ unsigned int val; ++ ++ val = simple_strtoul(buffer, 0, 16); ++ ++ if (val == 0xff) { ++ /* free all memory */ ++ imem_free_all(); ++ ipu_del_wired_entry(); ++ } ++ else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) { ++ /* allocate 2^val pages */ ++ imem_alloc(val); ++ } ++ else { ++ /* free buffer which phys_addr is val */ ++ imem_free(val); ++ } ++ ++ return count; ++} ++ ++#endif /* CONFIG_RESERVE_IPU_MEM */ ++ ++/* ++ * /proc/jz/xxx entry ++ * ++ */ ++static int __init jz_proc_init(void) ++{ ++ struct proc_dir_entry *res; ++#ifdef CONFIG_RESERVE_IPU_MEM ++ unsigned int virt_addr, i; ++#endif ++ ++ proc_jz_root = proc_mkdir("jz", 0); ++ ++ /* External Memory Controller */ ++ res = create_proc_entry("emc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = emc_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++ /* Power Management Controller */ ++ res = create_proc_entry("pmc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = pmc_read_proc; ++ res->write_proc = pmc_write_proc; ++ res->data = NULL; ++ } ++ ++ /* Clock Generation Module */ ++ res = create_proc_entry("cgm", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = cgm_read_proc; ++ res->write_proc = cgm_write_proc; ++ res->data = NULL; ++ } ++ ++ /* udc hotplug */ ++ res = create_proc_entry("udc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = udc_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++ /* mmc hotplug */ ++ res = create_proc_entry("mmc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = mmc_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++#ifdef CONFIG_RESERVE_IPU_MEM ++ /* Image process unit */ ++ res = create_proc_entry("ipu", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = ipu_read_proc; ++ res->write_proc = ipu_write_proc; ++ res->data = NULL; ++ } ++ ++ /* ++ * Reserve a 4MB memory for IPU on JZ4740. ++ */ ++ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER); ++ if (jz_imem_base) { ++ /* imem (IPU memory management) */ ++ res = create_proc_entry("imem", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = imem_read_proc; ++ res->write_proc = imem_write_proc; ++ res->data = NULL; ++ } ++ ++ /* Set page reserved */ ++ virt_addr = jz_imem_base; ++ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) { ++ SetPageReserved(virt_to_page((void *)virt_addr)); ++ virt_addr += PAGE_SIZE; ++ } ++ ++ /* Convert to physical address */ ++ jz_imem_base = virt_to_phys((void *)jz_imem_base); ++ ++ printk("Total %dMB memory at 0x%x was reserved for IPU\n", ++ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base); ++ } ++#endif ++ ++ return 0; ++} ++ ++__initcall(jz_proc_init); +diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c +new file mode 100644 +index 0000000..4068939 +--- /dev/null ++++ b/arch/mips/jz4740/prom.c +@@ -0,0 +1,198 @@ ++/* ++ * ++ * BRIEF MODULE DESCRIPTION ++ * PROM library initialisation code, supports YAMON and U-Boot. ++ * ++ * Copyright 2000, 2001, 2006 MontaVista Software Inc. ++ * Author: MontaVista Software, Inc. ++ * ppopov@mvista.com or source@mvista.com ++ * ++ * This file was derived from Carsten Langgaard's ++ * arch/mips/mips-boards/xx files. ++ * ++ * Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* #define DEBUG_CMDLINE */ ++ ++int prom_argc; ++char **prom_argv, **prom_envp; ++ ++char * prom_getcmdline(void) ++{ ++ return &(arcs_cmdline[0]); ++} ++ ++void prom_init_cmdline(void) ++{ ++ char *cp; ++ int actr; ++ ++ actr = 1; /* Always ignore argv[0] */ ++ ++ cp = &(arcs_cmdline[0]); ++ while(actr < prom_argc) { ++ strcpy(cp, prom_argv[actr]); ++ cp += strlen(prom_argv[actr]); ++ *cp++ = ' '; ++ actr++; ++ } ++ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ ++ --cp; ++ if (prom_argc > 1) ++ *cp = '\0'; ++ ++} ++ ++ ++char *prom_getenv(char *envname) ++{ ++#if 0 ++ /* ++ * Return a pointer to the given environment variable. ++ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". ++ */ ++ ++ char **env = prom_envp; ++ int i = strlen(envname); ++ int yamon = (*env && strchr(*env, '=') == NULL); ++ ++ while (*env) { ++ if (yamon) { ++ if (strcmp(envname, *env++) == 0) ++ return *env; ++ } else { ++ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') ++ return *env + i + 1; ++ } ++ env++; ++ } ++#endif ++ return NULL; ++} ++ ++inline unsigned char str2hexnum(unsigned char c) ++{ ++ if(c >= '0' && c <= '9') ++ return c - '0'; ++ if(c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if(c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return 0; /* foo */ ++} ++ ++inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for(i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= (str2hexnum(*str++)); ++ ea[i] = num; ++ } ++} ++ ++int get_ethernet_addr(char *ethernet_addr) ++{ ++ char *ethaddr_str; ++ ++ ethaddr_str = prom_getenv("ethaddr"); ++ if (!ethaddr_str) { ++ printk("ethaddr not set in boot prom\n"); ++ return -1; ++ } ++ str2eaddr(ethernet_addr, ethaddr_str); ++ ++#if 0 ++ { ++ int i; ++ ++ printk("get_ethernet_addr: "); ++ for (i=0; i<5; i++) ++ printk("%02x:", (unsigned char)*(ethernet_addr+i)); ++ printk("%02x\n", *(ethernet_addr+i)); ++ } ++#endif ++ ++ return 0; ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++void __init prom_init(void) ++{ ++ unsigned char *memsize_str; ++ unsigned long memsize; ++ ++ prom_argc = (int) fw_arg0; ++ prom_argv = (char **) fw_arg1; ++ prom_envp = (char **) fw_arg2; ++ ++ mips_machtype = MACH_INGENIC_JZ4740; ++ ++ prom_init_cmdline(); ++ memsize_str = prom_getenv("memsize"); ++ if (!memsize_str) { ++ memsize = 0x04000000; ++ } else { ++ memsize = simple_strtol(memsize_str, NULL, 0); ++ } ++ add_memory_region(0, memsize, BOOT_MEM_RAM); ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR); ++ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); ++ ++ *uart_tdr = (u8)c; ++} ++ ++const char *get_system_type(void) ++{ ++ return "JZ4740"; ++} ++ ++EXPORT_SYMBOL(prom_getcmdline); ++EXPORT_SYMBOL(get_ethernet_addr); ++EXPORT_SYMBOL(str2eaddr); +diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c +new file mode 100644 +index 0000000..83577d8 +--- /dev/null ++++ b/arch/mips/jz4740/reset.c +@@ -0,0 +1,46 @@ ++/* ++ * linux/arch/mips/jz4740/reset.c ++ * ++ * JZ4740 reset routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void jz_restart(char *command) ++{ ++ printk("Restarting after 4 ms\n"); ++ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; ++ REG_WDT_TCNT = 0; ++ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ ++ REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */ ++ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ ++ while (1); ++} ++ ++void jz_halt(void) ++{ ++ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); ++ ++ while (1) ++ __asm__(".set\tmips3\n\t" ++ "wait\n\t" ++ ".set\tmips0"); ++} ++ ++void jz_power_off(void) ++{ ++ jz_halt(); ++} +diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c +new file mode 100644 +index 0000000..e19f767 +--- /dev/null ++++ b/arch/mips/jz4740/setup.c +@@ -0,0 +1,182 @@ ++/* ++ * linux/arch/mips/jz4740/common/setup.c ++ * ++ * JZ4740 common setup routines. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PC_KEYB ++#include ++#endif ++ ++jz_clocks_t jz_clocks; ++ ++extern char * __init prom_getcmdline(void); ++extern void __init jz_board_setup(void); ++extern void jz_restart(char *); ++extern void jz_halt(void); ++extern void jz_power_off(void); ++extern void jz_time_init(void); ++ ++static void __init sysclocks_setup(void) ++{ ++#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ ++ jz_clocks.cclk = __cpm_get_cclk(); ++ jz_clocks.hclk = __cpm_get_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; ++ ++ jz_soc_setup(); ++ jz_serial_setup(); ++ jz_board_setup(); ++} ++ +diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c +new file mode 100644 +index 0000000..a82b17c +--- /dev/null ++++ b/arch/mips/jz4740/time.c +@@ -0,0 +1,158 @@ ++/* ++ * linux/arch/mips/jz4740/time.c ++ * ++ * Setting up the clock on the JZ4740 boards. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* This is for machines which generate the exact clock. */ ++ ++#define JZ_TIMER_CHAN 0 ++#define JZ_TIMER_IRQ IRQ_TCU0 ++ ++#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ ++ ++static struct clocksource clocksource_jz; /* Jz clock source */ ++static struct clock_event_device jz_clockevent_device; /* Jz clock event */ ++ ++void (*jz_timer_callback)(void); ++ ++static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ ++ REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */ ++ ++ if (jz_timer_callback) ++ jz_timer_callback(); ++ ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction jz_irqaction = { ++ .handler = jz_timer_interrupt, ++ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, ++ .name = "jz-timerirq", ++}; ++ ++ ++cycle_t jz_get_cycles(void) ++{ ++ /* convert jiffes to jz timer cycles */ ++ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_TCNT(JZ_TIMER_CHAN)); ++} ++ ++static struct clocksource clocksource_jz = { ++ .name = "jz_clocksource", ++ .rating = 300, ++ .read = jz_get_cycles, ++ .mask = 0xFFFF, ++ .shift = 10, ++ .flags = CLOCK_SOURCE_WATCHDOG, ++}; ++ ++static int __init jz_clocksource_init(void) ++{ ++ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); ++ clocksource_register(&clocksource_jz); ++ return 0; ++} ++ ++static int jz_set_next_event(unsigned long evt, ++ struct clock_event_device *unused) ++{ ++ return 0; ++} ++ ++static void jz_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ break; ++ } ++} ++ ++static struct clock_event_device jz_clockevent_device = { ++ .name = "jz-clockenvent", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ ++ ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ .rating = 300, ++ .irq = JZ_TIMER_IRQ, ++ .set_mode = jz_set_mode, ++ .set_next_event = jz_set_next_event, ++}; ++ ++static void __init jz_clockevent_init(void) ++{ ++ struct clock_event_device *cd = &jz_clockevent_device; ++ unsigned int cpu = smp_processor_id(); ++ ++ cd->cpumask = cpumask_of_cpu(cpu); ++ clockevents_register_device(cd); ++} ++ ++static void __init jz_timer_setup(void) ++{ ++ jz_clocksource_init(); /* init jz clock source */ ++ jz_clockevent_init(); /* init jz clock event */ ++ ++ /* ++ * Make irqs happen for the system timer ++ */ ++ jz_irqaction.dev_id = &jz_clockevent_device; ++ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); ++} ++ ++ ++void __init plat_time_init(void) ++{ ++ unsigned int latch; ++ /* Init timer */ ++ latch = ( JZ_TIMER_CLOCK + (HZ>>1)) / HZ; ++ ++ REG_TCU_TCSR(JZ_TIMER_CHAN) = TCU_TCSR_PRESCALE16 | TCU_TCSR_EXT_EN; ++ REG_TCU_TCNT(JZ_TIMER_CHAN) = 0; ++ REG_TCU_TDHR(JZ_TIMER_CHAN) = 0; ++ REG_TCU_TDFR(JZ_TIMER_CHAN) = latch; ++ ++ REG_TCU_TMSR = (1 << (JZ_TIMER_CHAN + 16)); /* mask half irq */ ++ REG_TCU_TMCR = (1 << JZ_TIMER_CHAN); /* unmask full irq */ ++ REG_TCU_TSCR = (1 << JZ_TIMER_CHAN); /* enable timer clock */ ++ REG_TCU_TESR = (1 << JZ_TIMER_CHAN); /* start counting up */ ++ ++ jz_timer_setup(); ++} +diff --git a/arch/mips/jz4750/Makefile b/arch/mips/jz4750/Makefile +new file mode 100644 +index 0000000..a9c6c16 +--- /dev/null ++++ b/arch/mips/jz4750/Makefile +@@ -0,0 +1,23 @@ ++# ++# Makefile for the Ingenic JZ4750. ++# ++ ++# Object file lists. ++ ++obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ ++ platform.o i2c.o ++ ++obj-$(CONFIG_PROC_FS) += proc.o ++ ++# board specific support ++ ++obj-$(CONFIG_JZ4750_FUWA) += board-fuwa.o ++obj-$(CONFIG_JZ4750_APUS) += board-apus.o ++ ++# PM support ++ ++obj-$(CONFIG_PM_LEGACY) +=pm.o ++ ++# CPU Frequency scaling support ++ ++obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o +diff --git a/arch/mips/jz4750/board-apus.c b/arch/mips/jz4750/board-apus.c +new file mode 100644 +index 0000000..7347dfa +--- /dev/null ++++ b/arch/mips/jz4750/board-apus.c +@@ -0,0 +1,64 @@ ++/* ++ * linux/arch/mips/jz4750/board-apus.c ++ * ++ * JZ4750 APUS board setup routines. ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++} ++ ++static void apus_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4750/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ __gpio_as_pcm(); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4750 APUS board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = apus_timer_callback; ++} +diff --git a/arch/mips/jz4750/board-fuwa.c b/arch/mips/jz4750/board-fuwa.c +new file mode 100644 +index 0000000..c5aae06 +--- /dev/null ++++ b/arch/mips/jz4750/board-fuwa.c +@@ -0,0 +1,105 @@ ++/* ++ * linux/arch/mips/jz4750/board-fuwa.c ++ * ++ * JZ4750 FUWA board setup routines. ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned char slash[] = "\\|/-"; ++// static volatile unsigned char *p = (unsigned char *)0xb6000058; ++ static volatile unsigned char *p = (unsigned char *)0xb6000016; ++ static unsigned int count = 0; ++ *p = slash[count++]; ++ count &= 3; ++} ++ ++static void fuwa_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4750/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Initialize SDRAM pins ++ */ ++ ++ /* PORT A: D0 ~ D31 */ ++ REG_GPIO_PXFUNS(0) = 0xffffffff; ++ REG_GPIO_PXSELC(0) = 0xffffffff; ++ ++ /* PORT B: A0 ~ A16, DCS#, RAS#, CAS#, CKE#, RDWE#, CKO#, WE0# */ ++ REG_GPIO_PXFUNS(1) = 0x81f9ffff; ++ REG_GPIO_PXSELC(1) = 0x81f9ffff; ++ ++ /* PORT C: WE1#, WE2#, WE3# */ ++ REG_GPIO_PXFUNS(2) = 0x07000000; ++ REG_GPIO_PXSELC(2) = 0x07000000; ++ ++ ++ /* ++ * Initialize UART0 pins ++ */ ++ ++ /* PORT D: TXD/RXD */ ++ REG_GPIO_PXFUNS(3) = 0x06000000; ++ REG_GPIO_PXSELS(3) = 0x06000000; ++ ++ ++ /* ++ * Initialize LED pins ++ */ ++ __gpio_as_lcd_18bit(); ++ ++ /* CS2# */ ++ REG_GPIO_PXFUNS(1) = 0x04000000; ++ REG_GPIO_PXSELC(1) = 0x04000000; ++ ++ __gpio_as_pcm(); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4750 FUWA board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = fuwa_timer_callback; ++} +diff --git a/arch/mips/jz4750/board-slt50.c b/arch/mips/jz4750/board-slt50.c +new file mode 100644 +index 0000000..e8e20b4 +--- /dev/null ++++ b/arch/mips/jz4750/board-slt50.c +@@ -0,0 +1,64 @@ ++/* ++ * linux/arch/mips/jz4750/board-apus.c ++ * ++ * JZ4750 APUS board setup routines. ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++} ++ ++static void apus_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4750/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ __gpio_as_pcm(); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4750 SLT_50 board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = apus_timer_callback; ++} +diff --git a/arch/mips/jz4750/cpufreq.c b/arch/mips/jz4750/cpufreq.c +new file mode 100644 +index 0000000..83f98b1 +--- /dev/null ++++ b/arch/mips/jz4750/cpufreq.c +@@ -0,0 +1,601 @@ ++/* ++ * linux/arch/mips/jz4750/cpufreq.c ++ * ++ * cpufreq driver for JZ4750 ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ ++ "cpufreq-jz4750", msg) ++ ++#undef CHANGE_PLL ++ ++#define PLL_UNCHANGED 0 ++#define PLL_GOES_UP 1 ++#define PLL_GOES_DOWN 2 ++ ++#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) ++ ++/* Saved the boot-time parameters */ ++static struct { ++ /* SDRAM parameters */ ++ unsigned int mclk; /* memory clock, KHz */ ++ unsigned int tras; /* RAS pulse width, cycles of mclk */ ++ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ ++ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ ++ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ ++ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ ++ unsigned int rtcor; /* Refresh Time Constant */ ++ unsigned int sdram_initialized; ++ ++ /* LCD parameters */ ++ unsigned int lcd_clk; /* LCD clock, Hz */ ++ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ ++ unsigned int lcd_clks_initialized; ++} boot_config; ++ ++struct jz4750_freq_percpu_info { ++ struct cpufreq_frequency_table table[7]; ++}; ++ ++static struct jz4750_freq_percpu_info jz4750_freq_table; ++ ++/* ++ * This contains the registers value for an operating point. ++ * If only part of a register needs to change then there is ++ * a mask value for that register. ++ * When going to a new operating point the current register ++ * value is ANDed with the ~mask and ORed with the new value. ++ */ ++struct dpm_regs { ++ u32 cpccr; /* Clock Freq Control Register */ ++ u32 cpccr_mask; /* Clock Freq Control Register mask */ ++ u32 cppcr; /* PLL1 Control Register */ ++ u32 cppcr_mask; /* PLL1 Control Register mask */ ++ u32 pll_up_flag; /* New PLL freq is higher than current or not */ ++}; ++ ++extern jz_clocks_t jz_clocks; ++ ++static void jz_update_clocks(void) ++{ ++ /* Next clocks must be updated if we have changed ++ * the PLL or divisors. ++ */ ++ jz_clocks.cclk = __cpm_get_cclk(); ++ jz_clocks.hclk = __cpm_get_hclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.i2sclk = __cpm_get_i2sclk(); ++ jz_clocks.usbclk = __cpm_get_usbclk(); ++ jz_clocks.mscclk = __cpm_get_mscclk(0); ++} ++ ++static void ++jz_init_boot_config(void) ++{ ++ if (!boot_config.lcd_clks_initialized) { ++ /* the first time to scale pll */ ++ boot_config.lcd_clk = __cpm_get_lcdclk(); ++ boot_config.lcdpix_clk = __cpm_get_pixclk(); ++ boot_config.lcd_clks_initialized = 1; ++ } ++ ++ if (!boot_config.sdram_initialized) { ++ /* the first time to scale frequencies */ ++ unsigned int dmcr, rtcor; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ ++ dmcr = REG_EMC_DMCR; ++ rtcor = REG_EMC_RTCOR; ++ ++ tras = (dmcr >> 13) & 0x7; ++ rcd = (dmcr >> 11) & 0x3; ++ tpc = (dmcr >> 8) & 0x7; ++ trwl = (dmcr >> 5) & 0x3; ++ trc = (dmcr >> 2) & 0x7; ++ ++ boot_config.mclk = __cpm_get_mclk() / 1000; ++ boot_config.tras = tras + 4; ++ boot_config.rcd = rcd + 1; ++ boot_config.tpc = tpc + 1; ++ boot_config.trwl = trwl + 1; ++ boot_config.trc = trc * 2 + 1; ++ boot_config.rtcor = rtcor; ++ ++ boot_config.sdram_initialized = 1; ++ } ++} ++ ++static void jz_update_dram_rtcor(unsigned int new_mclk) ++{ ++ unsigned int rtcor; ++ ++ new_mclk /= 1000; ++ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; ++ rtcor--; ++ ++ if (rtcor < 1) rtcor = 1; ++ if (rtcor > 255) rtcor = 255; ++ ++ REG_EMC_RTCOR = rtcor; ++ REG_EMC_RTCNT = rtcor; ++} ++ ++static void jz_update_dram_dmcr(unsigned int new_mclk) ++{ ++ unsigned int dmcr; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ unsigned int valid_time, new_time; /* ns */ ++ ++ new_mclk /= 1000; ++ tras = boot_config.tras * new_mclk / boot_config.mclk; ++ rcd = boot_config.rcd * new_mclk / boot_config.mclk; ++ tpc = boot_config.tpc * new_mclk / boot_config.mclk; ++ trwl = boot_config.trwl * new_mclk / boot_config.mclk; ++ trc = boot_config.trc * new_mclk / boot_config.mclk; ++ ++ /* Validation checking */ ++ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; ++ new_time = (tras * 1000000) / new_mclk; ++ if (new_time < valid_time) tras += 1; ++ ++ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; ++ new_time = (rcd * 1000000) / new_mclk; ++ if (new_time < valid_time) rcd += 1; ++ ++ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; ++ new_time = (tpc * 1000000) / new_mclk; ++ if (new_time < valid_time) tpc += 1; ++ ++ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; ++ new_time = (trwl * 1000000) / new_mclk; ++ if (new_time < valid_time) trwl += 1; ++ ++ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; ++ new_time = (trc * 1000000) / new_mclk; ++ if (new_time < valid_time) trc += 2; ++ ++ tras = (tras < 4) ? 4: tras; ++ tras = (tras > 11) ? 11: tras; ++ tras -= 4; ++ ++ rcd = (rcd < 1) ? 1: rcd; ++ rcd = (rcd > 4) ? 4: rcd; ++ rcd -= 1; ++ ++ tpc = (tpc < 1) ? 1: tpc; ++ tpc = (tpc > 8) ? 8: tpc; ++ tpc -= 1; ++ ++ trwl = (trwl < 1) ? 1: trwl; ++ trwl = (trwl > 4) ? 4: trwl; ++ trwl -= 1; ++ ++ trc = (trc < 1) ? 1: trc; ++ trc = (trc > 15) ? 15: trc; ++ trc /= 2; ++ ++ dmcr = REG_EMC_DMCR; ++ ++ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); ++ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); ++ ++ REG_EMC_DMCR = dmcr; ++} ++ ++static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR before changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } else { ++ /* We're going SLOWER: first update RTCOR value ++ * before changing the frequency. ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } ++} ++ ++static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so update RTCOR ++ * after changing the frequency ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } else { ++ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR after changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } ++} ++ ++static void jz_scale_divisors(struct dpm_regs *regs) ++{ ++ unsigned int cpccr; ++ unsigned int cur_mclk, new_mclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ cpccr = REG_CPM_CPCCR; ++ cpccr &= ~((unsigned long)regs->cpccr_mask); ++ cpccr |= regs->cpccr; ++ cpccr |= CPM_CPCCR_CE; /* update immediately */ ++ ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; ++ ++ /* Update some DRAM parameters before changing frequency */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++ ++#ifdef CHANGE_PLL ++/* Maintain the LCD clock and pixel clock */ ++static void jz_scale_lcd_divisors(struct dpm_regs *regs) ++{ ++ unsigned int new_pll, new_lcd_div, new_lcdpix_div; ++ unsigned int cpccr; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ if (!boot_config.lcd_clks_initialized) return; ++ ++ new_pll = __cpm_get_pllout(); ++ new_lcd_div = new_pll / boot_config.lcd_clk; ++ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; ++ ++ if (new_lcd_div < 1) ++ new_lcd_div = 1; ++ if (new_lcd_div > 16) ++ new_lcd_div = 16; ++ ++ if (new_lcdpix_div < 1) ++ new_lcdpix_div = 1; ++ if (new_lcdpix_div > 512) ++ new_lcdpix_div = 512; ++ ++// REG_CPM_CPCCR2 = new_lcdpix_div - 1; ++ ++ cpccr = REG_CPM_CPCCR; ++ cpccr &= ~CPM_CPCCR_LDIV_MASK; ++ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); ++ cpccr |= CPM_CPCCR_CE; /* update immediately */ ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); ++} ++ ++static void jz_scale_pll(struct dpm_regs *regs) ++{ ++ unsigned int cppcr; ++ unsigned int cur_mclk, new_mclk, new_pll; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ int od[] = {1, 2, 2, 4}; ++ ++ cppcr = REG_CPM_CPPCR; ++ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); ++ regs->cppcr &= ~CPM_CPPCR_PLLEN; ++ cppcr |= (regs->cppcr | 0xff); ++ ++ /* Update some DRAM parameters before changing frequency */ ++ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf]; ++ ++ /* ++ * Update some SDRAM parameters ++ */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* ++ * Update PLL, align code to cache line. ++ */ ++ cppcr |= CPM_CPPCR_PLLEN; ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPPCR), "r" (cppcr)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++#endif ++ ++static void jz4750_transition(struct dpm_regs *regs) ++{ ++ /* ++ * Get and save some boot-time conditions. ++ */ ++ jz_init_boot_config(); ++ ++#ifdef CHANGE_PLL ++ /* ++ * Disable LCD before scaling pll. ++ * LCD and LCD pixel clocks should not be changed even if the PLL ++ * output frequency has been changed. ++ */ ++ REG_LCD_CTRL &= ~LCD_CTRL_ENA; ++ ++ /* ++ * Stop module clocks before scaling PLL ++ */ ++ __cpm_stop_eth(); ++ __cpm_stop_aic(1); ++ __cpm_stop_aic(2); ++#endif ++ ++ /* ... add more as necessary */ ++ ++ if (regs->pll_up_flag == PLL_GOES_UP) { ++ /* the pll frequency is going up, so change dividors first */ ++ jz_scale_divisors(regs); ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ } ++ else if (regs->pll_up_flag == PLL_GOES_DOWN) { ++ /* the pll frequency is going down, so change pll first */ ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ jz_scale_divisors(regs); ++ } ++ else { ++ /* the pll frequency is unchanged, so change divisors only */ ++ jz_scale_divisors(regs); ++ } ++ ++#ifdef CHANGE_PLL ++ /* ++ * Restart module clocks before scaling PLL ++ */ ++ __cpm_start_eth(); ++ __cpm_start_aic(1); ++ __cpm_start_aic(2); ++ ++ /* ... add more as necessary */ ++ ++ /* Scale the LCD divisors after scaling pll */ ++ if (regs->pll_up_flag != PLL_UNCHANGED) { ++ jz_scale_lcd_divisors(regs); ++ } ++ ++ /* Enable LCD controller */ ++ REG_LCD_CTRL &= ~LCD_CTRL_DIS; ++ REG_LCD_CTRL |= LCD_CTRL_ENA; ++#endif ++ ++ /* Update system clocks */ ++ jz_update_clocks(); ++} ++ ++extern unsigned int idle_times; ++static unsigned int jz4750_freq_get(unsigned int cpu) ++{ ++ return (__cpm_get_cclk() / 1000); ++} ++ ++static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) ++{ ++ int n2FR[33] = { ++ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, ++ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, ++ 9 ++ }; ++ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ ++ unsigned int div_of_cclk, new_freq, i; ++ ++ regs->pll_up_flag = PLL_UNCHANGED; ++ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; ++ ++ new_freq = jz4750_freq_table.table[index].frequency; ++ ++ do { ++ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); ++ } while (div_of_cclk==0); ++ ++ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { ++ for(i = 1; i<4; i++) { ++ div[i] = 3; ++ } ++ } else { ++ for(i = 1; i<4; i++) { ++ div[i] = 2; ++ } ++ } ++ ++ for(i = 0; i<4; i++) { ++ div[i] *= div_of_cclk; ++ } ++ ++ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); ++ ++ regs->cpccr = ++ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | ++ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | ++ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | ++ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); ++ ++ return div_of_cclk; ++} ++ ++static void jz4750_set_cpu_divider_index(unsigned int cpu, unsigned int index) ++{ ++ unsigned long divisor, old_divisor; ++ struct cpufreq_freqs freqs; ++ struct dpm_regs regs; ++ ++ old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); ++ divisor = index_to_divisor(index, ®s); ++ ++ freqs.old = __cpm_get_cclk() / 1000; ++ freqs.new = __cpm_get_pllout() / (1000 * divisor); ++ freqs.cpu = cpu; ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (old_divisor != divisor) ++ jz4750_transition(®s); ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++} ++ ++static int jz4750_freq_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ unsigned int new_index = 0; ++ ++ if (cpufreq_frequency_table_target(policy, ++ &jz4750_freq_table.table[0], ++ target_freq, relation, &new_index)) ++ return -EINVAL; ++ ++ jz4750_set_cpu_divider_index(policy->cpu, new_index); ++ ++ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); ++ ++ return 0; ++} ++ ++static int jz4750_freq_verify(struct cpufreq_policy *policy) ++{ ++ return cpufreq_frequency_table_verify(policy, ++ &jz4750_freq_table.table[0]); ++} ++ ++static int __init jz4750_cpufreq_driver_init(struct cpufreq_policy *policy) ++{ ++ ++ struct cpufreq_frequency_table *table = &jz4750_freq_table.table[0]; ++ unsigned int MAX_FREQ; ++ ++ dprintk(KERN_INFO "Jz4750 cpufreq driver\n"); ++ ++ if (policy->cpu != 0) ++ return -EINVAL; ++ ++ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ ++ policy->cpuinfo.min_freq = MAX_FREQ/8; ++ policy->cpuinfo.max_freq = MAX_FREQ; ++ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ ++ ++ table[0].index = 0; ++ table[0].frequency = MAX_FREQ/8; ++ table[1].index = 1; ++ table[1].frequency = MAX_FREQ/6; ++ table[2].index = 2; ++ table[2].frequency = MAX_FREQ/4; ++ table[3].index = 3; ++ table[3].frequency = MAX_FREQ/3; ++ table[4].index = 4; ++ table[4].frequency = MAX_FREQ/2; ++ table[5].index = 5; ++ table[5].frequency = MAX_FREQ; ++ table[6].index = 6; ++ table[6].frequency = CPUFREQ_TABLE_END; ++ ++#ifdef CONFIG_CPU_FREQ_STAT_DETAILS ++ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ ++#endif ++ ++ return cpufreq_frequency_table_cpuinfo(policy, table); ++} ++ ++static struct cpufreq_driver cpufreq_jz4750_driver = { ++// .flags = CPUFREQ_STICKY, ++ .init = jz4750_cpufreq_driver_init, ++ .verify = jz4750_freq_verify, ++ .target = jz4750_freq_target, ++ .get = jz4750_freq_get, ++ .name = "jz4750", ++}; ++ ++static int __init jz4750_cpufreq_init(void) ++{ ++ return cpufreq_register_driver(&cpufreq_jz4750_driver); ++} ++ ++static void __exit jz4750_cpufreq_exit(void) ++{ ++ cpufreq_unregister_driver(&cpufreq_jz4750_driver); ++} ++ ++module_init(jz4750_cpufreq_init); ++module_exit(jz4750_cpufreq_exit); ++ ++MODULE_AUTHOR("Regen "); ++MODULE_DESCRIPTION("cpufreq driver for Jz4750"); ++MODULE_LICENSE("GPL"); +diff --git a/arch/mips/jz4750/dma.c b/arch/mips/jz4750/dma.c +new file mode 100644 +index 0000000..2508111 +--- /dev/null ++++ b/arch/mips/jz4750/dma.c +@@ -0,0 +1,836 @@ ++/* ++ * linux/arch/mips/jz4750/dma.c ++ * ++ * Support functions for the JZ4750 internal DMA channels. ++ * No-descriptor transfer only. ++ * Descriptor transfer should also call jz_request_dma() to get a free ++ * channel and call jz_free_dma() to free the channel. And driver should ++ * build the DMA descriptor and setup the DMA channel by itself. ++ * ++ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * A note on resource allocation: ++ * ++ * All drivers needing DMA channels, should allocate and release them ++ * through the public routines `jz_request_dma()' and `jz_free_dma()'. ++ * ++ * In order to avoid problems, all processes should allocate resources in ++ * the same sequence and release them in the reverse order. ++ * ++ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. ++ * When releasing them, first release the IRQ, then release the DMA. The ++ * main reason for this order is that, if you are requesting the DMA buffer ++ * done interrupt, you won't know the irq number until the DMA channel is ++ * returned from jz_request_dma(). ++ */ ++ ++struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { ++ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */ ++ {dev_id:-1,}, /* DMAC0 channel 1 */ ++ {dev_id:-1,}, /* DMAC0 channel 2 */ ++ {dev_id:-1,}, /* DMAC0 channel 3 */ ++ {dev_id:-1,}, /* DMAC0 channel 4 */ ++ {dev_id:-1,}, /* DMAC0 channel 5 */ ++ {dev_id:-1,}, /* DMAC1 channel 0 */ ++ {dev_id:-1,}, /* DMAC1 channel 1 */ ++ {dev_id:-1,}, /* DMAC1 channel 2 */ ++ {dev_id:-1,}, /* DMAC1 channel 3 */ ++ {dev_id:-1,}, /* DMAC1 channel 4 */ ++ {dev_id:-1,}, /* DMAC1 channel 5 */ ++}; ++ ++// Device FIFO addresses and default DMA modes ++static const struct { ++ unsigned int fifo_addr; ++ unsigned int dma_mode; ++ unsigned int dma_source; ++} dma_dev_table[DMA_ID_MAX] = { ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */ ++ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */ ++ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC}, ++ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC}, ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, ++// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN}, ++ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT}, ++ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN}, ++ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT}, ++ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN}, ++ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT}, ++ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN}, ++ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, ++ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, ++ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT}, ++ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN}, ++ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, ++ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, ++ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT}, ++ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN}, ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, ++ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */ ++ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */ ++ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */ ++ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT}, ++ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN}, ++ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT}, ++ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN}, ++ {}, ++}; ++ ++ ++int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data) ++{ ++ int i, len = 0; ++ struct jz_dma_chan *chan; ++ ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if ((chan = get_dma_chan(i)) != NULL) { ++ len += sprintf(buf + len, "%2d: %s\n", ++ i, chan->dev_str); ++ } ++ } ++ ++ if (fpos >= len) { ++ *start = buf; ++ *eof = 1; ++ return 0; ++ } ++ *start = buf + fpos; ++ if ((len -= fpos) > length) ++ return length; ++ *eof = 1; ++ return len; ++} ++ ++ ++void dump_jz_dma_channel(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > MAX_DMA_NUM) ++ return; ++ chan = &jz_dma_table[dmanr]; ++ ++ printk("DMA%d Registers:\n", dmanr); ++ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM)); ++ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); ++ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); ++ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); ++ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); ++ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); ++ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); ++ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); ++ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM)); ++} ++ ++ ++/** ++ * jz_request_dma - dynamically allcate an idle DMA channel to return ++ * @dev_id: the specified dma device id or DMA_ID_RAW_SET ++ * @dev_str: the specified dma device string name ++ * @irqhandler: the irq handler, or NULL ++ * @irqflags: the irq handler flags ++ * @irq_dev_id: the irq handler device id for shared irq ++ * ++ * Finds a free channel, and binds the requested device to it. ++ * Returns the allocated channel number, or negative on error. ++ * Requests the DMA done IRQ if irqhandler != NULL. ++ * ++*/ ++/*int jz_request_dma(int dev_id, const char *dev_str, ++ void (*irqhandler)(int, void *, struct pt_regs *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++*/ ++ ++int jz_request_dma(int dev_id, const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++{ ++ struct jz_dma_chan *chan; ++ int i, ret, chan0; ++ ++ if (dev_id < 0 || dev_id >= DMA_ID_MAX) ++ return -EINVAL; ++ ++ /* Because of a bug in DMA controller of jz4750, which causes auto ++ request and device request can't be allocated in a same DMA ++ controller, all device requests should be put in the second DMA ++ controller ++ */ ++ if (dev_id > DMA_ID_AUTO) ++ chan0 = 6; ++ else ++ chan0 = 0; ++ ++ for (i = chan0; i < MAX_DMA_NUM; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == MAX_DMA_NUM) /* no free channel */ ++ return -ENODEV; ++ ++ /* we got a free channel */ ++ chan = &jz_dma_table[i]; ++ ++ if (irqhandler) { ++ chan->irq = IRQ_DMA_0 + i; // allocate irq number ++ chan->irq_dev = irq_dev_id; ++ if ((ret = request_irq(chan->irq, irqhandler, irqflags, ++ dev_str, chan->irq_dev))) { ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ return ret; ++ } ++ } else { ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ } ++ ++ // fill it in ++ chan->io = i; ++ chan->dev_id = dev_id; ++ chan->dev_str = dev_str; ++ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; ++ chan->mode = dma_dev_table[dev_id].dma_mode; ++ chan->source = dma_dev_table[dev_id].dma_source; ++ ++ if (i < 6) ++ REG_DMAC_DMACKE(0) = 1 << i; ++ else ++ REG_DMAC_DMACKE(1) = 1 << (i - 6); ++ ++ return i; ++} ++ ++void jz_free_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) { ++ printk("Trying to free DMA%d\n", dmanr); ++ return; ++ } ++ ++ disable_dma(dmanr); ++ if (chan->irq) ++ free_irq(chan->irq, chan->irq_dev); ++ ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ chan->dev_id = -1; ++} ++ ++void jz_set_dma_dest_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_DWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCMD_DWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_DWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_DWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_src_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_SWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCMD_SWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_SWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_SWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_block_size(int dmanr, int nbyte) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_DS_MASK; ++ switch (nbyte) { ++ case 1: ++ chan->mode |= DMAC_DCMD_DS_8BIT; ++ break; ++ case 2: ++ chan->mode |= DMAC_DCMD_DS_16BIT; ++ break; ++ case 4: ++ chan->mode |= DMAC_DCMD_DS_32BIT; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_DS_16BYTE; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_DS_32BYTE; ++ break; ++ } ++} ++ ++unsigned int jz_get_dma_command(int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ return chan->mode; ++} ++ ++/** ++ * jz_set_dma_mode - do the raw settings for the specified DMA channel ++ * @dmanr: the specified DMA channel ++ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE ++ * @dma_mode: dma raw mode ++ * @dma_source: dma raw request source ++ * @fifo_addr: dma raw device fifo address ++ * ++ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call ++ * jz_set_dma_mode() rather than set_dma_mode() if you work with ++ * and external request dma device. ++ * ++ * NOTE: Don not dynamically allocate dma channel if one external request ++ * dma device will occupy this channel. ++*/ ++int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, ++ unsigned int dma_mode, unsigned int dma_source, ++ unsigned int fifo_addr) ++{ ++ int dev_id, i; ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > MAX_DMA_NUM) ++ return -ENODEV; ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == MAX_DMA_NUM) ++ return -ENODEV; ++ ++ chan = &jz_dma_table[dmanr]; ++ dev_id = chan->dev_id; ++ if (dev_id > 0) { ++ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", ++ __FUNCTION__, dmanr); ++ return -ENODEV; ++ } ++ ++ /* clone it from the dynamically allocated. */ ++ if (i != dmanr) { ++ chan->irq = jz_dma_table[i].irq; ++ chan->irq_dev = jz_dma_table[i].irq_dev; ++ chan->dev_str = jz_dma_table[i].dev_str; ++ jz_dma_table[i].irq = 0; ++ jz_dma_table[i].irq_dev = NULL; ++ jz_dma_table[i].dev_id = -1; ++ } ++ chan->dev_id = DMA_ID_RAW_SET; ++ chan->io = dmanr; ++ chan->fifo_addr = fifo_addr; ++ chan->mode = dma_mode; ++ chan->source = dma_source; ++ ++ set_dma_mode(dmanr, dma_mode); ++ ++ return dmanr; ++} ++ ++void enable_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ ++ __dmac_enable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_enable_irq(dmanr); ++} ++ ++#define DMA_DISABLE_POLL 0x10000 ++ ++void disable_dma(unsigned int dmanr) ++{ ++ int i; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ if (!__dmac_channel_enabled(dmanr)) ++ return; ++ ++ for (i = 0; i < DMA_DISABLE_POLL; i++) ++ if (__dmac_channel_transmit_end_detected(dmanr)) ++ break; ++#if 0 ++ if (i == DMA_DISABLE_POLL) ++ printk(KERN_INFO "disable_dma: poll expired!\n"); ++#endif ++ ++ __dmac_disable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_disable_irq(dmanr); ++} ++ ++/* Note: DMA_MODE_MASK is simulated by sw */ ++void set_dma_mode(unsigned int dmanr, unsigned int mode) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else { ++ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ } ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++} ++ ++void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) ++{ ++ unsigned int mode; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ mode = chan->mode & DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; ++ REG_DMAC_DTAR(chan->io) = phyaddr; ++ } else if (mode == DMA_MODE_WRITE) { ++ REG_DMAC_DSAR(chan->io) = phyaddr; ++ REG_DMAC_DTAR(chan->io) = chan->fifo_addr; ++ } else ++ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); ++} ++ ++void set_dma_count(unsigned int dmanr, unsigned int bytecnt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ unsigned int ds; ++ ++ if (!chan) ++ return; ++ ++ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; ++ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count ++} ++ ++unsigned int get_dma_residue(unsigned int dmanr) ++{ ++ unsigned int count, ds; ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ ++ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; ++ count = REG_DMAC_DTCR(chan->io); ++ count = count * dma_ds[ds]; ++ ++ return count; ++} ++ ++void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case AFMT_U8: ++ /* burst mode : 32BIT */ ++ break; ++ case AFMT_S16_LE: ++ /* burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else ++ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case 8: ++ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ ++ break; ++ case 16: ++ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else ++ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++//#define JZ4750_DMAC_TEST_ENABLE ++#undef JZ4750_DMAC_TEST_ENABLE ++ ++#ifdef JZ4750_DMAC_TEST_ENABLE ++ ++/* ++ * DMA test: external address <--> external address ++ */ ++#define TEST_DMA_SIZE 16*1024 ++ ++static jz_dma_desc *dma_desc; ++ ++static int dma_chan; ++static dma_addr_t dma_desc_phys_addr; ++static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; ++ ++static int dma_check_result(void *src, void *dst, int size) ++{ ++ unsigned int addr1, addr2, i, err = 0; ++ ++ addr1 = (unsigned int)src; ++ addr2 = (unsigned int)dst; ++ ++ for (i = 0; i < size; i += 4) { ++ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { ++ err++; ++ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); ++ } ++ addr1 += 4; ++ addr2 += 4; ++ } ++ printk("check DMA result err=%d\n", err); ++ return err; ++} ++ ++static irqreturn_t jz4750_dma_irq(int irq, void *dev_id) ++{ ++ printk("jz4750_dma_irq %d\n", irq); ++ ++ ++ if (__dmac_channel_transmit_halt_detected(dma_chan)) { ++ printk("DMA HALT\n"); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_halt(dma_chan); ++ } ++ ++ if (__dmac_channel_address_error_detected(dma_chan)) { ++ printk("DMA ADDR ERROR\n"); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */ ++ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */ ++ __dmac_channel_clear_address_error(dma_chan); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ printk("DMA DESC INVALID\n"); ++ __dmac_channel_clear_descriptor_invalid(dma_chan); ++ } ++ ++ if (__dmac_channel_count_terminated_detected(dma_chan)) { ++ printk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(dma_chan); ++ } ++ ++ if (__dmac_channel_transmit_end_detected(dma_chan)) { ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ printk("DMA TT\n"); ++ __dmac_channel_clear_transmit_end(dma_chan); ++ dump_jz_dma_channel(dma_chan); ++ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++void dma_nodesc_test(void) ++{ ++ unsigned int addr, i; ++ ++ printk("dma_nodesc_test\n"); ++ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq, ++ IRQF_DISABLED, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq failed\n"); ++ return; ++ } ++ ++ printk("Requested DMA channel = %d\n", dma_chan); ++ ++ /* Allocate DMA buffers */ ++ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ ++ dma_src_phys_addr = CPHYSADDR(dma_src_addr); ++ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); ++ ++ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); ++ ++ /* Prepare data for source buffer */ ++ addr = (unsigned int)dma_src_addr; ++ for (i = 0; i < TEST_DMA_SIZE; i += 4) { ++ *(volatile unsigned int *)addr = addr; ++ addr += 4; ++ } ++ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); ++ ++ /* Init target buffer */ ++ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); ++ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); ++ ++ /* Init DMA module */ ++ printk("Starting DMA\n"); ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0; ++ REG_DMAC_DCCSR(dma_chan) = 0; ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = 512; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); ++ ++ /* wait a long time, ensure transfer end */ ++ printk("wait 3s...\n"); ++ mdelay(3000); /* wait 3s */ ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ /* free buffers */ ++ printk("free DMA buffers\n"); ++ free_pages(dma_src_addr, 2); ++ free_pages(dma_dst_addr, 2); ++ ++ if (dma_desc) ++ free_pages((unsigned int)dma_desc, 0); ++ ++ /* free dma */ ++ jz_free_dma(dma_chan); ++} ++ ++void dma_desc_test(void) ++{ ++ unsigned int next, addr, i; ++ static jz_dma_desc *desc; ++ ++ printk("dma_desc_test\n"); ++ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq, ++ IRQF_DISABLED, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq failed\n"); ++ return; ++ } ++ ++ printk("Requested DMA channel = %d\n", dma_chan); ++ ++ /* Allocate DMA buffers */ ++ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ ++ dma_src_phys_addr = CPHYSADDR(dma_src_addr); ++ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); ++ ++ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); ++ ++ /* Prepare data for source buffer */ ++ addr = (unsigned int)dma_src_addr; ++ for (i = 0; i < TEST_DMA_SIZE; i += 4) { ++ *(volatile unsigned int *)addr = addr; ++ addr += 4; ++ } ++ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); ++ ++ /* Init target buffer */ ++ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); ++ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); ++ ++ /* Allocate DMA descriptors */ ++ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); ++ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); ++ ++ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); ++ ++ /* Setup DMA descriptors */ ++ desc = dma_desc; ++ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr; /* DMA target address */ ++ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ ++ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ ++ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; ++ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ ++ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ ++ ++ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; ++ ++ /* DMA doorbell set -- start DMA now ... */ ++ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan; ++ ++ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); ++ /* wait a long time, ensure transfer end */ ++ printk("wait 3s...\n"); ++ mdelay(3000); /* wait 3s */ ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ /* free buffers */ ++ printk("free DMA buffers\n"); ++ free_pages(dma_src_addr, 2); ++ free_pages(dma_dst_addr, 2); ++ ++ if (dma_desc) ++ free_pages((unsigned int)dma_desc, 0); ++ ++ /* free dma */ ++ jz_free_dma(dma_chan); ++} ++ ++#endif ++ ++//EXPORT_SYMBOL_NOVERS(jz_dma_table); ++EXPORT_SYMBOL(jz_dma_table); ++EXPORT_SYMBOL(jz_request_dma); ++EXPORT_SYMBOL(jz_free_dma); ++EXPORT_SYMBOL(jz_set_dma_src_width); ++EXPORT_SYMBOL(jz_set_dma_dest_width); ++EXPORT_SYMBOL(jz_set_dma_block_size); ++EXPORT_SYMBOL(jz_set_dma_mode); ++EXPORT_SYMBOL(set_dma_mode); ++EXPORT_SYMBOL(jz_set_oss_dma); ++EXPORT_SYMBOL(jz_set_alsa_dma); ++EXPORT_SYMBOL(set_dma_addr); ++EXPORT_SYMBOL(set_dma_count); ++EXPORT_SYMBOL(get_dma_residue); ++EXPORT_SYMBOL(enable_dma); ++EXPORT_SYMBOL(disable_dma); ++EXPORT_SYMBOL(dump_jz_dma_channel); +diff --git a/arch/mips/jz4750/i2c.c b/arch/mips/jz4750/i2c.c +new file mode 100644 +index 0000000..cdb1223 +--- /dev/null ++++ b/arch/mips/jz4750/i2c.c +@@ -0,0 +1,273 @@ ++/* ++ * linux/arch/mips/jz4750/i2c.c ++ * ++ * Jz4750 I2C routines. ++ * ++ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* I2C protocol */ ++#define I2C_READ 1 ++#define I2C_WRITE 0 ++ ++#define TIMEOUT 1000 ++ ++/* ++ * I2C bus protocol basic routines ++ */ ++static int i2c_put_data(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (!__i2c_received_ack() && timeout) ++ timeout--; ++ ++ if (timeout) ++ return 0; ++ else ++ return -ETIMEDOUT; ++} ++ ++#ifdef CONFIG_JZ_TPANEL_ATA2508 ++static int i2c_put_data_nack(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (timeout--); ++ return 0; ++} ++#endif ++ ++static int i2c_get_data(unsigned char *data, int ack) ++{ ++ int timeout = TIMEOUT*10; ++ ++ if (!ack) ++ __i2c_send_nack(); ++ else ++ __i2c_send_ack(); ++ ++ while (__i2c_check_drf() == 0 && timeout) ++ timeout--; ++ ++ if (timeout) { ++ if (!ack) ++ __i2c_send_stop(); ++ *data = __i2c_read(); ++ __i2c_clear_drf(); ++ return 0; ++ } else ++ return -ETIMEDOUT; ++} ++ ++/* ++ * I2C interface ++ */ ++void i2c_open(void) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ ++ __i2c_enable(); ++} ++ ++void i2c_close(void) ++{ ++ udelay(300); /* wait for STOP goes over. */ ++ __i2c_disable(); ++} ++ ++void i2c_setclk(unsigned int i2cclk) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, i2cclk); ++} ++ ++int i2c_lseek(unsigned char device, unsigned char offset) ++{ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++ if (i2c_put_data(offset) < 0) ++ goto address_err; ++ return 0; ++ device_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++ address_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); ++ __i2c_send_stop(); ++ return -EREMOTEIO; ++} ++ ++int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int timeout = 5; ++ ++L_try_again: ++ ++ if (timeout < 0) ++ goto L_timeout; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_werr; ++ if (i2c_put_data(address) < 0) ++ goto address_err; ++ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) ++ goto device_rerr; ++ __i2c_send_ack(); /* Master sends ACK for continue reading */ ++ while (cnt) { ++ if (cnt == 1) { ++ if (i2c_get_data(buf, 0) < 0) ++ break; ++ } else { ++ if (i2c_get_data(buf, 1) < 0) ++ break; ++ } ++ cnt--; ++ buf++; ++ } ++ ++ __i2c_send_stop(); ++ return count - cnt; ++ device_rerr: ++ device_werr: ++ address_err: ++ timeout --; ++ __i2c_send_stop(); ++ goto L_try_again; ++ ++L_timeout: ++ __i2c_send_stop(); ++ printk("Read I2C device 0x%2x failed.\n", device); ++ return -ENODEV; ++} ++ ++int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int cnt_in_pg; ++ int timeout = 5; ++ unsigned char *tmpbuf; ++ unsigned char tmpaddr; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ ++ W_try_again: ++ if (timeout < 0) ++ goto W_timeout; ++ ++ cnt = count; ++ tmpbuf = (unsigned char *)buf; ++ tmpaddr = address; ++ ++ start_write_page: ++ cnt_in_pg = 0; ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++#ifdef CONFIG_JZ_TPANEL_ATA2508 ++ if (address == 0xff) { ++ if (i2c_put_data_nack(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data_nack(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ } ++ else { ++ ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ } ++#else ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++#endif ++ __i2c_send_stop(); ++ return count - cnt; ++ device_err: ++ address_err: ++ timeout--; ++ __i2c_send_stop(); ++ goto W_try_again; ++ ++ W_timeout: ++ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++} ++ ++EXPORT_SYMBOL(i2c_open); ++EXPORT_SYMBOL(i2c_close); ++EXPORT_SYMBOL(i2c_setclk); ++EXPORT_SYMBOL(i2c_read); ++EXPORT_SYMBOL(i2c_write); +diff --git a/arch/mips/jz4750/irq.c b/arch/mips/jz4750/irq.c +new file mode 100644 +index 0000000..6a9d867 +--- /dev/null ++++ b/arch/mips/jz4750/irq.c +@@ -0,0 +1,299 @@ ++/* ++ * linux/arch/mips/jz4750/irq.c ++ * ++ * JZ4750 interrupt routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * INTC irq type ++ */ ++ ++static void enable_intc_irq(unsigned int irq) ++{ ++ __intc_unmask_irq(irq); ++} ++ ++static void disable_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++} ++ ++static void mask_and_ack_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++ __intc_ack_irq(irq); ++} ++ ++static void end_intc_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_intc_irq(irq); ++ } ++} ++ ++static unsigned int startup_intc_irq(unsigned int irq) ++{ ++ enable_intc_irq(irq); ++ return 0; ++} ++ ++static void shutdown_intc_irq(unsigned int irq) ++{ ++ disable_intc_irq(irq); ++} ++ ++static struct irq_chip intc_irq_type = { ++ .typename = "INTC", ++ .startup = startup_intc_irq, ++ .shutdown = shutdown_intc_irq, ++ .enable = enable_intc_irq, ++ .disable = disable_intc_irq, ++ .ack = mask_and_ack_intc_irq, ++ .end = end_intc_irq, ++}; ++ ++/* ++ * GPIO irq type ++ */ ++ ++static void enable_gpio_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if (irq < (IRQ_GPIO_0 + 32)) { ++ intc_irq = IRQ_GPIO0; ++ } ++ else if (irq < (IRQ_GPIO_0 + 64)) { ++ intc_irq = IRQ_GPIO1; ++ } ++ else if (irq < (IRQ_GPIO_0 + 96)) { ++ intc_irq = IRQ_GPIO2; ++ } ++ else if (irq < (IRQ_GPIO_0 + 128)) { ++ intc_irq = IRQ_GPIO3; ++ } ++ else if (irq < (IRQ_GPIO_0 + 160)) { ++ intc_irq = IRQ_GPIO4; ++ } ++ else { ++ intc_irq = IRQ_GPIO5; ++ } ++ ++ enable_intc_irq(intc_irq); ++ __gpio_unmask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void disable_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void mask_and_ack_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++ __gpio_ack_irq(irq - IRQ_GPIO_0); ++} ++ ++static void end_gpio_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_gpio_irq(irq); ++ } ++} ++ ++static unsigned int startup_gpio_irq(unsigned int irq) ++{ ++ enable_gpio_irq(irq); ++ return 0; ++} ++ ++static void shutdown_gpio_irq(unsigned int irq) ++{ ++ disable_gpio_irq(irq); ++} ++ ++static struct irq_chip gpio_irq_type = { ++ .typename = "GPIO", ++ .startup = startup_gpio_irq, ++ .shutdown = shutdown_gpio_irq, ++ .enable = enable_gpio_irq, ++ .disable = disable_gpio_irq, ++ .ack = mask_and_ack_gpio_irq, ++ .end = end_gpio_irq, ++}; ++ ++/* ++ * DMA irq type ++ */ ++ ++static void enable_dma_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ ++ intc_irq = IRQ_DMAC0; ++ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ ++ intc_irq = IRQ_DMAC1; ++ else { ++ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); ++ return; ++ } ++ __intc_unmask_irq(intc_irq); ++ __dmac_channel_enable_irq(irq - IRQ_DMA_0); ++} ++ ++static void disable_dma_irq(unsigned int irq) ++{ ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void mask_and_ack_dma_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ ++ intc_irq = IRQ_DMAC0; ++ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ ++ intc_irq = IRQ_DMAC1; ++ else { ++ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); ++ return ; ++ } ++ __intc_ack_irq(intc_irq); ++ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */ ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void end_dma_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_dma_irq(irq); ++ } ++} ++ ++static unsigned int startup_dma_irq(unsigned int irq) ++{ ++ enable_dma_irq(irq); ++ return 0; ++} ++ ++static void shutdown_dma_irq(unsigned int irq) ++{ ++ disable_dma_irq(irq); ++} ++ ++static struct irq_chip dma_irq_type = { ++ .typename = "DMA", ++ .startup = startup_dma_irq, ++ .shutdown = shutdown_dma_irq, ++ .enable = enable_dma_irq, ++ .disable = disable_dma_irq, ++ .ack = mask_and_ack_dma_irq, ++ .end = end_dma_irq, ++}; ++ ++//---------------------------------------------------------------------- ++ ++void __init arch_init_irq(void) ++{ ++ int i; ++ ++ clear_c0_status(0xff04); /* clear ERL */ ++ set_c0_status(0x0400); /* set IP2 */ ++ ++ /* Set up INTC irq ++ */ ++ for (i = 0; i < 32; i++) { ++ disable_intc_irq(i); ++ irq_desc[i].chip = &intc_irq_type; ++ } ++ ++ /* Set up DMAC irq ++ */ ++ for (i = 0; i < NUM_DMA; i++) { ++ disable_dma_irq(IRQ_DMA_0 + i); ++ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; ++ } ++ ++ /* Set up GPIO irq ++ */ ++ for (i = 0; i < NUM_GPIO; i++) { ++ disable_gpio_irq(IRQ_GPIO_0 + i); ++ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; ++ } ++} ++ ++static int plat_real_irq(int irq) ++{ ++ switch (irq) { ++ case IRQ_GPIO0: ++ irq = __gpio_group_irq(0) + IRQ_GPIO_0; ++ break; ++ case IRQ_GPIO1: ++ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; ++ break; ++ case IRQ_GPIO2: ++ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; ++ break; ++ case IRQ_GPIO3: ++ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; ++ break; ++ case IRQ_GPIO4: ++ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128; ++ break; ++ case IRQ_GPIO5: ++ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160; ++ break; ++ case IRQ_DMAC0: ++ case IRQ_DMAC1: ++ irq = __dmac_get_irq() + IRQ_DMA_0; ++ break; ++ } ++ ++ return irq; ++} ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ int irq = 0; ++ static unsigned long intc_ipr = 0; ++ ++ intc_ipr |= REG_INTC_IPR; ++ ++ if (!intc_ipr) return; ++ ++ irq = ffs(intc_ipr) - 1; ++ intc_ipr &= ~(1< ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* OHCI (USB full speed host controller) */ ++static struct resource jz_usb_ohci_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap ++ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UHC, ++ .end = IRQ_UHC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++/* The dmamask must be set for OHCI to work */ ++static u64 ohci_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_ohci_device = { ++ .name = "jz-ohci", ++ .id = 0, ++ .dev = { ++ .dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), ++ .resource = jz_usb_ohci_resources, ++}; ++ ++/*** LCD controller ***/ ++static struct resource jz_lcd_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(LCD_BASE), ++ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_LCD, ++ .end = IRQ_LCD, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_lcd_dmamask = ~(u32)0; ++ ++static struct platform_device jz_lcd_device = { ++ .name = "jz-lcd", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_lcd_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_lcd_resources), ++ .resource = jz_lcd_resources, ++}; ++ ++/* UDC (USB gadget controller) */ ++static struct resource jz_usb_gdt_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UDC_BASE), ++ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UDC, ++ .end = IRQ_UDC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static u64 udc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_gdt_device = { ++ .name = "jz-udc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &udc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), ++ .resource = jz_usb_gdt_resources, ++}; ++ ++/** MMC/SD controller **/ ++static struct resource jz_mmc_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(MSC_BASE), ++ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_MSC0, ++ .end = IRQ_MSC0, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_mmc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_mmc_device = { ++ .name = "jz-mmc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_mmc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_mmc_resources), ++ .resource = jz_mmc_resources, ++}; ++ ++/* All */ ++static struct platform_device *jz_platform_devices[] __initdata = { ++ &jz_usb_ohci_device, ++ &jz_lcd_device, ++ &jz_usb_gdt_device, ++ &jz_mmc_device, ++}; ++ ++static int __init jz_platform_init(void) ++{ ++ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); ++} ++ ++arch_initcall(jz_platform_init); +diff --git a/arch/mips/jz4750/pm.c b/arch/mips/jz4750/pm.c +new file mode 100644 +index 0000000..b918cb2 +--- /dev/null ++++ b/arch/mips/jz4750/pm.c +@@ -0,0 +1,463 @@ ++/* ++ * linux/arch/mips/jz4750/common/pm.c ++ * ++ * JZ4750 Power Management Routines ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++ ++#define GPIO_PORT_NUM 6 ++ ++/* ++ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input ++ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select. ++ */ ++#define __gpio_as_sleep() \ ++do { \ ++ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \ ++ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(2) = ~0x01e00000; \ ++ REG_GPIO_PXSELC(2) = ~0x01e00000; \ ++ REG_GPIO_PXDIRC(2) = ~0x01e00000; \ ++ REG_GPIO_PXPES(2) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(3) = 0xffffffff; \ ++ REG_GPIO_PXSELC(3) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(3) = 0xffffffff; \ ++ REG_GPIO_PXPES(3) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(4) = 0xffffffff; \ ++ REG_GPIO_PXSELC(4) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(4) = 0xffffffff; \ ++ REG_GPIO_PXPES(4) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(5) = 0xffffffff; \ ++ REG_GPIO_PXSELC(5) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(5) = 0xffffffff; \ ++ REG_GPIO_PXPES(5) = 0xffffffff; \ ++} while (0) ++ ++static int jz_pm_do_hibernate(void) ++{ ++ printk("Put CPU into hibernate mode.\n"); ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* ++ * RTC Wakeup or 1Hz interrupt can be enabled or disabled ++ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c). ++ */ ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */ ++ ++ /* Scratch pad register to be reserved */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HSPR = 0x12345678; ++ ++ /* clear wakeup status register */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HWRSR = 0x0; ++ ++ /* Put CPU to power down mode */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HCR = RTC_HCR_PD; ++ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ while(1); ++ ++ /* We can't get here */ ++ return 0; ++} ++ ++/* NOTES: ++ * 1: Pins that are floated (NC) should be set as input and pull-enable. ++ * 2: Pins that are pull-up or pull-down by outside should be set as input ++ * and pull-disable. ++ * 3: Pins that are connected to a chip except sdram and nand flash ++ * should be set as input and pull-disable, too. ++ */ ++static void jz_board_do_sleep(unsigned long *ptr) ++{ ++ unsigned char i; ++ ++ /* Print messages of GPIO registers for debug */ ++ for(i=0;i ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#define DEBUG 1 ++#undef DEBUG ++ ++ ++struct proc_dir_entry *proc_jz_root; ++ ++ ++/* ++ * EMC Modules ++ */ ++static int emc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); ++ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); ++ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); ++ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); ++ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); ++ return len; ++} ++ ++/* ++ * Power Manager Module ++ */ ++static int pmc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned long lcr = REG_CPM_LCR; ++ unsigned long clkgr = REG_CPM_CLKGR; ++ ++ len += sprintf (page+len, "Low Power Mode : %s\n", ++ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? ++ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? ++ "SLEEP" : "HIBERNATE")); ++ len += sprintf (page+len, "Doze Mode : %s\n", ++ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); ++ if (lcr & CPM_LCR_DOZE_ON) ++ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); ++ len += sprintf (page+len, "IPU : %s\n", ++ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); ++ len += sprintf (page+len, "DMAC : %s\n", ++ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); ++ len += sprintf (page+len, "UHC : %s\n", ++ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running"); ++ len += sprintf (page+len, "UDC : %s\n", ++ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); ++ len += sprintf (page+len, "LCD : %s\n", ++ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); ++ len += sprintf (page+len, "CIM : %s\n", ++ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); ++ len += sprintf (page+len, "SADC : %s\n", ++ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); ++ len += sprintf (page+len, "MSC0 : %s\n", ++ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running"); ++ len += sprintf (page+len, "MSC1 : %s\n", ++ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running"); ++ len += sprintf (page+len, "AIC1 : %s\n", ++ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running"); ++ len += sprintf (page+len, "AIC2 : %s\n", ++ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running"); ++ len += sprintf (page+len, "SSI0 : %s\n", ++ (clkgr & CPM_CLKGR_SSI0) ? "stopped" : "running"); ++ len += sprintf (page+len, "SSI1 : %s\n", ++ (clkgr & CPM_CLKGR_SSI1) ? "stopped" : "running"); ++ len += sprintf (page+len, "I2C : %s\n", ++ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); ++ len += sprintf (page+len, "RTC : %s\n", ++ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); ++ len += sprintf (page+len, "TCU : %s\n", ++ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART1 : %s\n", ++ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART0 : %s\n", ++ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); ++ return len; ++} ++ ++static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++/* ++ * Clock Generation Module ++ */ ++#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 ++#define TO_KHZ(x) (x/1000),(x%1000)/10 ++ ++static int cgm_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ ++ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ ++ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int od[4] = {1, 2, 2, 4}; ++ ++ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); ++ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); ++ len += sprintf (page+len, "PLL : %s\n", ++ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); ++ len += sprintf (page+len, "m:n:o : %d:%d:%d\n", ++ __cpm_get_pllm() + 2, ++ __cpm_get_plln() + 2, ++ od[__cpm_get_pllod()] ++ ); ++ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", ++ div[__cpm_get_cdiv()], ++ div[__cpm_get_hdiv()], ++ div[__cpm_get_mdiv()], ++ div[__cpm_get_pdiv()] ++ ); ++ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); ++ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); ++ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); ++ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); ++ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); ++ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk())); ++ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); ++ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); ++ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); ++ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0))); ++ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1))); ++ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0())); ++ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); ++ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); ++ ++ return len; ++} ++ ++static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++ ++/* USAGE: ++ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages. ++ * echo FF > /proc/jz/ipu // 255, free all buffer ++ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx ++ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l) ++ * echo 0 > /proc/jz/ipu // debug, print ipu_buf ++ * od -X /proc/jz/ipu // read mem addr ++ */ ++ ++typedef struct _ipu_buf { ++ unsigned int addr; /* phys addr */ ++ unsigned int page_shift; ++} ipu_buf_t; ++ ++#define IPU_BUF_MAX 4 /* 4 buffers */ ++ ++static struct _ipu_buf ipu_buf[IPU_BUF_MAX]; ++static int ipu_buf_cnt = 0; ++static unsigned char g_asid=0; ++ ++extern void local_flush_tlb_all(void); ++ ++/* CP0 hazard avoidance. */ ++#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ ++ "nop; nop; nop; nop; nop; nop;\n\t" \ ++ ".set reorder\n\t") ++void show_tlb(void) ++{ ++#define ASID_MASK 0xFF ++ ++ unsigned long flags; ++ unsigned int old_ctx; ++ unsigned int entry; ++ unsigned int entrylo0, entrylo1, entryhi; ++ unsigned int pagemask; ++ ++ local_irq_save(flags); ++ ++ /* Save old context */ ++ old_ctx = (read_c0_entryhi() & 0xff); ++ ++ printk("TLB content:\n"); ++ entry = 0; ++ while(entry < 32) { ++ write_c0_index(entry); ++ BARRIER; ++ tlb_read(); ++ BARRIER; ++ entryhi = read_c0_entryhi(); ++ entrylo0 = read_c0_entrylo0(); ++ entrylo1 = read_c0_entrylo1(); ++ pagemask = read_c0_pagemask(); ++ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); ++ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); ++ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); ++ ++ printk("\t\tpagemask=0x%08x", pagemask); ++ printk("\tentryhi=0x%08x\n", entryhi); ++ printk("\t\tentrylo0=0x%08x", entrylo0); ++ printk("\tentrylo1=0x%08x\n", entrylo1); ++ ++ entry++; ++ } ++ BARRIER; ++ write_c0_entryhi(old_ctx); ++ ++ local_irq_restore(flags); ++} ++ ++static void ipu_add_wired_entry(unsigned long pid, ++ unsigned long entrylo0, unsigned long entrylo1, ++ unsigned long entryhi, unsigned long pagemask) ++{ ++ unsigned long flags; ++ unsigned long wired; ++ unsigned long old_pagemask; ++ unsigned long old_ctx; ++ struct task_struct *g, *p; ++ ++ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ ++ entrylo0 = entrylo0 >> 6; ++ entrylo0 |= 0x6 | (0 << 3); ++ /*entrylo0 |= 0x6 | (1 << 3);*/ ++ ++ do_each_thread(g, p) { ++ if (p->pid == pid ) ++ g_asid = p->mm->context[0]; ++ } while_each_thread(g, p); ++ ++ local_irq_save(flags); ++ /* Save old context and create impossible VPN2 value */ ++ old_ctx = read_c0_entryhi() & 0xff; ++ old_pagemask = read_c0_pagemask(); ++ wired = read_c0_wired(); ++ write_c0_wired(wired + 1); ++ write_c0_index(wired); ++ BARRIER; ++ entryhi &= ~0xff; /* new add, 20070906 */ ++ entryhi |= g_asid; /* new add, 20070906 */ ++// entryhi |= old_ctx; /* new add, 20070906 */ ++ write_c0_pagemask(pagemask); ++ write_c0_entryhi(entryhi); ++ write_c0_entrylo0(entrylo0); ++ write_c0_entrylo1(entrylo1); ++ BARRIER; ++ tlb_write_indexed(); ++ BARRIER; ++ ++ write_c0_entryhi(old_ctx); ++ BARRIER; ++ write_c0_pagemask(old_pagemask); ++ local_flush_tlb_all(); ++ local_irq_restore(flags); ++#if defined(DEBUG) ++ printk("\nold_ctx=%03d\n", old_ctx); ++ ++ show_tlb(); ++#endif ++} ++ ++static void ipu_del_wired_entry( void ) ++{ ++ unsigned long flags; ++ unsigned long wired; ++ ++ local_irq_save(flags); ++ wired = read_c0_wired(); ++ if (wired) { ++ write_c0_wired(0); ++ } ++ local_irq_restore(flags); ++} ++ ++static inline void ipu_buf_get( unsigned int page_shift ) ++{ ++ unsigned char * virt_addr; ++ int i; ++ for ( i=0; i< IPU_BUF_MAX; ++i ) { ++ if ( ipu_buf[i].addr == 0 ) { ++ break; ++ } ++ } ++ ++ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) { ++ printk("Error, no free ipu buffer.\n"); ++ return ; ++ } ++ ++ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ ++ if ( virt_addr ) { ++ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr); ++ ipu_buf[ipu_buf_cnt].page_shift = page_shift; ++ ++ for (i = 0; i < (1<= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */ ++ printk("no free buffer.\n"); ++ *pint = 0; ++ } ++ else ++ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */ ++ len += sizeof(unsigned int); ++ ++#if defined(DEBUG) ++ show_tlb(); ++#endif ++ return len; ++ ++} ++ ++static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ unsigned int val ; ++ int cnt,i; ++ char buf[12]; ++ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask; ++#if defined(DEBUG) ++ printk("ipu write count=%u\n", count); ++#endif ++ if (count == 41) { ++ for (i=0;i<12;i++) ++ buf[i]=0; ++ strncpy(buf, buffer+8*0, 8); ++ pid = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) ++ buf[i]=0; ++ strncpy(buf, buffer+8*1, 8); ++ entrylo0 = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) ++ buf[i]=0; ++ strncpy(buf, buffer+8*2, 8); ++ entrylo1 = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) ++ buf[i]=0; ++ strncpy(buf, buffer+8*3, 8); ++ entryhi = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) ++ buf[i]=0; ++ strncpy(buf, buffer+8*4, 8); ++ pagemask = simple_strtoul(buf, 0, 16); ++ ++#if defined(DEBUG) ++ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n", ++ pid, entrylo0, entrylo1, entryhi, pagemask); ++#endif ++ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask); ++ return 41; ++ } else if ( count <= 9 ) { ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer, 8); ++ val = simple_strtoul(buf, 0, 16); ++ } else if (count == 44) { ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer, 10); ++ pid = simple_strtoul(buf, 0, 16); ++ ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 11, 10); ++ entryhi = simple_strtoul(buf, 0, 16);//vaddr ++ ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 22, 10); ++ entrylo0 = simple_strtoul(buf, 0, 16);//paddr ++ ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 33, 10); ++ pagemask = simple_strtoul(buf, 0, 16); ++ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */ ++ //pagemask = 0xfff << 13; /* Fixed to 16MB page size */ ++ ++ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask); ++ return 44; ++ } else if (count == 12) { ++ printk("\necho release tlb > /proc/jz/ipu\n"); ++ ipu_del_wired_entry(); ++ return 12; ++ } else { ++ printk("ipu write count error, count=%d\n.", (unsigned int)count); ++ return -1; ++ } ++ ++ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */ ++ if ( val == 0 ) { /* debug, print ipu_buf info */ ++ for ( cnt=0; cnt /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages ++ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx ++ * echo FF > /proc/jz/ipu // FF, free all buffers ++ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer ++ */ ++ ++//#define DEBUG_IMEM 1 ++ ++#define IMEM_MAX_ORDER 12 /* max 2^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; ++ } ++ ++ /* show tlb */ ++ res = create_proc_entry("tlb", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = tlb_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++ /* ++ * Reserve a 4MB memory for IPU on JZ4750. ++ */ ++ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER); ++ if (jz_imem_base) { ++ /* imem (IPU memory management) */ ++ res = create_proc_entry("imem", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = imem_read_proc; ++ res->write_proc = imem_write_proc; ++ res->data = NULL; ++ } ++ ++ /* Set page reserved */ ++ virt_addr = jz_imem_base; ++ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) { ++ SetPageReserved(virt_to_page((void *)virt_addr)); ++ virt_addr += PAGE_SIZE; ++ } ++ ++ /* Convert to physical address */ ++ jz_imem_base = virt_to_phys((void *)jz_imem_base); ++ ++ printk("Total %dMB memory at 0x%x was reserved for IPU\n", ++ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base); ++ } else ++ printk("NOT enough memory for imem\n"); ++ ++ return 0; ++} ++ ++__initcall(jz_proc_init); +diff --git a/arch/mips/jz4750/prom.c b/arch/mips/jz4750/prom.c +new file mode 100644 +index 0000000..d04bb3e +--- /dev/null ++++ b/arch/mips/jz4750/prom.c +@@ -0,0 +1,198 @@ ++/* ++ * ++ * BRIEF MODULE DESCRIPTION ++ * PROM library initialisation code, supports YAMON and U-Boot. ++ * ++ * Copyright 2000, 2001, 2006 MontaVista Software Inc. ++ * Author: MontaVista Software, Inc. ++ * ppopov@mvista.com or source@mvista.com ++ * ++ * This file was derived from Carsten Langgaard's ++ * arch/mips/mips-boards/xx files. ++ * ++ * Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* #define DEBUG_CMDLINE */ ++ ++int prom_argc; ++char **prom_argv, **prom_envp; ++ ++char * prom_getcmdline(void) ++{ ++ return &(arcs_cmdline[0]); ++} ++ ++void prom_init_cmdline(void) ++{ ++ char *cp; ++ int actr; ++ ++ actr = 1; /* Always ignore argv[0] */ ++ ++ cp = &(arcs_cmdline[0]); ++ while(actr < prom_argc) { ++ strcpy(cp, prom_argv[actr]); ++ cp += strlen(prom_argv[actr]); ++ *cp++ = ' '; ++ actr++; ++ } ++ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ ++ --cp; ++ if (prom_argc > 1) ++ *cp = '\0'; ++ ++} ++ ++ ++char *prom_getenv(char *envname) ++{ ++#if 0 ++ /* ++ * Return a pointer to the given environment variable. ++ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". ++ */ ++ ++ char **env = prom_envp; ++ int i = strlen(envname); ++ int yamon = (*env && strchr(*env, '=') == NULL); ++ ++ while (*env) { ++ if (yamon) { ++ if (strcmp(envname, *env++) == 0) ++ return *env; ++ } else { ++ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') ++ return *env + i + 1; ++ } ++ env++; ++ } ++#endif ++ return NULL; ++} ++ ++inline unsigned char str2hexnum(unsigned char c) ++{ ++ if(c >= '0' && c <= '9') ++ return c - '0'; ++ if(c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if(c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return 0; /* foo */ ++} ++ ++inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for(i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= (str2hexnum(*str++)); ++ ea[i] = num; ++ } ++} ++ ++int get_ethernet_addr(char *ethernet_addr) ++{ ++ char *ethaddr_str; ++ ++ ethaddr_str = prom_getenv("ethaddr"); ++ if (!ethaddr_str) { ++ printk("ethaddr not set in boot prom\n"); ++ return -1; ++ } ++ str2eaddr(ethernet_addr, ethaddr_str); ++ ++#if 0 ++ { ++ int i; ++ ++ printk("get_ethernet_addr: "); ++ for (i=0; i<5; i++) ++ printk("%02x:", (unsigned char)*(ethernet_addr+i)); ++ printk("%02x\n", *(ethernet_addr+i)); ++ } ++#endif ++ ++ return 0; ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++void __init prom_init(void) ++{ ++ unsigned char *memsize_str; ++ unsigned long memsize; ++ ++ prom_argc = (int) fw_arg0; ++ prom_argv = (char **) fw_arg1; ++ prom_envp = (char **) fw_arg2; ++ ++ mips_machtype = MACH_INGENIC_JZ4750; ++ ++ prom_init_cmdline(); ++ memsize_str = prom_getenv("memsize"); ++ if (!memsize_str) { ++ memsize = 0x04000000; ++ } else { ++ memsize = simple_strtol(memsize_str, NULL, 0); ++ } ++ add_memory_region(0, memsize, BOOT_MEM_RAM); ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR); ++ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); ++ ++ *uart_tdr = (u8)c; ++} ++ ++const char *get_system_type(void) ++{ ++ return "JZ4750"; ++} ++ ++EXPORT_SYMBOL(prom_getcmdline); ++EXPORT_SYMBOL(get_ethernet_addr); ++EXPORT_SYMBOL(str2eaddr); +diff --git a/arch/mips/jz4750/reset.c b/arch/mips/jz4750/reset.c +new file mode 100644 +index 0000000..90b521e +--- /dev/null ++++ b/arch/mips/jz4750/reset.c +@@ -0,0 +1,46 @@ ++/* ++ * linux/arch/mips/jz4750/reset.c ++ * ++ * JZ4750 reset routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void jz_restart(char *command) ++{ ++ printk("Restarting after 4 ms\n"); ++ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; ++ REG_WDT_TCNT = 0; ++ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ ++ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */ ++ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ ++ while (1); ++} ++ ++void jz_halt(void) ++{ ++ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); ++ ++ while (1) ++ __asm__(".set\tmips3\n\t" ++ "wait\n\t" ++ ".set\tmips0"); ++} ++ ++void jz_power_off(void) ++{ ++ jz_halt(); ++} +diff --git a/arch/mips/jz4750/setup.c b/arch/mips/jz4750/setup.c +new file mode 100644 +index 0000000..b9b4240 +--- /dev/null ++++ b/arch/mips/jz4750/setup.c +@@ -0,0 +1,197 @@ ++/* ++ * linux/arch/mips/jz4750/common/setup.c ++ * ++ * JZ4750 common setup routines. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PC_KEYB ++#include ++#endif ++ ++jz_clocks_t jz_clocks; ++ ++extern char * __init prom_getcmdline(void); ++extern void __init jz_board_setup(void); ++extern void jz_restart(char *); ++extern void jz_halt(void); ++extern void jz_power_off(void); ++extern void jz_time_init(void); ++ ++static void __init sysclocks_setup(void) ++{ ++#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ ++ jz_clocks.cclk = __cpm_get_cclk(); ++ jz_clocks.hclk = __cpm_get_hclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.i2sclk = __cpm_get_i2sclk(); ++ jz_clocks.usbclk = __cpm_get_usbclk(); ++ jz_clocks.mscclk = __cpm_get_mscclk(0); ++ jz_clocks.extalclk = __cpm_get_extalclk(); ++ jz_clocks.rtcclk = __cpm_get_rtcclk(); ++#else ++ ++#define FPGACLK 8000000 ++ ++ jz_clocks.cclk = FPGACLK; ++ jz_clocks.hclk = FPGACLK; ++ jz_clocks.pclk = FPGACLK; ++ jz_clocks.mclk = FPGACLK; ++ jz_clocks.lcdclk = FPGACLK; ++ jz_clocks.pixclk = FPGACLK; ++ jz_clocks.i2sclk = FPGACLK; ++ jz_clocks.usbclk = FPGACLK; ++ jz_clocks.mscclk = FPGACLK; ++ jz_clocks.extalclk = FPGACLK; ++ jz_clocks.rtcclk = FPGACLK; ++#endif ++ ++ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n", ++ (jz_clocks.cclk + 500000) / 1000000, ++ (jz_clocks.hclk + 500000) / 1000000, ++ (jz_clocks.pclk + 500000) / 1000000, ++ (jz_clocks.mclk + 500000) / 1000000); ++} ++ ++static void __init soc_cpm_setup(void) ++{ ++ /* Start all module clocks ++ */ ++ __cpm_start_all(); ++ ++ /* Enable CKO to external memory */ ++ __cpm_enable_cko(); ++ ++ /* CPU enters IDLE mode when executing 'wait' instruction */ ++ __cpm_idle_mode(); ++ ++ /* Setup system clocks */ ++ sysclocks_setup(); ++} ++ ++static void __init soc_harb_setup(void) ++{ ++// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ ++// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ ++// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ ++} ++ ++static void __init soc_emc_setup(void) ++{ ++} ++ ++static void __init soc_dmac_setup(void) ++{ ++ __dmac_enable_module(0); ++ __dmac_enable_module(1); ++} ++ ++static void __init jz_soc_setup(void) ++{ ++ soc_cpm_setup(); ++ soc_harb_setup(); ++ soc_emc_setup(); ++ soc_dmac_setup(); ++} ++ ++static void __init jz_serial_setup(void) ++{ ++#ifdef CONFIG_SERIAL_8250 ++ struct uart_port s; ++ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */ ++ memset(&s, 0, sizeof(s)); ++ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; ++ s.iotype = SERIAL_IO_MEM; ++ s.regshift = 2; ++ s.uartclk = jz_clocks.extalclk ; ++ ++ s.line = 0; ++ s.membase = (u8 *)UART0_BASE; ++ s.irq = IRQ_UART0; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); ++ } ++ ++ s.line = 1; ++ s.membase = (u8 *)UART1_BASE; ++ s.irq = IRQ_UART1; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); ++ } ++ ++ s.line = 2; ++ s.membase = (u8 *)UART2_BASE; ++ s.irq = IRQ_UART2; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS2 setup failed!\n"); ++ } ++ ++ s.line = 3; ++ s.membase = (u8 *)UART3_BASE; ++ s.irq = IRQ_UART3; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS3 setup failed!\n"); ++ } ++#endif ++} ++ ++void __init plat_mem_setup(void) ++{ ++ char *argptr; ++ ++ argptr = prom_getcmdline(); ++ ++ /* IO/MEM resources. Which will be the addtion value in `inX' and ++ * `outX' macros defined in asm/io.h */ ++ set_io_port_base(0); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ ++ _machine_restart = jz_restart; ++ _machine_halt = jz_halt; ++ pm_power_off = jz_power_off; ++ ++ jz_soc_setup(); ++ jz_serial_setup(); ++ jz_board_setup(); ++} ++ +diff --git a/arch/mips/jz4750/time.c b/arch/mips/jz4750/time.c +new file mode 100644 +index 0000000..e5d18b5 +--- /dev/null ++++ b/arch/mips/jz4750/time.c +@@ -0,0 +1,156 @@ ++/* ++ * linux/arch/mips/jz4750/time.c ++ * ++ * Setting up the clock on the JZ4750 boards. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* This is for machines which generate the exact clock. */ ++ ++#define JZ_TIMER_IRQ IRQ_TCU0 ++ ++#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ ++ ++static struct clocksource clocksource_jz; /* Jz clock source */ ++static struct clock_event_device jz_clockevent_device; /* Jz clock event */ ++ ++void (*jz_timer_callback)(void); ++ ++static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ ++ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */ ++ ++ if (jz_timer_callback) ++ jz_timer_callback(); ++ ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction jz_irqaction = { ++ .handler = jz_timer_interrupt, ++ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, ++ .name = "jz-timerirq", ++}; ++ ++ ++cycle_t jz_get_cycles(void) ++{ ++ /* convert jiffes to jz timer cycles */ ++ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT); ++} ++ ++static struct clocksource clocksource_jz = { ++ .name = "jz_clocksource", ++ .rating = 300, ++ .read = jz_get_cycles, ++ .mask = 0xFFFFFFFF, ++ .shift = 10, ++ .flags = CLOCK_SOURCE_WATCHDOG, ++}; ++ ++static int __init jz_clocksource_init(void) ++{ ++ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); ++ clocksource_register(&clocksource_jz); ++ return 0; ++} ++ ++static int jz_set_next_event(unsigned long evt, ++ struct clock_event_device *unused) ++{ ++ return 0; ++} ++ ++static void jz_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ break; ++ } ++} ++ ++static struct clock_event_device jz_clockevent_device = { ++ .name = "jz-clockenvent", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ ++ ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ .rating = 300, ++ .irq = JZ_TIMER_IRQ, ++ .set_mode = jz_set_mode, ++ .set_next_event = jz_set_next_event, ++}; ++ ++static void __init jz_clockevent_init(void) ++{ ++ struct clock_event_device *cd = &jz_clockevent_device; ++ unsigned int cpu = smp_processor_id(); ++ ++ cd->cpumask = cpumask_of_cpu(cpu); ++ clockevents_register_device(cd); ++} ++ ++static void __init jz_timer_setup(void) ++{ ++ jz_clocksource_init(); /* init jz clock source */ ++ jz_clockevent_init(); /* init jz clock event */ ++ ++ /* ++ * Make irqs happen for the system timer ++ */ ++ jz_irqaction.dev_id = &jz_clockevent_device; ++ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); ++} ++ ++ ++void __init plat_time_init(void) ++{ ++ unsigned int latch; ++ ++ /* Init timer */ ++ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ; ++ ++ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN; ++ REG_TCU_OSTCNT = 0; ++ REG_TCU_OSTDR = latch; ++ ++ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */ ++ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */ ++ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */ ++ ++ jz_timer_setup(); ++} +diff --git a/arch/mips/jz4750d/Makefile b/arch/mips/jz4750d/Makefile +new file mode 100644 +index 0000000..6bd5189 +--- /dev/null ++++ b/arch/mips/jz4750d/Makefile +@@ -0,0 +1,23 @@ ++# ++# Makefile for the Ingenic JZ4750D. ++# ++ ++# Object file lists. ++ ++obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ ++ platform.o i2c.o ++ ++obj-$(CONFIG_PROC_FS) += proc.o ++ ++# board specific support ++ ++obj-$(CONFIG_JZ4750D_FUWA1) += board-fuwa1.o ++obj-$(CONFIG_JZ4750D_CETUS) += board-cetus.o ++ ++# PM support ++ ++obj-$(CONFIG_PM_LEGACY) +=pm.o ++ ++# CPU Frequency scaling support ++ ++obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o +diff --git a/arch/mips/jz4750d/board-cetus.c b/arch/mips/jz4750d/board-cetus.c +new file mode 100644 +index 0000000..0febbd3 +--- /dev/null ++++ b/arch/mips/jz4750d/board-cetus.c +@@ -0,0 +1,72 @@ ++/* ++ * linux/arch/mips/jz4750d/board-cetus.c ++ * ++ * JZ4750D CETUS board setup routines. ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned char slash[] = "\\|/-"; ++// static volatile unsigned char *p = (unsigned char *)0xb6000058; ++ static volatile unsigned char *p = (unsigned char *)0xb6000016; ++ static unsigned int count = 0; ++ *p = slash[count++]; ++ count &= 3; ++} ++ ++static void cetus_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4750d/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Initialize SDRAM pins ++ */ ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4750D CETUS board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = cetus_timer_callback; ++} +diff --git a/arch/mips/jz4750d/board-fuwa1.c b/arch/mips/jz4750d/board-fuwa1.c +new file mode 100644 +index 0000000..e9294c3 +--- /dev/null ++++ b/arch/mips/jz4750d/board-fuwa1.c +@@ -0,0 +1,72 @@ ++/* ++ * linux/arch/mips/jz4750d/board-fuwa1.c ++ * ++ * JZ4750D FUWA1 board setup routines. ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++extern void (*jz_timer_callback)(void); ++ ++static void dancing(void) ++{ ++ static unsigned char slash[] = "\\|/-"; ++// static volatile unsigned char *p = (unsigned char *)0xb6000058; ++ static volatile unsigned char *p = (unsigned char *)0xb6000016; ++ static unsigned int count = 0; ++ *p = slash[count++]; ++ count &= 3; ++} ++ ++static void fuwa1_timer_callback(void) ++{ ++ static unsigned long count = 0; ++ ++ if ((++count) % 50 == 0) { ++ dancing(); ++ count = 0; ++ } ++} ++ ++static void __init board_cpm_setup(void) ++{ ++ /* Stop unused module clocks here. ++ * We have started all module clocks at arch/mips/jz4750d/setup.c. ++ */ ++} ++ ++static void __init board_gpio_setup(void) ++{ ++ /* ++ * Initialize SDRAM pins ++ */ ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("JZ4750D FUWA1 board setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = fuwa1_timer_callback; ++} +diff --git a/arch/mips/jz4750d/cpufreq.c b/arch/mips/jz4750d/cpufreq.c +new file mode 100644 +index 0000000..c0d63ac +--- /dev/null ++++ b/arch/mips/jz4750d/cpufreq.c +@@ -0,0 +1,598 @@ ++/* ++ * linux/arch/mips/jz4750d/cpufreq.c ++ * ++ * cpufreq driver for JZ4750D ++ * ++ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ ++ "cpufreq-jz4750d", msg) ++ ++#undef CHANGE_PLL ++ ++#define PLL_UNCHANGED 0 ++#define PLL_GOES_UP 1 ++#define PLL_GOES_DOWN 2 ++ ++#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) ++ ++/* Saved the boot-time parameters */ ++static struct { ++ /* SDRAM parameters */ ++ unsigned int mclk; /* memory clock, KHz */ ++ unsigned int tras; /* RAS pulse width, cycles of mclk */ ++ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ ++ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ ++ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ ++ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ ++ unsigned int rtcor; /* Refresh Time Constant */ ++ unsigned int sdram_initialized; ++ ++ /* LCD parameters */ ++ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ ++ unsigned int lcd_clks_initialized; ++} boot_config; ++ ++struct jz4750d_freq_percpu_info { ++ struct cpufreq_frequency_table table[7]; ++}; ++ ++static struct jz4750d_freq_percpu_info jz4750d_freq_table; ++ ++/* ++ * This contains the registers value for an operating point. ++ * If only part of a register needs to change then there is ++ * a mask value for that register. ++ * When going to a new operating point the current register ++ * value is ANDed with the ~mask and ORed with the new value. ++ */ ++struct dpm_regs { ++ u32 cpccr; /* Clock Freq Control Register */ ++ u32 cpccr_mask; /* Clock Freq Control Register mask */ ++ u32 cppcr; /* PLL1 Control Register */ ++ u32 cppcr_mask; /* PLL1 Control Register mask */ ++ u32 pll_up_flag; /* New PLL freq is higher than current or not */ ++}; ++ ++extern jz_clocks_t jz_clocks; ++ ++static void jz_update_clocks(void) ++{ ++ /* Next clocks must be updated if we have changed ++ * the PLL or divisors. ++ */ ++ jz_clocks.cclk = __cpm_get_cclk(); ++ jz_clocks.hclk = __cpm_get_hclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.i2sclk = __cpm_get_i2sclk(); ++ jz_clocks.usbclk = __cpm_get_usbclk(); ++ jz_clocks.mscclk = __cpm_get_mscclk(0); ++} ++ ++static void ++jz_init_boot_config(void) ++{ ++ if (!boot_config.lcd_clks_initialized) { ++ /* the first time to scale pll */ ++ boot_config.lcdpix_clk = __cpm_get_pixclk(); ++ boot_config.lcd_clks_initialized = 1; ++ } ++ ++ if (!boot_config.sdram_initialized) { ++ /* the first time to scale frequencies */ ++ unsigned int dmcr, rtcor; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ ++ dmcr = REG_EMC_DMCR; ++ rtcor = REG_EMC_RTCOR; ++ ++ tras = (dmcr >> 13) & 0x7; ++ rcd = (dmcr >> 11) & 0x3; ++ tpc = (dmcr >> 8) & 0x7; ++ trwl = (dmcr >> 5) & 0x3; ++ trc = (dmcr >> 2) & 0x7; ++ ++ boot_config.mclk = __cpm_get_mclk() / 1000; ++ boot_config.tras = tras + 4; ++ boot_config.rcd = rcd + 1; ++ boot_config.tpc = tpc + 1; ++ boot_config.trwl = trwl + 1; ++ boot_config.trc = trc * 2 + 1; ++ boot_config.rtcor = rtcor; ++ ++ boot_config.sdram_initialized = 1; ++ } ++} ++ ++static void jz_update_dram_rtcor(unsigned int new_mclk) ++{ ++ unsigned int rtcor; ++ ++ new_mclk /= 1000; ++ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; ++ rtcor--; ++ ++ if (rtcor < 1) rtcor = 1; ++ if (rtcor > 255) rtcor = 255; ++ ++ REG_EMC_RTCOR = rtcor; ++ REG_EMC_RTCNT = rtcor; ++} ++ ++static void jz_update_dram_dmcr(unsigned int new_mclk) ++{ ++ unsigned int dmcr; ++ unsigned int tras, rcd, tpc, trwl, trc; ++ unsigned int valid_time, new_time; /* ns */ ++ ++ new_mclk /= 1000; ++ tras = boot_config.tras * new_mclk / boot_config.mclk; ++ rcd = boot_config.rcd * new_mclk / boot_config.mclk; ++ tpc = boot_config.tpc * new_mclk / boot_config.mclk; ++ trwl = boot_config.trwl * new_mclk / boot_config.mclk; ++ trc = boot_config.trc * new_mclk / boot_config.mclk; ++ ++ /* Validation checking */ ++ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; ++ new_time = (tras * 1000000) / new_mclk; ++ if (new_time < valid_time) tras += 1; ++ ++ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; ++ new_time = (rcd * 1000000) / new_mclk; ++ if (new_time < valid_time) rcd += 1; ++ ++ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; ++ new_time = (tpc * 1000000) / new_mclk; ++ if (new_time < valid_time) tpc += 1; ++ ++ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; ++ new_time = (trwl * 1000000) / new_mclk; ++ if (new_time < valid_time) trwl += 1; ++ ++ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; ++ new_time = (trc * 1000000) / new_mclk; ++ if (new_time < valid_time) trc += 2; ++ ++ tras = (tras < 4) ? 4: tras; ++ tras = (tras > 11) ? 11: tras; ++ tras -= 4; ++ ++ rcd = (rcd < 1) ? 1: rcd; ++ rcd = (rcd > 4) ? 4: rcd; ++ rcd -= 1; ++ ++ tpc = (tpc < 1) ? 1: tpc; ++ tpc = (tpc > 8) ? 8: tpc; ++ tpc -= 1; ++ ++ trwl = (trwl < 1) ? 1: trwl; ++ trwl = (trwl > 4) ? 4: trwl; ++ trwl -= 1; ++ ++ trc = (trc < 1) ? 1: trc; ++ trc = (trc > 15) ? 15: trc; ++ trc /= 2; ++ ++ dmcr = REG_EMC_DMCR; ++ ++ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); ++ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); ++ ++ REG_EMC_DMCR = dmcr; ++} ++ ++static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR before changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } else { ++ /* We're going SLOWER: first update RTCOR value ++ * before changing the frequency. ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } ++} ++ ++static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) ++{ ++ /* No risk, no fun: run with interrupts on! */ ++ if (new_mclk > cur_mclk) { ++ /* We're going FASTER, so update RTCOR ++ * after changing the frequency ++ */ ++ jz_update_dram_rtcor(new_mclk); ++ } else { ++ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL ++ * and TRC of DMCR after changing the frequency. ++ */ ++ jz_update_dram_dmcr(new_mclk); ++ } ++} ++ ++static void jz_scale_divisors(struct dpm_regs *regs) ++{ ++ unsigned int cpccr; ++ unsigned int cur_mclk, new_mclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ cpccr = REG_CPM_CPCCR; ++ cpccr &= ~((unsigned long)regs->cpccr_mask); ++ cpccr |= regs->cpccr; ++ cpccr |= CPM_CPCCR_CE; /* update immediately */ ++ ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; ++ ++ /* Update some DRAM parameters before changing frequency */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++ ++#ifdef CHANGE_PLL ++/* Maintain the LCD clock and pixel clock */ ++static void jz_scale_lcd_divisors(struct dpm_regs *regs) ++{ ++ unsigned int new_pll, new_lcd_div, new_lcdpix_div; ++ unsigned int cpccr; ++ unsigned int tmp = 0, wait = PLL_WAIT_500NS; ++ ++ if (!boot_config.lcd_clks_initialized) return; ++ ++ new_pll = __cpm_get_pllout(); ++ new_lcd_div = new_pll / boot_config.lcd_clk; ++ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; ++ ++ if (new_lcd_div < 1) ++ new_lcd_div = 1; ++ if (new_lcd_div > 16) ++ new_lcd_div = 16; ++ ++ if (new_lcdpix_div < 1) ++ new_lcdpix_div = 1; ++ if (new_lcdpix_div > 512) ++ new_lcdpix_div = 512; ++ ++// REG_CPM_CPCCR2 = new_lcdpix_div - 1; ++ ++ cpccr = REG_CPM_CPCCR; ++ cpccr &= ~CPM_CPCCR_LDIV_MASK; ++ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); ++ cpccr |= CPM_CPCCR_CE; /* update immediately */ ++ ++ /* update register to change the clocks. ++ * align this code to a cache line. ++ */ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "li %3,0\n\t" ++ "1:\n\t" ++ "bne %3,%2,1b\n\t" ++ "addi %3, 1\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); ++} ++ ++static void jz_scale_pll(struct dpm_regs *regs) ++{ ++ unsigned int cppcr; ++ unsigned int cur_mclk, new_mclk, new_pll; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ int od[] = {1, 2, 2, 4}; ++ ++ cppcr = REG_CPM_CPPCR; ++ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); ++ regs->cppcr &= ~CPM_CPPCR_PLLEN; ++ cppcr |= (regs->cppcr | 0xff); ++ ++ /* Update some DRAM parameters before changing frequency */ ++ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); ++ cur_mclk = __cpm_get_mclk(); ++ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf]; ++ ++ /* ++ * Update some SDRAM parameters ++ */ ++ jz_update_dram_prev(cur_mclk, new_mclk); ++ ++ /* ++ * Update PLL, align code to cache line. ++ */ ++ cppcr |= CPM_CPPCR_PLLEN; ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".align 5\n" ++ "sw %1,0(%0)\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ "nop\n\t" ++ ".set reorder\n\t" ++ : ++ : "r" (CPM_CPPCR), "r" (cppcr)); ++ ++ /* Update some other DRAM parameters after changing frequency */ ++ jz_update_dram_post(cur_mclk, new_mclk); ++} ++#endif ++ ++static void jz4750d_transition(struct dpm_regs *regs) ++{ ++ /* ++ * Get and save some boot-time conditions. ++ */ ++ jz_init_boot_config(); ++ ++#ifdef CHANGE_PLL ++ /* ++ * Disable LCD before scaling pll. ++ * LCD and LCD pixel clocks should not be changed even if the PLL ++ * output frequency has been changed. ++ */ ++ REG_LCD_CTRL &= ~LCD_CTRL_ENA; ++ ++ /* ++ * Stop module clocks before scaling PLL ++ */ ++ __cpm_stop_eth(); ++ __cpm_stop_aic(1); ++ __cpm_stop_aic(2); ++#endif ++ ++ /* ... add more as necessary */ ++ ++ if (regs->pll_up_flag == PLL_GOES_UP) { ++ /* the pll frequency is going up, so change dividors first */ ++ jz_scale_divisors(regs); ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ } ++ else if (regs->pll_up_flag == PLL_GOES_DOWN) { ++ /* the pll frequency is going down, so change pll first */ ++#ifdef CHANGE_PLL ++ jz_scale_pll(regs); ++#endif ++ jz_scale_divisors(regs); ++ } ++ else { ++ /* the pll frequency is unchanged, so change divisors only */ ++ jz_scale_divisors(regs); ++ } ++ ++#ifdef CHANGE_PLL ++ /* ++ * Restart module clocks before scaling PLL ++ */ ++ __cpm_start_eth(); ++ __cpm_start_aic(1); ++ __cpm_start_aic(2); ++ ++ /* ... add more as necessary */ ++ ++ /* Scale the LCD divisors after scaling pll */ ++ if (regs->pll_up_flag != PLL_UNCHANGED) { ++ jz_scale_lcd_divisors(regs); ++ } ++ ++ /* Enable LCD controller */ ++ REG_LCD_CTRL &= ~LCD_CTRL_DIS; ++ REG_LCD_CTRL |= LCD_CTRL_ENA; ++#endif ++ ++ /* Update system clocks */ ++ jz_update_clocks(); ++} ++ ++extern unsigned int idle_times; ++static unsigned int jz4750d_freq_get(unsigned int cpu) ++{ ++ return (__cpm_get_cclk() / 1000); ++} ++ ++static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) ++{ ++ int n2FR[33] = { ++ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, ++ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, ++ 9 ++ }; ++ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ ++ unsigned int div_of_cclk, new_freq, i; ++ ++ regs->pll_up_flag = PLL_UNCHANGED; ++ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; ++ ++ new_freq = jz4750d_freq_table.table[index].frequency; ++ ++ do { ++ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); ++ } while (div_of_cclk==0); ++ ++ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { ++ for(i = 1; i<4; i++) { ++ div[i] = 3; ++ } ++ } else { ++ for(i = 1; i<4; i++) { ++ div[i] = 2; ++ } ++ } ++ ++ for(i = 0; i<4; i++) { ++ div[i] *= div_of_cclk; ++ } ++ ++ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); ++ ++ regs->cpccr = ++ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | ++ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | ++ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | ++ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); ++ ++ return div_of_cclk; ++} ++ ++static void jz4750d_set_cpu_divider_index(unsigned int cpu, unsigned int index) ++{ ++ unsigned long divisor, old_divisor; ++ struct cpufreq_freqs freqs; ++ struct dpm_regs regs; ++ ++ old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); ++ divisor = index_to_divisor(index, ®s); ++ ++ freqs.old = __cpm_get_cclk() / 1000; ++ freqs.new = __cpm_get_pllout() / (1000 * divisor); ++ freqs.cpu = cpu; ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (old_divisor != divisor) ++ jz4750d_transition(®s); ++ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++} ++ ++static int jz4750d_freq_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ unsigned int new_index = 0; ++ ++ if (cpufreq_frequency_table_target(policy, ++ &jz4750d_freq_table.table[0], ++ target_freq, relation, &new_index)) ++ return -EINVAL; ++ ++ jz4750d_set_cpu_divider_index(policy->cpu, new_index); ++ ++ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); ++ ++ return 0; ++} ++ ++static int jz4750d_freq_verify(struct cpufreq_policy *policy) ++{ ++ return cpufreq_frequency_table_verify(policy, ++ &jz4750d_freq_table.table[0]); ++} ++ ++static int __init jz4750d_cpufreq_driver_init(struct cpufreq_policy *policy) ++{ ++ ++ struct cpufreq_frequency_table *table = &jz4750d_freq_table.table[0]; ++ unsigned int MAX_FREQ; ++ ++ dprintk(KERN_INFO "Jz4750d cpufreq driver\n"); ++ ++ if (policy->cpu != 0) ++ return -EINVAL; ++ ++ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ ++ policy->cpuinfo.min_freq = MAX_FREQ/8; ++ policy->cpuinfo.max_freq = MAX_FREQ; ++ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ ++ ++ table[0].index = 0; ++ table[0].frequency = MAX_FREQ/8; ++ table[1].index = 1; ++ table[1].frequency = MAX_FREQ/6; ++ table[2].index = 2; ++ table[2].frequency = MAX_FREQ/4; ++ table[3].index = 3; ++ table[3].frequency = MAX_FREQ/3; ++ table[4].index = 4; ++ table[4].frequency = MAX_FREQ/2; ++ table[5].index = 5; ++ table[5].frequency = MAX_FREQ; ++ table[6].index = 6; ++ table[6].frequency = CPUFREQ_TABLE_END; ++ ++#ifdef CONFIG_CPU_FREQ_STAT_DETAILS ++ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ ++#endif ++ ++ return cpufreq_frequency_table_cpuinfo(policy, table); ++} ++ ++static struct cpufreq_driver cpufreq_jz4750d_driver = { ++// .flags = CPUFREQ_STICKY, ++ .init = jz4750d_cpufreq_driver_init, ++ .verify = jz4750d_freq_verify, ++ .target = jz4750d_freq_target, ++ .get = jz4750d_freq_get, ++ .name = "jz4750d", ++}; ++ ++static int __init jz4750d_cpufreq_init(void) ++{ ++ return cpufreq_register_driver(&cpufreq_jz4750d_driver); ++} ++ ++static void __exit jz4750d_cpufreq_exit(void) ++{ ++ cpufreq_unregister_driver(&cpufreq_jz4750d_driver); ++} ++ ++module_init(jz4750d_cpufreq_init); ++module_exit(jz4750d_cpufreq_exit); ++ ++MODULE_AUTHOR("Regen "); ++MODULE_DESCRIPTION("cpufreq driver for Jz4750d"); ++MODULE_LICENSE("GPL"); +diff --git a/arch/mips/jz4750d/dma.c b/arch/mips/jz4750d/dma.c +new file mode 100644 +index 0000000..290cc12 +--- /dev/null ++++ b/arch/mips/jz4750d/dma.c +@@ -0,0 +1,822 @@ ++/* ++ * linux/arch/mips/jz4750d/dma.c ++ * ++ * Support functions for the JZ4750D internal DMA channels. ++ * No-descriptor transfer only. ++ * Descriptor transfer should also call jz_request_dma() to get a free ++ * channel and call jz_free_dma() to free the channel. And driver should ++ * build the DMA descriptor and setup the DMA channel by itself. ++ * ++ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * A note on resource allocation: ++ * ++ * All drivers needing DMA channels, should allocate and release them ++ * through the public routines `jz_request_dma()' and `jz_free_dma()'. ++ * ++ * In order to avoid problems, all processes should allocate resources in ++ * the same sequence and release them in the reverse order. ++ * ++ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. ++ * When releasing them, first release the IRQ, then release the DMA. The ++ * main reason for this order is that, if you are requesting the DMA buffer ++ * done interrupt, you won't know the irq number until the DMA channel is ++ * returned from jz_request_dma(). ++ */ ++ ++struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { ++ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */ ++ {dev_id:-1,}, /* DMAC0 channel 1 */ ++ {dev_id:-1,}, /* DMAC0 channel 2 */ ++ {dev_id:-1,}, /* DMAC0 channel 3 */ ++ {dev_id:-1,}, /* DMAC1 channel 0 */ ++ {dev_id:-1,}, /* DMAC1 channel 1 */ ++ {dev_id:-1,}, /* DMAC1 channel 2 */ ++ {dev_id:-1,}, /* DMAC1 channel 3 */ ++}; ++ ++// Device FIFO addresses and default DMA modes ++static const struct { ++ unsigned int fifo_addr; ++ unsigned int dma_mode; ++ unsigned int dma_source; ++} dma_dev_table[DMA_ID_MAX] = { ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */ ++ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */ ++ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC}, ++ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC}, ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, ++// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN}, ++ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT}, ++ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN}, ++ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT}, ++ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN}, ++ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT}, ++ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN}, ++ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, ++ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, ++ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT}, ++ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN}, ++ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, ++ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, ++ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT}, ++ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN}, ++ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, ++ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */ ++ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */ ++ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */ ++ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT}, ++ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN}, ++ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT}, ++ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN}, ++ {}, ++}; ++ ++ ++int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data) ++{ ++ int i, len = 0; ++ struct jz_dma_chan *chan; ++ ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if ((chan = get_dma_chan(i)) != NULL) { ++ len += sprintf(buf + len, "%2d: %s\n", ++ i, chan->dev_str); ++ } ++ } ++ ++ if (fpos >= len) { ++ *start = buf; ++ *eof = 1; ++ return 0; ++ } ++ *start = buf + fpos; ++ if ((len -= fpos) > length) ++ return length; ++ *eof = 1; ++ return len; ++} ++ ++ ++void dump_jz_dma_channel(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > MAX_DMA_NUM) ++ return; ++ chan = &jz_dma_table[dmanr]; ++ ++ printk("DMA%d Registers:\n", dmanr); ++ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM)); ++ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); ++ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); ++ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); ++ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); ++ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); ++ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); ++ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); ++ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM)); ++} ++ ++ ++/** ++ * jz_request_dma - dynamically allcate an idle DMA channel to return ++ * @dev_id: the specified dma device id or DMA_ID_RAW_SET ++ * @dev_str: the specified dma device string name ++ * @irqhandler: the irq handler, or NULL ++ * @irqflags: the irq handler flags ++ * @irq_dev_id: the irq handler device id for shared irq ++ * ++ * Finds a free channel, and binds the requested device to it. ++ * Returns the allocated channel number, or negative on error. ++ * Requests the DMA done IRQ if irqhandler != NULL. ++ * ++*/ ++/*int jz_request_dma(int dev_id, const char *dev_str, ++ void (*irqhandler)(int, void *, struct pt_regs *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++*/ ++ ++int jz_request_dma(int dev_id, const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id) ++{ ++ struct jz_dma_chan *chan; ++ int i, ret; ++ ++ if (dev_id < 0 || dev_id >= DMA_ID_MAX) ++ return -EINVAL; ++ ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == MAX_DMA_NUM) /* no free channel */ ++ return -ENODEV; ++ ++ /* we got a free channel */ ++ chan = &jz_dma_table[i]; ++ ++ if (irqhandler) { ++ chan->irq = IRQ_DMA_0 + i; // allocate irq number ++ chan->irq_dev = irq_dev_id; ++ if ((ret = request_irq(chan->irq, irqhandler, irqflags, ++ dev_str, chan->irq_dev))) { ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ return ret; ++ } ++ } else { ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ } ++ ++ // fill it in ++ chan->io = i; ++ chan->dev_id = dev_id; ++ chan->dev_str = dev_str; ++ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; ++ chan->mode = dma_dev_table[dev_id].dma_mode; ++ chan->source = dma_dev_table[dev_id].dma_source; ++ ++ if (i < HALF_DMA_NUM) ++ REG_DMAC_DMACKE(0) = 1 << i; ++ else ++ REG_DMAC_DMACKE(1) = 1 << (i - HALF_DMA_NUM); ++ ++ return i; ++} ++ ++void jz_free_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) { ++ printk("Trying to free DMA%d\n", dmanr); ++ return; ++ } ++ ++ disable_dma(dmanr); ++ if (chan->irq) ++ free_irq(chan->irq, chan->irq_dev); ++ ++ chan->irq = -1; ++ chan->irq_dev = NULL; ++ chan->dev_id = -1; ++} ++ ++void jz_set_dma_dest_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_DWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCMD_DWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_DWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_DWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_src_width(int dmanr, int nbit) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_SWDH_MASK; ++ switch (nbit) { ++ case 8: ++ chan->mode |= DMAC_DCMD_SWDH_8; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_SWDH_16; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_SWDH_32; ++ break; ++ } ++} ++ ++void jz_set_dma_block_size(int dmanr, int nbyte) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode &= ~DMAC_DCMD_DS_MASK; ++ switch (nbyte) { ++ case 1: ++ chan->mode |= DMAC_DCMD_DS_8BIT; ++ break; ++ case 2: ++ chan->mode |= DMAC_DCMD_DS_16BIT; ++ break; ++ case 4: ++ chan->mode |= DMAC_DCMD_DS_32BIT; ++ break; ++ case 16: ++ chan->mode |= DMAC_DCMD_DS_16BYTE; ++ break; ++ case 32: ++ chan->mode |= DMAC_DCMD_DS_32BYTE; ++ break; ++ } ++} ++ ++unsigned int jz_get_dma_command(int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ return chan->mode; ++} ++ ++/** ++ * jz_set_dma_mode - do the raw settings for the specified DMA channel ++ * @dmanr: the specified DMA channel ++ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE ++ * @dma_mode: dma raw mode ++ * @dma_source: dma raw request source ++ * @fifo_addr: dma raw device fifo address ++ * ++ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call ++ * jz_set_dma_mode() rather than set_dma_mode() if you work with ++ * and external request dma device. ++ * ++ * NOTE: Don not dynamically allocate dma channel if one external request ++ * dma device will occupy this channel. ++*/ ++int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, ++ unsigned int dma_mode, unsigned int dma_source, ++ unsigned int fifo_addr) ++{ ++ int dev_id, i; ++ struct jz_dma_chan *chan; ++ ++ if (dmanr > MAX_DMA_NUM) ++ return -ENODEV; ++ for (i = 0; i < MAX_DMA_NUM; i++) { ++ if (jz_dma_table[i].dev_id < 0) ++ break; ++ } ++ if (i == MAX_DMA_NUM) ++ return -ENODEV; ++ ++ chan = &jz_dma_table[dmanr]; ++ dev_id = chan->dev_id; ++ if (dev_id > 0) { ++ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", ++ __FUNCTION__, dmanr); ++ return -ENODEV; ++ } ++ ++ /* clone it from the dynamically allocated. */ ++ if (i != dmanr) { ++ chan->irq = jz_dma_table[i].irq; ++ chan->irq_dev = jz_dma_table[i].irq_dev; ++ chan->dev_str = jz_dma_table[i].dev_str; ++ jz_dma_table[i].irq = 0; ++ jz_dma_table[i].irq_dev = NULL; ++ jz_dma_table[i].dev_id = -1; ++ } ++ chan->dev_id = DMA_ID_RAW_SET; ++ chan->io = dmanr; ++ chan->fifo_addr = fifo_addr; ++ chan->mode = dma_mode; ++ chan->source = dma_source; ++ ++ set_dma_mode(dmanr, dma_mode); ++ ++ return dmanr; ++} ++ ++void enable_dma(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ ++ __dmac_enable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_enable_irq(dmanr); ++} ++ ++#define DMA_DISABLE_POLL 0x10000 ++ ++void disable_dma(unsigned int dmanr) ++{ ++ int i; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ if (!__dmac_channel_enabled(dmanr)) ++ return; ++ ++ for (i = 0; i < DMA_DISABLE_POLL; i++) ++ if (__dmac_channel_transmit_end_detected(dmanr)) ++ break; ++#if 0 ++ if (i == DMA_DISABLE_POLL) ++ printk(KERN_INFO "disable_dma: poll expired!\n"); ++#endif ++ ++ __dmac_disable_channel(dmanr); ++ if (chan->irq) ++ __dmac_channel_disable_irq(dmanr); ++} ++ ++/* Note: DMA_MODE_MASK is simulated by sw */ ++void set_dma_mode(unsigned int dmanr, unsigned int mode) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else { ++ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ } ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++} ++ ++void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) ++{ ++ unsigned int mode; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ mode = chan->mode & DMA_MODE_MASK; ++ if (mode == DMA_MODE_READ) { ++ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; ++ REG_DMAC_DTAR(chan->io) = phyaddr; ++ } else if (mode == DMA_MODE_WRITE) { ++ REG_DMAC_DSAR(chan->io) = phyaddr; ++ REG_DMAC_DTAR(chan->io) = chan->fifo_addr; ++ } else ++ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); ++} ++ ++void set_dma_count(unsigned int dmanr, unsigned int bytecnt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ unsigned int ds; ++ ++ if (!chan) ++ return; ++ ++ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; ++ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count ++} ++ ++unsigned int get_dma_residue(unsigned int dmanr) ++{ ++ unsigned int count, ds; ++ int dma_ds[] = {4, 1, 2, 16, 32}; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ ++ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; ++ count = REG_DMAC_DTCR(chan->io); ++ count = count * dma_ds[ds]; ++ ++ return count; ++} ++ ++void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case AFMT_U8: ++ /* burst mode : 32BIT */ ++ break; ++ case AFMT_S16_LE: ++ /* burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else ++ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ ++ if (!chan) ++ return; ++ ++ switch (audio_fmt) { ++ case 8: ++ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ ++ break; ++ case 16: ++ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ ++ if (mode == DMA_MODE_READ) { ++ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_DAI; ++ chan->mode &= ~DMAC_DCMD_SAI; ++ } else if (mode == DMA_MODE_WRITE) { ++ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; ++ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); ++ mode &= DMA_MODE_MASK; ++ chan->mode |= DMAC_DCMD_SAI; ++ chan->mode &= ~DMAC_DCMD_DAI; ++ } else ++ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); ++ ++ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; ++ REG_DMAC_DRSR(chan->io) = chan->source; ++ break; ++ } ++} ++ ++//#define JZ4750D_DMAC_TEST_ENABLE ++#undef JZ4750D_DMAC_TEST_ENABLE ++ ++#ifdef JZ4750D_DMAC_TEST_ENABLE ++ ++/* ++ * DMA test: external address <--> external address ++ */ ++#define TEST_DMA_SIZE 16*1024 ++ ++static jz_dma_desc *dma_desc; ++ ++static int dma_chan; ++static dma_addr_t dma_desc_phys_addr; ++static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; ++ ++static int dma_check_result(void *src, void *dst, int size) ++{ ++ unsigned int addr1, addr2, i, err = 0; ++ ++ addr1 = (unsigned int)src; ++ addr2 = (unsigned int)dst; ++ ++ for (i = 0; i < size; i += 4) { ++ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { ++ err++; ++ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); ++ } ++ addr1 += 4; ++ addr2 += 4; ++ } ++ printk("check DMA result err=%d\n", err); ++ return err; ++} ++ ++static irqreturn_t jz4750d_dma_irq(int irq, void *dev_id) ++{ ++ printk("jz4750d_dma_irq %d\n", irq); ++ ++ ++ if (__dmac_channel_transmit_halt_detected(dma_chan)) { ++ printk("DMA HALT\n"); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_halt(dma_chan); ++ } ++ ++ if (__dmac_channel_address_error_detected(dma_chan)) { ++ printk("DMA ADDR ERROR\n"); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */ ++ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */ ++ __dmac_channel_clear_address_error(dma_chan); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ printk("DMA DESC INVALID\n"); ++ __dmac_channel_clear_descriptor_invalid(dma_chan); ++ } ++ ++ if (__dmac_channel_count_terminated_detected(dma_chan)) { ++ printk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(dma_chan); ++ } ++ ++ if (__dmac_channel_transmit_end_detected(dma_chan)) { ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ printk("DMA TT\n"); ++ __dmac_channel_clear_transmit_end(dma_chan); ++ dump_jz_dma_channel(dma_chan); ++ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++void dma_nodesc_test(void) ++{ ++ unsigned int addr, i; ++ ++ printk("dma_nodesc_test\n"); ++ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq, ++ IRQF_DISABLED, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq failed\n"); ++ return; ++ } ++ ++ printk("Requested DMA channel = %d\n", dma_chan); ++ ++ /* Allocate DMA buffers */ ++ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ ++ dma_src_phys_addr = CPHYSADDR(dma_src_addr); ++ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); ++ ++ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); ++ ++ /* Prepare data for source buffer */ ++ addr = (unsigned int)dma_src_addr; ++ for (i = 0; i < TEST_DMA_SIZE; i += 4) { ++ *(volatile unsigned int *)addr = addr; ++ addr += 4; ++ } ++ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); ++ ++ /* Init target buffer */ ++ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); ++ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); ++ ++ /* Init DMA module */ ++ printk("Starting DMA\n"); ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0; ++ REG_DMAC_DCCSR(dma_chan) = 0; ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = 512; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); ++ ++ /* wait a long time, ensure transfer end */ ++ printk("wait 3s...\n"); ++ mdelay(3000); /* wait 3s */ ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ /* free buffers */ ++ printk("free DMA buffers\n"); ++ free_pages(dma_src_addr, 2); ++ free_pages(dma_dst_addr, 2); ++ ++ if (dma_desc) ++ free_pages((unsigned int)dma_desc, 0); ++ ++ /* free dma */ ++ jz_free_dma(dma_chan); ++} ++ ++void dma_desc_test(void) ++{ ++ unsigned int next, addr, i; ++ static jz_dma_desc *desc; ++ ++ printk("dma_desc_test\n"); ++ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq, ++ IRQF_DISABLED, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq failed\n"); ++ return; ++ } ++ ++ printk("Requested DMA channel = %d\n", dma_chan); ++ ++ /* Allocate DMA buffers */ ++ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ ++ ++ dma_src_phys_addr = CPHYSADDR(dma_src_addr); ++ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); ++ ++ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); ++ ++ /* Prepare data for source buffer */ ++ addr = (unsigned int)dma_src_addr; ++ for (i = 0; i < TEST_DMA_SIZE; i += 4) { ++ *(volatile unsigned int *)addr = addr; ++ addr += 4; ++ } ++ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); ++ ++ /* Init target buffer */ ++ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); ++ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); ++ ++ /* Allocate DMA descriptors */ ++ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); ++ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); ++ ++ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); ++ ++ /* Setup DMA descriptors */ ++ desc = dma_desc; ++ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr; /* DMA target address */ ++ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ ++ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; ++ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ ++ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ ++ ++ desc++; ++ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; ++ ++ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; ++ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ ++ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ ++ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ ++ ++ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; ++ ++ /* DMA doorbell set -- start DMA now ... */ ++ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan; ++ ++ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); ++ /* wait a long time, ensure transfer end */ ++ printk("wait 3s...\n"); ++ mdelay(3000); /* wait 3s */ ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ /* free buffers */ ++ printk("free DMA buffers\n"); ++ free_pages(dma_src_addr, 2); ++ free_pages(dma_dst_addr, 2); ++ ++ if (dma_desc) ++ free_pages((unsigned int)dma_desc, 0); ++ ++ /* free dma */ ++ jz_free_dma(dma_chan); ++} ++ ++#endif ++ ++//EXPORT_SYMBOL_NOVERS(jz_dma_table); ++EXPORT_SYMBOL(jz_dma_table); ++EXPORT_SYMBOL(jz_request_dma); ++EXPORT_SYMBOL(jz_free_dma); ++EXPORT_SYMBOL(jz_set_dma_src_width); ++EXPORT_SYMBOL(jz_set_dma_dest_width); ++EXPORT_SYMBOL(jz_set_dma_block_size); ++EXPORT_SYMBOL(jz_set_dma_mode); ++EXPORT_SYMBOL(set_dma_mode); ++EXPORT_SYMBOL(jz_set_oss_dma); ++EXPORT_SYMBOL(jz_set_alsa_dma); ++EXPORT_SYMBOL(set_dma_addr); ++EXPORT_SYMBOL(set_dma_count); ++EXPORT_SYMBOL(get_dma_residue); ++EXPORT_SYMBOL(enable_dma); ++EXPORT_SYMBOL(disable_dma); ++EXPORT_SYMBOL(dump_jz_dma_channel); +diff --git a/arch/mips/jz4750d/i2c.c b/arch/mips/jz4750d/i2c.c +new file mode 100644 +index 0000000..c12142f +--- /dev/null ++++ b/arch/mips/jz4750d/i2c.c +@@ -0,0 +1,273 @@ ++/* ++ * linux/arch/mips/jz4750d/i2c.c ++ * ++ * Jz4750D I2C routines. ++ * ++ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* I2C protocol */ ++#define I2C_READ 1 ++#define I2C_WRITE 0 ++ ++#define TIMEOUT 1000 ++ ++/* ++ * I2C bus protocol basic routines ++ */ ++static int i2c_put_data(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (!__i2c_received_ack() && timeout) ++ timeout--; ++ ++ if (timeout) ++ return 0; ++ else ++ return -ETIMEDOUT; ++} ++ ++#ifdef CONFIG_JZ_TPANEL_ATA2508 ++static int i2c_put_data_nack(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (timeout--); ++ return 0; ++} ++#endif ++ ++static int i2c_get_data(unsigned char *data, int ack) ++{ ++ int timeout = TIMEOUT*10; ++ ++ if (!ack) ++ __i2c_send_nack(); ++ else ++ __i2c_send_ack(); ++ ++ while (__i2c_check_drf() == 0 && timeout) ++ timeout--; ++ ++ if (timeout) { ++ if (!ack) ++ __i2c_send_stop(); ++ *data = __i2c_read(); ++ __i2c_clear_drf(); ++ return 0; ++ } else ++ return -ETIMEDOUT; ++} ++ ++/* ++ * I2C interface ++ */ ++void i2c_open(void) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ ++ __i2c_enable(); ++} ++ ++void i2c_close(void) ++{ ++ udelay(300); /* wait for STOP goes over. */ ++ __i2c_disable(); ++} ++ ++void i2c_setclk(unsigned int i2cclk) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, i2cclk); ++} ++ ++int i2c_lseek(unsigned char device, unsigned char offset) ++{ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++ if (i2c_put_data(offset) < 0) ++ goto address_err; ++ return 0; ++ device_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++ address_err: ++ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); ++ __i2c_send_stop(); ++ return -EREMOTEIO; ++} ++ ++int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int timeout = 5; ++ ++L_try_again: ++ ++ if (timeout < 0) ++ goto L_timeout; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_werr; ++ if (i2c_put_data(address) < 0) ++ goto address_err; ++ ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) ++ goto device_rerr; ++ __i2c_send_ack(); /* Master sends ACK for continue reading */ ++ while (cnt) { ++ if (cnt == 1) { ++ if (i2c_get_data(buf, 0) < 0) ++ break; ++ } else { ++ if (i2c_get_data(buf, 1) < 0) ++ break; ++ } ++ cnt--; ++ buf++; ++ } ++ ++ __i2c_send_stop(); ++ return count - cnt; ++ device_rerr: ++ device_werr: ++ address_err: ++ timeout --; ++ __i2c_send_stop(); ++ goto L_try_again; ++ ++L_timeout: ++ __i2c_send_stop(); ++ printk("Read I2C device 0x%2x failed.\n", device); ++ return -ENODEV; ++} ++ ++int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count) ++{ ++ int cnt = count; ++ int cnt_in_pg; ++ int timeout = 5; ++ unsigned char *tmpbuf; ++ unsigned char tmpaddr; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ ++ W_try_again: ++ if (timeout < 0) ++ goto W_timeout; ++ ++ cnt = count; ++ tmpbuf = (unsigned char *)buf; ++ tmpaddr = address; ++ ++ start_write_page: ++ cnt_in_pg = 0; ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++#ifdef CONFIG_JZ_TPANEL_ATA2508 ++ if (address == 0xff) { ++ if (i2c_put_data_nack(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data_nack(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ } ++ else { ++ ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ } ++#else ++ if (i2c_put_data(tmpaddr) < 0) ++ goto address_err; ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ tmpaddr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++#endif ++ __i2c_send_stop(); ++ return count - cnt; ++ device_err: ++ address_err: ++ timeout--; ++ __i2c_send_stop(); ++ goto W_try_again; ++ ++ W_timeout: ++ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++} ++ ++EXPORT_SYMBOL(i2c_open); ++EXPORT_SYMBOL(i2c_close); ++EXPORT_SYMBOL(i2c_setclk); ++EXPORT_SYMBOL(i2c_read); ++EXPORT_SYMBOL(i2c_write); +diff --git a/arch/mips/jz4750d/irq.c b/arch/mips/jz4750d/irq.c +new file mode 100644 +index 0000000..aa43d9b +--- /dev/null ++++ b/arch/mips/jz4750d/irq.c +@@ -0,0 +1,299 @@ ++/* ++ * linux/arch/mips/jz4750d/irq.c ++ * ++ * JZ4750D interrupt routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * INTC irq type ++ */ ++ ++static void enable_intc_irq(unsigned int irq) ++{ ++ __intc_unmask_irq(irq); ++} ++ ++static void disable_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++} ++ ++static void mask_and_ack_intc_irq(unsigned int irq) ++{ ++ __intc_mask_irq(irq); ++ __intc_ack_irq(irq); ++} ++ ++static void end_intc_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_intc_irq(irq); ++ } ++} ++ ++static unsigned int startup_intc_irq(unsigned int irq) ++{ ++ enable_intc_irq(irq); ++ return 0; ++} ++ ++static void shutdown_intc_irq(unsigned int irq) ++{ ++ disable_intc_irq(irq); ++} ++ ++static struct irq_chip intc_irq_type = { ++ .typename = "INTC", ++ .startup = startup_intc_irq, ++ .shutdown = shutdown_intc_irq, ++ .enable = enable_intc_irq, ++ .disable = disable_intc_irq, ++ .ack = mask_and_ack_intc_irq, ++ .end = end_intc_irq, ++}; ++ ++/* ++ * GPIO irq type ++ */ ++ ++static void enable_gpio_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if (irq < (IRQ_GPIO_0 + 32)) { ++ intc_irq = IRQ_GPIO0; ++ } ++ else if (irq < (IRQ_GPIO_0 + 64)) { ++ intc_irq = IRQ_GPIO1; ++ } ++ else if (irq < (IRQ_GPIO_0 + 96)) { ++ intc_irq = IRQ_GPIO2; ++ } ++ else if (irq < (IRQ_GPIO_0 + 128)) { ++ intc_irq = IRQ_GPIO3; ++ } ++ else if (irq < (IRQ_GPIO_0 + 160)) { ++ intc_irq = IRQ_GPIO4; ++ } ++ else { ++ intc_irq = IRQ_GPIO5; ++ } ++ ++ enable_intc_irq(intc_irq); ++ __gpio_unmask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void disable_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++} ++ ++static void mask_and_ack_gpio_irq(unsigned int irq) ++{ ++ __gpio_mask_irq(irq - IRQ_GPIO_0); ++ __gpio_ack_irq(irq - IRQ_GPIO_0); ++} ++ ++static void end_gpio_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_gpio_irq(irq); ++ } ++} ++ ++static unsigned int startup_gpio_irq(unsigned int irq) ++{ ++ enable_gpio_irq(irq); ++ return 0; ++} ++ ++static void shutdown_gpio_irq(unsigned int irq) ++{ ++ disable_gpio_irq(irq); ++} ++ ++static struct irq_chip gpio_irq_type = { ++ .typename = "GPIO", ++ .startup = startup_gpio_irq, ++ .shutdown = shutdown_gpio_irq, ++ .enable = enable_gpio_irq, ++ .disable = disable_gpio_irq, ++ .ack = mask_and_ack_gpio_irq, ++ .end = end_gpio_irq, ++}; ++ ++/* ++ * DMA irq type ++ */ ++ ++static void enable_dma_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ ++ intc_irq = IRQ_DMAC0; ++ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ ++ intc_irq = IRQ_DMAC1; ++ else { ++ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); ++ return; ++ } ++ __intc_unmask_irq(intc_irq); ++ __dmac_channel_enable_irq(irq - IRQ_DMA_0); ++} ++ ++static void disable_dma_irq(unsigned int irq) ++{ ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void mask_and_ack_dma_irq(unsigned int irq) ++{ ++ unsigned int intc_irq; ++ ++ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ ++ intc_irq = IRQ_DMAC0; ++ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ ++ intc_irq = IRQ_DMAC1; ++ else { ++ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); ++ return ; ++ } ++ __intc_ack_irq(intc_irq); ++ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */ ++ __dmac_channel_disable_irq(irq - IRQ_DMA_0); ++} ++ ++static void end_dma_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { ++ enable_dma_irq(irq); ++ } ++} ++ ++static unsigned int startup_dma_irq(unsigned int irq) ++{ ++ enable_dma_irq(irq); ++ return 0; ++} ++ ++static void shutdown_dma_irq(unsigned int irq) ++{ ++ disable_dma_irq(irq); ++} ++ ++static struct irq_chip dma_irq_type = { ++ .typename = "DMA", ++ .startup = startup_dma_irq, ++ .shutdown = shutdown_dma_irq, ++ .enable = enable_dma_irq, ++ .disable = disable_dma_irq, ++ .ack = mask_and_ack_dma_irq, ++ .end = end_dma_irq, ++}; ++ ++//---------------------------------------------------------------------- ++ ++void __init arch_init_irq(void) ++{ ++ int i; ++ ++ clear_c0_status(0xff04); /* clear ERL */ ++ set_c0_status(0x0400); /* set IP2 */ ++ ++ /* Set up INTC irq ++ */ ++ for (i = 0; i < 32; i++) { ++ disable_intc_irq(i); ++ irq_desc[i].chip = &intc_irq_type; ++ } ++ ++ /* Set up DMAC irq ++ */ ++ for (i = 0; i < NUM_DMA; i++) { ++ disable_dma_irq(IRQ_DMA_0 + i); ++ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; ++ } ++ ++ /* Set up GPIO irq ++ */ ++ for (i = 0; i < NUM_GPIO; i++) { ++ disable_gpio_irq(IRQ_GPIO_0 + i); ++ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; ++ } ++} ++ ++static int plat_real_irq(int irq) ++{ ++ switch (irq) { ++ case IRQ_GPIO0: ++ irq = __gpio_group_irq(0) + IRQ_GPIO_0; ++ break; ++ case IRQ_GPIO1: ++ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; ++ break; ++ case IRQ_GPIO2: ++ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; ++ break; ++ case IRQ_GPIO3: ++ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; ++ break; ++ case IRQ_GPIO4: ++ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128; ++ break; ++ case IRQ_GPIO5: ++ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160; ++ break; ++ case IRQ_DMAC0: ++ case IRQ_DMAC1: ++ irq = __dmac_get_irq() + IRQ_DMA_0; ++ break; ++ } ++ ++ return irq; ++} ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ int irq = 0; ++ static unsigned long intc_ipr = 0; ++ ++ intc_ipr |= REG_INTC_IPR; ++ ++ if (!intc_ipr) return; ++ ++ irq = ffs(intc_ipr) - 1; ++ intc_ipr &= ~(1< ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#if 0 ++/* OHCI (USB full speed host controller) */ ++static struct resource jz_usb_ohci_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap ++ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UHC, ++ .end = IRQ_UHC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++/* The dmamask must be set for OHCI to work */ ++static u64 ohci_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_ohci_device = { ++ .name = "jz-ohci", ++ .id = 0, ++ .dev = { ++ .dma_mask = &ohci_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), ++ .resource = jz_usb_ohci_resources, ++}; ++#endif ++/*** LCD controller ***/ ++static struct resource jz_lcd_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(LCD_BASE), ++ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_LCD, ++ .end = IRQ_LCD, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_lcd_dmamask = ~(u32)0; ++ ++static struct platform_device jz_lcd_device = { ++ .name = "jz-lcd", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_lcd_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_lcd_resources), ++ .resource = jz_lcd_resources, ++}; ++ ++/* UDC (USB gadget controller) */ ++static struct resource jz_usb_gdt_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(UDC_BASE), ++ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_UDC, ++ .end = IRQ_UDC, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static u64 udc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_usb_gdt_device = { ++ .name = "jz-udc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &udc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), ++ .resource = jz_usb_gdt_resources, ++}; ++ ++/** MMC/SD controller **/ ++static struct resource jz_mmc_resources[] = { ++ [0] = { ++ .start = CPHYSADDR(MSC_BASE), ++ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_MSC0, ++ .end = IRQ_MSC0, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 jz_mmc_dmamask = ~(u32)0; ++ ++static struct platform_device jz_mmc_device = { ++ .name = "jz-mmc", ++ .id = 0, ++ .dev = { ++ .dma_mask = &jz_mmc_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(jz_mmc_resources), ++ .resource = jz_mmc_resources, ++}; ++ ++/* All */ ++static struct platform_device *jz_platform_devices[] __initdata = { ++// &jz_usb_ohci_device, ++ &jz_lcd_device, ++ &jz_usb_gdt_device, ++ &jz_mmc_device, ++}; ++ ++static int __init jz_platform_init(void) ++{ ++ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); ++} ++ ++arch_initcall(jz_platform_init); +diff --git a/arch/mips/jz4750d/pm.c b/arch/mips/jz4750d/pm.c +new file mode 100644 +index 0000000..7f58372 +--- /dev/null ++++ b/arch/mips/jz4750d/pm.c +@@ -0,0 +1,461 @@ ++/* ++ * linux/arch/mips/jz4750d/common/pm.c ++ * ++ * JZ4750D Power Management Routines ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++ ++#define GPIO_PORT_NUM 6 ++ ++/* ++ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input ++ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select. ++ */ ++#define __gpio_as_sleep() \ ++do { \ ++ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \ ++ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(2) = ~0x01e00000; \ ++ REG_GPIO_PXSELC(2) = ~0x01e00000; \ ++ REG_GPIO_PXDIRC(2) = ~0x01e00000; \ ++ REG_GPIO_PXPES(2) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(3) = 0xffffffff; \ ++ REG_GPIO_PXSELC(3) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(3) = 0xffffffff; \ ++ REG_GPIO_PXPES(3) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(4) = 0xffffffff; \ ++ REG_GPIO_PXSELC(4) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(4) = 0xffffffff; \ ++ REG_GPIO_PXPES(4) = 0xffffffff; \ ++ REG_GPIO_PXFUNC(5) = 0xffffffff; \ ++ REG_GPIO_PXSELC(5) = 0xffffffff; \ ++ REG_GPIO_PXDIRC(5) = 0xffffffff; \ ++ REG_GPIO_PXPES(5) = 0xffffffff; \ ++} while (0) ++ ++static int jz_pm_do_hibernate(void) ++{ ++ printk("Put CPU into hibernate mode.\n"); ++ ++ /* Mask all interrupts */ ++ REG_INTC_IMSR = 0xffffffff; ++ ++ /* ++ * RTC Wakeup or 1Hz interrupt can be enabled or disabled ++ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c). ++ */ ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */ ++ ++ /* Scratch pad register to be reserved */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HSPR = 0x12345678; ++ ++ /* clear wakeup status register */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HWRSR = 0x0; ++ ++ /* Put CPU to power down mode */ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_HCR = RTC_HCR_PD; ++ ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ while(1); ++ ++ /* We can't get here */ ++ return 0; ++} ++ ++/* NOTES: ++ * 1: Pins that are floated (NC) should be set as input and pull-enable. ++ * 2: Pins that are pull-up or pull-down by outside should be set as input ++ * and pull-disable. ++ * 3: Pins that are connected to a chip except sdram and nand flash ++ * should be set as input and pull-disable, too. ++ */ ++static void jz_board_do_sleep(unsigned long *ptr) ++{ ++ unsigned char i; ++ ++ /* Print messages of GPIO registers for debug */ ++ for(i=0;i ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#define DEBUG 1 ++#undef DEBUG ++ ++ ++struct proc_dir_entry *proc_jz_root; ++ ++ ++/* ++ * EMC Modules ++ */ ++static int emc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); ++ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); ++ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); ++ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); ++ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); ++ return len; ++} ++ ++/* ++ * Power Manager Module ++ */ ++static int pmc_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned long lcr = REG_CPM_LCR; ++ unsigned long clkgr = REG_CPM_CLKGR; ++ ++ len += sprintf (page+len, "Low Power Mode : %s\n", ++ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? ++ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? ++ "SLEEP" : "HIBERNATE")); ++ len += sprintf (page+len, "Doze Mode : %s\n", ++ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); ++ if (lcr & CPM_LCR_DOZE_ON) ++ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); ++ len += sprintf (page+len, "AUX_CPU : %s\n", ++ (clkgr & CPM_CLKGR_AUX_CPU) ? "stopped" : "running"); ++ len += sprintf (page+len, "AHB1 : %s\n", ++ (clkgr & CPM_CLKGR_AHB1) ? "stopped" : "running"); ++ len += sprintf (page+len, "IDCT : %s\n", ++ (clkgr & CPM_CLKGR_IDCT) ? "stopped" : "running"); ++ len += sprintf (page+len, "DB : %s\n", ++ (clkgr & CPM_CLKGR_DB) ? "stopped" : "running"); ++ len += sprintf (page+len, "ME : %s\n", ++ (clkgr & CPM_CLKGR_ME) ? "stopped" : "running"); ++ len += sprintf (page+len, "MC : %s\n", ++ (clkgr & CPM_CLKGR_MC) ? "stopped" : "running"); ++ len += sprintf (page+len, "TVE : %s\n", ++ (clkgr & CPM_CLKGR_TVE) ? "stopped" : "running"); ++ len += sprintf (page+len, "TSSI : %s\n", ++ (clkgr & CPM_CLKGR_TSSI) ? "stopped" : "running"); ++ len += sprintf (page+len, "IPU : %s\n", ++ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); ++ len += sprintf (page+len, "DMAC : %s\n", ++ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); ++ len += sprintf (page+len, "UDC : %s\n", ++ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); ++ len += sprintf (page+len, "LCD : %s\n", ++ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); ++ len += sprintf (page+len, "CIM : %s\n", ++ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); ++ len += sprintf (page+len, "SADC : %s\n", ++ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); ++ len += sprintf (page+len, "MSC0 : %s\n", ++ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running"); ++ len += sprintf (page+len, "MSC1 : %s\n", ++ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running"); ++ len += sprintf (page+len, "SSI : %s\n", ++ (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running"); ++ len += sprintf (page+len, "I2C : %s\n", ++ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); ++ len += sprintf (page+len, "RTC : %s\n", ++ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); ++ len += sprintf (page+len, "TCU : %s\n", ++ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART1 : %s\n", ++ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); ++ len += sprintf (page+len, "UART0 : %s\n", ++ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); ++ return len; ++} ++ ++static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++/* ++ * Clock Generation Module ++ */ ++#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 ++#define TO_KHZ(x) (x/1000),(x%1000)/10 ++ ++static int cgm_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ ++ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ ++ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned int od[4] = {1, 2, 2, 4}; ++ ++ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); ++ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); ++ len += sprintf (page+len, "PLL : %s\n", ++ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); ++ len += sprintf (page+len, "m:n:o : %d:%d:%d\n", ++ __cpm_get_pllm() + 2, ++ __cpm_get_plln() + 2, ++ od[__cpm_get_pllod()] ++ ); ++ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", ++ div[__cpm_get_cdiv()], ++ div[__cpm_get_hdiv()], ++ div[__cpm_get_mdiv()], ++ div[__cpm_get_pdiv()] ++ ); ++ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); ++ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); ++ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); ++ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); ++ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); ++ len += sprintf (page+len, "H1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_h1clk())); ++ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); ++ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); ++ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); ++ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0))); ++ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1))); ++ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0())); ++ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); ++ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); ++ ++ return len; ++} ++ ++static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); ++ return count; ++} ++ ++ ++/* USAGE: ++ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages. ++ * echo FF > /proc/jz/ipu // 255, free all buffer ++ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx ++ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l) ++ * echo 0 > /proc/jz/ipu // debug, print ipu_buf ++ * od -X /proc/jz/ipu // read mem addr ++ */ ++ ++typedef struct _ipu_buf { ++ unsigned int addr; /* phys addr */ ++ unsigned int page_shift; ++} ipu_buf_t; ++ ++#define IPU_BUF_MAX 4 /* 4 buffers */ ++ ++static struct _ipu_buf ipu_buf[IPU_BUF_MAX]; ++static int ipu_buf_cnt = 0; ++static unsigned char g_asid=0; ++ ++extern void local_flush_tlb_all(void); ++ ++/* CP0 hazard avoidance. */ ++#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ ++ "nop; nop; nop; nop; nop; nop;\n\t" \ ++ ".set reorder\n\t") ++void show_tlb(void) ++{ ++#define ASID_MASK 0xFF ++ ++ unsigned long flags; ++ unsigned int old_ctx; ++ unsigned int entry; ++ unsigned int entrylo0, entrylo1, entryhi; ++ unsigned int pagemask; ++ ++ local_irq_save(flags); ++ ++ /* Save old context */ ++ old_ctx = (read_c0_entryhi() & 0xff); ++ ++ printk("TLB content:\n"); ++ entry = 0; ++ while(entry < 32) { ++ write_c0_index(entry); ++ BARRIER; ++ tlb_read(); ++ BARRIER; ++ entryhi = read_c0_entryhi(); ++ entrylo0 = read_c0_entrylo0(); ++ entrylo1 = read_c0_entrylo1(); ++ pagemask = read_c0_pagemask(); ++ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); ++ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); ++ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); ++ ++ printk("\t\tpagemask=0x%08x", pagemask); ++ printk("\tentryhi=0x%08x\n", entryhi); ++ printk("\t\tentrylo0=0x%08x", entrylo0); ++ printk("\tentrylo1=0x%08x\n", entrylo1); ++ ++ entry++; ++ } ++ BARRIER; ++ write_c0_entryhi(old_ctx); ++ ++ local_irq_restore(flags); ++} ++ ++static void ipu_add_wired_entry(unsigned long pid, ++ unsigned long entrylo0, unsigned long entrylo1, ++ unsigned long entryhi, unsigned long pagemask) ++{ ++ unsigned long flags; ++ unsigned long wired; ++ unsigned long old_pagemask; ++ unsigned long old_ctx; ++ struct task_struct *g, *p; ++ ++ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ ++ wired = read_c0_wired(); ++ if (wired) return; ++ ++ do_each_thread(g, p) { ++ if (p->pid == pid ) ++ g_asid = p->mm->context[0]; ++ } while_each_thread(g, p); ++ ++ ++ local_irq_save(flags); ++ ++ entrylo0 = entrylo0 >> 6; /* PFN */ ++ entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */ ++ ++ /* Save old context and create impossible VPN2 value */ ++ old_ctx = read_c0_entryhi() & 0xff; ++ old_pagemask = read_c0_pagemask(); ++ wired = read_c0_wired(); ++ write_c0_wired(wired + 1); ++ write_c0_index(wired); ++ BARRIER; ++ entryhi &= ~0xff; /* new add, 20070906 */ ++ entryhi |= g_asid; /* new add, 20070906 */ ++// entryhi |= old_ctx; /* new add, 20070906 */ ++ write_c0_pagemask(pagemask); ++ write_c0_entryhi(entryhi); ++ write_c0_entrylo0(entrylo0); ++ write_c0_entrylo1(entrylo1); ++ BARRIER; ++ tlb_write_indexed(); ++ BARRIER; ++ ++ write_c0_entryhi(old_ctx); ++ BARRIER; ++ write_c0_pagemask(old_pagemask); ++ local_flush_tlb_all(); ++ local_irq_restore(flags); ++#if defined(DEBUG) ++ printk("\nold_ctx=%03d\n", old_ctx); ++ ++ show_tlb(); ++#endif ++} ++ ++static void ipu_del_wired_entry( void ) ++{ ++ unsigned long flags; ++ unsigned long wired; ++ ++ local_irq_save(flags); ++ wired = read_c0_wired(); ++ if ( wired > 0 ) { ++ write_c0_wired(wired - 1); ++ } ++ local_irq_restore(flags); ++} ++ ++static inline void ipu_buf_get( unsigned int page_shift ) ++{ ++ unsigned char * virt_addr; ++ int i; ++ for ( i=0; i< IPU_BUF_MAX; ++i ) { ++ if ( ipu_buf[i].addr == 0 ) { ++ break; ++ } ++ } ++ ++ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) { ++ printk("Error, no free ipu buffer.\n"); ++ return ; ++ } ++ ++ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ ++ if ( virt_addr ) { ++ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr); ++ ipu_buf[ipu_buf_cnt].page_shift = page_shift; ++ ++ for (i = 0; i < (1<= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */ ++ printk("no free buffer.\n"); ++ *pint = 0; ++ } ++ else ++ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */ ++ len += sizeof(unsigned int); ++ ++#if defined(DEBUG) ++ show_tlb(); ++#endif ++ return len; ++ ++} ++ ++static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ unsigned int val ; ++ int cnt,i; ++ char buf[12]; ++ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask; ++#if defined(DEBUG) ++ printk("ipu write count=%u\n", count); ++#endif ++ if (count == (8*5+1)) { ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*0, 8); ++ pid = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*1, 8); ++ entrylo0 = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*2, 8); ++ entrylo1 = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*3, 8); ++ entryhi = simple_strtoul(buf, 0, 16); ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer+8*4, 8); ++ pagemask = simple_strtoul(buf, 0, 16); ++ ++#if defined(DEBUG) ++ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n", ++ pid, entrylo0, entrylo1, entryhi, pagemask); ++#endif ++ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask); ++ return 41; ++ } ++ else if ( count <= 8+1 ) { ++ for (i=0;i<12;i++) buf[i]=0; ++ strncpy(buf, buffer, 8); ++ val = simple_strtoul(buf, 0, 16); ++ } else if (count == 44) { ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer, 10); ++ pid = simple_strtoul(buf, 0, 16); ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 11, 10); ++ entryhi = simple_strtoul(buf, 0, 16);//vaddr ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 22, 10); ++ entrylo0 = simple_strtoul(buf, 0, 16);//paddr ++ for (i = 0; i < 12; i++) ++ buf[i] = 0; ++ strncpy(buf, buffer + 33, 10); ++ pagemask = simple_strtoul(buf, 0, 16); ++ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */ ++ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask); ++ return 44; ++ } else { ++ printk("ipu write count error, count=%d\n.", (unsigned int)count); ++ return -1; ++ } ++ ++ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */ ++ if ( val == 0 ) { /* debug, print ipu_buf info */ ++ for ( cnt=0; cnt /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages ++ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx ++ * echo FF > /proc/jz/ipu // FF, free all buffers ++ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer ++ */ ++ ++//#define DEBUG_IMEM 1 ++ ++#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */ ++ ++static unsigned int jz_imem_base; /* physical base address of ipu memory */ ++ ++static unsigned int allocated_phys_addr = 0; ++ ++/* ++ * Allocated buffer list ++ */ ++typedef struct imem_list { ++ unsigned int phys_start; /* physical start addr */ ++ unsigned int phys_end; /* physical end addr */ ++ struct imem_list *next; ++} imem_list_t; ++ ++static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */ ++ ++#ifdef DEBUG_IMEM ++static void dump_imem_list(void) ++{ ++ struct imem_list *imem; ++ ++ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head); ++ imem = imem_list_head; ++ while (imem) { ++ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next); ++ imem = imem->next; ++ } ++} ++#endif ++ ++/* allocate 2^order pages inside the 4MB memory */ ++static int imem_alloc(unsigned int order) ++{ ++ int alloc_ok = 0; ++ unsigned int start, end; ++ unsigned int size = (1 << order) * PAGE_SIZE; ++ struct imem_list *imem, *imemn, *imemp; ++ ++ allocated_phys_addr = 0; ++ ++ start = jz_imem_base; ++ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; ++ ++ imem = imem_list_head; ++ while (imem) { ++ if ((imem->phys_start - start) >= size) { ++ /* we got a valid address range */ ++ alloc_ok = 1; ++ break; ++ } ++ ++ start = imem->phys_end + 1; ++ imem = imem->next; ++ } ++ ++ if (!alloc_ok) { ++ if ((end - start) >= size) ++ alloc_ok = 1; ++ } ++ ++ if (alloc_ok) { ++ end = start + size - 1; ++ allocated_phys_addr = start; ++ ++ /* add to imem_list, up sorted by phys_start */ ++ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL); ++ if (!imemn) { ++ return -ENOMEM; ++ } ++ imemn->phys_start = start; ++ imemn->phys_end = end; ++ imemn->next = NULL; ++ ++ if (!imem_list_head) ++ imem_list_head = imemn; ++ else { ++ imem = imemp = imem_list_head; ++ while (imem) { ++ if (start < imem->phys_start) { ++ break; ++ } ++ ++ imemp = imem; ++ imem = imem->next; ++ } ++ ++ if (imem == imem_list_head) { ++ imem_list_head = imemn; ++ imemn->next = imem; ++ } ++ else { ++ imemn->next = imemp->next; ++ imemp->next = imemn; ++ } ++ } ++ } ++ ++#ifdef DEBUG_IMEM ++ dump_imem_list(); ++#endif ++ return 0; ++} ++ ++static void imem_free(unsigned int phys_addr) ++{ ++ struct imem_list *imem, *imemp; ++ ++ imem = imemp = imem_list_head; ++ while (imem) { ++ if (phys_addr == imem->phys_start) { ++ if (imem == imem_list_head) { ++ imem_list_head = imem->next; ++ } ++ else { ++ imemp->next = imem->next; ++ } ++ ++ kfree(imem); ++ break; ++ } ++ ++ imemp = imem; ++ imem = imem->next; ++ } ++ ++#ifdef DEBUG_IMEM ++ dump_imem_list(); ++#endif ++} ++ ++static void imem_free_all(void) ++{ ++ struct imem_list *imem; ++ ++ imem = imem_list_head; ++ while (imem) { ++ kfree(imem); ++ imem = imem->next; ++ } ++ ++ imem_list_head = NULL; ++ ++ allocated_phys_addr = 0; ++ ++#ifdef DEBUG_IMEM ++ dump_imem_list(); ++#endif ++} ++ ++/* ++ * Return the allocated buffer address and the max order of free buffer ++ */ ++static int imem_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ unsigned int start_addr, end_addr, max_order, max_size; ++ struct imem_list *imem; ++ ++ unsigned int *tmp = (unsigned int *)(page + len); ++ ++ start_addr = jz_imem_base; ++ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; ++ ++ if (!imem_list_head) ++ max_size = end_addr - start_addr; ++ else { ++ max_size = 0; ++ imem = imem_list_head; ++ while (imem) { ++ if (max_size < (imem->phys_start - start_addr)) ++ max_size = imem->phys_start - start_addr; ++ ++ start_addr = imem->phys_end + 1; ++ imem = imem->next; ++ } ++ ++ if (max_size < (end_addr - start_addr)) ++ max_size = end_addr - start_addr; ++ } ++ ++ if (max_size > 0) { ++ max_order = get_order(max_size); ++ if (((1 << max_order) * PAGE_SIZE) > max_size) ++ max_order--; ++ } ++ else { ++ max_order = 0xffffffff; /* No any free buffer */ ++ } ++ ++ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */ ++ *tmp = max_order; /* max order of current free buffers */ ++ ++ len += 2 * sizeof(unsigned int); ++ ++ return len; ++} ++ ++static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) ++{ ++ unsigned int val; ++ ++ val = simple_strtoul(buffer, 0, 16); ++ ++ if (val == 0xff) { ++ /* free all memory */ ++ imem_free_all(); ++ } ++ else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) { ++ /* allocate 2^val pages */ ++ imem_alloc(val); ++ } ++ else { ++ /* free buffer which phys_addr is val */ ++ imem_free(val); ++ } ++ ++ return count; ++} ++ ++/* ++ * /proc/jz/xxx entry ++ * ++ */ ++static int __init jz_proc_init(void) ++{ ++ struct proc_dir_entry *res; ++ unsigned int virt_addr, i; ++ ++ proc_jz_root = proc_mkdir("jz", 0); ++ ++ /* External Memory Controller */ ++ res = create_proc_entry("emc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = emc_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++ /* Power Management Controller */ ++ res = create_proc_entry("pmc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = pmc_read_proc; ++ res->write_proc = pmc_write_proc; ++ res->data = NULL; ++ } ++ ++ /* Clock Generation Module */ ++ res = create_proc_entry("cgm", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = cgm_read_proc; ++ res->write_proc = cgm_write_proc; ++ res->data = NULL; ++ } ++ ++ /* Image process unit */ ++ res = create_proc_entry("ipu", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = ipu_read_proc; ++ res->write_proc = ipu_write_proc; ++ res->data = NULL; ++ } ++ ++ /* udc hotplug */ ++ res = create_proc_entry("udc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = udc_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++ /* mmc hotplug */ ++ res = create_proc_entry("mmc", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = mmc_read_proc; ++ res->write_proc = NULL; ++ res->data = NULL; ++ } ++ ++ /* ++ * Reserve a 4MB memory for IPU on JZ4750D. ++ */ ++ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER); ++ if (jz_imem_base) { ++ /* imem (IPU memory management) */ ++ res = create_proc_entry("imem", 0644, proc_jz_root); ++ if (res) { ++ res->read_proc = imem_read_proc; ++ res->write_proc = imem_write_proc; ++ res->data = NULL; ++ } ++ ++ /* Set page reserved */ ++ virt_addr = jz_imem_base; ++ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) { ++ SetPageReserved(virt_to_page((void *)virt_addr)); ++ virt_addr += PAGE_SIZE; ++ } ++ ++ /* Convert to physical address */ ++ jz_imem_base = virt_to_phys((void *)jz_imem_base); ++ ++ printk("Total %dMB memory at 0x%x was reserved for IPU\n", ++ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base); ++ } ++ ++ return 0; ++} ++ ++__initcall(jz_proc_init); +diff --git a/arch/mips/jz4750d/prom.c b/arch/mips/jz4750d/prom.c +new file mode 100644 +index 0000000..3c173d6 +--- /dev/null ++++ b/arch/mips/jz4750d/prom.c +@@ -0,0 +1,198 @@ ++/* ++ * ++ * BRIEF MODULE DESCRIPTION ++ * PROM library initialisation code, supports YAMON and U-Boot. ++ * ++ * Copyright 2000, 2001, 2006 MontaVista Software Inc. ++ * Author: MontaVista Software, Inc. ++ * ppopov@mvista.com or source@mvista.com ++ * ++ * This file was derived from Carsten Langgaard's ++ * arch/mips/mips-boards/xx files. ++ * ++ * Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* #define DEBUG_CMDLINE */ ++ ++int prom_argc; ++char **prom_argv, **prom_envp; ++ ++char * prom_getcmdline(void) ++{ ++ return &(arcs_cmdline[0]); ++} ++ ++void prom_init_cmdline(void) ++{ ++ char *cp; ++ int actr; ++ ++ actr = 1; /* Always ignore argv[0] */ ++ ++ cp = &(arcs_cmdline[0]); ++ while(actr < prom_argc) { ++ strcpy(cp, prom_argv[actr]); ++ cp += strlen(prom_argv[actr]); ++ *cp++ = ' '; ++ actr++; ++ } ++ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ ++ --cp; ++ if (prom_argc > 1) ++ *cp = '\0'; ++ ++} ++ ++ ++char *prom_getenv(char *envname) ++{ ++#if 0 ++ /* ++ * Return a pointer to the given environment variable. ++ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". ++ */ ++ ++ char **env = prom_envp; ++ int i = strlen(envname); ++ int yamon = (*env && strchr(*env, '=') == NULL); ++ ++ while (*env) { ++ if (yamon) { ++ if (strcmp(envname, *env++) == 0) ++ return *env; ++ } else { ++ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') ++ return *env + i + 1; ++ } ++ env++; ++ } ++#endif ++ return NULL; ++} ++ ++inline unsigned char str2hexnum(unsigned char c) ++{ ++ if(c >= '0' && c <= '9') ++ return c - '0'; ++ if(c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if(c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return 0; /* foo */ ++} ++ ++inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for(i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= (str2hexnum(*str++)); ++ ea[i] = num; ++ } ++} ++ ++int get_ethernet_addr(char *ethernet_addr) ++{ ++ char *ethaddr_str; ++ ++ ethaddr_str = prom_getenv("ethaddr"); ++ if (!ethaddr_str) { ++ printk("ethaddr not set in boot prom\n"); ++ return -1; ++ } ++ str2eaddr(ethernet_addr, ethaddr_str); ++ ++#if 0 ++ { ++ int i; ++ ++ printk("get_ethernet_addr: "); ++ for (i=0; i<5; i++) ++ printk("%02x:", (unsigned char)*(ethernet_addr+i)); ++ printk("%02x\n", *(ethernet_addr+i)); ++ } ++#endif ++ ++ return 0; ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++void __init prom_init(void) ++{ ++ unsigned char *memsize_str; ++ unsigned long memsize; ++ ++ prom_argc = (int) fw_arg0; ++ prom_argv = (char **) fw_arg1; ++ prom_envp = (char **) fw_arg2; ++ ++ mips_machtype = MACH_INGENIC_JZ4750D; ++ ++ prom_init_cmdline(); ++ memsize_str = prom_getenv("memsize"); ++ if (!memsize_str) { ++ memsize = 0x04000000; ++ } else { ++ memsize = simple_strtol(memsize_str, NULL, 0); ++ } ++ add_memory_region(0, memsize, BOOT_MEM_RAM); ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ volatile u8 *uart_lsr = (volatile u8 *)(UART1_BASE + OFF_LSR); ++ volatile u8 *uart_tdr = (volatile u8 *)(UART1_BASE + OFF_TDR); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); ++ ++ *uart_tdr = (u8)c; ++} ++ ++const char *get_system_type(void) ++{ ++ return "JZ4750D"; ++} ++ ++EXPORT_SYMBOL(prom_getcmdline); ++EXPORT_SYMBOL(get_ethernet_addr); ++EXPORT_SYMBOL(str2eaddr); +diff --git a/arch/mips/jz4750d/reset.c b/arch/mips/jz4750d/reset.c +new file mode 100644 +index 0000000..90b521e +--- /dev/null ++++ b/arch/mips/jz4750d/reset.c +@@ -0,0 +1,46 @@ ++/* ++ * linux/arch/mips/jz4750/reset.c ++ * ++ * JZ4750 reset routines. ++ * ++ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void jz_restart(char *command) ++{ ++ printk("Restarting after 4 ms\n"); ++ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; ++ REG_WDT_TCNT = 0; ++ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ ++ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */ ++ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ ++ while (1); ++} ++ ++void jz_halt(void) ++{ ++ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); ++ ++ while (1) ++ __asm__(".set\tmips3\n\t" ++ "wait\n\t" ++ ".set\tmips0"); ++} ++ ++void jz_power_off(void) ++{ ++ jz_halt(); ++} +diff --git a/arch/mips/jz4750d/setup.c b/arch/mips/jz4750d/setup.c +new file mode 100644 +index 0000000..b9b8aab +--- /dev/null ++++ b/arch/mips/jz4750d/setup.c +@@ -0,0 +1,199 @@ ++/* ++ * linux/arch/mips/jz4750d/common/setup.c ++ * ++ * JZ4750D common setup routines. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PC_KEYB ++#include ++#endif ++ ++jz_clocks_t jz_clocks; ++ ++extern char * __init prom_getcmdline(void); ++extern void __init jz_board_setup(void); ++extern void jz_restart(char *); ++extern void jz_halt(void); ++extern void jz_power_off(void); ++extern void jz_time_init(void); ++ ++static void __init sysclocks_setup(void) ++{ ++#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ ++ jz_clocks.cclk = __cpm_get_cclk(); ++ jz_clocks.hclk = __cpm_get_hclk(); ++ jz_clocks.pclk = __cpm_get_pclk(); ++ jz_clocks.mclk = __cpm_get_mclk(); ++ jz_clocks.h1clk = __cpm_get_h1clk(); ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.i2sclk = __cpm_get_i2sclk(); ++ jz_clocks.usbclk = __cpm_get_usbclk(); ++ jz_clocks.mscclk = __cpm_get_mscclk(0); ++ jz_clocks.extalclk = __cpm_get_extalclk(); ++ jz_clocks.rtcclk = __cpm_get_rtcclk(); ++#else ++ ++#define FPGACLK 8000000 ++ ++ jz_clocks.cclk = FPGACLK; ++ jz_clocks.hclk = FPGACLK; ++ jz_clocks.pclk = FPGACLK; ++ jz_clocks.mclk = FPGACLK; ++ jz_clocks.h1clk = FPGACLK; ++ jz_clocks.pixclk = FPGACLK; ++ jz_clocks.i2sclk = FPGACLK; ++ jz_clocks.usbclk = FPGACLK; ++ jz_clocks.mscclk = FPGACLK; ++ jz_clocks.extalclk = FPGACLK; ++ jz_clocks.rtcclk = FPGACLK; ++#endif ++ ++ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n", ++ (jz_clocks.cclk + 500000) / 1000000, ++ (jz_clocks.hclk + 500000) / 1000000, ++ (jz_clocks.pclk + 500000) / 1000000, ++ (jz_clocks.mclk + 500000) / 1000000); ++} ++ ++static void __init soc_cpm_setup(void) ++{ ++ /* Start all module clocks ++ */ ++ __cpm_start_all(); ++ ++ /* Enable CKO to external memory */ ++ __cpm_enable_cko(); ++ ++ /* CPU enters IDLE mode when executing 'wait' instruction */ ++ __cpm_idle_mode(); ++ ++ /* Setup system clocks */ ++ sysclocks_setup(); ++} ++ ++static void __init soc_harb_setup(void) ++{ ++// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ ++// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ ++// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ ++} ++ ++static void __init soc_emc_setup(void) ++{ ++} ++ ++static void __init soc_dmac_setup(void) ++{ ++ __dmac_enable_module(0); ++ __dmac_enable_module(1); ++} ++ ++static void __init jz_soc_setup(void) ++{ ++ soc_cpm_setup(); ++ soc_harb_setup(); ++ soc_emc_setup(); ++ soc_dmac_setup(); ++} ++ ++static void __init jz_serial_setup(void) ++{ ++#ifdef CONFIG_SERIAL_8250 ++ struct uart_port s; ++ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */ ++ memset(&s, 0, sizeof(s)); ++ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; ++ s.iotype = SERIAL_IO_MEM; ++ s.regshift = 2; ++ s.uartclk = jz_clocks.extalclk ; ++ ++ s.line = 0; ++ s.membase = (u8 *)UART0_BASE; ++ s.irq = IRQ_UART0; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); ++ } ++ ++ s.line = 1; ++ s.membase = (u8 *)UART1_BASE; ++ s.irq = IRQ_UART1; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); ++ } ++ ++ s.line = 2; ++ s.membase = (u8 *)UART2_BASE; ++ s.irq = IRQ_UART2; ++ ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS2 setup failed!\n"); ++ } ++/* ++ s.line = 3; ++ s.membase = (u8 *)UART3_BASE; ++ s.irq = IRQ_UART3; ++ if (early_serial_setup(&s) != 0) { ++ printk(KERN_ERR "Serial ttyS3 setup failed!\n"); ++ } ++*/ ++#endif ++} ++ ++void __init plat_mem_setup(void) ++{ ++ char *argptr; ++ ++ argptr = prom_getcmdline(); ++ ++ /* IO/MEM resources. Which will be the addtion value in `inX' and ++ * `outX' macros defined in asm/io.h */ ++ set_io_port_base(0); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ ++ _machine_restart = jz_restart; ++ _machine_halt = jz_halt; ++ pm_power_off = jz_power_off; ++ ++ jz_soc_setup(); ++ jz_serial_setup(); ++ jz_board_setup(); ++} ++ +diff --git a/arch/mips/jz4750d/time.c b/arch/mips/jz4750d/time.c +new file mode 100644 +index 0000000..0c6d647 +--- /dev/null ++++ b/arch/mips/jz4750d/time.c +@@ -0,0 +1,156 @@ ++/* ++ * linux/arch/mips/jz4750d/time.c ++ * ++ * Setting up the clock on the JZ4750D boards. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* This is for machines which generate the exact clock. */ ++ ++#define JZ_TIMER_IRQ IRQ_TCU0 ++ ++#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ ++ ++static struct clocksource clocksource_jz; /* Jz clock source */ ++static struct clock_event_device jz_clockevent_device; /* Jz clock event */ ++ ++void (*jz_timer_callback)(void); ++ ++static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *cd = dev_id; ++ ++ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */ ++ ++ if (jz_timer_callback) ++ jz_timer_callback(); ++ ++ cd->event_handler(cd); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction jz_irqaction = { ++ .handler = jz_timer_interrupt, ++ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, ++ .name = "jz-timerirq", ++}; ++ ++ ++cycle_t jz_get_cycles(void) ++{ ++ /* convert jiffes to jz timer cycles */ ++ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT); ++} ++ ++static struct clocksource clocksource_jz = { ++ .name = "jz_clocksource", ++ .rating = 300, ++ .read = jz_get_cycles, ++ .mask = 0xFFFFFFFF, ++ .shift = 10, ++ .flags = CLOCK_SOURCE_WATCHDOG, ++}; ++ ++static int __init jz_clocksource_init(void) ++{ ++ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); ++ clocksource_register(&clocksource_jz); ++ return 0; ++} ++ ++static int jz_set_next_event(unsigned long evt, ++ struct clock_event_device *unused) ++{ ++ return 0; ++} ++ ++static void jz_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ case CLOCK_EVT_MODE_UNUSED: ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ break; ++ } ++} ++ ++static struct clock_event_device jz_clockevent_device = { ++ .name = "jz-clockenvent", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ ++ ++ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ ++ .rating = 300, ++ .irq = JZ_TIMER_IRQ, ++ .set_mode = jz_set_mode, ++ .set_next_event = jz_set_next_event, ++}; ++ ++static void __init jz_clockevent_init(void) ++{ ++ struct clock_event_device *cd = &jz_clockevent_device; ++ unsigned int cpu = smp_processor_id(); ++ ++ cd->cpumask = cpumask_of_cpu(cpu); ++ clockevents_register_device(cd); ++} ++ ++static void __init jz_timer_setup(void) ++{ ++ jz_clocksource_init(); /* init jz clock source */ ++ jz_clockevent_init(); /* init jz clock event */ ++ ++ /* ++ * Make irqs happen for the system timer ++ */ ++ jz_irqaction.dev_id = &jz_clockevent_device; ++ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); ++} ++ ++ ++void __init plat_time_init(void) ++{ ++ unsigned int latch; ++ ++ /* Init timer */ ++ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ; ++ ++ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN; ++ REG_TCU_OSTCNT = 0; ++ REG_TCU_OSTDR = latch; ++ ++ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */ ++ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */ ++ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */ ++ ++ jz_timer_setup(); ++} +diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c +index 1abe990..bdcf5b6 100644 +--- a/arch/mips/kernel/cpu-probe.c ++++ b/arch/mips/kernel/cpu-probe.c +@@ -159,6 +159,7 @@ void __init check_wait(void) + case CPU_25KF: + case CPU_PR4450: + case CPU_BCM3302: ++ case CPU_JZRISC: + case CPU_CAVIUM_OCTEON: + cpu_wait = r4k_wait; + break; +@@ -580,6 +581,14 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) + MIPS_CPU_32FPR; + c->tlbsize = 64; + break; ++ case PRID_IMP_JZRISC: ++ c->cputype = CPU_JZRISC; ++ __cpu_name[cpu] = "Ingenic JZRISC"; ++ c->isa_level = MIPS_CPU_ISA_M32R1; ++ /* JZRISC does not implement the CP0 counter. */ ++ c->options &= ~MIPS_CPU_COUNTER; ++ c->tlbsize = 32; ++ break; + } + } + +@@ -888,6 +897,23 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) + } + } + ++static inline void cpu_probe_ingenic(struct cpuinfo_mips *c) ++{ ++ decode_configs(c); ++ c->options &= ~MIPS_CPU_COUNTER; /* JZRISC does not implement the CP0 counter. */ ++ switch (c->processor_id & 0xff00) { ++ case PRID_IMP_JZRISC: ++ c->cputype = CPU_JZRISC; ++ __cpu_name[cpu] = "Ingenic JZRISC"; ++ c->isa_level = MIPS_CPU_ISA_M32R1; ++ c->tlbsize = 32; ++ break; ++ default: ++ panic("Unknown Ingenic Processor ID!"); ++ break; ++ } ++} ++ + const char *__cpu_name[NR_CPUS]; + + __cpuinit void cpu_probe(void) +@@ -925,6 +951,9 @@ __cpuinit void cpu_probe(void) + case PRID_COMP_CAVIUM: + cpu_probe_cavium(c, cpu); + break; ++ case PRID_COMP_INGENIC: ++ cpu_probe_ingenic(c); ++ break; + } + + BUG_ON(!__cpu_name[cpu]); +diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c +index 67bd626..9d6dca1 100644 +--- a/arch/mips/kernel/unaligned.c ++++ b/arch/mips/kernel/unaligned.c +@@ -497,6 +497,11 @@ sigill: + force_sig(SIGILL, current); + } + ++#if defined(CONFIG_JZ_TCSM) ++#undef user_mode ++#define user_mode(regs) ((((regs)->cp0_status & KU_MASK) == KU_USER) || (regs->cp0_badvaddr < 0x80000000)) ++#endif ++ + asmlinkage void do_ade(struct pt_regs *regs) + { + unsigned int __user *pc; +@@ -522,8 +527,9 @@ asmlinkage void do_ade(struct pt_regs *regs) + * This is all so but ugly ... + */ + seg = get_fs(); +- if (!user_mode(regs)) ++ if (!user_mode(regs)) { + set_fs(KERNEL_DS); ++ } + emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); + set_fs(seg); + +diff --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); +diff --git a/crypto/Makefile b/crypto/Makefile +index 673d9f7..7180908 100644 +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -77,6 +77,7 @@ obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o + obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o + obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o + obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o ++obj-$(CONFIG_CRYPTO_LZO) += lzo.o + obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o + obj-$(CONFIG_CRYPTO_LZO) += lzo.o + obj-$(CONFIG_CRYPTO_RNG2) += rng.o +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index d59ba50..217080e 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -680,6 +680,11 @@ static int do_test(int m) + ret += tcrypt_test("rfc4309(ccm(aes))"); + break; + ++ case 33: ++ test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template, ++ LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS); ++ break; ++ + case 100: + ret += tcrypt_test("hmac(md5)"); + break; +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index 6a06913..357a6c0 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -831,6 +831,16 @@ config RTC + To compile this driver as a module, choose M here: the + module will be called rtc. + ++config RTC_PCF8563 ++ bool 'Philips PCF8563 Real Time Clock (I2C Bus)' ++ help ++ Philips PCF8563 Real Time Clock (I2C Bus) ++ ++config RTC_JZ ++ bool 'Jz47XX On-Chip Real Time Clock' ++ help ++ Jz47XX On-Chip Real Time Clock ++ + config JS_RTC + tristate "Enhanced Real Time Clock Support" + depends on SPARC32 && PCI +@@ -1109,6 +1119,7 @@ config DEVPORT + default y + + source "drivers/s390/char/Kconfig" ++source "drivers/char/jzchar/Kconfig" + + endmenu + +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index 66f779a..ae98c77 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -98,6 +98,10 @@ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o + obj-$(CONFIG_GPIO_TB0219) += tb0219.o + obj-$(CONFIG_TELCLOCK) += tlclk.o + ++obj-$(CONFIG_RTC_PCF8563) += rtc_pcf8563.o ++obj-$(CONFIG_RTC_JZ) += rtc_jz.o ++obj-$(CONFIG_JZCHAR) += jzchar/ ++ + obj-$(CONFIG_MWAVE) += mwave/ + obj-$(CONFIG_AGP) += agp/ + obj-$(CONFIG_PCMCIA) += pcmcia/ +diff --git a/drivers/char/jzchar/Kconfig b/drivers/char/jzchar/Kconfig +new file mode 100644 +index 0000000..4f7ff70 +--- /dev/null ++++ b/drivers/char/jzchar/Kconfig +@@ -0,0 +1,70 @@ ++# ++# JzSOC char devices configuration ++# ++ ++menu "JZSOC char device support" ++ depends on SOC_JZ4740 || SOC_JZ4730 || SOC_JZ4750 || SOC_JZ4750D ++ ++config JZCHAR ++ tristate 'JzSOC char device support' ++ ++config JZ_CAMERA_SENSOR ++ bool ++ ++config JZ_CIM ++ tristate 'JzSOC Camera Interface Module (CIM) support' ++ depends on JZCHAR ++ select JZ_CAMERA_SENSOR ++ ++config JZ_TPANEL_ATA2508 ++ tristate 'JzSOC MPEG4 TOUCH PANEL ATA2508 support' ++ depends on JZCHAR ++ ++config JZ_TPANEL ++ tristate 'JzSOC touchpanel driver support' ++ depends on JZCHAR ++# select JZ_SADC if SOC_JZ4740 ++# select JZ_TPANEL_AK4182 if SOC_JZ4730 ++ ++choice ++ prompt "Touch Panel ADC type" ++ depends on JZ_TPANEL ++ default JZ_SADC if SOC_JZ4740 || SOC_JZ4750 || SOC_JZ4750D ++ default JZ_TPANEL_AK4182 if SOC_JZ4730 ++ ++config JZ_SADC ++ bool 'Select the JZ47XX internal SADC' ++ ++config JZ_TPANEL_AK4182 ++ bool 'Select the AK4182 codec' ++ ++config JZ_TPANEL_UCB1400 ++ bool 'Select the UCB1400 codec' ++ ++config JZ_TPANEL_WM9712 ++ bool 'Select the WM9712 codec' ++ ++endchoice ++ ++config JZ_UDC_HOTPLUG ++ tristate 'JZ UDC hotplug driver support' ++ depends on JZCHAR ++ ++config JZ_POWEROFF ++ tristate 'JZ board poweroff support' ++ depends on JZCHAR ++ ++config JZ_OW ++ tristate 'JZ One-wire bus support' ++ depends on JZCHAR ++ ++config JZ_TCSM ++ tristate 'JZ TCSM support' ++ depends on JZCHAR ++ ++config JZ_TSSI ++ tristate 'JZ MPEG2-TS interface support' ++ depends on JZCHAR && (SOC_JZ4750 || SOC_JZ4750D) ++ ++endmenu ++ +diff --git a/drivers/char/jzchar/Makefile b/drivers/char/jzchar/Makefile +new file mode 100644 +index 0000000..b079ffc +--- /dev/null ++++ b/drivers/char/jzchar/Makefile +@@ -0,0 +1,24 @@ ++# ++# Makefile for jzchar ++# ++obj-$(CONFIG_JZCHAR) += jzchars.o ++ ++obj-$(CONFIG_JZ_SCC) += scc.o ++obj-$(CONFIG_JZ_CIM) += cim.o ++obj-$(CONFIG_JZ_TPANEL_ATA2508) += ata2508.o ++obj-$(CONFIG_JZ_CAMERA_SENSOR) += sensor.o ++obj-$(CONFIG_JZ_I2C_EEPROM) += eeprom.o ++obj-$(CONFIG_JZ_EJTAG) += ejtag.o ++obj-$(CONFIG_JZ_POWEROFF) += poweroff.o ++ ++obj-$(CONFIG_JZ_TPANEL) += jz_ts.o ++obj-$(CONFIG_JZ_TPANEL_UCB1400) += ucb1400.o ++obj-$(CONFIG_JZ_TPANEL_WM9712) += wm9712.o ++obj-$(CONFIG_JZ_TPANEL_AK4182) += ak4182.o ++obj-$(CONFIG_JZ_SADC) += sadc.o ++ ++obj-$(CONFIG_JZ_SMART_LCD) += slcd.o ++obj-$(CONFIG_JZ_UDC_HOTPLUG) += udc_hotplug.o ++obj-$(CONFIG_JZ_OW) += jz_ow.o ++obj-$(CONFIG_JZ_TCSM) += tcsm.o ++obj-$(CONFIG_JZ_TSSI) += jz_tssi.o +diff --git a/drivers/char/jzchar/ak4182.c b/drivers/char/jzchar/ak4182.c +new file mode 100644 +index 0000000..c88aa9a +--- /dev/null ++++ b/drivers/char/jzchar/ak4182.c +@@ -0,0 +1,657 @@ ++/* ++ * ak4182.c using national microwire protocol ++ * ++ * Touch screen driver interface to the AK4182A . ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "jz_ts.h" ++#include "ak4182.h" ++ ++#define TS_PIN GPIO_TS_PENIRQ ++#define TS_IRQ (IRQ_GPIO_0 + TS_PIN) ++ ++static int samples = 5; ++static int first_time = 0; ++static unsigned long last_x, last_y, last_p; ++ ++static int adcsync = 0; ++ ++static struct ak4182 *ak; ++ ++extern unsigned int (*codec_read_battery)(void); ++ ++/*------------------JzSoc SSI configure----------------*/ ++static void ak4182_ssi_reset(void) ++{ ++ REG_SSI_CR0 = 0x0000; ++ REG_SSI_CR1 = 0x00007960; ++ REG_SSI_SR = 0x00000098; ++ REG_SSI_ITR = 0x0000; ++ REG_SSI_ICR = 0x00; ++ REG_SSI_GR = 0x0000; ++ ++ __ssi_disable(); ++ __ssi_flush_fifo(); ++ __ssi_clear_errors(); ++ __ssi_select_ce(); ++} ++ ++static void ak4182_ssi_enable(void) ++{ ++ __ssi_enable(); ++} ++ ++#ifdef CONFIG_PM ++static void ak4182_ssi_disable(void) ++{ ++ __ssi_disable(); ++} ++#endif ++ ++static void ak4182_ssi_set_trans_mode_format(void) ++{ ++ __ssi_microwire_format(); ++ __ssi_set_msb(); ++ __ssi_set_microwire_command_length(8); ++ __ssi_set_frame_length(12); ++} ++ ++static void ak4182_ssi_set_clk_div_ratio(int dev_clk, int ssi_clk) ++{ ++ __ssi_set_clk(dev_clk, ssi_clk); ++} ++ ++static void ak4182_ssi_set_normal_mode(void) ++{ ++ __ssi_normal_mode(); ++} ++ ++static void ak4182_ssi_set_IRQ(void) ++{ ++ __ssi_disable_tx_intr(); ++ __ssi_disable_rx_intr(); ++} ++ ++/*------------------ AK4182 routines ------------------*/ ++static inline void ak4182_reg_write(unsigned short val) ++{ ++ __ssi_transmit_data(val); ++} ++ ++static inline unsigned int ak4182_reg_read(void) ++{ ++ unsigned int val; ++ val = __ssi_receive_data(); ++ return val; ++} ++ ++static unsigned int ak4182_adc_read(int cmd_code, int sync) ++{ ++ unsigned int val, timeout = 10000; ++ unsigned int status,valid1,valid2,dataentry; ++ ++ ak4182_reg_write(cmd_code); ++ udelay(2);//wait 2 D_CLK ++ for (;;) { ++ status =0; ++ status = REG_SSI_SR; ++ valid1 = (status>>7) & 1; ++ valid2 = (status>>6) & 1; ++ if( valid1==1 && valid2==0 )//SSI transfer is finished ++ { ++ //Receive FIFO data entry number ++ dataentry = val = 0; ++ dataentry = (status>>8) & 0x1F; ++ if( dataentry > 5 ) ++ { ++ printk("R-FIFO entry=%d,SSI transfer is wrong!\n",dataentry); ++ while(dataentry > 0) ++ { ++ ak4182_reg_read(); ++ dataentry--; ++ } ++ return 0; ++ } ++ while(dataentry > 0) ++ { ++ val = ak4182_reg_read(); ++ dataentry--; ++ } ++ return val; ++ } ++ ++ if (--timeout == 0) ++ break; ++ udelay(1); ++ } ++ return 0; ++} ++ ++ ++//enable pen down IRQ ++static void ak4182_enable_irq(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ak->lock, flags); ++ __gpio_unmask_irq(TS_PIN); ++ spin_unlock_irqrestore(&ak->lock, flags); ++} ++ ++//disable pen down IRQ ++static void ak4182_disable_irq(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ak->lock, flags); ++ __gpio_mask_irq(TS_PIN); ++// spin_unlock_irqrestore(&ucb->lock, flags); ++ spin_unlock_irqrestore(&ak->lock, flags); ++} ++/* ++ * Switch to X position mode and measure Y plate. We switch the plate ++ * configuration in pressure mode, then switch to position mode. This ++ * gives a faster response time. Even so, we need to wait about 55us ++ * for things to stabilise. ++ */ ++static inline unsigned int ak4182_ts_read_xpos(void) ++{ ++ return ak4182_adc_read(0xD0, adcsync);//X-axis,0xD0 for 12bit,0xD8 for 8bit ++} ++ ++ ++/* ++ * Switch to pressure mode, and read pressure. We don't need to wait ++ * here, since both plates are being driven. ++ */ ++static inline unsigned int ak4182_ts_read_pressure(void) ++{ ++ unsigned int z1,z2,xpos,pressureval=0;//300 Om ++ //Z1 pressure ++ z1 = ak4182_adc_read(0xB0, adcsync);//0xB0 for 12bit,0xB8 for 8bit ++ if(z1>0) ++ { ++ //Z2 pressure ++ z2 = ak4182_adc_read(0xC0, adcsync);//0xC0 for 12bit,0xC8 for 8bit ++ if(z2>z1) ++ { ++ xpos = ak4182_ts_read_xpos(); ++ pressureval = (300*xpos*(z2-z1))/(4096*z1); ++ } ++ } ++ ++ return pressureval; ++} ++ ++ ++/* ++ * Switch to Y position mode and measure X plate. We switch the plate ++ * configuration in pressure mode, then switch to position mode. This ++ * gives a faster response time. Even so, we need to wait about 55us ++ * for things to stabilise. ++ */ ++static inline unsigned int ak4182_ts_read_ypos(void) ++{ ++ return ak4182_adc_read(0x90, adcsync);//Y-axis,0x90 for 12bit,0x98 for 8bit ++} ++ ++/*------------------------------------------------------------ ++ * Read the battery voltage ++ */ ++ ++unsigned int ak4182_read_battery(void) ++{ ++ unsigned int v; ++ int bat_val[5]; ++ int total = 0, max_bat, min_bat; ++ ++ v = ak4182_adc_read(0xA7, adcsync); ++ v = ak4182_adc_read(0xA7, adcsync); ++ for(v = 0;v <= 4;v++) ++ bat_val[v] = ak4182_adc_read(0xA7, adcsync); ++ ++ ak4182_adc_read(0xA4, adcsync); ++ max_bat = min_bat = bat_val[0]; ++ for(v = 0;v <= 4;v++) { ++ total += bat_val[v]; ++ if(bat_val[v] > max_bat) ++ max_bat = bat_val[v]; ++ if(bat_val[v] < min_bat) ++ min_bat = bat_val[v]; ++ } ++ total = total - max_bat - min_bat; ++ v = total / 3; ++ return v; ++} ++ ++/*------------------ Calibrate samples -------------------*/ ++ ++#define DIFF(a,b) ((a>b)?(a-b):(b-a)) ++ ++static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) ++{ ++ unsigned long *xp = (unsigned long *)xbuf; ++ unsigned long *yp = (unsigned long *)ybuf; ++ unsigned long *pp = (unsigned long *)pbuf; ++ unsigned long x_cal = 0, y_cal = 0, p_cal = 0, tmp; ++ int ignored, i, j; ++ int valid = 0; ++ ++ /* throw away the max cases */ ++ tmp = xp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (xp[i] > tmp) { ++ tmp = xp[i]; ++ ignored = i; ++ } ++ }//find the max val ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ xp[j++] = xp[i]; ++ }//shift val and delete the max val ++ ++ tmp = yp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (yp[i] > tmp) { ++ tmp = yp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ yp[j++] = yp[i]; ++ } ++ ++ tmp = pp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (pp[i] > tmp) { ++ tmp = pp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ pp[j++] = pp[i]; ++ } ++ ++ /* throw away the min cases */ ++ ++ count -= 1; // decrement by 1 ++ ++ tmp = xp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (xp[i] < tmp) { ++ tmp = xp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ xp[j++] = xp[i]; ++ } ++ ++ tmp = yp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (yp[i] < tmp) { ++ tmp = yp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ yp[j++] = yp[i]; ++ } ++ ++ tmp = pp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (pp[i] < tmp) { ++ tmp = pp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ pp[j++] = pp[i]; ++ } ++ ++ count -= 1; // decrement by 1 ++ ++ /* calculate the average of the rest */ ++ for (i = 0; i < count; i++) { ++ x_cal += xp[i]; ++ y_cal += yp[i]; ++ p_cal += pp[i]; ++ } ++ x_cal /= count; ++ y_cal /= count; ++ p_cal /= count; ++ ++ if (first_time) { ++ first_time = 0; ++ last_x = x_cal; ++ last_y = y_cal; ++ last_p = p_cal; ++ valid = 1; ++ } ++ else { ++ if ((DIFF(x_cal, last_x) > 100) || ++ (DIFF(y_cal, last_y) > 100)) ++ valid = 0; ++ else ++ valid = 1; ++ } ++ ++ //printk("x_cal=%d y_cal=%d p_cal=%d valid=%d\n", x_cal, y_cal, p_cal, valid); ++ ++ if (valid) { ++ *xp = last_x = x_cal; ++ *yp = last_y = y_cal; ++ *pp = last_p = p_cal; ++ } ++ ++ return valid; ++} ++ ++ ++#define TSMAXX 945 ++#define TSMAXY 830 ++#define TSMINX 90 ++#define TSMINY 105 ++ ++#define SCREEN_X 480 ++#define SCREEN_Y 272 ++ ++static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) ++{ ++ ++ if (ts->minx) ++ { ++ if (x < ts->minx) x = ts->minx; ++ if (x > ts->maxx) x = ts->maxx; ++ ++ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); ++ } ++ else ++ { ++ if (x < TSMINX) x = TSMINX; ++ if (x > TSMAXX) x = TSMAXX; ++ ++ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); ++ } ++} ++ ++static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) ++{ ++ if (ts->miny) ++ { ++ if (y < ts->miny) y = ts->miny; ++ if (y > ts->maxy) y = ts->maxy; ++ ++ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); ++ } ++ else ++ { ++ if (y < TSMINY) y = TSMINY; ++ if (y > TSMAXY) y = TSMAXY; ++ ++ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); ++ } ++} ++ ++/*------------------ Common routines -------------------*/ ++ ++void ts_enable_irq(void) ++{ ++ /* interrupt mode */ ++ ak4182_enable_irq(); ++ enable_irq(TS_IRQ); ++} ++ ++void ts_disable_irq(void) ++{ ++ ak4182_disable_irq(); ++ disable_irq(TS_IRQ); ++} ++ ++int ts_request_irq(u32 *irq, ++ irqreturn_t (*handler)(int, void *), ++ const char *devname, ++ void *dev_id) ++{ ++ int retval; ++ ++ /* return the irq number */ ++ *irq = TS_IRQ; ++ /* initializate ssi for AK4182 */ ++ ak4182_ssi_reset(); ++ ak4182_ssi_set_trans_mode_format(); ++ ak4182_ssi_set_normal_mode(); ++ ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max ++ ak4182_ssi_set_IRQ(); ++ ++ ak4182_enable_irq(); ++ ++ /* enable gpio irq */ ++ __gpio_as_irq_fall_edge(TS_PIN); ++ ++ /* register irq handler */ ++ retval = request_irq(TS_IRQ, handler, IRQF_DISABLED, devname, dev_id); ++ ak4182_ssi_enable(); ++ udelay(10); ++ return retval; ++} ++ ++void ts_free_irq(struct jz_ts_t *ts) ++{ ++ free_irq(ts->pendown_irq, ts); ++ //Close SSI mode ++ ak4182_ssi_reset(); ++} ++ ++void ts_irq_callback(void) ++{ ++ /* clear interrupt status */ ++ __gpio_ack_irq(TS_PIN); ++ first_time = 1; // first time to acquire sample ++} ++ ++int PenIsDown(void) ++{ ++ unsigned int p; ++ p = ak4182_ts_read_pressure(); ++ return (p > 100) ? 1 : 0; ++} ++ ++/* ++ * Acquire Raw pen coodinate data and compute touch screen ++ * pressure resistance. Hold spinlock when calling. ++ */ ++int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) ++{ ++ unsigned int x_raw[8], y_raw[8], p_raw[8]; ++ int valid, i; ++ ++ for (i = 0; i < samples; i++) { ++ x_raw[i] = ak4182_ts_read_xpos(); ++ } ++ for (i = 0; i < samples; i++) { ++ y_raw[i] = ak4182_ts_read_ypos(); ++ } ++ for (i = 0; i < samples; i++) { ++ p_raw[i] = ak4182_ts_read_pressure(); ++ } ++ ++ valid = calibrate_samples(x_raw, y_raw, p_raw, samples); ++ ++ if (valid) { ++ unsigned int x_scr, y_scr; ++ ++ if(ts->filter) { ++ x_scr = transform_to_screen_x(ts, x_raw[0]); ++ y_scr = transform_to_screen_y(ts, y_raw[0]); ++ ++ if (ts->prints) ++ printk("filter:x_raw:%d,y_raw:%d,x_tran:%d,y_tran:%d\n", x_raw[0], y_raw[0], x_scr, y_scr); ++ } ++ else { ++ x_scr = x_raw[0]; ++ y_scr = y_raw[0]; ++ ++ if (ts->prints) ++ printk("no filter:x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); ++ } ++ ++ event->x = x_scr; ++ event->y = y_scr; ++ event->pressure = (u16)p_raw[0]; ++ event->status = PENDOWN; ++ return 1; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++/* ++ * Suspend the Touch pad. ++ */ ++static int ak4182_suspend(struct ak4182 *ak , int state) ++{ ++ ak4182_ssi_disable(); ++ ++ return 0; ++} ++ ++/* ++ * Resume the Touch panel. ++ */ ++static int ak4182_resume(struct ak4182 *ak) ++{ ++ /* initializate ssi for AK4182 */ ++ ak4182_ssi_reset(); ++ ak4182_ssi_set_trans_mode_format(); ++ ak4182_ssi_set_normal_mode(); ++ ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max ++ ak4182_ssi_set_IRQ(); ++ ++ ak4182_enable_irq(); ++ ++ ak4182_ssi_enable(); ++ ++ return 0; ++} ++ ++static int ak4182_pm_callback(struct pm_dev *pm_dev, pm_request_t rqst, void *data) ++{ ++ int ret; ++ struct ak4182 *akinfo = pm_dev->data; ++ ++ if (!akinfo) ++ return -EINVAL; ++ ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ ret = ak4182_suspend(akinfo, (int)data); ++ break; ++ ++ case PM_RESUME: ++ ret = ak4182_resume(akinfo); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#endif /* CONFIG_PM */ ++ ++ ++/* ++ * Module init and exit ++ */ ++ ++int __init ak4182_init(void) ++{ ++ ak = kmalloc(sizeof(struct ak4182), GFP_KERNEL); ++ if (!ak) return -ENOMEM; ++ ++ memset(ak, 0, sizeof(struct ak4182)); ++ ++ codec_read_battery = ak4182_read_battery; ++ ++ spin_lock_init(&ak->lock); ++ sema_init(&ak->adc_sem, 1); ++ ++ //initialize AK4182 register ++ __gpio_clear_pin(73); ++ __gpio_as_output(73); ++ mdelay(2); ++ __gpio_set_pin(73); ++ __gpio_as_ssi(); ++ ++ ak4182_read_battery(); ++ ++#ifdef CONFIG_PM ++ ak->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ak4182_pm_callback); ++ if (ak->pmdev) ++ { ++ ak->pmdev->data = ak; ++ } ++#endif ++ ++ printk("AK4182 touch screen driver initialized\n"); ++ ++ return 0; ++} ++ ++void ak4182_cleanup(void) ++{ ++} ++ ++module_init(ak4182_init); ++module_exit(ak4182_cleanup); ++ +diff --git a/drivers/char/jzchar/ak4182.h b/drivers/char/jzchar/ak4182.h +new file mode 100644 +index 0000000..e8b1bf8 +--- /dev/null ++++ b/drivers/char/jzchar/ak4182.h +@@ -0,0 +1,16 @@ ++#ifndef __AK4182_H__ ++#define __AK4182_H__ ++ ++/* Device data structure */ ++ ++struct ak4182 { ++ spinlock_t lock; ++ struct pm_dev *pmdev; ++ struct semaphore adc_sem; ++ u16 adc_cr; ++ u16 irq_fal_enbl; ++ u16 irq_ris_enbl; ++ int irq_enabled; ++}; ++ ++#endif /* __AK4182_H__ */ +diff --git a/drivers/char/jzchar/ata2508.c b/drivers/char/jzchar/ata2508.c +new file mode 100644 +index 0000000..41a4ff4 +--- /dev/null ++++ b/drivers/char/jzchar/ata2508.c +@@ -0,0 +1,227 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define MP4_KEY_RST (32*3+3) ++#define MP4_KEY_TINT (32*3+2) ++#define MP4_KEY_SCL (32*3+1) ++#define MP4_KEY_SDA (32*3+0) ++#define MP4_TINT_IRQ (IRQ_GPIO_0 + MP4_KEY_TINT) ++ ++#define ADDR_WARM_RESET 0xFF ++#define ATA2508_SENSOR_MASK 0x1F ++ ++const unsigned char init_data_burst[] = {//Address:0x0D-0x3E ++ 0x04, // BETA ++ 0x27, // AIC_WAIT ++ //0x32, // REF_DELAY ++ 0x16, // REF_DELAY ++ 0x02, // HYSTERESIS01 ++ 0x02, // HYSTERESIS1 ++ 0x02, // HYSTERESIS2 ++ 0x02, // HYSTERESIS3 ++ 0x02, // HYSTERESIS4 ++ 0x02, // HYSTERESIS51 ++ 0x02, // HYSTERESIS61 ++ 0x02, // HYSTERESIS7 ++ 0x02, // HYSTERESIS8 ++ 0x02, // HYSTERESIS9 ++ 0x02, // HYSTERESIS10 ++ 0x02, // HYSTERESIS11 ++ 0x64, // STRENGTH_THRESHOLD0 ++ 0x64, // STRENGTH_THRESHOLD1 ++ 0x64, // STRENGTH_THRESHOLD2 ++ 0x64, // STRENGTH_THRESHOLD3 ++ 0x64, // STRENGTH_THRESHOLD4 ++ 0x64, // STRENGTH_THRESHOLD5 ++ 0x64, // STRENGTH_THRESHOLD6 ++ 0x64, // STRENGTH_THRESHOLD7 ++ 0x64, // STRENGTH_THRESHOLD8 ++ 0x64, // STRENGTH_THRESHOLD9 ++ 0x64, // STRENGTH_THRESHOLD10 ++ 0x64, // STRENGTH_THRESHOLD11 ++ 0x0f, // Sampling Interval ++ 0xC8, // INTEGRATION TIME ++ 0x0f, // IDLE TIME ++ 0x00, // SIF_SETUP(RESERVED) ++ 0x01, // MODE ++ 0x00, // GPIO_REG_L ++ 0x00, // GPIO_REG_H ++ 0x00, // GPIO_CONFIGURATION_L ++ 0x00, // GPIO_CONFIGURATION_H ++ 0x00, // GPIO_DIR_L ++ 0x00, // GPIO_DIR_H ++ 0x0c, // CONTROL ++ 0x38, // INT_MASK ++ 0x00, // INT_CLEAR ++ 0xFF, // INT_edge ++ 0x02, // CONTROL_2 ++ 0xAF, // BEEP_TIME ++ 0x7F, // BEEP_FREQUENCY ++ 0x30, // CALIBRATION INTERVAL ++ 0x00, // EINT_ENABLE ++ 0x00, // EINT_POL ++ 0x00, // FILTER_PERIOD ++ 0x00, // FILTER_THRESHOLD ++}; ++const unsigned char init_data_alpha[] = {//Address:0x00-0x0C ++ 0x02, // APIS ++ 0x08, // ALPHA0 ++ 0x08, // ALPHA1 ++ 0x08, // ALPHA2 ++ 0x08, // ALPHA3 ++ 0x08, // ALPHA4 ++ 0x28, // ALPHA5 ++ 0x28, // ALPHA6 ++ 0x28, // ALPHA7 ++ 0x28, // ALPHA8 ++ 0x28, // ALPHA9 ++ 0x28, // ALPHA10 ++ 0x28, // ALPHA11 ++}; ++static unsigned int i2c_addr = 0x58; ++static unsigned int i2c_clk = 100000; ++ ++static void write_reg(u8 reg, u8 val) ++{ ++ int ret; ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ ret = i2c_write(i2c_addr, &val, reg, 1); ++ i2c_close(); ++} ++ ++static u8 read_reg(u8 reg) ++{ ++ u8 val; ++ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_read(i2c_addr, &val, reg, 1); ++ i2c_close(); ++ return val; ++} ++ ++/* ++ * Interrupt handler ++ */ ++static irqreturn_t mp4_tint_irq(int irq, void *dev_id) ++{ ++ int key_num = 0; ++ u8 value0, value1; ++ ++ __gpio_ack_irq(MP4_KEY_TINT); ++ value0 = read_reg(0x75); ++ value1 = read_reg(0x76); ++ value0 &= ATA2508_SENSOR_MASK; ++ if (value0 == 0) { ++ printk("\nRelease key!\n"); ++ return IRQ_HANDLED; ++ } ++ while(value0 >> 1){ ++ value0 >>= 1; ++ key_num++; ++ } ++ ++ printk("\nPress key %d!\n", key_num); ++ return IRQ_HANDLED; ++} ++ ++static int __init init_ata2508(void) ++{ ++ int i; ++ unsigned char data1; ++ int retval; ++ ++ __gpio_as_output(MP4_KEY_RST); ++ __gpio_set_pin(MP4_KEY_RST); ++ mdelay(100); ++ __gpio_clear_pin(MP4_KEY_RST); ++ mdelay(800); ++ __gpio_set_pin(MP4_KEY_RST); ++ __gpio_mask_irq(MP4_KEY_TINT); ++ ++ /*write registers*/ ++ for(i=0; i<13; i++) ++ { ++ data1 = init_data_alpha[i]; ++ write_reg(i, data1); ++ } ++ ++ for(i=13; i<63; i++) ++ { ++ data1 = init_data_burst[i-13]; ++ write_reg(i, data1); ++ } ++#if 0 ++ for (i = 0; i < 63; i++) ++ { ++ data1 = read_reg(i); ++ printk("REG0x%02x = 0x%02x\n", i, data1); ++ } ++#endif ++ ++ /* wait for 1 ms*/ ++ mdelay(1); ++#if 0 ++ while(1) ++ { ++ data1 = read_reg(0x68); ++ printk("REG0x68 = %d\n", data1); ++ data1 = read_reg(0x75); ++ printk("REG0x75 = 0x%02x\n", data1); ++ data1 = read_reg(0x76); ++ printk("REG0x76 = 0x%02x\n", data1); ++ mdelay(2000); ++ } ++#endif ++ data1 = read_reg(0x68); ++ printk("REG0x68 = %d\n", data1); ++ ++ /* to activate all the new settings, give a WARM RESET.*/ ++ write_reg(ADDR_WARM_RESET, 0x00); //ADDR_WARM_RESET=0xFF ++ ++ //printk("REG0x68 = %d\n", data1); ++ ++ /* wait for 1 ~ 10 ms.*/ ++ mdelay(10); ++ data1 = read_reg(0x68); ++ ++ /* Enable INT that connected to ATA2508's TINT.*/ ++ __gpio_as_irq_rise_edge(MP4_KEY_TINT); ++ ++ retval = request_irq(MP4_TINT_IRQ, mp4_tint_irq, ++ IRQF_DISABLED, "mp4_key_tint", NULL); ++ if (retval) { ++ printk("Could not get mp4 key irq %d\n", MP4_TINT_IRQ); ++ return retval; ++ } ++ ++ printk("MP4 touch panel register!\n"); ++ ++ return 0; ++} ++ ++static void __exit exit_ata2508(void) ++{ ++ free_irq(MP4_TINT_IRQ, NULL); ++} ++ ++module_init(init_ata2508); ++module_exit(exit_ata2508); +diff --git a/drivers/char/jzchar/cim.c b/drivers/char/jzchar/cim.c +new file mode 100644 +index 0000000..c320d67 +--- /dev/null ++++ b/drivers/char/jzchar/cim.c +@@ -0,0 +1,366 @@ ++/* ++ * linux/drivers/char/jzchar/cim.c ++ * ++ * Camera Interface Module (CIM) driver for JzSOC ++ * This driver is independent of the camera sensor ++ * ++ * Copyright (C) 2005 JunZheng semiconductor ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "jzchars.h" ++ ++#define CIM_NAME "cim" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("JzSOC Camera Interface Module driver"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Define the Max Image Size ++ */ ++#define MAX_IMAGE_WIDTH 640 ++#define MAX_IMAGE_HEIGHT 480 ++#define MAX_IMAGE_BPP 16 ++#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8) ++ ++typedef struct ++{ ++ u32 width; ++ u32 height; ++ u32 bpp; ++} img_param_t; ++ ++typedef struct ++{ ++ u32 cfg; ++ u32 ctrl; ++ u32 mclk; ++} cim_config_t; ++ ++/* ++ * IOCTL_XXX commands ++ */ ++#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t * ++#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t * ++ ++/* Actual image size, must less than max values */ ++static int img_width = MAX_IMAGE_WIDTH, img_height = MAX_IMAGE_HEIGHT, img_bpp = MAX_IMAGE_BPP; ++ ++/* ++ * CIM DMA descriptor ++ */ ++struct cim_desc { ++ u32 nextdesc; /* Physical address of next desc */ ++ u32 framebuf; /* Physical address of frame buffer */ ++ u32 frameid; /* Frame ID */ ++ u32 dmacmd; /* DMA command */ ++}; ++ ++/* ++ * CIM device structure ++ */ ++struct cim_device { ++ unsigned char *framebuf; ++ unsigned int frame_size; ++ unsigned int page_order; ++ wait_queue_head_t wait_queue; ++ struct cim_desc frame_desc __attribute__ ((aligned (16))); ++}; ++ ++// global ++static struct cim_device *cim_dev; ++ ++/*========================================================================== ++ * CIM init routines ++ *========================================================================*/ ++ ++static void cim_config(cim_config_t *c) ++{ ++ REG_CIM_CFG = c->cfg; ++ REG_CIM_CTRL = c->ctrl; ++ // Set the master clock output ++#if defined(CONFIG_SOC_JZ4730) ++ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); ++#elif defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#else ++ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); ++#endif ++ // Enable sof, eof and stop interrupts ++ __cim_enable_sof_intr(); ++ __cim_enable_eof_intr(); ++ __cim_enable_stop_intr(); ++} ++ ++/*========================================================================== ++ * CIM start/stop operations ++ *========================================================================*/ ++ ++static int cim_start_dma(char *ubuf) ++{ ++ __cim_disable(); ++ ++ dma_cache_wback((unsigned long)cim_dev->framebuf, (2 ^ (cim_dev->page_order)) * 4096); ++ ++ // set the desc addr ++ __cim_set_da(virt_to_phys(&(cim_dev->frame_desc))); ++ ++ __cim_clear_state(); // clear state register ++ __cim_reset_rxfifo(); // resetting rxfifo ++ __cim_unreset_rxfifo(); ++ __cim_enable_dma(); // enable dma ++ ++ // start ++ __cim_enable(); ++ ++ // wait for interrupts ++ interruptible_sleep_on(&cim_dev->wait_queue); ++ ++ // copy frame data to user buffer ++ memcpy(ubuf, cim_dev->framebuf, cim_dev->frame_size); ++ ++ return cim_dev->frame_size; ++} ++ ++static void cim_stop(void) ++{ ++ __cim_disable(); ++ __cim_clear_state(); ++} ++ ++/*========================================================================== ++ * Framebuffer allocation and destroy ++ *========================================================================*/ ++ ++static void cim_fb_destroy(void) ++{ ++ if (cim_dev->framebuf) { ++ free_pages((unsigned long)(cim_dev->framebuf), cim_dev->page_order); ++ cim_dev->framebuf = NULL; ++ } ++} ++ ++static int cim_fb_alloc(void) ++{ ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++ cim_dev->page_order = get_order(cim_dev->frame_size); ++ ++ /* frame buffer */ ++ cim_dev->framebuf = (unsigned char *)__get_free_pages(GFP_KERNEL, cim_dev->page_order); ++ if ( !(cim_dev->framebuf) ) { ++ return -ENOMEM; ++ } ++ ++ cim_dev->frame_desc.nextdesc = virt_to_phys(&(cim_dev->frame_desc)); ++ cim_dev->frame_desc.framebuf = virt_to_phys(cim_dev->framebuf); ++ cim_dev->frame_desc.frameid = 0x52052018; ++ cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame ++ ++ dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16); ++ ++ return 0; ++} ++ ++/*========================================================================== ++ * File operations ++ *========================================================================*/ ++ ++static int cim_open(struct inode *inode, struct file *filp); ++static int cim_release(struct inode *inode, struct file *filp); ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++ ++static struct file_operations cim_fops = ++{ ++ open: cim_open, ++ release: cim_release, ++ read: cim_read, ++ write: cim_write, ++ ioctl: cim_ioctl ++}; ++ ++static int cim_open(struct inode *inode, struct file *filp) ++{ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int cim_release(struct inode *inode, struct file *filp) ++{ ++ cim_stop(); ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ if (size < cim_dev->frame_size) ++ return -EINVAL; ++ ++ return cim_start_dma(buf); ++} ++ ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("cim error: write is not implemented\n"); ++ return -1; ++} ++ ++static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case IOCTL_SET_IMG_PARAM: ++ { ++ img_param_t i; ++ ++ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) ++ return -EFAULT; ++ ++ img_width = i.width; ++ img_height = i.height; ++ img_bpp = i.bpp; ++ ++ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE) { ++ /* realloc the buffer */ ++ cim_fb_destroy(); ++ if (cim_fb_alloc() < 0) ++ return -ENOMEM; ++ } ++ ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++ ++ cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame ++ ++ dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16); ++ ++ break; ++ } ++ case IOCTL_CIM_CONFIG: ++ { ++ cim_config_t c; ++ ++ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t))) ++ return -EFAULT; ++ ++ cim_config(&c); ++ ++ break; ++ } ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return 0; ++} ++ ++/*========================================================================== ++ * Interrupt handler ++ *========================================================================*/ ++ ++static irqreturn_t cim_irq_handler(int irq, void *dev_id) ++{ ++ u32 state = REG_CIM_STATE; ++#if 0 ++ if (state & CIM_STATE_DMA_EOF) { ++ wake_up_interruptible(&cim_dev->wait_queue); ++ } ++#endif ++ if (state & CIM_STATE_DMA_STOP) { ++ // Got a frame, wake up wait routine ++ wake_up_interruptible(&cim_dev->wait_queue); ++ } ++ ++ // clear status flags ++ REG_CIM_STATE = 0; ++ return IRQ_HANDLED; ++} ++ ++/*========================================================================== ++ * Module init and exit ++ *========================================================================*/ ++ ++static int __init cim_init(void) ++{ ++ struct cim_device *dev; ++ int ret; ++ ++ /* allocate device */ ++ dev = kmalloc(sizeof(struct cim_device), GFP_KERNEL); ++ if (!dev) return -ENOMEM; ++ ++ /* record device */ ++ cim_dev = dev; ++ ++ /* allocate a frame buffer */ ++ if (cim_fb_alloc() < 0) { ++ kfree(dev); ++ return -ENOMEM; ++ } ++ ++ init_waitqueue_head(&dev->wait_queue); ++ ++ ret = jz_register_chrdev(CIM_MINOR, CIM_NAME, &cim_fops, dev); ++ if (ret < 0) { ++ cim_fb_destroy(); ++ kfree(dev); ++ return ret; ++ } ++ ++ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, ++ CIM_NAME, dev))) { ++ cim_fb_destroy(); ++ kfree(dev); ++ printk(KERN_ERR "CIM could not get IRQ"); ++ return ret; ++ } ++ ++ printk("JzSOC Camera Interface Module (CIM) driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit cim_exit(void) ++{ ++ free_irq(IRQ_CIM, cim_dev); ++ jz_unregister_chrdev(CIM_MINOR, CIM_NAME); ++ cim_fb_destroy(); ++ kfree(cim_dev); ++} ++ ++module_init(cim_init); ++module_exit(cim_exit); +diff --git a/drivers/char/jzchar/cim.h b/drivers/char/jzchar/cim.h +new file mode 100644 +index 0000000..c21431b +--- /dev/null ++++ b/drivers/char/jzchar/cim.h +@@ -0,0 +1,36 @@ ++/* ++ * JzSOC CIM driver ++ * ++ * Copyright (C) 2005 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef __CIM_H__ ++#define __CIM_H__ ++ ++typedef struct ++{ ++ u32 width; ++ u32 height; ++ u32 bpp; ++} IMG_PARAM; ++ ++/* ++ * IOCTL_XXX commands ++ */ ++#define IOCTL_SET_IMG_PARAM 0 // arg type: IMG_PARAM * ++ ++#endif /* __CIM_H__ */ +diff --git a/drivers/char/jzchar/jz_ow.c b/drivers/char/jzchar/jz_ow.c +new file mode 100644 +index 0000000..86b3c00 +--- /dev/null ++++ b/drivers/char/jzchar/jz_ow.c +@@ -0,0 +1,497 @@ ++/* ++ * linux/drivers/char/jzchar/jz_ow.c ++ * ++ * One Wire Bus test driver ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "jzchars.h" ++ ++#define OW_CPU_READ_ROM 1 ++#define OW_INTC_READ_ROM 1 ++#define OW_CPU_SEARCH_ROM 0 ++#define OW_INTC_SEARCH_ROM 0 ++ ++#define OW_DEBUG 0 ++#if OW_DEBUG ++#define OWI_MAX 10 ++static char CFG[OWI_MAX]; ++static char CTL[OWI_MAX]; ++static char STS[OWI_MAX]; ++static char DAT[OWI_MAX]; ++static char DIV[OWI_MAX]; ++static void owi_register_dump(int i) ++{ ++ CFG[i]= REG_OWI_CFG; ++ CTL[i]= REG_OWI_CTL; ++ STS[i]= REG_OWI_STS; ++ DAT[i]= REG_OWI_DAT; ++ DIV[i]= REG_OWI_DIV; ++} ++static void owi_register_print(int i) ++{ ++ printk(" REG_OWI_CFG: 0x%08x\n", CFG[i]); ++ printk(" REG_OWI_CTL: 0x%08x\n", CTL[i]); ++ printk(" REG_OWI_STS: 0x%08x\n", STS[i]); ++ printk(" REG_OWI_DAT: 0x%08x\n", DAT[i]); ++ printk(" REG_OWI_DIV: 0x%08x\n", DIV[i]); ++} ++#endif ++ ++static DECLARE_WAIT_QUEUE_HEAD (ow_wait_queue); ++ ++/* ++ * fops routines ++ */ ++static int ow_open(struct inode *inode, struct file *filp); ++static int ow_release(struct inode *inode, struct file *filp); ++static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t ow_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int ow_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ++ ++static void do_ow_rddata(void); ++static void do_ow_wrdata(void); ++static void do_ow_wr1rd(void); ++static void do_ow_wr0(void); ++static void do_ow_rst(void); ++ ++static void do_interrupt_mode_test(void); ++static void do_cpu_mode_test(void); ++ ++static struct file_operations ow_fops = ++{ ++ open: ow_open, ++ release: ow_release, ++ read: ow_read, ++ write: ow_write, ++ ioctl: ow_ioctl, ++}; ++ ++static int ow_open(struct inode *inode, struct file *filp) ++{ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int ow_release(struct inode *inode, struct file *filp) ++{ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ printk("OW: read is not implemented\n"); ++ return -1; ++} ++ ++static ssize_t ow_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("ow: write is not implemented\n"); ++ return -1; ++} ++ ++static int ow_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ switch (cmd) { ++ ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static void do_ow_rddata(void) ++{ ++ __owi_clr_sts(); ++ __owi_set_rddata(); ++ __owi_enable_ow_ops(); ++} ++ ++static void do_ow_wrdata(void) ++{ ++ __owi_clr_sts(); ++ __owi_set_wrdata(); ++ __owi_enable_ow_ops(); ++} ++ ++static void do_ow_wr1rd(void) ++{ ++ __owi_clr_sts(); ++ __owi_set_wr1rd(); ++ __owi_enable_ow_ops(); ++} ++ ++static void do_ow_wr0(void) ++{ ++ __owi_clr_sts(); ++ __owi_set_wr0(); ++ __owi_enable_ow_ops(); ++} ++ ++static void do_ow_rst(void) ++{ ++ __owi_clr_sts(); ++ __owi_set_rst(); ++ __owi_enable_ow_ops(); ++} ++ ++static irqreturn_t ow_interrupt(int irq, void *dev_id) ++{ ++ __owi_clr_sts(); ++ wake_up(&ow_wait_queue); ++ ++ return IRQ_HANDLED; ++} ++ ++static void ow_intcm_read_rom(char *rom) ++{ ++ int i; ++ ++ __owi_select_regular_mode(); ++ REG_OWI_DIV = 23; ++ __owi_clr_sts(); ++ __intc_unmask_irq(IRQ_OWI); ++ __owi_enable_all_interrupts(); ++ ++ do_ow_rst(); ++ sleep_on(&ow_wait_queue); ++ ++ REG_OWI_DAT = 0x33; ++ do_ow_wrdata(); ++ sleep_on(&ow_wait_queue); ++ ++ for(i=0; i<8; i++){ ++ do_ow_rddata(); ++ sleep_on(&ow_wait_queue); ++ rom[i] = REG_OWI_DAT; ++ } ++ __intc_mask_irq(IRQ_OWI); ++} ++ ++static void ow_intcm_search_rom(void) ++{ ++ int i, j; ++ int normal, reverse; ++#if 1 ++ unsigned char rom[8]={0x01, 0xf9, 0x35, 0x53, 0x11, 0x00, 0x00, 0x3e}; ++#else ++ unsigned char rom[8]={0x01, 0xd8, 0x10, 0x02, 0x10, 0x00, 0x00, 0x22}; ++#endif ++ __owi_select_regular_mode(); ++ REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1; ++ __owi_clr_sts(); ++ __intc_unmask_irq(IRQ_OWI); ++ __owi_enable_all_interrupts(); ++ ++ /* reset */ ++ do_ow_rst(); ++ sleep_on(&ow_wait_queue); ++ ++ /* send search ROM command */ ++ REG_OWI_DAT = 0xf0; ++ do_ow_wrdata(); ++ sleep_on(&ow_wait_queue); ++ ++ for( i=0; i<8; i++){ ++ for (j=0; j<8; j++){ ++ do_ow_wr1rd(); ++ sleep_on(&ow_wait_queue); ++ normal = ( __owi_get_rdst() !=0); ++ printk("normal: %d\n",normal); ++ ++ do_ow_wr1rd(); ++ sleep_on(&ow_wait_queue); ++ reverse = ( __owi_get_rdst() !=0); ++ printk("reverse: %d\n",reverse); ++ ++ if(normal ==1 && reverse ==1){ ++ printk("Search rom INTC mode: 11 NO device found\n"); ++ __intc_mask_irq(IRQ_OWI); ++ return; ++ } ++#if 1 ++ if ( (rom[i]>>j) & 1 ){ ++ printk("write 1\n"); ++ do_ow_wr1rd(); ++ sleep_on(&ow_wait_queue); ++ } ++ else{ ++ printk("write 0\n"); ++ do_ow_wr0(); ++ sleep_on(&ow_wait_queue); ++ } ++ ++#else ++ if(normal ==0 && reverse ==0){ ++ if (!((rom[i]>>j) & 1) ){ ++ printk("write 1\n"); ++ do_ow_wr1rd(); ++ sleep_on(&ow_wait_queue); ++ } ++ else{ ++ printk("write 0\n"); ++ do_ow_wr0(); ++ sleep_on(&ow_wait_queue); ++ } ++ }else{ ++ ++ if(normal ==0){ ++ printk("write 0\n"); ++ do_ow_wr0(); ++ sleep_on(&ow_wait_queue); ++ } ++ if(normal ==1){ ++ printk("write 1\n"); ++ do_ow_wr1rd(); ++ sleep_on(&ow_wait_queue); ++ } ++ } ++#endif ++ ++ } ++ printk("\n\n"); ++ } ++ ++ printk("\nSearch rom INTC mode: device found SUCCESSFULLY\n"); ++ __intc_mask_irq(IRQ_OWI); ++ ++} ++ ++static void ow_cpum_read_rom(char *rom) ++{ ++ int i; ++ ++ __owi_select_regular_mode(); ++ REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1; ++ __owi_clr_sts(); ++ __owi_disable_all_interrupts(); ++ ++ do_ow_rst(); ++ __owi_wait_ops_rdy(); ++ ++ if(!__owi_get_sts_pst()) ++ printk("read rom no device found\n"); ++ ++ REG_OWI_DAT = 0x33; ++ do_ow_wrdata(); ++ __owi_wait_ops_rdy(); ++ ++ for(i=0; i<8; i++){ ++ do_ow_rddata(); ++ __owi_wait_ops_rdy(); ++ rom[i] = REG_OWI_DAT; ++ } ++} ++ ++ ++static void ow_comm_bit(unsigned comm) ++{ ++ int i; ++ for(i=0; i<8; i++){ ++ if ( comm & (1<>j) & 1 ){ ++ printk("write 1\n"); ++ do_ow_wr1rd(); ++ while(!__owi_get_sts_bit_rdy()) ; ++ } ++ else{ ++ printk("write 0\n"); ++ do_ow_wr0(); ++ while(!__owi_get_sts_bit_rdy()) ; ++ } ++ ++#else ++ if(normal ==0 && reverse ==0){ ++ if (!((rom[i]>>j) & 1) ){ ++ printk("write 1\n"); ++ do_ow_wr1rd(); ++ while(!__owi_get_sts_bit_rdy()) ; ++ } ++ else{ ++ printk("write 0\n"); ++ do_ow_wr0(); ++ while(!__owi_get_sts_bit_rdy()) ; ++ } ++ }else{ ++ ++ if(normal ==0){ ++ printk("write 0\n"); ++ do_ow_wr0(); ++ while(!__owi_get_sts_bit_rdy()) ; ++ } ++ if(normal ==1){ ++ printk("write 1\n"); ++ do_ow_wr1rd(); ++ while(!__owi_get_sts_bit_rdy()) ; ++ } ++ } ++#endif ++ ++ } ++ printk("\n\n"); ++ } ++ printk("\nSearch rom CPU mode: device found SUCCESSFULLY\n"); ++} ++ ++static void do_interrupt_mode_test(void) ++{ ++ int ret, i; ++ unsigned char rom[8]; ++ ++ /* interrupt mode */ ++ ret = request_irq(IRQ_OWI, ow_interrupt, IRQF_DISABLED, ++ "JZ_OWI", NULL); ++ if(ret) ++ printk("failed irq \n"); ++ ++#if OW_INTC_READ_ROM ++ ow_intcm_read_rom(rom); ++ printk("\n\nAfter intc mode read ROM ops: \n"); ++ printk("ROM: "); ++ for(i=0; i<8; i++) ++ printk("0x%02x,",rom[i]); ++#endif ++ ++#if OW_INTC_SEARCH_ROM ++ ow_intcm_search_rom(); ++#endif ++ ++} ++ ++static void do_cpu_mode_test(void) ++{ ++ ++#if OW_CPU_READ_ROM ++ int i; ++ unsigned char rom[8]; ++ ++ ow_cpum_read_rom(rom); ++ printk("\n\nAfter CPU mode read ROM ops: \n"); ++ printk("ROM: "); ++ for(i=0; i<8; i++) ++ printk("0x%02x,",rom[i]); ++#endif ++ ++#if OW_CPU_SEARCH_ROM ++ ow_cpum_search_rom(); ++#endif ++} ++ ++/* ++ * Module init and exit ++ */ ++static int __init ow_init(void) ++{ ++ int ret; ++ ++ ret = jz_register_chrdev(OW_MINOR, "ow", &ow_fops, NULL); ++ if (ret < 0) { ++ return ret; ++ } ++ __gpio_as_func1(153); ++ ++ REG_OWI_CFG=0; ++ REG_OWI_CTL=0; ++ REG_OWI_STS=0; ++ REG_OWI_DAT=0; ++ REG_OWI_DIV=0; ++ ++ do_interrupt_mode_test(); ++ do_cpu_mode_test(); ++ ++ printk("Ingenic OW driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit ow_exit(void) ++{ ++ free_irq(IRQ_OWI, NULL); ++ jz_unregister_chrdev(OW_MINOR, "ow"); ++} ++ ++module_init(ow_init); ++module_exit(ow_exit); ++ ++MODULE_AUTHOR("Yurong Tan"); ++MODULE_DESCRIPTION("One Wire Bus test Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/char/jzchar/jz_ts.c b/drivers/char/jzchar/jz_ts.c +new file mode 100644 +index 0000000..16b46a2 +--- /dev/null ++++ b/drivers/char/jzchar/jz_ts.c +@@ -0,0 +1,443 @@ ++/* ++ * jz_ts.c ++ * ++ * Touch screen driver for the Ingenic JZ47XX. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz_ts.h" ++ ++MODULE_AUTHOR("Peter Wei "); ++MODULE_DESCRIPTION("Ingenic Touch Screen Driver"); ++MODULE_LICENSE("GPL"); ++ ++#define TS_NAME "jz-ts" ++#define TS_MINOR 16 /* MAJOR: 10, MINOR: 16 */ ++#define PFX TS_NAME ++ ++//#define JZ_TS_DEBUG ++ ++#ifdef JZ_TS_DEBUG ++#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) ++#else ++#define dbg(format, arg...) do {} while (0) ++#endif ++#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) ++#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) ++#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) ++ ++static struct jz_ts_t jz_ts; ++ ++unsigned int (*codec_read_battery)(void) = NULL; ++ ++// hold the spinlock before calling. ++static void event_add(struct jz_ts_t *ts, struct ts_event *event) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ts->lock, flags); ++ ++ // add this event to the event queue ++ ts->event_buf[ts->nextIn] = *event; ++ ts->nextIn = (ts->nextIn + 1) & (EVENT_BUFSIZE - 1); ++ if (ts->event_count < EVENT_BUFSIZE) { ++ ts->event_count++; ++ } else { ++ // throw out the oldest event ++ ts->nextOut = (ts->nextOut + 1) & (EVENT_BUFSIZE - 1); ++ } ++ ++ spin_unlock_irqrestore(&ts->lock, flags); ++ ++ // async notify ++ if (ts->fasync) ++ kill_fasync(&ts->fasync, SIGIO, POLL_IN); ++ // wake up any read call ++ if (waitqueue_active(&ts->wait)) ++ wake_up_interruptible(&ts->wait); ++} ++ ++static int event_pull(struct jz_ts_t *ts, struct ts_event *event) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&ts->lock, flags); ++ ret = ts->event_count; ++ if (ts->event_count) { ++ *event = ts->event_buf[ts->nextOut]; ++ ts->nextOut = (ts->nextOut + 1) & (EVENT_BUFSIZE - 1); ++ ts->event_count--; ++ } ++ spin_unlock_irqrestore(&ts->lock, flags); ++ ++ return ret; ++} ++ ++static int pen_is_down = 0; ++ ++static irqreturn_t pendown_interrupt(int irq, void * dev_id) ++{ ++ struct jz_ts_t* ts = &jz_ts; ++ struct ts_event event; ++ ++ dbg("pen down"); ++#if defined(CONFIG_SOC_JZ4740) ++ if (ts->sleeping) { ++ ts->sleeping = 0; ++ ts_data_ready(); ++ return IRQ_HANDLED; ++ } ++#endif ++ spin_lock(&ts->lock); ++ ++ if (ts->irq_enabled) { ++ ts->irq_enabled = 0; ++ } ++ else ++ ts->irq_enabled = 1; ++ ++ ++ if (pen_is_down) ++ pen_is_down = 0; ++ else ++ pen_is_down = 1; ++ ++ // callback routine to clear irq status ++ ts_irq_callback(); ++ ++ if ( (pen_is_down == 0)){ ++ del_timer(&ts->acq_timer); ++ spin_unlock(&ts->lock); ++ event.x = event.y = event.pressure = 0; ++ event.status = PENUP; ++ ts->first_read = 0; ++ event_add(ts, &event); ++ return IRQ_HANDLED; ++ } ++ ++ if ( (pen_is_down == 1)) ++ { ++ ts->acq_timer.expires = jiffies + HZ / 100; ++ del_timer(&ts->acq_timer); ++ ts->first_read = 1; ++ add_timer(&ts->acq_timer); ++ spin_unlock(&ts->lock); ++ } ++ return IRQ_HANDLED; ++} ++ ++ ++/* ++ * Raw X,Y,pressure acquisition timer function. It gets scheduled ++ * only while pen is down. Its duration between calls is the polling ++ * rate. ++ */ ++static void ++jz_acq_timer(unsigned long data) ++{ ++ struct jz_ts_t *ts = (struct jz_ts_t *)data; ++ struct ts_event event; ++ int pen_was_down = ts->pen_is_down; ++ ++ spin_lock(&ts->lock); ++ ++ if (PenIsDown()) { ++ ++ ts->pen_is_down = 1; ++ ++ if (AcquireEvent(ts, &event)) // check event is valid or not? ++ event_add(ts, &event); ++ ++ // schedule next acquire ++ ts->acq_timer.expires = jiffies + HZ / 100; ++ del_timer(&ts->acq_timer); ++ add_timer(&ts->acq_timer); ++ } else { ++ ++ if (!ts->irq_enabled) { ++ ts->irq_enabled = 1; ++ } ++ ts->pen_is_down = 0; ++ if (pen_was_down) { ++ event.x = event.y = event.pressure = 0; ++ event.status = PENUP; ++ event_add(ts, &event); ++ } ++ } ++ ++ spin_unlock(&ts->lock); ++} ++ ++/* +++++++++++++ Read battery voltage routine ++++++++++++++*/ ++ ++unsigned int jz_read_battery(void) ++{ ++ unsigned int v = 0; ++ struct jz_ts_t *ts = &jz_ts; ++ ++ spin_lock(&ts->lock); ++ ++ if (codec_read_battery) ++ v = codec_read_battery(); ++ ++ spin_unlock(&ts->lock); ++ ++ return v; ++} ++ ++/* +++++++++++++ File operations ++++++++++++++*/ ++ ++static int ++jz_fasync(int fd, struct file *filp, int mode) ++{ ++ struct jz_ts_t *ts = (struct jz_ts_t *)filp->private_data; ++ return fasync_helper(fd, filp, mode, &ts->fasync); ++} ++ ++ ++static unsigned int ++jz_poll(struct file * filp, poll_table * wait) ++{ ++ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data; ++ poll_wait(filp, &ts->wait, wait); ++ if (ts->event_count) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++static ssize_t ++jz_read(struct file * filp, char * buffer, size_t count, loff_t * ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data; ++ char *ptr = buffer; ++ struct ts_event event; ++ int err = 0; ++ ++ dbg("jz_read"); ++ ++ add_wait_queue(&ts->wait, &wait); ++ while (count >= sizeof(struct ts_event)) { ++ err = -ERESTARTSYS; ++ if (signal_pending(current)) ++ break; ++ ++ ++ if (event_pull(ts, &event)) { ++ err = copy_to_user(ptr, &event, ++ sizeof(struct ts_event)); ++ if (err) ++ break; ++ ptr += sizeof(struct ts_event); ++ count -= sizeof(struct ts_event); ++ } else { ++ set_current_state(TASK_INTERRUPTIBLE); ++ err = -EAGAIN; ++ if (filp->f_flags & O_NONBLOCK) ++ break; ++ schedule(); ++ } ++ } ++ ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&ts->wait, &wait); ++ ++ return ptr == buffer ? err : ptr - buffer; ++} ++ ++ ++static int ++jz_open(struct inode * inode, struct file * filp) ++{ ++ struct jz_ts_t *ts; ++ int retval; ++ ++ dbg("open ts device"); ++ filp->private_data = ts = &jz_ts; ++ ++ spin_lock(&ts->lock); ++ ++ ts->pen_is_down = 0; // start with pen up ++ ts->sleeping = 0; ++ // flush event queue ++ ts->nextIn = ts->nextOut = ts->event_count = 0; ++ ++ // Init acquisition timer function ++ init_timer(&ts->acq_timer); ++ ts->acq_timer.function = jz_acq_timer; ++ ts->acq_timer.data = (unsigned long)ts; ++ ++ ts->irq_enabled = 1; ++ ++ spin_unlock(&ts->lock); ++ ++ /* Since ts interrupt can happen immediately after request_irq, ++ * we wait until we've completed init of all relevent driver ++ * state variables. Now we grab the PenDown IRQ ++ */ ++ retval = ts_request_irq(&ts->pendown_irq, pendown_interrupt, TS_NAME, ts); ++ if (retval) { ++ err("unable to get PenDown IRQ %d", ts->pendown_irq); ++ return retval; ++ } ++ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int ++jz_release(struct inode * inode, struct file * filp) ++{ ++ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data; ++ ++ ts_free_irq(ts); ++ jz_fasync(-1, filp, 0); ++ del_timer_sync(&ts->acq_timer); ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static int jz_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) ++{ ++ struct txy { ++ int minx; ++ int miny; ++ int maxx; ++ int maxy; ++ }; ++ ++ struct txy ch; ++ ++ /* ++ * Switch according to the ioctl called ++ */ ++ switch (ioctl_num) ++ { ++ case IOCTL_SET_MSG: ++ jz_ts.filter=1; ++ break; ++ case IOCTL_SET_NUM: ++ if (copy_from_user((void *)&ch, (void *)ioctl_param, sizeof(ch))) ++ return -EFAULT; ++ jz_ts.minx = ch.minx; ++ jz_ts.miny = ch.miny; ++ jz_ts.maxx = ch.maxx; ++ jz_ts.maxy = ch.maxy; ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct file_operations ts_fops = { ++ owner: THIS_MODULE, ++ read: jz_read, ++ poll: jz_poll, ++ fasync: jz_fasync, ++ ioctl: jz_ioctl, ++ open: jz_open, ++ release: jz_release, ++}; ++ ++/* +++++++++++++ End File operations ++++++++++++++*/ ++ ++static int __init minx_setup(char *str) ++{ ++ int i; ++ ++ if (get_option(&str,&i)) jz_ts.minx = i; ++ jz_ts.filter=i; ++ return 1; ++} ++ ++__setup("ts_minx=", minx_setup); ++ ++static int __init miny_setup(char *str) ++{ ++ int i; ++ if (get_option(&str,&i)) jz_ts.miny = i; ++ return 1; ++} ++ ++__setup("ts_miny=", miny_setup); ++ ++static int __init maxx_setup(char *str) ++{ ++ int i; ++ if (get_option(&str,&i)) jz_ts.maxx = i; ++ return 1; ++} ++ ++__setup("ts_maxx=", maxx_setup); ++ ++static int __init maxy_setup(char *str) ++{ ++ int i; ++ if (get_option(&str,&i)) jz_ts.maxy = i; ++ return 1; ++} ++ ++__setup("ts_maxy=", maxy_setup); ++ ++static int __init printraw_setup(char *str) ++{ ++ if (str) ++ jz_ts.prints = 1; ++ ++ return 0; ++} ++ ++__setup("ts_debug", printraw_setup); ++ ++ ++static struct miscdevice jz_ts_dev = { ++ minor: TS_MINOR, ++ name: TS_NAME, ++ fops: &ts_fops, ++}; ++ ++static int __init jzts_init_module(void) ++{ ++ struct jz_ts_t *ts = &jz_ts; ++ int ret; ++ ++ if ((ret = misc_register(&jz_ts_dev)) < 0) { ++ err("can't register misc device"); ++ return ret; ++ } ++ ++// memset(ts, 0, sizeof(struct jz_ts_t)); ++ init_waitqueue_head(&ts->wait); ++ spin_lock_init(&ts->lock); ++ ++ printk("Jz generic touch screen driver registered\n"); ++ ++ return 0; ++} ++ ++static void jzts_cleanup_module(void) ++{ ++ misc_deregister(&jz_ts_dev); ++} ++ ++module_init(jzts_init_module); ++module_exit(jzts_cleanup_module); +diff --git a/drivers/char/jzchar/jz_ts.h b/drivers/char/jzchar/jz_ts.h +new file mode 100644 +index 0000000..4285797 +--- /dev/null ++++ b/drivers/char/jzchar/jz_ts.h +@@ -0,0 +1,54 @@ ++#ifndef __JZ_TS_H__ ++#define __JZ_TS_H__ ++ ++/* ++ * IOCTL commands ++ */ ++#define IOCTL_SET_MSG 0 ++#define IOCTL_SET_NUM 1 ++ ++ ++/* ++ * TS Event type ++ */ ++struct ts_event { ++ u16 status; ++ u16 x; ++ u16 y; ++ u16 pressure; ++ u16 pad; ++}; ++ ++/* TS event status */ ++#define PENUP 0x00 ++#define PENDOWN 0x01 ++ ++#define EVENT_BUFSIZE 64 // must be power of two ++ ++struct jz_ts_t { ++ int pendown_irq; // IRQ of pendown interrupt ++ int pen_is_down; // 1 = pen is down, 0 = pen is up ++ int irq_enabled; ++ struct ts_event event_buf[EVENT_BUFSIZE];// The event queue ++ int nextIn, nextOut; ++ int event_count; ++ struct fasync_struct *fasync; // asynch notification ++ struct timer_list acq_timer; // Timer for triggering acquisitions ++ wait_queue_head_t wait; // read wait queue ++ spinlock_t lock; ++ int minx, miny, maxx, maxy; ++ int filter, prints; ++ int sleeping; ++ int first_read; ++}; ++ ++extern void ts_enable_irq(void); ++extern void ts_disable_irq(void); ++extern int ts_request_irq(u32 *irq,irqreturn_t (*handler)(int, void *), const char *devname, void *dev_id); ++extern void ts_free_irq(struct jz_ts_t *ts); ++extern int PenIsDown(void); ++extern int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event); ++extern void ts_irq_callback(void); ++extern void ts_data_ready(void); ++ ++#endif /* __JZ_TS_H__ */ +diff --git a/drivers/char/jzchar/jz_tssi.c b/drivers/char/jzchar/jz_tssi.c +new file mode 100644 +index 0000000..fe4978a +--- /dev/null ++++ b/drivers/char/jzchar/jz_tssi.c +@@ -0,0 +1,457 @@ ++/* ++ * jz_tssi.c ++ * ++ * MPEG2-TS interface driver for the Ingenic JZ47XX. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "jzchars.h" ++ ++#include "jz_tssi.h" ++ ++ ++MODULE_AUTHOR("Lucifer Liu "); ++MODULE_DESCRIPTION("Ingenic MPEG2-TS interface Driver"); ++MODULE_LICENSE("GPL"); ++ ++#define TSSI_NAME "JZ MPEG2-TS SI" ++#define TSSI_MINOR 204 /* MAJOR: 10, MINOR: 16 */ ++#define TSSI_IRQ IRQ_TSSI ++#define PFX TSSI_NAME ++#define RING_BUF_NUM 100 ++ ++#define USE_DMA ++#define TRIG_PIN ( 32 * 2 + 15 ) ++#define DMA_ID_TSSI 5 ++//#define JZ_TSSI_DEBUG ++ ++#ifdef JZ_TSSISI_DEBUG ++#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) ++#else ++#define dbg(format, arg...) do {} while (0) ++#endif ++#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) ++#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) ++#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) ++ ++static struct jz_tssi_t jz_tssi_g; ++static struct jz_tssi_buf_ring_t jz_tssi_ring_g; ++static int tssi_dma_reinit(int dma_chan, unsigned char *dma_buf, int size); ++ ++static void print_reg( void ) ++{ ++ printk("REG_TSSI_ENA %8x \n ", REG8( TSSI_ENA )); ++ printk("REG_TSSI_CFG %8x \n ", REG16( TSSI_CFG )); ++ printk("REG_TSSI_CTRL %8x \n ", REG8( TSSI_CTRL )); ++ printk("REG_TSSI_STAT %8x \n ", REG8( TSSI_STAT )); ++ printk("REG_TSSI_FIFO %8x \n ", REG32( TSSI_FIFO )); ++ printk("REG_TSSI_PEN %8x \n ", REG32( TSSI_PEN )); ++ printk("REG_TSSI_PID0 %8x \n ", REG32( TSSI_PID0 )); ++ printk("REG_TSSI_PID1 %8x \n ", REG32( TSSI_PID1 )); ++ printk("REG_TSSI_PID2 %8x \n ", REG32( TSSI_PID2 )); ++ printk("REG_TSSI_PID3 %8x \n ", REG32( TSSI_PID3 )); ++ printk("REG_TSSI_PID4 %8x \n ", REG32( TSSI_PID4 )); ++ printk("REG_TSSI_PID5 %8x \n ", REG32( TSSI_PID5 )); ++ printk("REG_TSSI_PID6 %8x \n ", REG32( TSSI_PID6 )); ++ printk("REG_TSSI_PID7 %8x \n ", REG32( TSSI_PID7 )); ++} ++ ++void dump_dma_channel(unsigned int dmanr) ++{ ++ printk("DMA%d Registers:\n", dmanr); ++ printk(" DMACR = 0x%8x\n", REG_DMAC_DMACR(0)); ++ printk(" DSAR = 0x%8x\n", REG_DMAC_DSAR(dmanr)); ++ printk(" DTAR = 0x%8x\n", REG_DMAC_DTAR(dmanr)); ++ printk(" DTCR = 0x%8x\n", REG_DMAC_DTCR(dmanr)); ++ printk(" DRSR = 0x%8x\n", REG_DMAC_DRSR(dmanr)); ++ printk(" DCCSR = 0x%8x\n", REG_DMAC_DCCSR(dmanr)); ++ printk(" DCMD = 0x%8x\n", REG_DMAC_DCMD(dmanr)); ++ printk(" DDA = 0x%8x\n", REG_DMAC_DDA(dmanr)); ++ printk(" DMADBR = 0x%8x\n", REG_DMAC_DMADBR(1)); ++} ++ ++static int tssi_buf_init( struct jz_tssi_buf_ring_t * ring ) ++{ ++ int i; ++ struct jz_tssi_buf * bp,* ap, *cp; ++ ++ ap = cp = bp = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); //the first ++ if ( !bp ) { ++ printk("Can not malloc buffer! \n"); ++ return -1; ++ } ++ ++ for ( i = 0; i < RING_BUF_NUM; i ++ ) { ++ bp = ap; ++ bp->buf = (unsigned int *) kmalloc(MPEG2_TS_PACHAGE_SIZE / 4 * sizeof(unsigned int) ,GFP_KERNEL); ++ if ( !bp->buf ) { ++ printk("Can not malloc buffer! \n"); ++ return -1; ++ } ++ bp->index = i; ++ bp->pos = 0; ++ ap = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); ++ if ( !ap ) { ++ printk("Can not malloc buffer! \n"); ++ return -1; ++ } ++ ++ bp->next = ap; //point to next ! ++ } ++ ++ bp->next = cp; //point loop to first! ++ ring->front = cp; ++ ring->rear = cp; ++ ring->fu_num = 0; ++ kfree(ap); ++ return 0; ++} ++ ++static void tssi_free_buf( struct jz_tssi_buf_ring_t * ring ) ++{ ++ int i; ++ struct jz_tssi_buf * ap; ++ for ( i = 0; i < RING_BUF_NUM; i ++ ) ++ { ++ ap = ring->front; ++ ring->front = ring->front->next; ++ kfree( ap ); ++ } ++} ++ ++#if 0 ++static void tssi_read_fifo(void *dev_id) ++{ ++ struct jz_tssi_t* tssi = ( struct jz_tssi_t* )dev_id; ++ struct jz_tssi_buf_ring_t * ring = tssi->cur_buf; ++ struct jz_tssi_buf *buf = ring->rear; ++ int i; ++#if 0 ++ if ( ring->fu_num > RING_BUF_NUM ) ++ { ++ printk("Ring buffer full ! %d \n",ring->fu_num); ++ return; ++ } ++#endif ++ ++ for ( i = 0; i < 8 ; i ++ ) ++ { ++ ring->front->buf[ring->front->pos++] = REG_TSSI_FIFO; ++ } ++ ++ if ( ring->front->pos >= MPEG2_TS_PACHAGE_SIZE ) ++ { ++ ring->fu_num ++; ++ ring->front = ring->front->next; ++ ring->front->pos = 0; ++ } ++} ++#endif ++ ++static void tssi_config_filting( void ) ++{ ++ __tssi_soft_reset(); ++ __gpio_as_tssi(); ++ __tssi_disable_ovrn_irq(); //use dma ,no need irq ++ __tssi_disable_trig_irq(); ++ __tssi_set_tigger_num( 8 ); //trig is 4 word! ++// __tssi_filter_enable(); ++ __tssi_clear_state(); ++ __tssi_filter_disable(); ++ __tssi_state_clear_overrun(); ++// __tssi_clear_trig_irq_flag(); ++#ifdef USE_DMA ++ __tssi_dma_enable(); ++#else ++ __tssi_dma_disable(); ++#endif ++ ++ __tssi_enable_ovrn_irq(); ++// __tssi_enable_trig_irq(); ++ ++ //set config ++// __tssi_set_bt_1(); ++ __tssi_set_wd_1(); ++ __tssi_set_data_use_data7(); ++ __tssi_set_data_pola_high(); ++// __tssi_select_serail_mode(); ++ __tssi_select_paral_mode(); ++ __tssi_select_clk_fast(); ++ __tssi_select_clk_posi_edge(); ++ __tssi_select_frm_act_high(); ++ __tssi_select_str_act_high(); ++ __tssi_select_fail_act_high(); ++// __tssi_select_fail_act_low(); ++ __tssi_disable_filte_pid0(); //we disable pid0 filter for ever! ++} ++ ++static void tssi_add_pid(int pid_num, int pid) ++{ ++ unsigned int addr ; ++ int n = pid_num / 2, hl = pid_num % 2; ++ if ( hl ) //use high pid, pid1 ++ { ++ addr = TSSI_PID0 + ( n * 4 ); ++ REG32( addr ) |= ( (pid & 0x1fff) << 16 ); //13bit ++ REG_TSSI_PEN |= ( 1 << (16 + n) ); ++ } ++ else //use low pid, pid0 ++ { ++ addr = TSSI_PID0 + ( n * 4 ); ++ REG32( addr ) |= pid & 0x1fff; //13bit ++ REG_TSSI_PEN |= ( 1 << n ); ++ } ++} ++ ++static irqreturn_t tssi_dma_irq(int irq, void * dev_id) ++{ ++ struct jz_tssi_t *tssi = (struct jz_tssi_t *)dev_id; ++ struct jz_tssi_buf_ring_t *buf = tssi->cur_buf; ++ ++ REG_DMAC_DCCSR(tssi->dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ ++ if (__dmac_channel_transmit_end_detected(tssi->dma_chan)) { ++ __dmac_channel_clear_transmit_end(tssi->dma_chan); ++ if ( buf->fu_num < RING_BUF_NUM ) ++ { ++ buf->front = buf->front->next; ++ REG_DMAC_DSAR(tssi->dma_chan) = CPHYSADDR(TSSI_FIFO); ++ REG_DMAC_DTAR(tssi->dma_chan) = CPHYSADDR((unsigned int)buf->front->buf); ++ REG_DMAC_DTCR(tssi->dma_chan) = MPEG2_TS_PACHAGE_SIZE / 32; ++ REG_DMAC_DCCSR(tssi->dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ buf->fu_num ++; ++ } ++ __tssi_clear_state(); ++ } ++ ++ if (__dmac_channel_transmit_halt_detected(tssi->dma_chan)) { ++ printk("DMA HALT\n"); ++ __dmac_channel_clear_transmit_halt(tssi->dma_chan); ++ } ++ ++ if (__dmac_channel_address_error_detected(tssi->dma_chan)) { ++ printk("DMA ADDR ERROR\n"); ++ __dmac_channel_clear_address_error(tssi->dma_chan); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(tssi->dma_chan)) { ++ printk("DMA DESC INVALID\n"); ++ __dmac_channel_clear_descriptor_invalid(tssi->dma_chan); ++ } ++ ++ if (__dmac_channel_count_terminated_detected(tssi->dma_chan)) { ++ printk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(tssi->dma_chan); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t tssi_interrupt(int irq, void * dev_id) ++{ ++ __intc_mask_irq(TSSI_IRQ); ++#if 1 ++ if ( REG_TSSI_STAT & TSSI_STAT_OVRN ) ++ { ++ printk("tssi over run occur! %x\n",REG8( TSSI_STAT )); ++ __tssi_clear_state(); ++ printk("clear ! %x\n",REG8( TSSI_STAT )); ++ } ++#endif ++ if ( REG_TSSI_STAT & TSSI_STAT_TRIG ) ++ { ++ printk("tssi trig irq occur! \n"); ++ tssi_read_fifo( dev_id ); ++ } ++ ++ __intc_ack_irq(TSSI_IRQ); ++ __intc_unmask_irq(TSSI_IRQ); ++ return IRQ_HANDLED; ++} ++ ++static ssize_t jz_read(struct file * filp, char * buffer, size_t count, loff_t * ppos) ++{ ++ jz_char_dev_t *adev = (jz_char_dev_t *)filp->private_data; ++ struct jz_tssi_t* tssi = (struct jz_tssi_t*)adev->private; ++ struct jz_tssi_buf_ring_t* ring = tssi->cur_buf; ++ ++ int i; ++ ++ count /= MPEG2_TS_PACHAGE_SIZE; ++ ++ if ( count > ring->fu_num ) ++ count = ring->fu_num; ++ ++ for ( i = 0; i < count; i ++ ) ++ { ++ memcpy( buffer + ( i * MPEG2_TS_PACHAGE_SIZE), ++ ring->rear->buf, MPEG2_TS_PACHAGE_SIZE ); ++ ring->rear->pos = 0; ++ ring->rear = ring->rear->next; ++ } ++ ring->fu_num -= count; ++ return count * MPEG2_TS_PACHAGE_SIZE; ++} ++ ++static int tssi_dma_reinit(int dma_chan, unsigned char *dma_buf, int size) ++{ ++ static unsigned int dma_src_phys_addr, dma_dst_phys_addr; ++ REG_DMAC_DMACKE(0) = 0xff; ++ dma_src_phys_addr = CPHYSADDR(TSSI_FIFO); ++ dma_dst_phys_addr = CPHYSADDR((unsigned int)dma_buf); ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0; ++ REG_DMAC_DCCSR(dma_chan) = 0; ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_TSSIIN; ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = size / 32; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ return 0; ++} ++ ++static int jz_open(struct inode * inode, struct file * filp) ++{ ++ try_module_get(THIS_MODULE); ++ ++ __tssi_soft_reset(); ++ __intc_mask_irq(TSSI_IRQ); ++ tssi_config_filting(); ++ ++ return 0; ++} ++ ++static int jz_release(struct inode * inode, struct file * filp) ++{ ++ __intc_mask_irq(TSSI_IRQ); ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static int jz_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ jz_char_dev_t *adev = (jz_char_dev_t *)file->private_data; ++ struct jz_tssi_t* tssi = (struct jz_tssi_t*)adev->private; ++ ++ switch (cmd) ++ { ++ case IOCTL_TSSI_ENABLE : ++ __intc_ack_irq(TSSI_IRQ); ++ __intc_unmask_irq(TSSI_IRQ); ++ __tssi_enable(); ++ print_reg(); ++ ++ break; ++ case IOCTL_TSSI_DISABLE : ++ __tssi_disable(); ++ ++ break; ++ case IOCTL_TSSI_SOFTRESET : ++ __tssi_soft_reset(); ++ ++ break; ++ case IOCTL_TSSI_ENFILTER : ++ __tssi_filter_enable(); ++ break; ++ case IOCTL_TSSI_DEFILTER : ++ __tssi_filter_disable(); ++ break; ++ case IOCTL_TSSI_ADDPID : //add one pid to filter ++ if ( tssi->pid_num < 15 ) ++ { ++ tssi_add_pid(tssi->pid_num, arg); ++ tssi->pid_num ++ ; ++ } ++ break; ++ ++ case IOCTL_TSSI_FLUSHPID : //set all filting pid to false ++ REG_TSSI_PEN = 0x0; ++ REG_TSSI_PID0 = 0x0; ++ REG_TSSI_PID1 = 0x0; ++ REG_TSSI_PID2 = 0x0; ++ REG_TSSI_PID3 = 0x0; ++ REG_TSSI_PID4 = 0x0; ++ REG_TSSI_PID5 = 0x0; ++ REG_TSSI_PID6 = 0x0; ++ REG_TSSI_PID7 = 0x0; ++ break; ++ ++ case IOCTL_TSSI_INIT_DMA: ++ tssi_dma_reinit(tssi->dma_chan, tssi->cur_buf->front->buf, MPEG2_TS_PACHAGE_SIZE); ++ break; ++ case IOCTL_TSSI_DISABLE_DMA: ++ REG_DMAC_DCCSR(tssi->dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct file_operations tssi_fops = { ++ owner: THIS_MODULE, ++ read: jz_read, ++ poll: NULL, ++ fasync: NULL, ++ ioctl: jz_ioctl, ++ open: jz_open, ++ release: jz_release, ++}; ++ ++static int __init jztssi_init_module(void) ++{ ++ int retval; ++ struct jz_tssi_t *tssi = &jz_tssi_g; ++ ++ __cpm_start_tssi(); ++ __cpm_start_dmac(); ++ tssi_buf_init( &jz_tssi_ring_g ); ++ tssi->cur_buf = &jz_tssi_ring_g; ++ tssi->pid_num = 0; ++ retval = request_irq(TSSI_IRQ, tssi_interrupt, IRQF_DISABLED, TSSI_NAME, &jz_tssi_g); ++ ++ if (retval) { ++ printk("unable to get IRQ %d",TSSI_IRQ); ++ return retval; ++ } ++ ++ tssi->dma_chan = jz_request_dma(DMA_ID_TSSI, "tssi", tssi_dma_irq, ++ IRQF_DISABLED, &jz_tssi_g); ++ if ( tssi->dma_chan < 0 ) ++ { ++ printk("MPEG2-TS request irq fail! \n"); ++ return -1; ++ } ++ ++ jz_register_chrdev(TSSI_MINOR, TSSI_NAME, &tssi_fops, &jz_tssi_g); ++ ++ printk("Jz MPEG2-TS interface driver registered %x %d\n",&jz_tssi_g,tssi->dma_chan); ++ return 0; ++} ++ ++static void jztssi_cleanup_module(void) ++{ ++ free_irq(TSSI_IRQ,0); ++ jz_free_dma(jz_tssi_g.dma_chan); ++ tssi_free_buf( &jz_tssi_ring_g ); ++ jz_unregister_chrdev(TSSI_MINOR, TSSI_NAME); ++} ++ ++module_init(jztssi_init_module); ++module_exit(jztssi_cleanup_module); +diff --git a/drivers/char/jzchar/jz_tssi.h b/drivers/char/jzchar/jz_tssi.h +new file mode 100644 +index 0000000..7ac424d +--- /dev/null ++++ b/drivers/char/jzchar/jz_tssi.h +@@ -0,0 +1,76 @@ ++#ifndef __JZ_TSSI_H__ ++#define __JZ_TSSI_H__ ++ ++/* ++ * IOCTL commands ++ */ ++#define IOCTL_TSSI_ENABLE 0x01 ++#define IOCTL_TSSI_DISABLE 0x02 ++#define IOCTL_TSSI_SOFTRESET 0x03 ++#define IOCTL_TSSI_ENFILTER 0x04 ++#define IOCTL_TSSI_DEFILTER 0x05 ++#define IOCTL_TSSI_ADDPID 0x06 ++#define IOCTL_TSSI_FLUSHPID 0x07 ++#define IOCTL_TSSI_INIT_DMA 0x08 ++#define IOCTL_TSSI_DISABLE_DMA 0x09 ++ ++#if 0 ++#define IOCTL_TSSI_SET_CFG 0x06 ++#define IOCTL_TSSI_GET_CFG 0x07 ++#define IOCTL_TSSI_ENIRQ_TRIG 0x08 ++#define IOCTL_TSSI_DEIRQ_TRIG 0x09 ++#define IOCTL_TSSI_ENIRQ_OVRN 0x0a ++#define IOCTL_TSSI_DEIRQ_OVRN 0x0b ++#define IOCTL_TSSI_ENPID0 0x0c ++#define IOCTL_TSSI_DEPID0 0x0d ++#define IOCTL_TSSI_ENPIDN 0x0e ++#define IOCTL_TSSI_DEPIDN 0x0f ++#define IOCTL_TSSI_SETPIDN 0x10 ++#define IOCTL_TSSI_SET_TRIG 0x11 ++#endif ++ ++#define MAX_PID_NUM 15 ++#define MPEG2_TS_PACHAGE_SIZE 19200 ++ ++struct jz_tssi_cfg_t ++{ ++ unsigned char wordorder; ++ unsigned char byteorder; ++ unsigned char dataploa; ++ unsigned char use0; ++ unsigned char clkch; ++ unsigned char mode; ++ unsigned char clkpola; ++ unsigned char frmpola; ++ unsigned char strpola; ++ unsigned char failpola; ++ unsigned char trignum; ++ ++ unsigned short pid; ++ unsigned char pid_index; //0 to 15 ++}; ++ ++struct jz_tssi_buf ++{ ++ unsigned int *buf; ++ unsigned int pos; ++ unsigned int index; ++ struct jz_tssi_buf *next; ++}; ++ ++struct jz_tssi_buf_ring_t ++{ ++ struct jz_tssi_buf *front; ++ struct jz_tssi_buf *rear; ++ unsigned int fu_num; ++}; ++ ++struct jz_tssi_t ++{ ++ struct jz_tssi_cfg_t cur_config; ++ struct jz_tssi_buf_ring_t *cur_buf; ++ struct semaphore tssi_sem; ++ int dma_chan, pid_num; ++}; ++ ++#endif /* __JZ_TSSI_H__ */ +diff --git a/drivers/char/jzchar/jzchars.c b/drivers/char/jzchar/jzchars.c +new file mode 100644 +index 0000000..1a1b944 +--- /dev/null ++++ b/drivers/char/jzchar/jzchars.c +@@ -0,0 +1,158 @@ ++/* ++ * linux/drivers/char/jzchar/jzchars.c ++ * ++ * JzSOC char device family common layer. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "jzchars.h" ++ ++LIST_HEAD(jz_char_devs); ++ ++int jz_register_chrdev(unsigned char minor, const char *name, ++ struct file_operations *fops, void *private) ++{ ++ struct list_head *p; ++ jz_char_dev_t *new; ++ list_for_each(p, &jz_char_devs) { ++ jz_char_dev_t *dev = (jz_char_dev_t *)p; ++ if (minor == dev->dev_minor) ++ return -EBUSY; ++ } ++ new = (jz_char_dev_t *)kmalloc(sizeof(jz_char_dev_t), GFP_KERNEL); ++ new->dev_minor = minor; ++ new->name = (char *)name; ++ new->fops = fops; ++ new->private = private; ++ list_add_tail((struct list_head *)new, &jz_char_devs); ++ return 0; ++} ++ ++int jz_unregister_chrdev(unsigned char minor, const char *name) ++{ ++ struct list_head *p; ++ jz_char_dev_t *dev = NULL; ++ list_for_each(p, &jz_char_devs) { ++ jz_char_dev_t *one = (jz_char_dev_t *)p; ++ if (minor == one->dev_minor) { ++ dev = one; ++ break; ++ } ++ } ++ if (dev == NULL) ++ return -EINVAL; ++ list_del((struct list_head *)dev); ++ kfree(dev); ++ return 0; ++} ++ ++static ssize_t jz_char_read(struct file *, char *, size_t, loff_t *); ++static ssize_t jz_char_write(struct file *, const char *, size_t, loff_t *); ++static int jz_char_open(struct inode *, struct file *); ++static int jz_char_release(struct inode *, struct file *); ++static int jz_char_ioctl(struct inode *, struct file *, ++ unsigned int, unsigned long); ++ ++static struct file_operations jz_char_fops = ++{ ++ read: jz_char_read, ++ write: jz_char_write, ++ ioctl: jz_char_ioctl, ++ open: jz_char_open, ++ release: jz_char_release ++}; ++ ++static int __init jz_char_family_init(void) ++{ ++ printk("JzSOC: char device family.\n"); ++ return register_chrdev(JZ_CHAR_MAJOR, "JzChar", &jz_char_fops); ++} ++ ++static void __exit jz_char_family_exit(void) ++{ ++ printk("JzSOC: exit char device family.\n"); ++ unregister_chrdev(JZ_CHAR_MAJOR, "JzChar"); ++} ++ ++module_init(jz_char_family_init); ++module_exit(jz_char_family_exit); ++ ++static int jz_char_open(struct inode *inode, struct file *filp) ++{ ++ jz_char_dev_t *dev = NULL; ++ unsigned int minor = iminor(inode); //minor extend to 20bit! ++ struct list_head *p; ++ list_for_each(p, &jz_char_devs) { ++ jz_char_dev_t *one = (jz_char_dev_t *)p; ++ if (one->dev_minor == minor) { ++ dev = one; ++ filp->private_data = dev; ++ return dev->fops->open(inode, filp); ++ } ++ } ++ printk("JzChar: No such device\n"); ++ return -EINVAL; ++} ++ ++static int jz_char_release(struct inode *inode, struct file *filp) ++{ ++ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; ++ if (dev->fops->release) ++ return dev->fops->release(inode, filp); ++ return 0; ++} ++ ++static int jz_char_ioctl(struct inode *inode, struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; ++ if (dev->fops->ioctl) ++ return dev->fops->ioctl(inode, filp, cmd, arg); ++ return 0; ++} ++ ++static ssize_t jz_char_read(struct file *filp, char *buf, ++ size_t count, loff_t *ppos) ++{ ++ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; ++ if (dev->fops->read) ++ return dev->fops->read(filp, buf, count, ppos); ++ return 0; ++} ++ ++static ssize_t jz_char_write(struct file *filp, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; ++ if (dev->fops->write) ++ return dev->fops->write(filp, buf, count, ppos); ++ return 0; ++} ++ ++EXPORT_SYMBOL(jz_register_chrdev); ++EXPORT_SYMBOL(jz_unregister_chrdev); +diff --git a/drivers/char/jzchar/jzchars.h b/drivers/char/jzchar/jzchars.h +new file mode 100644 +index 0000000..a76f2ae +--- /dev/null ++++ b/drivers/char/jzchar/jzchars.h +@@ -0,0 +1,47 @@ ++#ifndef __JZ_CHARS_H__ ++#define __JZ_CHARS_H__ ++ ++#include ++#include ++ ++#define JZ_CHAR_MAJOR 238 ++ ++#define UPRT_MINOR 0 // Micro printer ++#define CIM_MINOR 1 // Camera interface module ++#define TPANEL_MINOR 2 // Touchpanel ++#define KEYPAD_MINOR 3 // Keypad ++#define MEMCARD_MINOR 4 // Memory card ++#define MAGCARD_MINOR 5 // Magcard ++#define VFD_MINOR 6 // VFD ++#define POWERFAIL_MINOR 7 // Powerfail ++#define EJTAG_MINOR 8 // EJTAG emulation ++#define REMR0_MINOR 9 // Remote output receive 0 ++#define REMR1_MINOR 10 // Remote output receive 1 ++#define USPI_MINOR 11 // Ultra-speed SPI device ++#define SADC_MINOR 12 // SAR-ADC ++#define SLCD_MINOR 13 // Smart LCD ++ ++// 32 to 47 are reserved for SCC ++#define SCC_MINOR 32 ++// 48 to 63 are reserved for Camera sensor ++#define SENSOR_MINOR 48 ++// 64 to 71 are for EEPROM ++#define EEPROM_MINOR_BASE 64 ++// 72 for OWI ++#define OW_MINOR 72 ++// 73 for TCSM_MINOR ++#define TCSM_MINOR 73 ++ ++typedef struct { ++ struct list_head list; ++ char *name; ++ struct file_operations *fops; ++ void *private; ++ unsigned short dev_minor; ++} jz_char_dev_t; ++ ++extern int jz_register_chrdev(unsigned char minor, const char *name, ++ struct file_operations *fops, void * private); ++extern int jz_unregister_chrdev(unsigned char minor, const char *name); ++ ++#endif /* __JZ_CHARS_H__ */ +diff --git a/drivers/char/jzchar/poweroff.c b/drivers/char/jzchar/poweroff.c +new file mode 100644 +index 0000000..a488f5f +--- /dev/null ++++ b/drivers/char/jzchar/poweroff.c +@@ -0,0 +1,396 @@ ++/* ++ * linux/drivers/char/jzchar/poweroff.c ++ * ++ * Power off handling. ++ * ++ * Copyright (C) 2005-2007 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "jzchars.h" ++ ++MODULE_AUTHOR("Jianli Wei "); ++MODULE_DESCRIPTION("Poweroff handling"); ++MODULE_LICENSE("GPL"); ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++ ++//#define USE_SUSPEND_HOTPLUG ++ ++#ifdef CONFIG_SOC_JZ4730 ++#define GPIO_PW_I 97 ++#define GPIO_PW_O 66 ++#define POWEROFF_PIN_DOWN 1 ++#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_rise_edge(POWEROFF_PIN) ++#define DO_SHUTDOWN_SYSTEM __gpio_clear_pin(GPIO_PW_O) ++#define DO_SUSPEND jz_pm_suspend() ++ ++#define GPIO_DISP_OFF_N 93 ++#define __lcd_set_backlight_level(n) \ ++do { \ ++ REG_PWM_DUT(0) = n; \ ++ REG_PWM_PER(0) = 7; \ ++ REG_PWM_CTR(0) = 0x81; \ ++} while (0) ++#define __lcd_close_backlight() \ ++do { \ ++ __lcd_set_backlight_level(0); \ ++} while (0) ++#endif ++ ++#ifdef CONFIG_SOC_JZ4740 ++#define GPIO_PW_I 125 ++#define POWEROFF_PIN_DOWN 0 ++#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) ++#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate() ++#define DO_SUSPEND { \ ++ jz_pm_sleep();\ ++ suspend_flag = 0;\ ++ SET_POWEROFF_PIN_AS_IRQ;\ ++ } ++ ++#define GPIO_DISP_OFF_N 118 ++#define GPIO_PWM 123 ++#define __lcd_close_backlight() \ ++do { \ ++__gpio_as_output(GPIO_PWM); \ ++__gpio_clear_pin(GPIO_PWM); \ ++} while (0) ++#endif ++ ++#ifdef CONFIG_SOC_JZ4750 ++#define GPIO_PW_I GPIO_WAKEUP ++#define POWEROFF_PIN_DOWN 0 ++#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) ++#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate() ++#define DO_SUSPEND { \ ++ jz_pm_sleep();\ ++ suspend_flag = 0;\ ++ SET_POWEROFF_PIN_AS_IRQ;\ ++ } ++#endif ++ ++#ifdef CONFIG_SOC_JZ4750D ++#define GPIO_PW_I GPIO_WAKEUP ++#define POWEROFF_PIN_DOWN 0 ++#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) ++#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate() ++#define DO_SUSPEND { \ ++ jz_pm_sleep();\ ++ suspend_flag = 0;\ ++ SET_POWEROFF_PIN_AS_IRQ;\ ++ } ++#endif ++ ++ ++#define POWEROFF_PIN GPIO_PW_I ++#define POWEROFF_IRQ (IRQ_GPIO_0 + POWEROFF_PIN) ++ ++#define POWEROFF_PERIOD 1000 /* unit: ms */ ++#define POWEROFF_DELAY 100 /* unit: ms */ ++ ++static struct timer_list poweroff_timer; ++static struct timer_list poweroff_delaytimer; ++static struct work_struct suspend_work; ++ ++static int poweroff_flag = 0; ++static int suspend_flag = 0; ++static int num_seconds = 0; ++ ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++extern int jz_udc_active; ++#endif ++ ++extern void jz_pm_suspend(void); ++extern int jz_pm_hibernate(void); ++extern int jz_pm_sleep(void); ++ ++static void poweroff_timer_routine(unsigned long dummy) ++{ ++ if (__gpio_get_pin(POWEROFF_PIN) == POWEROFF_PIN_DOWN) { ++ if (++num_seconds > 3) ++ { ++ printk("\nShutdown system now ..\n"); ++ ++#ifndef USE_SUSPEND_HOTPLUG ++ /* Turn off LCD to inform user that the system is shutting down. ++ * But the information of shutting down system will be shown ++ * by userspace program if hotplug is used. ++ */ ++ __lcd_close_backlight(); ++#endif ++ ++ /* ++ * Wait until the power key is up, or the system will reset with ++ * power key down after entering hibernate. ++ */ ++ while(__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN); ++ ++ poweroff_flag = 1; ++ schedule_work(&suspend_work); /* inform user to poweroff */ ++ } ++ else { ++ del_timer(&poweroff_timer); ++ init_timer(&poweroff_timer); ++ poweroff_timer.expires = jiffies + POWEROFF_PERIOD/10; ++ poweroff_timer.data = 0; ++ poweroff_timer.function = poweroff_timer_routine; ++ add_timer(&poweroff_timer); ++ } ++ } ++ else ++ { ++ printk("\nSuspend system now ..\n"); ++ num_seconds = 0; ++ suspend_flag = 1; ++ poweroff_flag = 0; ++ schedule_work(&suspend_work); /* we are entering suspend */ ++ } ++} ++ ++static void poweroff_delaytimer_routine(unsigned long dummy) ++{ ++ __gpio_as_input(POWEROFF_PIN); ++ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN) { ++ if (suspend_flag) { ++ suspend_flag = 0; ++ del_timer(&poweroff_delaytimer); ++ SET_POWEROFF_PIN_AS_IRQ; ++ __gpio_unmask_irq(POWEROFF_PIN); ++ return; ++ } ++ del_timer(&poweroff_delaytimer); ++ del_timer(&poweroff_timer); ++ init_timer(&poweroff_timer); ++ poweroff_timer.expires = jiffies + POWEROFF_PERIOD/100; ++ poweroff_timer.data = 0; ++ poweroff_timer.function = poweroff_timer_routine; ++ add_timer(&poweroff_timer); ++ } ++ else { ++ del_timer(&poweroff_delaytimer); ++ SET_POWEROFF_PIN_AS_IRQ; ++ __gpio_unmask_irq(POWEROFF_PIN); ++ ++ printk("This is a dummy key\n"); ++ } ++} ++ ++/* ++ * Poweroff pin interrupt handler ++ */ ++static irqreturn_t poweroff_irq(int irq, void *dev_id) ++{ ++ __gpio_ack_irq(POWEROFF_PIN); ++ __gpio_mask_irq(POWEROFF_PIN); ++ __gpio_as_input(POWEROFF_PIN); ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN && jz_udc_active == 0){ ++#else ++ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN){ ++#endif ++ del_timer(&poweroff_delaytimer); ++ init_timer(&poweroff_delaytimer); ++ poweroff_delaytimer.expires = jiffies + POWEROFF_DELAY/10; ++ poweroff_delaytimer.data = 0; ++ poweroff_delaytimer.function = poweroff_delaytimer_routine; ++ add_timer(&poweroff_delaytimer); ++ } ++ else { ++ ++/* ++ * If it reaches here without jz_udc_active == 0, then it indicates POWEROFF_PIN was ++ * changed to WAKEUP key in pm.c for hand is not able to rise up so quickly, so the ++ * irq handler entered because of WAKEUP key not POWEROFF_PIN. ++ */ ++ ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++ if (jz_udc_active == 1) ++ printk("\nUSB is working; Operation is denied\n"); ++#endif ++ SET_POWEROFF_PIN_AS_IRQ; ++ __gpio_unmask_irq(POWEROFF_PIN); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_PM ++ ++static struct pm_dev *poweroff_dev; ++ ++static int poweroff_suspend(int *poweroff , int state) ++{ ++ suspend_flag = 1; ++ poweroff_flag = 0; ++ ++ return 0; ++} ++ ++static int poweroff_resume(int *poweroff) ++{ ++ suspend_flag = 0; ++ SET_POWEROFF_PIN_AS_IRQ; ++ __gpio_unmask_irq(POWEROFF_PIN); ++ ++ return 0; ++} ++ ++static int poweroff_pm_callback(struct pm_dev *pm_dev, pm_request_t rqst, void *data) ++{ ++ int ret; ++ int *poweroff_info = pm_dev->data; ++ ++ if (!poweroff_info) ++ return -EINVAL; ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ ret = poweroff_suspend(poweroff_info, (int)data); ++ break; ++ case PM_RESUME: ++ ret = poweroff_resume(poweroff_info); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#endif /* CONFIG_PM */ ++ ++#ifdef USE_SUSPEND_HOTPLUG ++static void run_sbin_hotplug(int state) ++{ ++ int i; ++ char *argv[3], *envp[8]; ++ char media[64], slotnum[16]; ++ if (!uevent_helper[0]) ++ return; ++ ++ i = 0; ++ argv[i++] = uevent_helper; ++ //argv[i++] = "home/lhhuang/hotplug"; ++ ++ if ( poweroff_flag == 1 ) ++ argv[i++] = "poweroff"; ++ else ++ argv[i++] = "suspend"; ++ ++ argv[i] = 0; ++ ++ /* minimal command environment */ ++ i = 0; ++ envp[i++] = "HOME=/"; ++ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ ++ /* other stuff we want to pass to /sbin/hotplug */ ++ sprintf(slotnum, "SLOT=0"); ++ ++ if ( poweroff_flag == 1 ) ++ sprintf(media, "MEDIA=poweroff"); ++ else ++ sprintf(media, "MEDIA=suspend"); ++ ++ envp[i++] = slotnum; ++ envp[i++] = media; ++ ++ if (state) ++ envp[i++] = "ACTION=enter"; ++ else ++ envp[i++] = "ACTION=exit"; ++ ++ envp[i] = 0; ++ ++ dprintk("SUSPEND: hotplug path=%s state=%d\n", argv[0], state); ++ ++ SET_POWEROFF_PIN_AS_IRQ; ++ __gpio_unmask_irq(POWEROFF_PIN); /* set it because call hotplug with call_usermodehelper() \ ++ might failed, especially when using nfsroot */ ++ ++ call_usermodehelper (argv [0], argv, envp, -1); ++} ++#endif ++ ++static void suspend_handler(struct work_struct *work) ++{ ++#ifdef USE_SUSPEND_HOTPLUG ++ int state = 1; ++ run_sbin_hotplug(state); ++#else ++ if (poweroff_flag) { ++ dprintk("DO_SHUTDOWN_SYSTEM\n"); ++ DO_SHUTDOWN_SYSTEM; ++ } else { ++ dprintk("DO_SUSPEND\n"); ++ DO_SUSPEND; ++ } ++#endif ++} ++ ++static int __init poweroff_init(void) ++{ ++ int retval; ++ ++ retval = request_irq(POWEROFF_IRQ, poweroff_irq, ++ IRQF_DISABLED, "poweroff", NULL); ++ ++ SET_POWEROFF_PIN_AS_IRQ; ++ ++ if (retval) { ++ printk("Could not get poweroff irq %d\n", POWEROFF_IRQ); ++ return retval; ++ } ++ ++#ifdef CONFIG_PM ++ poweroff_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, poweroff_pm_callback); ++ if (poweroff_dev) { ++ poweroff_dev->data = &poweroff_dev; ++ } ++#endif ++ ++ INIT_WORK(&suspend_work, suspend_handler); ++ ++ return 0; ++} ++ ++static void __exit poweroff_exit(void) ++{ ++ free_irq(POWEROFF_IRQ, NULL); ++} ++ ++module_init(poweroff_init); ++module_exit(poweroff_exit); ++ +diff --git a/drivers/char/jzchar/sadc.c b/drivers/char/jzchar/sadc.c +new file mode 100644 +index 0000000..dc43404 +--- /dev/null ++++ b/drivers/char/jzchar/sadc.c +@@ -0,0 +1,580 @@ ++/* ++ * linux/drivers/char/jzchar/sadc.c ++ * ++ * SAR-ADC driver for JZ4740. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "jzchars.h" ++#include "jz_ts.h" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("JZ4740 SADC driver"); ++MODULE_LICENSE("GPL"); ++ ++#define SADC_NAME "sadc" ++static DECLARE_WAIT_QUEUE_HEAD (sadc_wait_queue); ++ ++struct sadc_device { ++ int mode; ++ int dma_chan; ++ char *ts_buf; ++ char *pbat_buf; ++}; ++ ++static struct sadc_device *sadc_dev; ++ ++static int samples = 3; /* we sample 3 every time */ ++static int first_time = 0; ++static unsigned long last_x, last_y, last_p; ++ ++typedef struct datasource { ++ u16 xbuf; ++ u16 ybuf; ++ u16 zbuf; ++}datasource_t; ++ ++static datasource_t data_s; ++static unsigned int p; ++static unsigned int old_x, old_y; ++extern unsigned int (*codec_read_battery)(void); ++ ++/* ++ * set adc clock to 12MHz/div. A/D works at freq between 500KHz to 6MHz. ++ */ ++static void sadc_init_clock(int div) ++{ ++ if (div < 2) div = 2; ++ if (div > 23) div = 23; ++#if defined(CONFIG_SOC_JZ4740) ++ REG_SADC_CFG &= ~SADC_CFG_CLKDIV_MASK; ++ REG_SADC_CFG |= (div - 1) << SADC_CFG_CLKDIV_BIT; ++#endif ++#if defined(CONFIG_SOC_JZ4750) ++ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_MASK; ++ REG_SADC_ADCLK |= (div - 1) << SADC_ADCLK_CLKDIV_BIT; ++ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_BIT; ++ REG_SADC_ADCLK |= 39 << SADC_ADCLK_CLKDIV_10_BIT; /* if div ==3,here is 39 */ ++#endif ++} ++ ++void start_sadcin(void) ++{ ++ REG_SADC_CTRL &= ~SADC_CTRL_SRDYM; /* enable interrupt */ ++ REG_SADC_ENA |= SADC_ENA_SADCINEN; ++} ++ ++void start_pbat_adc(void) ++{ ++ REG_SADC_CFG |= SADC_CFG_PBAT_HIGH ; /* full baterry voltage >= 2.5V */ ++// REG_SADC_CFG |= SADC_CFG_PBAT_LOW; /* full baterry voltage < 2.5V */ ++ ++ REG_SADC_ENA |= SADC_ENA_PBATEN; /* Enable pbat adc */ ++} ++ ++void start_ts_adc(void) ++{ ++ REG_SADC_SAMETIME = 10; /* about 0.1 ms,you can change it */ ++ REG_SADC_WAITTIME = 2; /* about 0.02 ms,you can change it */ ++ ++ REG_SADC_CFG &= ~(SADC_CFG_TS_DMA | SADC_CFG_XYZ_MASK | SADC_CFG_SNUM_MASK); ++ REG_SADC_CFG |= (SADC_CFG_EXIN | SADC_CFG_XYZ | SADC_CFG_SNUM_3); ++ REG_SADC_CTRL |= (SADC_CTRL_TSRDYM|SADC_CTRL_PBATRDYM|SADC_CTRL_PENUM |SADC_CTRL_SRDYM); ++ REG_SADC_CTRL &= ~SADC_CTRL_PENDM; ++ REG_SADC_ENA |= SADC_ENA_TSEN; ++} ++ ++static int jz4740_adc_read(struct jz_ts_t *ts) ++{ ++ struct datasource *ds = &data_s; ++ u32 xybuf,z; ++ ++ if (!(REG_SADC_STATE & SADC_STATE_TSRDY)) { ++ /* sleep */ ++ REG_SADC_CTRL &= ~SADC_CTRL_TSRDYM; ++ ts->sleeping = 1; ++ sleep_on(&sadc_wait_queue); ++ } ++ ts->sleeping = 0; ++ ++ xybuf = REG_SADC_TSDAT; ++ ds->xbuf = (xybuf>>16) & 0x0fff; ++ ds->ybuf = (xybuf)& 0x0fff; ++ z = REG_SADC_TSDAT; ++ ds->zbuf = z& 0x0fff; ++ REG_SADC_STATE &= ~SADC_STATE_TSRDY; ++ return 0; ++} ++ ++/*------------------------------------------------------------ ++ * Read the battery voltage ++ */ ++unsigned int jz4740_read_battery(void) ++{ ++ unsigned int v; ++ unsigned int timeout = 0x3ff; ++ u16 pbat; ++ ++ if(!(REG_SADC_STATE & SADC_STATE_PBATRDY) ==1) ++ start_pbat_adc(); ++ ++ while(!(REG_SADC_STATE & SADC_STATE_PBATRDY) && --timeout) ++ ; ++ ++ pbat = REG_SADC_BATDAT; ++ v = pbat & 0x0fff; ++ REG_SADC_STATE = SADC_STATE_PBATRDY; ++ return v; ++} ++ ++/*------------------ Calibrate samples -------------------*/ ++ ++#define DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a))) ++#define MIN(a,b) (((a)<(b))?(a):(b)) ++ ++#if 0 ++#define XM 36 /* XM and YM may be changed for your screen */ ++#define YM 20 ++static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) ++{ ++ unsigned long usd0,usd1,usd2; ++ int xMaxError = XM,yMaxError = YM; ++ int x_valid = 0,y_valid = 0,valid = 0; ++ unsigned long x_cal = 0, y_cal = 0, p_cal = 0; ++ unsigned long *xp = (unsigned long *)xbuf; ++ unsigned long *yp = (unsigned long *)ybuf; ++ unsigned long *pp = (unsigned long *)pbuf; ++ ++ usd0 = (xp[0] > xp[1]) ? (xp[0] - xp[1]) : (xp[1] - xp[0]); ++ usd1 = (xp[1] > xp[2]) ? (xp[1] - xp[2]) : (xp[2] - xp[1]); ++ usd2 = (xp[2] > xp[0]) ? (xp[2] - xp[0]) : (xp[0] - xp[2]); ++ ++ if ( usd0 < usd1) ++ x_cal = xp[0] + ((usd2 < usd0) ? xp[2] : xp[1]); ++ else ++ x_cal= xp[2] + ((usd2 < usd1) ? xp[0] : xp[1]); ++ x_cal >>= 1; ++ ++ if ( (usd0 < xMaxError) && (usd1 < xMaxError) && (usd2 < xMaxError) ) ++ x_valid = 1; ++ ++ usd0 = (yp[0] > yp[1]) ? (yp[0] - yp[1]) : (yp[1] - yp[0]); ++ usd1 = (yp[1] > yp[2]) ? (yp[1] - yp[2]) : (yp[2] - yp[1]); ++ usd2 = (yp[2] > yp[0]) ? (yp[2] - yp[0]) : (yp[0] - yp[2]); ++ ++ if ( usd0 < usd1) ++ y_cal = yp[0] + ((usd2 < usd0) ? yp[2] : yp[1]); ++ else ++ y_cal = yp[2] + ((usd2 < usd1) ? yp[0] : yp[1]); ++ ++ y_cal >>= 1; ++ ++ if ( (usd0 < yMaxError) && (usd1 < yMaxError) && (usd2 < yMaxError) ) ++ y_valid = 1; ++ ++ if( x_valid && y_valid) ++ valid = 1; ++ ++ usd0 = (pp[0] > pp[1]) ? (pp[0] - pp[1]) : (pp[1] - pp[0]); ++ usd1 = (pp[1] > pp[2]) ? (pp[1] - pp[2]) : (pp[2] - pp[1]); ++ usd2 = (pp[2] > pp[0]) ? (pp[2] - pp[0]) : (pp[0] - pp[2]); ++ ++ if ( usd0 < usd1) ++ p_cal = pp[0] + ((usd2 < usd0) ? pp[2] : pp[1]); ++ else ++ p_cal= pp[2] + ((usd2 < usd1) ? pp[0] : pp[1]); ++ ++ p_cal >>= 1; ++ ++ if (first_time) { ++ first_time = 0; ++ last_x = x_cal; ++ last_y = y_cal; ++ last_p = p_cal; ++ } ++ else{ ++ if ((DIFF(x_cal, last_x) > 50) || ++ (DIFF(y_cal, last_y) > 50)) ++ valid = 0; ++ else ++ valid = 1; ++ } ++ *xp = last_x = x_cal; ++ *yp = last_y = y_cal; ++ *pp = last_p = p_cal; ++ ++ return valid; ++} ++#endif ++ ++static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) ++{ ++ unsigned long *xp = (unsigned long *)xbuf; ++ unsigned long *yp = (unsigned long *)ybuf; ++ unsigned long *pp = (unsigned long *)pbuf; ++ unsigned long x_cal = 0, y_cal = 0, p_cal = 0; ++ int i; ++ int valid = 1; ++ ++ /* calculate the average of the rest */ ++ for (i = 0; i < count; i++) { ++ x_cal += xp[i]; ++ y_cal += yp[i]; ++ p_cal += pp[i]; ++ } ++ x_cal /= count; ++ y_cal /= count; ++ p_cal /= count; ++ ++ if (first_time) { ++ first_time = 0; ++ last_x = x_cal; ++ last_y = y_cal; ++ last_p = p_cal; ++ } ++ else { ++ if ((DIFF(x_cal, last_x) > 50) || ++ (DIFF(y_cal, last_y) > 50)) ++ valid = 0; ++ else ++ valid = 1; ++ } ++ ++ *xp = last_x = x_cal; ++ *yp = last_y = y_cal; ++ *pp = last_p = p_cal; ++ ++ return valid; ++} ++ ++#define TSMAXX 945 ++#define TSMAXY 830 ++#define TSMINX 90 ++#define TSMINY 105 ++ ++#define SCREEN_X 480 ++#define SCREEN_Y 272 ++ ++static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) ++{ ++ ++ if (ts->minx) ++ { ++ if (x < ts->minx) x = ts->minx; ++ if (x > ts->maxx) x = ts->maxx; ++ ++ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); ++ } ++ else ++ { ++ if (x < TSMINX) x = TSMINX; ++ if (x > TSMAXX) x = TSMAXX; ++ ++ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); ++ } ++} ++ ++static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) ++{ ++ if (ts->minx) ++ { ++ if (y < ts->minx) y = ts->miny; ++ if (y > ts->maxx) y = ts->maxy; ++ ++ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); ++ } ++ else ++ { ++ if (y < TSMINX) y = TSMINY; ++ if (y > TSMAXX) y = TSMAXY; ++ ++ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); ++ } ++} ++ ++/* ++ * File operations ++ */ ++static int sadc_open(struct inode *inode, struct file *filp); ++static int sadc_release(struct inode *inode, struct file *filp); ++static ssize_t sadc_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int sadc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++ ++static struct file_operations sadc_fops = ++{ ++ open: sadc_open, ++ release: sadc_release, ++ read: sadc_read, ++ write: sadc_write, ++ ioctl: sadc_ioctl ++}; ++ ++static int sadc_open(struct inode *inode, struct file *filp) ++{ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int sadc_release(struct inode *inode, struct file *filp) ++{ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t sadc_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ return size; ++} ++ ++static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ return size; ++} ++ ++static int sadc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return 0; ++} ++ ++/*------------------ Common routines -------------------*/ ++ ++void ts_enable_irq(void) ++{ ++ REG_SADC_CTRL &= ~SADC_CTRL_PENDM; ++} ++ ++void ts_disable_irq(void) ++{ ++ REG_SADC_CTRL |= (SADC_CTRL_PENDM | SADC_CTRL_PENUM); ++} ++ ++void ts_free_irq(struct jz_ts_t *ts) ++{ ++ free_irq(ts->pendown_irq, ts); ++} ++ ++void ts_data_ready(void) ++{ ++ REG_SADC_CTRL |= SADC_CTRL_TSRDYM; ++ wake_up(&sadc_wait_queue); ++} ++ ++/* ++ * Interrupt handler ++ */ ++void ts_irq_callback(void) ++{ ++ u32 state; ++ ++ state = REG_SADC_STATE; ++ if (!(REG_SADC_CTRL&SADC_CTRL_PENDM)&&(REG_SADC_STATE & SADC_STATE_PEND)) { ++ REG_SADC_STATE = SADC_STATE_PEND; ++ REG_SADC_STATE = SADC_STATE_PENU; ++ REG_SADC_CTRL |= SADC_CTRL_PENDM; ++ REG_SADC_CTRL &= ~SADC_CTRL_PENUM; ++ p = 1; ++ } ++ ++ if (!(REG_SADC_CTRL&SADC_CTRL_PENUM)&&(REG_SADC_STATE & SADC_STATE_PENU)) { ++ REG_SADC_STATE = SADC_STATE_PENU; ++ REG_SADC_CTRL |= SADC_CTRL_PENUM; ++ REG_SADC_CTRL &= ~SADC_CTRL_PENDM; ++ p = 0; ++ } ++ ++ first_time = 1; // first time to acquire sample ++} ++ ++int PenIsDown(void) ++{ ++ return p; ++} ++ ++int ts_request_irq(u32 *irq, ++ irqreturn_t (*handler)(int, void *), ++ const char *devname, ++ void *dev_id) ++{ ++ int ret; ++ ++ /* return the irq number */ ++ *irq = IRQ_SADC; ++ ts_disable_irq(); ++ /* interrupt mode */ ++ ret = request_irq(IRQ_SADC, handler, IRQF_DISABLED, ++ devname, dev_id); ++ if(ret) ++ printk("failed irq \n"); ++ ++ start_ts_adc(); ++ return ret; ++} ++ ++/* ++ * Acquire Raw pen coodinate data and compute touch screen ++ * pressure resistance. Hold spinlock when calling. ++ */ ++int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) ++{ ++ unsigned int x_raw[8], y_raw[8], p_raw[8]; ++ int valid, i; ++ unsigned int avl_x, avl_y, diff_x, diff_y; ++ struct datasource *ds = &data_s; ++ avl_x = avl_y = 0; ++ ++ for (i = 0; i < samples; i++) { ++ if (jz4740_adc_read(ts)) { ++ return 0; ++ } ++ ++ x_raw[i] = ds->ybuf; ++ y_raw[i] = ds->xbuf; ++ p_raw[i] = ds->zbuf; ++ avl_x += x_raw[i]; ++ avl_y += y_raw[i]; ++#if 0 ++ printk("x_raw=%x y_raw=%x z_raw=%x\n",x_raw[i],y_raw[i],p_raw[i]); ++#endif ++ } ++ ++ avl_x /= samples; ++ avl_y /= samples; ++#define MAX_DELTA 20 ++ valid = 1; ++ ++ for (i = 1; i < samples; i++) ++ { ++ if ((100 * DIFF(x_raw[i],x_raw[i-1])/MIN(x_raw[i],x_raw[i-1])) > MAX_DELTA) { ++ valid = 0; ++ break; ++ } ++ ++ if ((100 * DIFF(y_raw[i],y_raw[i-1])/MIN(y_raw[i],y_raw[i-1])) > MAX_DELTA) { ++ valid = 0; ++ break; ++ } ++ ++ if ((100 * DIFF(p_raw[i],p_raw[i-1])/MIN(p_raw[i],p_raw[i-1])) > MAX_DELTA) { ++ valid = 0; ++ break; ++ } ++ } ++ ++ if (valid) { ++ if (ts->first_read) { ++ ts->first_read = 0; ++ old_x = avl_x; ++ old_y = avl_y; ++ } ++ diff_x = DIFF(old_x, avl_x); ++ diff_y = DIFF(old_y, avl_y); ++ if (diff_x < 100 && diff_y < 100) { ++ old_x = avl_x; ++ old_y = avl_y; ++ } else ++ valid = 0; ++ } ++ if (valid) { ++ valid = calibrate_samples(x_raw, y_raw, p_raw, samples); ++ } ++ ++ if (valid) { ++ unsigned int x_scr, y_scr; ++ ++ if(ts->filter) { ++ x_scr = transform_to_screen_x(ts, x_raw[0]); ++ y_scr = transform_to_screen_y(ts, y_raw[0]); ++ ++ if (ts->prints) ++ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", x_raw[0], y_raw[0], x_scr, y_scr); ++ } ++ else { ++ x_scr = x_raw[0]; ++ y_scr = y_raw[0]; ++ ++ if (ts->prints) ++ printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); ++ } ++ ++ event->x = x_scr; ++ event->y = y_scr; ++ event->pressure = (u16)p_raw[0]; ++ event->status = PENDOWN; ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * Module init and exit ++ */ ++static int __init sadc_init(void) ++{ ++ struct sadc_device *dev; ++ int ret; ++ ++ /* allocate device */ ++ dev = kmalloc(sizeof(struct sadc_device), GFP_KERNEL); ++ if (!dev) return -ENOMEM; ++ ++ sadc_dev = dev; ++ ret = jz_register_chrdev(SADC_MINOR, SADC_NAME, &sadc_fops, dev); ++ if (ret < 0) { ++ kfree(dev); ++ return ret; ++ } ++ ++ codec_read_battery = jz4740_read_battery; ++ sadc_init_clock(3); ++ ++ printk("JZ4740 SAR-ADC driver registered\n"); ++ return 0; ++} ++ ++static void __exit sadc_exit(void) ++{ ++ struct sadc_device *dev = sadc_dev; ++ ++ free_irq(IRQ_SADC, dev); ++ jz_unregister_chrdev(SADC_MINOR, SADC_NAME); ++ kfree(dev); ++} ++ ++module_init(sadc_init); ++module_exit(sadc_exit); +diff --git a/drivers/char/jzchar/sensor.c b/drivers/char/jzchar/sensor.c +new file mode 100644 +index 0000000..8123203 +--- /dev/null ++++ b/drivers/char/jzchar/sensor.c +@@ -0,0 +1,182 @@ ++/* ++ * linux/drivers/char/jzchar/sensor.c ++ * ++ * Common CMOS Camera Sensor Driver ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "jzchars.h" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("Common CMOS Camera Sensor Driver"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * ioctl commands ++ */ ++#define IOCTL_SET_ADDR 0 /* set i2c address */ ++#define IOCTL_SET_CLK 1 /* set i2c clock */ ++#define IOCTL_WRITE_REG 2 /* write sensor register */ ++#define IOCTL_READ_REG 3 /* read sensor register */ ++ ++/* ++ * i2c related ++ */ ++static unsigned int i2c_addr = 0x42; ++static unsigned int i2c_clk = 100000; ++ ++static void write_reg(u8 reg, u8 val) ++{ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_write((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++} ++ ++static u8 read_reg(u8 reg) ++{ ++ u8 val; ++ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_read((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++ return val; ++} ++ ++/* ++ * fops routines ++ */ ++ ++static int sensor_open(struct inode *inode, struct file *filp); ++static int sensor_release(struct inode *inode, struct file *filp); ++static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ++ ++static struct file_operations sensor_fops = ++{ ++ open: sensor_open, ++ release: sensor_release, ++ read: sensor_read, ++ write: sensor_write, ++ ioctl: sensor_ioctl, ++}; ++ ++static int sensor_open(struct inode *inode, struct file *filp) ++{ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int sensor_release(struct inode *inode, struct file *filp) ++{ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ printk("sensor: read is not implemented\n"); ++ return -1; ++} ++ ++static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("sensor: write is not implemented\n"); ++ return -1; ++} ++ ++static int sensor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ ++ switch (cmd) { ++ case IOCTL_SET_ADDR: ++ if (copy_from_user(&i2c_addr, (void *)arg, 4)) ++ return -EFAULT; ++ break; ++ case IOCTL_SET_CLK: ++ if (copy_from_user(&i2c_clk, (void *)arg, 4)) ++ return -EFAULT; ++ break; ++ case IOCTL_WRITE_REG: ++ { ++ u8 regval[2]; ++ ++ if (copy_from_user(regval, (void *)arg, 2)) ++ return -EFAULT; ++ ++ write_reg(regval[0], regval[1]); ++ break; ++ } ++ case IOCTL_READ_REG: ++ { ++ u8 reg, val; ++ ++ if (copy_from_user(®, (void *)arg, 1)) ++ return -EFAULT; ++ ++ val = read_reg(reg); ++ ++ if (copy_to_user((void *)(arg + 1), &val, 1)) ++ return -EFAULT; ++ break; ++ } ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++/* ++ * Module init and exit ++ */ ++ ++static int __init sensor_init(void) ++{ ++ int ret; ++ ++ ret = jz_register_chrdev(SENSOR_MINOR, "sensor", &sensor_fops, NULL); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ printk("Ingenic CMOS camera sensor driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit sensor_exit(void) ++{ ++ jz_unregister_chrdev(SENSOR_MINOR, "sensor"); ++} ++ ++module_init(sensor_init); ++module_exit(sensor_exit); +diff --git a/drivers/char/jzchar/tcsm.c b/drivers/char/jzchar/tcsm.c +new file mode 100644 +index 0000000..1941d14 +--- /dev/null ++++ b/drivers/char/jzchar/tcsm.c +@@ -0,0 +1,123 @@ ++/* ++ * linux/drivers/char/jzchar/tcsm.c ++ * ++ * Virtual device driver with tricky appoach to manage TCSM ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "jzchars.h" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("Virtual Driver of TCSM"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * fops routines ++ */ ++ ++static int tcsm_open(struct inode *inode, struct file *filp); ++static int tcsm_release(struct inode *inode, struct file *filp); ++static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int tcsm_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ++ ++static struct file_operations tcsm_fops = ++{ ++ open: tcsm_open, ++ release: tcsm_release, ++ read: tcsm_read, ++ write: tcsm_write, ++ ioctl: tcsm_ioctl, ++}; ++ ++static int tcsm_open(struct inode *inode, struct file *filp) ++{ ++ struct pt_regs *info = task_pt_regs(current); ++ ++ info->cp0_status &= ~0x10;// clear UM bit ++ info->cp0_status |= 0x08000000; // set RP bit a tricky ++ ++ return 0; ++} ++ ++static int tcsm_release(struct inode *inode, struct file *filp) ++{ ++ struct pt_regs *info = task_pt_regs(current); ++ ++ info->cp0_status |= 0x10;// set UM bit ++ info->cp0_status &= ~0x08000000; // clear RP bit a tricky ++ ++ return 0; ++} ++ ++static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ printk("tcsm: read is not implemented\n"); ++ return -1; ++} ++ ++static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("tcsm: write is not implemented\n"); ++ return -1; ++} ++ ++static int tcsm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ printk("tcsm: ioctl is not implemented\n"); ++ return ret; ++} ++ ++/* ++ * Module init and exit ++ */ ++ ++static int __init tcsm_init(void) ++{ ++ int ret; ++ ++ ret = jz_register_chrdev(TCSM_MINOR, "tcsm", &tcsm_fops, NULL); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ printk("Virtual Driver of TCSM registered\n"); ++ return 0; ++} ++ ++static void __exit tcsm_exit(void) ++{ ++ jz_unregister_chrdev(TCSM_MINOR, "tcsm"); ++} ++ ++module_init(tcsm_init); ++module_exit(tcsm_exit); +diff --git a/drivers/char/jzchar/ucb1400.c b/drivers/char/jzchar/ucb1400.c +new file mode 100644 +index 0000000..d5d06f7 +--- /dev/null ++++ b/drivers/char/jzchar/ucb1400.c +@@ -0,0 +1,585 @@ ++/* ++ * ucb1400.c ++ * ++ * Touch screen driver interface to the UCB1400 codec. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz_ts.h" ++#include "ucb1400.h" ++ ++#ifndef GPIO_TS_PENIRQ ++#define GPIO_TS_PENIRQ 68 ++#endif ++ ++#define TS_PIN GPIO_TS_PENIRQ ++#define TS_IRQ (IRQ_GPIO_0 + TS_PIN) ++ ++static int samples = 5; /* we sample 5 every time, and throw away the max and min cases, then use the average of the other 3 samples */ ++static int first_time = 0; ++static unsigned long last_x, last_y, last_p; ++ ++static int adcsync = 0; ++ ++static unsigned int ucb_id = 0; ++static struct ucb1400 *ucb; ++ ++extern struct ac97_codec * find_ac97_codec(void); ++ ++extern unsigned int (*codec_read_battery)(void); ++ ++/*------------------ UCB1400 routines ------------------*/ ++ ++static inline void ucb1400_reg_write(unsigned char reg, unsigned short val) ++{ ++ struct ac97_codec *codec = find_ac97_codec(); ++ if (!codec) ++ return; ++ codec->codec_write(codec, reg, val); ++} ++ ++static inline unsigned int ucb1400_reg_read(unsigned char reg) ++{ ++ struct ac97_codec *codec = find_ac97_codec(); ++ if (!codec) ++ return 0; ++ return codec->codec_read(codec, reg); ++} ++ ++static void ucb1400_adc_enable(void) ++{ ++ down(&ucb->adc_sem); ++ ++ ucb->adc_cr |= UCB_ADC_ENA; ++ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr); ++} ++ ++static unsigned int ucb1400_adc_read(int adc_channel, int sync) ++{ ++ unsigned int val, timeout = 10000; ++ ++ if (sync) ++ adc_channel |= UCB_ADC_SYNC_ENA; ++ ++ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr | adc_channel); ++ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START); ++ ++ for (;;) { ++ val = ucb1400_reg_read(UCB_ADC_DATA); ++ if (val & UCB_ADC_DAT_VAL) ++ break; ++ if (--timeout == 0) ++ break; ++ udelay(1); ++ } ++ ++ return UCB_ADC_DAT(val); ++} ++ ++static void ucb1400_adc_disable(void) ++{ ++ ucb->adc_cr &= ~UCB_ADC_ENA; ++ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr); ++ ++ up(&ucb->adc_sem); ++} ++ ++static void ucb1400_enable_irq(unsigned int idx, int edges) ++{ ++ unsigned long flags; ++ ++ if (idx < 16) { ++ spin_lock_irqsave(&ucb->lock, flags); ++ ++ /* This prevents spurious interrupts on the UCB1400 */ ++ ucb1400_reg_write(UCB_IE_CLEAR, 1 << idx); ++ ucb1400_reg_write(UCB_IE_CLEAR, 0); ++ ++ if (edges & UCB_RISING) { ++ ucb->irq_ris_enbl |= 1 << idx; ++ ucb1400_reg_write(UCB_IE_RIS, ucb->irq_ris_enbl); ++ } ++ if (edges & UCB_FALLING) { ++ ucb->irq_fal_enbl |= 1 << idx; ++ ucb1400_reg_write(UCB_IE_FAL, ucb->irq_fal_enbl); ++ } ++ spin_unlock_irqrestore(&ucb->lock, flags); ++ } ++} ++ ++static void ucb1400_disable_irq(unsigned int idx, int edges) ++{ ++ unsigned long flags; ++ ++ if (idx < 16) { ++ spin_lock_irqsave(&ucb->lock, flags); ++ ++ if (edges & UCB_RISING) { ++ ucb->irq_ris_enbl &= ~(1 << idx); ++ ucb1400_reg_write(UCB_IE_RIS, ucb->irq_ris_enbl); ++ } ++ if (edges & UCB_FALLING) { ++ ucb->irq_fal_enbl &= ~(1 << idx); ++ ucb1400_reg_write(UCB_IE_FAL, ucb->irq_fal_enbl); ++ } ++ spin_unlock_irqrestore(&ucb->lock, flags); ++ } ++} ++ ++/* ++ * Switch to interrupt mode. ++ */ ++static inline void ucb1400_ts_mode_int(void) ++{ ++ if (!ucb_id) { ++ ucb_id = ucb1400_reg_read(UCB_ID); ++ } ++ ++ if (ucb_id == UCB_ID_1400_BUGGY) ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); ++ else ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); ++} ++ ++/* ++ * Switch to pressure mode, and read pressure. We don't need to wait ++ * here, since both plates are being driven. ++ */ ++static inline unsigned int ucb1400_ts_read_pressure(void) ++{ ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ ++ return ucb1400_adc_read(UCB_ADC_INP_TSPY, adcsync); ++} ++ ++/* ++ * Switch to X position mode and measure Y plate. We switch the plate ++ * configuration in pressure mode, then switch to position mode. This ++ * gives a faster response time. Even so, we need to wait about 55us ++ * for things to stabilise. ++ */ ++static inline unsigned int ucb1400_ts_read_xpos(void) ++{ ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); ++ ++ udelay(55); ++ ++ return ucb1400_adc_read(UCB_ADC_INP_TSPY, adcsync); ++} ++ ++/* ++ * Switch to Y position mode and measure X plate. We switch the plate ++ * configuration in pressure mode, then switch to position mode. This ++ * gives a faster response time. Even so, we need to wait about 55us ++ * for things to stabilise. ++ */ ++static inline unsigned int ucb1400_ts_read_ypos(void) ++{ ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | ++ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ++ ucb1400_reg_write(UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | ++ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); ++ ++ udelay(55); ++ ++ return ucb1400_adc_read(UCB_ADC_INP_TSPX, adcsync); ++} ++ ++/*------------------------------------------------------------ ++ * Read the battery voltage ++ */ ++ ++unsigned int ucb1400_read_battery(void) ++{ ++ unsigned int v; ++ ++ ucb1400_adc_enable(); ++ ++ // read twice to reduce fault value ++ v = ucb1400_adc_read(UCB_ADC_INP_AD0, adcsync); ++ v = ucb1400_adc_read(UCB_ADC_INP_AD0, adcsync); ++ ++ ucb1400_adc_disable(); ++ ++// printk("ucb1400_read_battery v=%d\n", v); ++ ++ return v; ++} ++ ++/*------------------ Calibrate samples -------------------*/ ++ ++#define DIFF(a,b) ((a>b)?(a-b):(b-a)) ++ ++static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) ++{ ++ unsigned long *xp = (unsigned long *)xbuf; ++ unsigned long *yp = (unsigned long *)ybuf; ++ unsigned long *pp = (unsigned long *)pbuf; ++ unsigned long x_cal = 0, y_cal = 0, p_cal = 0, tmp; ++ int ignored, i, j; ++ int valid = 0; ++ ++ /* throw away the max cases */ ++ tmp = xp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (xp[i] > tmp) { ++ tmp = xp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ xp[j++] = xp[i]; ++ } ++ ++ tmp = yp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (yp[i] > tmp) { ++ tmp = yp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ yp[j++] = yp[i]; ++ } ++ ++ tmp = pp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (pp[i] > tmp) { ++ tmp = pp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ pp[j++] = pp[i]; ++ } ++ ++ /* throw away the min cases */ ++ ++ count -= 1; // decrement by 1 ++ ++ tmp = xp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (xp[i] < tmp) { ++ tmp = xp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ xp[j++] = xp[i]; ++ } ++ ++ tmp = yp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (yp[i] < tmp) { ++ tmp = yp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ yp[j++] = yp[i]; ++ } ++ ++ tmp = pp[0]; ++ ignored = 0; ++ for (i = 1; i < count; i++) { ++ if (pp[i] < tmp) { ++ tmp = pp[i]; ++ ignored = i; ++ } ++ } ++ j = 0; ++ for (i = 0; i < count; i++) { ++ if (i == ignored) ++ continue; ++ pp[j++] = pp[i]; ++ } ++ ++ count -= 1; // decrement by 1 ++ ++ /* calculate the average of the rest */ ++ for (i = 0; i < count; i++) { ++ x_cal += xp[i]; ++ y_cal += yp[i]; ++ p_cal += pp[i]; ++ } ++ x_cal /= count; ++ y_cal /= count; ++ p_cal /= count; ++ ++ if (first_time) { ++ first_time = 0; ++ last_x = x_cal; ++ last_y = y_cal; ++ last_p = p_cal; ++ valid = 1; ++ } ++ else { ++ if ((DIFF(x_cal, last_x) > 50) || ++ (DIFF(y_cal, last_y) > 50)) ++ valid = 0; ++ else ++ valid = 1; ++ } ++ ++// printk("x_cal=%d y_cal=%d p_cal=%d valid=%d\n", x_cal, y_cal, p_cal, valid); ++ ++ if (valid) { ++ *xp = last_x = x_cal; ++ *yp = last_y = y_cal; ++ *pp = last_p = p_cal; ++ } ++ ++ return valid; ++} ++ ++ ++#define TSMAXX 945 ++#define TSMAXY 830 ++#define TSMINX 90 ++#define TSMINY 105 ++ ++#define SCREEN_X 480 ++#define SCREEN_Y 272 ++ ++static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) ++{ ++ ++ if (ts->minx) ++ { ++ if (x < ts->minx) x = ts->minx; ++ if (x > ts->maxx) x = ts->maxx; ++ ++ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); ++ } ++ else ++ { ++ if (x < TSMINX) x = TSMINX; ++ if (x > TSMAXX) x = TSMAXX; ++ ++ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); ++ } ++} ++ ++static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) ++{ ++ if (ts->minx) ++ { ++ if (y < ts->minx) y = ts->miny; ++ if (y > ts->maxx) y = ts->maxy; ++ ++ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); ++ } ++ else ++ { ++ if (y < TSMINX) y = TSMINY; ++ if (y > TSMAXX) y = TSMAXY; ++ ++ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); ++ } ++} ++ ++/*------------------ Common routines -------------------*/ ++ ++void ts_enable_irq(void) ++{ ++ /* interrupt mode */ ++ ucb1400_ts_mode_int(); ++ ucb1400_enable_irq(UCB_IRQ_TSPX, UCB_FALLING); ++ ++ enable_irq(TS_IRQ); ++} ++ ++void ts_disable_irq(void) ++{ ++ ucb1400_disable_irq(UCB_IRQ_TSPX, UCB_FALLING); ++ disable_irq(TS_IRQ); ++} ++ ++int ts_request_irq(u32 *irq, ++ void (*handler)(int, void *, struct pt_regs *), ++ const char *devname, ++ void *dev_id) ++{ ++ int retval; ++ ++ /* return the irq number */ ++ *irq = TS_IRQ; ++ ++ /* interrupt mode */ ++ ucb1400_ts_mode_int(); ++ ucb1400_enable_irq(UCB_IRQ_TSPX, UCB_FALLING); ++ ++ /* enable gpio irq */ ++ __gpio_as_irq_rise_edge(TS_PIN); ++ ++ /* register irq handler */ ++ retval = request_irq(TS_IRQ, handler, SA_INTERRUPT, devname, dev_id); ++ ++ return retval; ++} ++ ++void ts_free_irq(struct jz_ts_t *ts) ++{ ++ free_irq(ts->pendown_irq, ts); ++} ++ ++void ts_irq_callback(void) ++{ ++ /* clear interrupt status */ ++ ucb1400_reg_write(UCB_IE_CLEAR, ucb1400_reg_read(UCB_IE_STATUS)); ++ __gpio_ack_irq(TS_PIN); ++ ++ first_time = 1; // first time to acquire sample ++} ++ ++int PenIsDown(void) ++{ ++ unsigned int p; ++ ++ ucb1400_adc_enable(); ++ p = ucb1400_ts_read_pressure(); ++ ucb1400_adc_disable(); ++ ++ return (p > 100) ? 1 : 0; ++} ++ ++/* ++ * Acquire Raw pen coodinate data and compute touch screen ++ * pressure resistance. Hold spinlock when calling. ++ */ ++int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) ++{ ++ unsigned int x_raw[8], y_raw[8], p_raw[8]; ++ int valid, i; ++ ++ /* Enable ADC */ ++ ucb1400_adc_enable(); ++ ++ for (i = 0; i < samples; i++) { ++ x_raw[i] = ucb1400_ts_read_xpos(); ++ } ++ for (i = 0; i < samples; i++) { ++ y_raw[i] = ucb1400_ts_read_ypos(); ++ } ++ for (i = 0; i < samples; i++) { ++ p_raw[i] = ucb1400_ts_read_pressure(); ++ } ++ ++ /* Disable ADC */ ++ ucb1400_adc_disable(); ++ ++ valid = calibrate_samples(x_raw, y_raw, p_raw, samples); ++ ++ if (valid) { ++ unsigned int x_scr, y_scr; ++ ++ if(ts->filter) { ++ x_scr = transform_to_screen_x(ts, x_raw[0]); ++ y_scr = transform_to_screen_y(ts, y_raw[0]); ++ ++ if (ts->prints) ++ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", x_raw[0], y_raw[0], x_scr, y_scr); ++ } ++ else { ++ x_scr = x_raw[0]; ++ y_scr = y_raw[0]; ++ ++ if (ts->prints) ++ printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); ++ } ++ ++ event->x = x_scr; ++ event->y = y_scr; ++ event->pressure = (u16)p_raw[0]; ++ event->status = PENDOWN; ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * Module init and exit ++ */ ++ ++int __init ucb1400_init(void) ++{ ++ ucb = kmalloc(sizeof(struct ucb1400), GFP_KERNEL); ++ if (!ucb) return -ENOMEM; ++ ++ memset(ucb, 0, sizeof(struct ucb1400)); ++ ++ codec_read_battery = ucb1400_read_battery; ++ ++ spin_lock_init(&ucb->lock); ++ sema_init(&ucb->adc_sem, 1); ++ ++ return 0; ++} ++ ++void ucb1400_cleanup(void) ++{ ++ kfree(ucb); ++} ++ ++module_init(ucb1400_init); ++module_exit(ucb1400_cleanup); +diff --git a/drivers/char/jzchar/ucb1400.h b/drivers/char/jzchar/ucb1400.h +new file mode 100644 +index 0000000..318c004 +--- /dev/null ++++ b/drivers/char/jzchar/ucb1400.h +@@ -0,0 +1,113 @@ ++#ifndef __UCB1400_H__ ++#define __UCB1400_H__ ++ ++/* ucb1400 aclink register mappings */ ++ ++#define UCB_IO_DATA 0x5a ++#define UCB_IO_DIR 0x5c ++#define UCB_IE_RIS 0x5e ++#define UCB_IE_FAL 0x60 ++#define UCB_IE_STATUS 0x62 ++#define UCB_IE_CLEAR 0x62 ++#define UCB_TS_CR 0x64 ++#define UCB_ADC_CR 0x66 ++#define UCB_ADC_DATA 0x68 ++#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */ ++ ++#define UCB_ADC_DAT(x) ((x) & 0x3ff) ++ ++/* register bits */ ++ ++#define UCB_IO_0 (1 << 0) ++#define UCB_IO_1 (1 << 1) ++#define UCB_IO_2 (1 << 2) ++#define UCB_IO_3 (1 << 3) ++#define UCB_IO_4 (1 << 4) ++#define UCB_IO_5 (1 << 5) ++#define UCB_IO_6 (1 << 6) ++#define UCB_IO_7 (1 << 7) ++#define UCB_IO_8 (1 << 8) ++#define UCB_IO_9 (1 << 9) ++ ++#define UCB_IE_ADC (1 << 11) ++#define UCB_IE_TSPX (1 << 12) ++#define UCB_IE_TSMX (1 << 13) ++#define UCB_IE_TCLIP (1 << 14) ++#define UCB_IE_ACLIP (1 << 15) ++ ++#define UCB_IRQ_TSPX 12 ++ ++#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ ++#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ ++ ++#define UCB_TC_B_VOICE_ENA (1 << 3) ++#define UCB_TC_B_CLIP (1 << 4) ++#define UCB_TC_B_ATT (1 << 6) ++#define UCB_TC_B_SIDE_ENA (1 << 11) ++#define UCB_TC_B_MUTE (1 << 13) ++#define UCB_TC_B_IN_ENA (1 << 14) ++#define UCB_TC_B_OUT_ENA (1 << 15) ++ ++#define UCB_AC_B_LOOP (1 << 8) ++#define UCB_AC_B_MUTE (1 << 13) ++#define UCB_AC_B_IN_ENA (1 << 14) ++#define UCB_AC_B_OUT_ENA (1 << 15) ++ ++#define UCB_TS_CR_TSMX_POW (1 << 0) ++#define UCB_TS_CR_TSPX_POW (1 << 1) ++#define UCB_TS_CR_TSMY_POW (1 << 2) ++#define UCB_TS_CR_TSPY_POW (1 << 3) ++#define UCB_TS_CR_TSMX_GND (1 << 4) ++#define UCB_TS_CR_TSPX_GND (1 << 5) ++#define UCB_TS_CR_TSMY_GND (1 << 6) ++#define UCB_TS_CR_TSPY_GND (1 << 7) ++#define UCB_TS_CR_MODE_INT (0 << 8) ++#define UCB_TS_CR_MODE_PRES (1 << 8) ++#define UCB_TS_CR_MODE_POS (2 << 8) ++#define UCB_TS_CR_BIAS_ENA (1 << 11) ++#define UCB_TS_CR_TSPX_LOW (1 << 12) ++#define UCB_TS_CR_TSMX_LOW (1 << 13) ++ ++#define UCB_ADC_SYNC_ENA (1 << 0) ++#define UCB_ADC_VREFBYP_CON (1 << 1) ++#define UCB_ADC_INP_TSPX (0 << 2) ++#define UCB_ADC_INP_TSMX (1 << 2) ++#define UCB_ADC_INP_TSPY (2 << 2) ++#define UCB_ADC_INP_TSMY (3 << 2) ++#define UCB_ADC_INP_AD0 (4 << 2) ++#define UCB_ADC_INP_AD1 (5 << 2) ++#define UCB_ADC_INP_AD2 (6 << 2) ++#define UCB_ADC_INP_AD3 (7 << 2) ++#define UCB_ADC_EXT_REF (1 << 5) ++#define UCB_ADC_START (1 << 7) ++#define UCB_ADC_ENA (1 << 15) ++ ++#define UCB_ADC_DAT_VAL (1 << 15) ++ ++#define UCB_ID_1200 0x1004 ++#define UCB_ID_1300 0x1005 ++#define UCB_ID_1400 0x4304 ++#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */ ++ ++#define UCB_MODE_DYN_VFLAG_ENA (1 << 12) ++#define UCB_MODE_AUD_OFF_CAN (1 << 13) ++ ++/* ++ * Which edges of the IRQ do you want to control today? ++ */ ++#define UCB_RISING (1 << 0) ++#define UCB_FALLING (1 << 1) ++ ++/* Device data structure */ ++ ++struct ucb1400 { ++ spinlock_t lock; ++ struct pm_dev *pmdev; ++ struct semaphore adc_sem; ++ u16 adc_cr; ++ u16 irq_fal_enbl; ++ u16 irq_ris_enbl; ++ int irq_enabled; ++}; ++ ++#endif /* __UCB1400_H__ */ +diff --git a/drivers/char/jzchar/udc_hotplug.c b/drivers/char/jzchar/udc_hotplug.c +new file mode 100644 +index 0000000..1c3e576 +--- /dev/null ++++ b/drivers/char/jzchar/udc_hotplug.c +@@ -0,0 +1,451 @@ ++/* ++ * linux/drivers/char/jzchar/udc_hotplug.c ++ * ++ * New UDC hotplug driver. ++ * ++ * Copyright (C) 2007 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "jzchars.h" ++ ++#ifndef GPIO_UDC_HOTPLUG ++#define GPIO_UDC_HOTPLUG 86 ++#endif ++ ++#define UDC_HOTPLUG_PIN GPIO_UDC_HOTPLUG ++#define UDC_HOTPLUG_IRQ (IRQ_GPIO_0 + UDC_HOTPLUG_PIN) ++ ++#define dprintk(x,...) ++ ++//simple meaning define ++#define NOT_CONNECT 0 ++#define YES_CONNECT 1 ++#define MAX_GPIO_TIME 50 ++ ++#define EVENT_USB_ADD 1 ++#define EVENT_USB_REMOVE 2 ++#define EVENT_POWER_ADD 3 ++#define EVENT_POWER_REMOVE 4 ++#define EVENT_POWER_TO_USB 5 ++#define EVENT_USB_SUSPEND_POWER 6 ++ ++struct udc_pnp_stat ++{ ++ char cable_stat, old_cable_stat; ++ char protl_stat, old_protl_stat; ++ char object_stat1; ++ char object_stat2; ++}; ++ ++static struct udc_pnp_stat cur_pnp_stat; ++ ++static struct file_operations cable_fops = { ++ owner: THIS_MODULE, ++}; ++ ++static struct miscdevice cable_dev= ++{ ++ 231, ++ "udc_cable", ++ &cable_fops ++}; ++ ++static struct file_operations power_fops = { ++ owner: THIS_MODULE, ++}; ++ ++static struct miscdevice power_dev= ++{ ++ 232, ++ "power_cable", ++ &power_fops ++}; ++ ++int jz_udc_active = 0; /* 0: Have no actions; 1: Have actions */ ++ ++static int udc_pin_level; ++static int udc_old_state; ++static int udc_pin_time; ++ ++static struct timer_list udc_long_timer, udc_gpio_timer; ++ ++/* Kernel thread to deliver event to user space */ ++static struct task_struct *kudcd_task; ++ ++static void udc_gpio_timer_routine(unsigned long data) ++{ ++ wake_up_process(kudcd_task); ++} ++ ++static void udc_long_timer_routine(unsigned long data) ++{ ++ dprintk("udc_timer\n"); ++ if (jz_udc_active) ++ udc_old_state = 1; ++ if (!jz_udc_active && udc_old_state) //udc irq timeout! do suspend ++ { ++ dprintk("udc suspend!\n"); ++ udc_old_state = 0; ++ cur_pnp_stat.protl_stat = NOT_CONNECT; ++ del_timer(&udc_long_timer); ++ wake_up_process(kudcd_task); ++ return; ++ } ++ jz_udc_active = 0; ++ udc_long_timer.expires = jiffies + 3 * HZ; /* about 3 s */ ++ add_timer(&udc_long_timer); ++} ++ ++static int udc_get_pnp_stat(void) ++{ ++ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN); ++ udc_pin_time = 1; ++ ++ init_timer(&udc_gpio_timer); ++ del_timer(&udc_gpio_timer); ++ udc_gpio_timer.function = udc_gpio_timer_routine; ++ udc_gpio_timer.expires = jiffies + 1; /* about 10 ms */ ++ add_timer(&udc_gpio_timer); ++ ++ while(1) ++ { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ ++ if (__gpio_get_pin(UDC_HOTPLUG_PIN) != udc_pin_level) ++ { ++ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN); ++ udc_pin_time = 1; ++ dprintk("udc gpio detect restart! \n"); ++ } ++ ++ udc_pin_time ++; ++ if (udc_pin_time > MAX_GPIO_TIME) ++ break; ++ ++ del_timer(&udc_gpio_timer); ++ udc_gpio_timer.function = udc_gpio_timer_routine; ++ udc_gpio_timer.expires = jiffies + 1; /* about 10 ms */ ++ add_timer(&udc_gpio_timer); ++ } ++ ++ del_timer(&udc_gpio_timer); ++ if (__gpio_get_pin(UDC_HOTPLUG_PIN)) ++ return YES_CONNECT; ++ else ++ return NOT_CONNECT; ++} ++ ++static void udc_get_cable(void) ++{ ++ u32 intr_usb; ++ ++ __intc_mask_irq(IRQ_UDC); ++ ++ /* Now enable PHY to start detect */ ++#ifdef CONFIG_SOC_JZ4740 ++ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; ++#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE; ++#endif ++ /* Clear IRQs */ ++ REG16(USB_REG_INTRINE) = 0; ++ REG16(USB_REG_INTROUTE) = 0; ++ REG8(USB_REG_INTRUSBE) = 0; ++ ++ /* disable UDC IRQs first */ ++ REG16(USB_REG_INTRINE) = 0; ++ REG16(USB_REG_INTROUTE) = 0; ++ REG8(USB_REG_INTRUSBE) = 0; ++ ++ /* Disable DMA */ ++ REG32(USB_REG_CNTL1) = 0; ++ REG32(USB_REG_CNTL2) = 0; ++ ++ /* Enable HS Mode */ ++ REG8(USB_REG_POWER) |= USB_POWER_HSENAB; ++ /* Enable soft connect */ ++ REG8(USB_REG_POWER) |= USB_POWER_SOFTCONN; ++ ++ dprintk("enable phy! %x %x %x %x %x\n", ++ REG8(USB_REG_POWER), ++ REG_CPM_SCR, ++ REG16(USB_REG_INTRINE), ++ REG16(USB_REG_INTROUTE), ++ REG8(USB_REG_INTRUSBE)); ++ ++ init_timer(&udc_gpio_timer); ++ del_timer(&udc_gpio_timer); ++ udc_gpio_timer.function = udc_gpio_timer_routine; ++ udc_gpio_timer.expires = jiffies + 11; /* about 100 ms */ ++ add_timer(&udc_gpio_timer); ++ /* Sleep a short time to see result */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ ++ del_timer(&udc_gpio_timer); ++ intr_usb = REG8(USB_REG_INTRUSB); ++ if ((intr_usb & USB_INTR_RESET) || ++ (intr_usb & USB_INTR_RESUME) || ++ (intr_usb & USB_INTR_SUSPEND)) ++ { ++ cur_pnp_stat.protl_stat = YES_CONNECT; ++ dprintk("cable is usb! \n"); ++ } ++ else ++ { ++ cur_pnp_stat.protl_stat = NOT_CONNECT; ++ dprintk("cable is power! \n"); ++ } ++ ++ /* Detect finish ,clean every thing */ ++ /* Disconnect from usb */ ++ REG8(USB_REG_POWER) &= ~USB_POWER_SOFTCONN; ++ /* Disable the USB PHY */ ++#ifdef CONFIG_SOC_JZ4740 ++ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE; ++#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; ++#endif ++ /* Clear IRQs */ ++ REG16(USB_REG_INTRINE) = 0; ++ REG16(USB_REG_INTROUTE) = 0; ++ REG8(USB_REG_INTRUSBE) = 0; ++ __intc_ack_irq(IRQ_UDC); ++ __intc_unmask_irq(IRQ_UDC); ++} ++ ++static void send_event_udev(int event) ++{ ++ dprintk("Send udev message: cable=%d old=%d protl=%d old=%d \n", ++ cur_pnp_stat.cable_stat, ++ cur_pnp_stat.old_cable_stat, ++ cur_pnp_stat.protl_stat, ++ cur_pnp_stat.old_protl_stat); ++ ++ switch (event) ++ { ++ case EVENT_USB_ADD: ++ printk("usb cable insert! \n"); ++ misc_register(&cable_dev); ++ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_ADD); ++ init_timer(&udc_long_timer); ++ del_timer(&udc_long_timer); ++ udc_long_timer.function = udc_long_timer_routine; ++ udc_long_timer.expires = jiffies + 3 * HZ; /* about 3 s */ ++ add_timer(&udc_long_timer); ++ break; ++ case EVENT_USB_REMOVE: ++ printk("usb cable remove! \n"); ++ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_REMOVE); ++ misc_deregister(&cable_dev); ++ del_timer(&udc_long_timer); ++ break; ++ case EVENT_POWER_ADD: ++ printk("power cable insert! \n"); ++ misc_register(&power_dev); ++ kobject_uevent(&power_dev.this_device->kobj, KOBJ_ADD); ++ break; ++ case EVENT_POWER_REMOVE: ++ printk("power cable remove! \n"); ++ kobject_uevent(&power_dev.this_device->kobj, KOBJ_REMOVE); ++ misc_deregister(&power_dev); ++ break; ++ case EVENT_POWER_TO_USB: ++ printk("change power cable to usb! \n"); ++ kobject_uevent(&power_dev.this_device->kobj, KOBJ_REMOVE); ++ misc_deregister(&power_dev); ++ misc_register(&cable_dev); ++ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_ADD); ++ break; ++ case EVENT_USB_SUSPEND_POWER: ++ printk("usb cable suspend! \n"); ++ printk("as power cable insert! \n"); ++ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_REMOVE); ++ misc_deregister(&cable_dev); ++ misc_register(&power_dev); ++ kobject_uevent(&power_dev.this_device->kobj, KOBJ_ADD); ++ break; ++ }; ++} ++ ++static void udc_pnp_detect(void) ++{ ++ if (cur_pnp_stat.cable_stat == YES_CONNECT) /* already connected! */ ++ { ++ if (udc_get_pnp_stat() == NOT_CONNECT) ++ { ++ dprintk("cable real out! \n"); ++ cur_pnp_stat.cable_stat = NOT_CONNECT; ++ cur_pnp_stat.protl_stat = NOT_CONNECT; ++ /* Deliver this event to user space in udev model */ ++ if (cur_pnp_stat.old_protl_stat) ++ send_event_udev(EVENT_USB_REMOVE); ++ else ++ send_event_udev(EVENT_POWER_REMOVE); ++ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; ++ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; ++ } ++ else ++ { ++ if (cur_pnp_stat.old_protl_stat != cur_pnp_stat.protl_stat) ++ { ++ send_event_udev(EVENT_USB_SUSPEND_POWER); ++ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; ++ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; ++ } ++ else //change power to cable ++ { ++#if 0 //not support yet! ++ udc_get_cable(); ++ if (cur_pnp_stat.old_protl_stat != cur_pnp_stat.protl_stat) ++ send_event_udev(EVENT_POWER_TO_USB); ++ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; ++ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; ++#endif ++ } ++ } ++ } ++ else ++ { ++ if (udc_get_pnp_stat() == YES_CONNECT) ++ { ++ dprintk("cable real in! \n"); ++ cur_pnp_stat.cable_stat = YES_CONNECT; ++ udc_get_cable(); ++ /* Deliver this event to user space in udev model */ ++ if (cur_pnp_stat.protl_stat) ++ send_event_udev(EVENT_USB_ADD); ++ else ++ send_event_udev(EVENT_POWER_ADD); ++ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; ++ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; ++ } ++ else ++ dprintk("cable false in! \n"); ++ ++ } ++} ++ ++static void udc_pnp_set_gpio(void) ++{ ++ if (cur_pnp_stat.cable_stat == YES_CONNECT) ++ __gpio_as_irq_fall_edge(UDC_HOTPLUG_PIN); ++ else ++ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN); ++ ++ /* clear interrupt pending status */ ++ __gpio_ack_irq(UDC_HOTPLUG_PIN); ++ /* unmask interrupt */ ++ __gpio_unmask_irq(UDC_HOTPLUG_PIN); ++} ++ ++static int udc_pnp_thread(void *unused) ++{ ++ printk(KERN_NOTICE "UDC starting pnp monitor thread\n"); ++ ++ while(1) ++ { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ ++ dprintk("pnp thread wake up! \n"); ++ /* wake up here */ ++ udc_pnp_detect(); ++ /* Reset gpio state last */ ++ udc_pnp_set_gpio(); ++ } ++} ++ ++static irqreturn_t udc_pnp_irq(int irq, void *dev_id) ++{ ++ printk("udc_pnp_irq----\n"); ++ /* clear interrupt pending status */ ++ __gpio_ack_irq(UDC_HOTPLUG_PIN); ++ /* mask interrupt */ ++ __gpio_mask_irq(UDC_HOTPLUG_PIN); ++ /* wake up pnp detect thread */ ++ wake_up_process(kudcd_task); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Module init and exit ++ */ ++static int __init udc_hotplug_init(void) ++{ ++ int retval; ++ /* Init pnp stat first */ ++ cur_pnp_stat.cable_stat = NOT_CONNECT; ++ cur_pnp_stat.protl_stat = NOT_CONNECT; ++ cur_pnp_stat.old_cable_stat = NOT_CONNECT; ++ cur_pnp_stat.old_protl_stat = NOT_CONNECT; ++ cur_pnp_stat.object_stat1 = NOT_CONNECT; ++ cur_pnp_stat.object_stat2 = NOT_CONNECT; ++ udc_old_state = 0; ++ ++ /* create pnp thread and register IRQ */ ++ kudcd_task = kthread_run(udc_pnp_thread, NULL, "kudcd"); ++ if (IS_ERR(kudcd_task)) { ++ printk(KERN_ERR "jz_udc_hotplug: Failed to create system monitor thread.\n"); ++ return PTR_ERR(kudcd_task); ++ } ++ ++ retval = request_irq(UDC_HOTPLUG_IRQ, udc_pnp_irq, ++ IRQF_DISABLED, "udc_pnp", NULL); ++ if (retval) { ++ printk("Could not get udc hotplug irq %d\n", UDC_HOTPLUG_IRQ); ++ return retval; ++ } ++ ++ /* get current pin level */ ++ __gpio_disable_pull(UDC_HOTPLUG_PIN); ++ __gpio_as_input(UDC_HOTPLUG_PIN); ++ udelay(1); ++ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN); ++ ++ if (udc_pin_level) { ++ dprintk("Cable already in! \n"); ++ /* Post a event */ ++ wake_up_process(kudcd_task); ++ } ++ else { ++ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN); ++ dprintk("Cable not in! \n"); ++ } ++ ++ printk("JZ UDC hotplug driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit udc_hotplug_exit(void) ++{ ++ free_irq(UDC_HOTPLUG_IRQ, NULL); ++} ++ ++module_init(udc_hotplug_init); ++module_exit(udc_hotplug_exit); ++ ++EXPORT_SYMBOL(jz_udc_active); ++ ++MODULE_AUTHOR("Lucifer "); ++MODULE_DESCRIPTION("JzSOC OnChip udc hotplug driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/char/jzchar/wm9712.c b/drivers/char/jzchar/wm9712.c +new file mode 100644 +index 0000000..de75435 +--- /dev/null ++++ b/drivers/char/jzchar/wm9712.c +@@ -0,0 +1,334 @@ ++/* ++ * wm9712.c ++ * ++ * Touch screen driver interface to the Wolfson WM9712 codec. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz_ts.h" ++#include "wm9712.h" ++ ++#define POLL_TIMES 10 ++ ++static int samples = 1; ++static int inited = 0, started = 0; ++ ++extern struct ac97_codec * find_ac97_codec(void); ++extern int PenIsDown(void); ++ ++ ++static inline void wm9712_reg_write(unsigned int reg, unsigned int val) ++{ ++ struct ac97_codec *codec = find_ac97_codec(); ++ if (!codec) ++ return; ++ codec->codec_write(codec, reg, val); ++} ++ ++static inline unsigned int wm9712_reg_read(unsigned int reg) ++{ ++ struct ac97_codec *codec = find_ac97_codec(); ++ if (!codec) ++ return 0; ++ return codec->codec_read(codec, reg); ++} ++ ++static unsigned int wm9712_adc_read(int adc_channel) ++{ ++ unsigned int val; ++ ++ if (!PenIsDown()) ++ return 0; ++ ++ val = wm9712_reg_read(DIGI_REG1); ++ wm9712_reg_write(DIGI_REG1, val|adc_channel|DIGI_REG1_POLL); ++ ++ for (;;) { ++ if (wm9712_reg_read(0x54) & (1 << 12)) { ++ val = wm9712_reg_read(DIGI_READBACK); ++ break; ++ } ++ } ++ ++ /* stop the measure */ ++ wm9712_reg_write(DIGI_REG1, 0); ++ ++ return (val & 0x0fff); ++} ++ ++static struct timer_list pndn_timer; ++static void (*irq_handler)(int, void *, struct pt_regs *) = NULL; ++ ++void ts_irq_callback(void) ++{ ++#ifdef TS_IRQ ++ __gpio_ack_irq(TS_IRQ); ++#else ++#endif ++} ++ ++void ts_enable_irq(void) ++{ ++ if (!inited) ++ return; ++#ifdef TS_IRQ ++ enable_irq(TS_IRQ); ++#else ++ pndn_timer.expires = jiffies + HZ/POLL_TIMES; ++ add_timer(&pndn_timer); ++#endif ++} ++ ++void ts_disable_irq(void) ++{ ++ if (!inited) ++ return; ++#ifdef TS_IRQ ++ disable_irq(TS_IRQ); ++#endif ++} ++ ++#ifndef TS_IRQ ++static void pndn_detect(unsigned long data) ++{ ++ if (PenIsDown()) { ++ if (!started) ++ return; ++ if (irq_handler) ++ irq_handler(NULL, data, NULL); ++ } else { ++ pndn_timer.expires = jiffies + HZ/POLL_TIMES; ++ add_timer(&pndn_timer); ++ } ++} ++#endif ++ ++void ts_free_irq(struct jz_ts_t *ts) ++{ ++#ifdef TS_IRQ ++ free_irq(ts->pendown_irq, ts); ++#else ++ started = 0; ++ del_timer_sync(&pndn_timer); ++#endif ++} ++ ++int ts_request_irq(u32 *irq, ++ void (*handler)(int, void *, struct pt_regs *), ++ const char *devname, ++ void *dev_id) ++{ ++ /* 4wire, Ip=400uA, Rpu=64Kohm/64, wake-up on pendown without ++ * reset, meassure on pen down. Do not use wait mode. ++ */ ++ started = 1; ++ if (!inited) { ++ wm9712_reg_write(DIGI_REG2, ++ DIGI_REG2_WIRE_4 | ++ DIGI_REG2_PIL_200uA | ++ (31 << DIGI_REG2_RPU_BIT) | ++ DIGI_REG2_PRP_ALLON | ++ DIGI_REG2_RPR_NWOR); ++ /* Polling mode and no measurement */ ++ wm9712_reg_write(DIGI_REG1, 0); ++ } ++ ++#ifdef TS_IRQ ++ /* Generate irq request on PENDOWN pin, pendown cause the level high */ ++ wm9712_reg_write(0x56, wm9712_reg_read(0x56) & ~(1 << 3)); ++ wm9712_reg_write(0x4c, wm9712_reg_read(0x4c) & ~(1 << 3)); ++ ++ *irq = TS_IRQ; ++ return request_irq(TS_IRQ, handler, SA_INTERRUPT, devname, dev_id); ++#else ++ if (!inited) { ++ irq_handler = handler; ++ init_timer(&pndn_timer); ++ pndn_timer.function = pndn_detect; ++ pndn_timer.data = (unsigned long)dev_id; ++ pndn_timer.expires = jiffies + HZ/POLL_TIMES; ++ add_timer(&pndn_timer); ++ inited = 1; ++ } else { ++ pndn_timer.expires = jiffies + HZ/POLL_TIMES; ++ add_timer(&pndn_timer); ++ } ++ return 0; ++#endif ++} ++ ++int PenIsDown(void) ++{ ++ if (wm9712_reg_read(DIGI_READBACK) & DIGI_READBACK_PNDN) ++ return 1; ++ return 0; ++} ++ ++#if defined(CONFIG_MIPS_JZ4730_GPS) ++#define adj_data(r1, r2, r3, s) \ ++do { \ ++ if (r1 < 0x90) \ ++ r1 = 0x90; \ ++ if (r2 < 0xed) \ ++ r2 = 0xed; \ ++ r1 = ((r1 - 0x90) * 240) / 3354; \ ++ r2 = ((r2 - 0xed) * 320) / 3671; \ ++ if (r1 > 239) \ ++ r1 = 239; \ ++ if (r2 > 319) \ ++ r2 = 319; \ ++ \ ++ *s = r2; \ ++ *(s+1) = 239 - r1; \ ++ *(s+2) = z_raw; \ ++} while (0) ++#endif ++ ++#ifndef adj_data ++#define adj_data(r1, r2, r3, s) ++#endif ++ ++static int read_adc(unsigned int *sdata) ++{ ++ unsigned long x_raw=0, y_raw=0, z_raw=0, t, fail = 0; ++ int i; ++ ++ for (i=0; i 1) { ++ x_raw = (x_raw + (samples>>1)) / samples; ++ y_raw = (y_raw + (samples>>1)) / samples; ++ z_raw = (z_raw + (samples>>1)) / samples; ++ } ++ ++ adj_data (x_raw, y_raw, z_raw, sdata); ++ ++ return 1; ++} ++ ++ ++#define TSMAXX 945 ++#define TSMAXY 830 ++#define TSMINX 90 ++#define TSMINY 105 ++ ++#define SCREEN_X 480 ++#define SCREEN_Y 272 ++ ++static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) ++{ ++ ++ if (ts->minx) ++ { ++ if (x < ts->minx) x = ts->minx; ++ if (x > ts->maxx) x = ts->maxx; ++ ++ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); ++ } ++ else ++ { ++ if (x < TSMINX) x = TSMINX; ++ if (x > TSMAXX) x = TSMAXX; ++ ++ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); ++ } ++} ++ ++static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) ++{ ++ if (ts->minx) ++ { ++ if (y < ts->minx) y = ts->miny; ++ if (y > ts->maxx) y = ts->maxy; ++ ++ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); ++ } ++ else ++ { ++ if (y < TSMINX) y = TSMINY; ++ if (y > TSMAXX) y = TSMAXY; ++ ++ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); ++ } ++} ++ ++ ++/* ++ * Acquire Raw pen coodinate data and compute touch screen ++ * pressure resistance. Hold spinlock when calling. ++ */ ++int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) ++{ ++ unsigned int s[3]; ++ unsigned int x_scr, y_scr; ++ if (!read_adc(s)) ++ return 0; ++ if(ts->filter) { ++ x_scr = transform_to_screen_x(ts, s[0]); ++ y_scr = transform_to_screen_y(ts, s[1]); ++ ++ if (ts->prints) ++ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", s[0], s[1], x_scr, y_scr); } ++ else { ++ x_scr = s[0]; ++ y_scr = s[1]; ++ ++ if (ts->prints) ++ printk("x_raw=%d y_raw=%d \n", s[0], s[1]); ++ } ++ event->x = x_scr; ++ event->y = y_scr; ++ event->pressure = (u16)s[2]; ++ event->status = PENDOWN; ++ return 1; ++#if 0 ++ do_gettimeofday(&event->stamp); ++#endif ++} ++ ++int __init wm9712_init(void) ++{ ++ return 0; ++} ++ ++void wm9712_cleanup(void) ++{ ++} ++ ++module_init(wm9712_init); ++module_exit(wm9712_cleanup); ++ +diff --git a/drivers/char/jzchar/wm9712.h b/drivers/char/jzchar/wm9712.h +new file mode 100644 +index 0000000..7cd9e5c +--- /dev/null ++++ b/drivers/char/jzchar/wm9712.h +@@ -0,0 +1,58 @@ ++#ifndef __WM9712_H__ ++#define __WM9712_H__ ++ ++#define DIGI_REG1 0x76 ++#define DIGI_REG2 0x78 ++#define DIGI_READBACK 0x7A ++ ++#define ADCSEL_BIT 12 ++#define ADCSEL_MASK (7 << ADCSEL_BIT) ++#define ADCSEL_NONE (0 << ADCSEL_BIT) ++#define ADCSEL_XPOS (1 << ADCSEL_BIT) ++#define ADCSEL_YPOS (2 << ADCSEL_BIT) ++#define ADCSEL_PRESSURE (3 << ADCSEL_BIT) ++#define ADCSEL_COMP1 (4 << ADCSEL_BIT) ++#define ADCSEL_COMP2 (5 << ADCSEL_BIT) ++#define ADCSEL_BMON (6 << ADCSEL_BIT) ++#define ADCSEL_WIPER (7 << ADCSEL_BIT) ++ ++#define DIGI_REG1_CTC (1 << 10) ++#define DIGI_REG1_POLL (1 << 15) ++#define DIGI_REG1_CR_BIT 8 ++#define DIGI_REG1_CR_MASK (3 << DIGI_REG1_CR_BIT) ++#define DIGI_REG1_COO (1 << 11) ++#define DIGI_REG1_SLEN (1 << 3) ++#define DIGI_REG1_SLT_BIT 0 ++#define DIGI_REG1_SLT_MASK (7 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_5 (0 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_6 (1 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_7 (2 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_8 (3 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_9 (4 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_10 (5 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_11 (6 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_SLT_RES (7 << DIGI_REG1_SLT_BIT) ++#define DIGI_REG1_DEL_BIT 4 ++#define DIGI_REG1_DEL_MASK (0x0f << DIGI_REG1_DEL_BIT) ++ ++#define DIGI_REG2_WIRE_5 (1 << 12) ++#define DIGI_REG2_WIRE_4 (0 << 12) ++#define DIGI_REG2_RPU_BIT 0 ++#define DIGI_REG2_RPU_MASK (0x3f << DIGI_REG2_RPU_BIT) ++#define DIGI_REG2_PIL_400uA (1 << 8) ++#define DIGI_REG2_PIL_200uA (0 << 8) ++#define DIGI_REG2_PRP_BIT 14 ++#define DIGI_REG2_PRP_MASK (3 << DIGI_REG2_PRP_BIT) ++#define DIGI_REG2_PRP_ALLOFF (0 << DIGI_REG2_PRP_BIT) ++#define DIGI_REG2_PRP_WOP (1 << DIGI_REG2_PRP_BIT) ++#define DIGI_REG2_PRP_NWOP (2 << DIGI_REG2_PRP_BIT) ++#define DIGI_REG2_PRP_ALLON (3 << DIGI_REG2_PRP_BIT) ++#define DIGI_REG2_RPR_WOR (0 << 13) ++#define DIGI_REG2_RPR_NWOR (1 << 13) ++#define DIGI_REG2_PDEN (1 << 11) ++#define DIGI_REG2_WAIT (1 << 9) ++ ++#define DIGI_READBACK_PNDN (1 << 15) ++ ++#endif /* __WM9712_H__ */ ++ +diff --git a/drivers/char/rtc_jz.c b/drivers/char/rtc_jz.c +new file mode 100644 +index 0000000..55da710 +--- /dev/null ++++ b/drivers/char/rtc_jz.c +@@ -0,0 +1,503 @@ ++/* ++ * Jz OnChip Real Time Clock interface for Linux ++ * ++ * NOTE: we need to wait rtc write ready before read or write RTC registers. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* get the user-level API */ ++#include ++#include ++ ++#include "rtc_jz.h" ++ ++ ++char sbin_rtc_alarm_handler_path[] = "/sbin/rtcalarm"; ++//call_usermodehelper(char *path, char **argv, char **envp, int wait) ++//extern int call_usermodehelper(char *path, char **argv, char **envp); ++ ++extern spinlock_t rtc_lock; ++ ++static int rtc_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++ ++static void get_rtc_time (struct rtc_time *rtc_tm); ++static int set_rtc_time (struct rtc_time *rtc_tm); ++static void get_rtc_alm_time (struct rtc_time *alm_tm); ++static int set_rtc_alm_time (struct rtc_time *alm_tm); ++ ++static void set_rtc_irq_bit(int bit); ++static void mask_rtc_irq_bit(int bit); ++ ++static unsigned int rtc_status = 0; ++static unsigned int epoch = 1900; ++ ++static void get_rtc_time(struct rtc_time *rtc_tm) ++{ ++ unsigned long lval; ++ struct rtc_time ltm; ++ ++ spin_lock_irq(&rtc_lock); ++ while ( !__rtc_write_ready() ) ; ++ lval = REG_RTC_RSR; ++ rtc_time_to_tm(lval, <m); ++ if(rtc_valid_tm(<m) == 0) { ++ /* is valid */ ++ rtc_tm->tm_sec = ltm.tm_sec; ++ rtc_tm->tm_min = ltm.tm_min; ++ rtc_tm->tm_hour = ltm.tm_hour; ++ rtc_tm->tm_mday = ltm.tm_mday; ++ rtc_tm->tm_wday = ltm.tm_wday; ++ rtc_tm->tm_mon = ltm.tm_mon; ++ rtc_tm->tm_year = ltm.tm_year; ++ } else { ++ printk("invlaid data / time!\n"); ++ } ++ spin_unlock_irq(&rtc_lock); ++} ++ ++static int set_rtc_time(struct rtc_time *rtc_tm) ++{ ++ unsigned long lval; ++ ++ rtc_tm_to_time(rtc_tm, &lval); ++ ++ spin_lock_irq(&rtc_lock); ++ while ( !__rtc_write_ready() ) ; ++ REG_RTC_RSR = lval; ++ ++ spin_unlock_irq(&rtc_lock); ++ ++ return 0; ++ ++} ++ ++static void get_rtc_alm_time(struct rtc_time *alm_tm) ++{ ++ unsigned long lval; ++ struct rtc_time altm; ++ ++ spin_lock_irq(&rtc_lock); ++ while ( !__rtc_write_ready() ) ; ++ lval = REG_RTC_RSAR; ++ rtc_time_to_tm(lval, &altm); ++ if(rtc_valid_tm(&altm) == 0) { ++ /* is valid */ ++ alm_tm->tm_sec = altm.tm_sec; ++ alm_tm->tm_min = altm.tm_min; ++ alm_tm->tm_hour = altm.tm_hour; ++ alm_tm->tm_mday = altm.tm_mday; ++ alm_tm->tm_wday = altm.tm_wday; ++ alm_tm->tm_mon = altm.tm_mon; ++ alm_tm->tm_year = altm.tm_year; ++ } else { ++ printk("invlaid data / time in Line:%d!\n",__LINE__); ++ } ++ spin_unlock_irq(&rtc_lock); ++} ++ ++static int set_rtc_alm_time(struct rtc_time *alm_tm) ++{ ++ unsigned long lval; ++ ++ rtc_tm_to_time(alm_tm, &lval); ++ ++ spin_lock_irq(&rtc_lock); ++ while ( !__rtc_write_ready() ) ; ++ REG_RTC_RSAR = lval; ++ ++ while ( !__rtc_write_ready() ) ; /* set alarm function */ ++ if ( !((REG_RTC_RCR>>2) & 0x1) ) { ++ while ( !__rtc_write_ready() ) ; ++ __rtc_enable_alarm(); ++ } ++ ++ while ( !__rtc_write_ready() ) ; ++ if ( !(REG_RTC_RCR & RTC_RCR_AIE) ) { /* Enable alarm irq */ ++ __rtc_enable_alarm_irq(); ++ } ++ ++ spin_unlock_irq(&rtc_lock); ++ ++ return 0; ++} ++ ++static void get_rtc_wakeup_alarm(struct rtc_wkalrm *wkalm) ++{ ++ int enabled, pending; ++ ++ get_rtc_alm_time(&wkalm->time); ++ ++ spin_lock_irq(&rtc_lock); ++ while ( !__rtc_write_ready() ) ; ++ enabled = (REG_RTC_HWCR & 0x1); ++ pending = 0; ++ if ( enabled ) { ++ if ( (u32)REG_RTC_RSAR > (u32)REG_RTC_RSR ) /* 32bit val */ ++ pending = 1; ++ } ++ ++ wkalm->enabled = enabled; ++ wkalm->pending = pending; ++ spin_unlock_irq(&rtc_lock); ++} ++ ++static int set_rtc_wakeup_alarm(struct rtc_wkalrm *wkalm) ++{ ++ int enabled; ++ //int pending; ++ ++ enabled = wkalm->enabled; ++ //pending = wkalm->pending; /* Fix me, what's pending mean??? */ ++ ++ while ( !__rtc_write_ready() ) ; /* set wakeup alarm enable */ ++ if ( enabled != (REG_RTC_HWCR & 0x1) ) { ++ while ( !__rtc_write_ready() ) ; ++ REG_RTC_HWCR = (REG_RTC_HWCR & ~0x1) | enabled; ++ } ++ while ( !__rtc_write_ready() ) ; /* set alarm function */ ++ if ( enabled != ((REG_RTC_RCR>>2) & 0x1) ) { ++ while ( !__rtc_write_ready() ) ; ++ REG_RTC_RCR = (REG_RTC_RCR & ~(1<<2)) | (enabled<<2); ++ } ++ ++ if ( !enabled ) /* if disabled wkalrm, rturn. */ ++ { ++ return 0; ++ } ++ ++ while ( !__rtc_write_ready() ) ; ++ if ( !(REG_RTC_RCR & RTC_RCR_AIE) ) { /* Enable alarm irq */ ++ __rtc_enable_alarm_irq(); ++ } ++ ++ set_rtc_alm_time(&wkalm->time); ++ ++ return 0; ++} ++ ++ ++static void set_rtc_irq_bit( int bit ) ++{ ++ spin_lock_irq(&rtc_lock); ++ ++ while ( !__rtc_write_ready() ) ; ++ REG_RTC_RCR |= (1<= 0xc0 ++ * means "don't care" or "match all". Only the tm_hour, ++ * tm_min, and tm_sec values are filled in. ++ */ ++ ++ get_rtc_alm_time(&wtime); ++ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; ++ ++ case RTC_ALM_SET: /* Store a time into the alarm */ ++ { ++ struct rtc_time alm_tm; ++ ++ if (copy_from_user(&alm_tm, (struct rtc_time*)arg, ++ sizeof(struct rtc_time))) ++ return -EFAULT; ++ if(rtc_valid_tm(&alm_tm) != 0) { ++ printk("invalid time set in Line:%d! \n",__LINE__); ++ return -EFAULT; ++ } ++ ++ return set_rtc_alm_time(&alm_tm); ++ } ++ case RTC_RD_TIME: /* Read the time/date from RTC */ ++ get_rtc_time(&wtime); ++ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; ++ case RTC_SET_TIME: /* Set the RTC */ ++ { ++ struct rtc_time rtc_tm; ++ ++ if (!capable(CAP_SYS_TIME)) ++ return -EACCES; ++ ++ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, ++ sizeof(struct rtc_time))) ++ return -EFAULT; ++ if(rtc_valid_tm(&rtc_tm) != 0) { ++ printk("invalid time set in Line:%d! \n",__LINE__); ++ return -EFAULT; ++ } ++ ++ return set_rtc_time(&rtc_tm); ++ } ++ case RTC_EPOCH_READ: /* Read the epoch. */ ++ return put_user (epoch, (unsigned long *)arg); ++ case RTC_EPOCH_SET: /* Set the epoch. */ ++ /* ++ * There were no RTC clocks before 1900. ++ */ ++ if (arg < 1900) ++ return -EINVAL; ++ ++ if (!capable(CAP_SYS_TIME)) ++ return -EACCES; ++ ++ epoch = arg; ++ return 0; ++ case RTC_WKALM_SET: /* Wake alarm set. */ ++ { ++ struct rtc_wkalrm wkalrm; ++ ++ if (copy_from_user(&wkalrm, (struct rtc_wkalrm*)arg, ++ sizeof(struct rtc_wkalrm))) ++ return -EFAULT; ++ return set_rtc_wakeup_alarm(&wkalrm); ++ } ++ case RTC_WKALM_RD: /* Wake alarm read. */ ++ { ++ struct rtc_wkalrm wkalrm; ++ get_rtc_wakeup_alarm(&wkalrm); ++ return copy_to_user((void *)arg, &wkalrm, sizeof(struct rtc_wkalrm)) ? -EFAULT : 0; ++ } ++ /* set power down: shut down the machine. */ ++ case RTC_POWER_DOWN: /* enter HIBERNATE mode */ ++ dprintk("Power down. Bye....\n"); ++ while ( !__rtc_write_ready() ) ; ++ REG_RTC_HCR = 0x1; ++ return 0; ++#ifdef DEBUG ++ case RTC_PRINT_REG: /* Print RTC registers */ ++ print_rtc_registers(); ++ return 0; ++#endif ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * We enforce only one user at a time here with the open/close. ++ * Also clear the previous interrupt data on an open, and clean ++ * up things on a close. ++ */ ++ ++/* We use rtc_lock to protect against concurrent opens. So the BKL is not ++ * needed here. Or anywhere else in this driver. */ ++static int rtc_open(struct inode *inode, struct file *file) ++{ ++ spin_lock_irq (&rtc_lock); ++ ++ if(rtc_status) ++ goto out_busy; ++ ++ rtc_status = 1; ++ ++ spin_unlock_irq (&rtc_lock); ++ return 0; ++ ++out_busy: ++ return -EBUSY; ++} ++ ++static int rtc_release(struct inode *inode, struct file *file) ++{ ++ ++ rtc_status = 0; ++ /* No need for locking -- nobody else can do anything until this rmw is ++ * committed, and no timer is running. */ ++ return 0; ++} ++ ++/* ++ * The various file operations we support. ++ */ ++ ++static struct file_operations rtc_fops = { ++ owner: THIS_MODULE, ++ llseek: no_llseek, ++ ioctl: rtc_ioctl, ++ open: rtc_open, ++ release: rtc_release, ++}; ++ ++ ++static void run_sbin_rtc_alarm( void ) ++{ ++ int i; ++ char *argv[2], *envp[3]; ++ ++ if (!sbin_rtc_alarm_handler_path[0]) ++ return; ++ ++ print_dbg(": sbin_rtc_alarm_handler_path=%s\n", sbin_rtc_alarm_handler_path); ++ ++ i = 0; ++ argv[i++] = sbin_rtc_alarm_handler_path; ++ argv[i] = 0; ++ ++ /* minimal command environment */ ++ i = 0; ++ envp[i++] = "HOME=/"; ++ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ ++ /* other stuff we want to pass to /sbin/hotplug */ ++ ++ envp[i] = 0; ++ ++ call_usermodehelper (argv [0], argv, envp, 0); ++} ++ ++static void rtc_alarm_task_handler(struct work_struct *work) ++{ ++ run_sbin_rtc_alarm(); ++} ++ ++static struct work_struct rtc_alarm_task; ++ ++static irqreturn_t jz_rtc_interrupt(int irq, void *dev_id) ++{ ++ REG_RTC_HCR = 0x0; ++ printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__); ++ spin_lock_irq(&rtc_lock); ++ ++ if ( __rtc_get_1Hz_flag() ) { ++ while ( !__rtc_write_ready() ) ; ++ __rtc_clear_1Hz_flag(); ++ dprintk("RTC 1Hz interrupt occur.\n"); ++ } ++ ++ if ( __rtc_get_alarm_flag() ) { /* rtc alarm interrupt */ ++ while ( !__rtc_write_ready() ) ; ++ __rtc_clear_alarm_flag(); ++ dprintk("RTC alarm interrupt occur.\n"); ++ //schedule_task( &rtc_alarm_task ); ++ schedule_work( &rtc_alarm_task ); ++ } ++ spin_unlock_irq(&rtc_lock); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++#define RTC_MINOR 135 ++ ++static struct miscdevice rtc_dev= ++{ ++ RTC_MINOR, ++ "rtc", ++ &rtc_fops ++}; ++ ++int __init Jz_rtc_init(void) ++{ ++ ++ INIT_WORK(&rtc_alarm_task, rtc_alarm_task_handler); ++ ++ /* Enabled rtc function, enable rtc alarm function */ ++ while ( !__rtc_write_ready() ) ; /* need we wait for WRDY??? */ ++ if ( !(REG_RTC_RCR & RTC_RCR_RTCE) || !(REG_RTC_RCR &RTC_RCR_AE) ) { ++ REG_RTC_RCR |= RTC_RCR_AE | RTC_RCR_RTCE; ++ } ++ /* clear irq flags */ ++ __rtc_clear_1Hz_flag(); ++ /* In a alarm reset, we expect a alarm interrupt. ++ * We can do something in the interrupt handler. ++ * So, do not clear alarm flag. ++ */ ++/* __rtc_clear_alarm_flag(); */ ++ ++ if (request_irq(IRQ_RTC, jz_rtc_interrupt, 0, "rtc", NULL) < 0) ++ return -EBUSY; ++ ++ misc_register(&rtc_dev); ++ ++ printk("JzSOC onchip RTC installed !!!\n"); ++ return 0; ++ ++} ++ ++void __exit Jz_rtc_exit (void) ++{ ++ misc_deregister(&rtc_dev); ++ free_irq (IRQ_RTC, NULL); ++} ++ ++module_init(Jz_rtc_init); ++module_exit(Jz_rtc_exit); ++ +diff --git a/drivers/char/rtc_jz.h b/drivers/char/rtc_jz.h +new file mode 100644 +index 0000000..6c754d6 +--- /dev/null ++++ b/drivers/char/rtc_jz.h +@@ -0,0 +1,74 @@ ++#ifndef __RTC_JZ_H__ ++#define __RTC_JZ_H__ ++ ++//#define DEBUG 1 ++#undef DEBUG ++ ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#define print_dbg(f, arg...) \ ++ printk("%s, %s[%d]:" f , __FUNCTION__, __FILE__, __LINE__ , ##arg ) ++#else ++#define dprintk(x...) ++#define print_dbg(n, arg...) ++#endif ++ ++ ++#ifdef DEBUG ++ ++static void print_rtc_time( struct rtc_time * tm ) ++{ ++ printk("%02d%02d-%02d:%02d:%02d-%d\n", tm->tm_mon, tm->tm_mday, ++ tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year); ++ printk("sec:\t%d\n", tm->tm_sec); ++ printk("min:\t%d\n", tm->tm_min); ++ printk("hour:\t%d\n", tm->tm_hour); ++ printk("mday:\t%d\n", tm->tm_mday); ++ printk("mon:\t%d\n", tm->tm_mon); ++ printk("year:\t%d\n", tm->tm_year); ++ printk("wday:\t%d\n", tm->tm_wday); ++ printk("yday:\t%d\n", tm->tm_yday); ++ printk("isdst:\t%d\n", tm->tm_isdst); ++ ++} ++ ++static void print_rtc_registers( void ) ++{ ++ while ( !__rtc_write_ready() ) ; ++ printk("REG_RTC_RCR:\t 0x%8.8x\n", REG_RTC_RCR ); ++ printk("REG_RTC_RSR:\t 0x%8.8x\n", REG_RTC_RSR ); ++ printk("REG_RTC_RSAR:\t 0x%8.8x\n", REG_RTC_RSAR ); ++ printk("REG_RTC_RGR:\t 0x%8.8x\n", REG_RTC_RGR ); ++ printk("REG_RTC_HCR:\t 0x%8.8x\n", REG_RTC_HCR ); ++ printk("REG_RTC_HWFCR:\t 0x%8.8x\n", REG_RTC_HWFCR ); ++ printk("REG_RTC_HRCR:\t 0x%8.8x\n", REG_RTC_HRCR ); ++ printk("REG_RTC_HWCR:\t 0x%8.8x\n", REG_RTC_HWCR ); ++ printk("REG_RTC_HWRSR:\t 0x%8.8x\n", REG_RTC_HWRSR ); ++ printk("REG_RTC_HSPR:\t 0x%8.8x\n", REG_RTC_HSPR ); ++} ++ ++#define RTC_PRINT_REG _IOR('p', 0x12, unsigned long)/* Set power down */ ++#endif /* #ifdef DEBUG */ ++ ++ ++/* ++ * JZSOC ioctl calls that are permitted to the /dev/rtc interface ++ */ ++ ++#define RTC_ENABLED _IO('p', 0x11) /* enable rtc */ ++#define RTC_DISABLED _IO('p', 0x12) /* disable rtc */ ++#define RTC_ALM_ON _IO('p', 0x13) /* enable rtc */ ++#define RTC_ALM_OFF _IO('p', 0x14) /* disable rtc */ ++#define RTC_1HZIE_ON _IO('p', 0x15) /* 1Hz int. enable on */ ++#define RTC_1HZIE_OFF _IO('p', 0x16) /* ... off */ ++ ++#define RTC_POWER_DOWN _IOR('p', 0x11, unsigned long)/* Set power down */ ++ ++/* Registers define */ ++/* RTC Control register */ ++#define RTC_AIE 3 /* jz4740_06_rtc_spec.pdf, RTC Control Register */ ++#define RTC_1HZIE 5 /* ... */ ++#define RTC_ALM_EN 2 /* ... */ ++#define RTC_EN 0 /* ... */ ++ ++#endif /* #define __RTC_JZ_H__ */ +diff --git a/drivers/char/rtc_pcf8563.c b/drivers/char/rtc_pcf8563.c +new file mode 100644 +index 0000000..08dc30b +--- /dev/null ++++ b/drivers/char/rtc_pcf8563.c +@@ -0,0 +1,448 @@ ++/* ++ * PCF8563 Real Time Clock interface for Linux ++ * ++ * It only support 24Hour Mode, And the stored values are in BCD format. ++ * The alarm register is start at minute reg, no second alarm register. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* get the user-level API */ ++#include ++#include ++ ++/********************************************************************** ++ * register summary ++ **********************************************************************/ ++#define RTC_SECONDS 2 ++#define RTC_MINUTES 3 ++#define RTC_HOURS 4 ++#define RTC_DAY_OF_MONTH 5 ++#define RTC_DAY_OF_WEEK 6 ++#define RTC_MONTH 7 ++#define RTC_YEAR 8 ++ ++#define RTC_MINUTES_ALARM 9 ++#define RTC_HOURS_ALARM 0x0a ++#define RTC_DAY_ALARM 0x0b ++#define RTC_WEEKDAY_ALARM 0x0c ++ ++/* control registers - Moto names ++ */ ++#define RTC_CONTROL 0x00 ++#define RTC_STATUS 0x01 ++#define RTC_CLKOUT 0x0d ++#define RTC_TIMERCTL 0x0e ++#define RTC_TIMERCOUNTDOWN 0x0f ++ ++ ++/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ++ * determines if the following two #defines are needed ++ */ ++#ifndef BCD2BIN ++#define BCD2BIN(val) (((val) & 0x0f) + ((val) >> 4) * 10) ++#endif ++ ++#ifndef BIN2BCD ++#define BIN2BCD(val) ((((val) / 10) << 4) + (val) % 10) ++#endif ++ ++extern spinlock_t rtc_lock; ++extern void i2c_open(void); ++extern void i2c_close(void); ++extern int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++extern int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++/* ++ * We sponge a minor off of the misc major. No need slurping ++ * up another valuable major dev number for this. If you add ++ * an ioctl, make sure you don't conflict with SPARC's RTC ++ * ioctls. ++ */ ++ ++static int rtc_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++ ++static void get_rtc_time (struct rtc_time *rtc_tm); ++static void get_rtc_alm_time (struct rtc_time *alm_tm); ++ ++/* ++ * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is ++ * protected by the big kernel lock. However, ioctl can still disable the timer ++ * in rtc_status and then with del_timer after the interrupt has read ++ * rtc_status but before mod_timer is called, which would then reenable the ++ * timer (but you would need to have an awful timing before you'd trip on it) ++ */ ++static unsigned long rtc_status = 0; /* bitmapped status byte. */ ++ ++/* ++ * If this driver ever becomes modularised, it will be really nice ++ * to make the epoch retain its value across module reload... ++ */ ++static unsigned int epoch = 1900; ++static const unsigned char days_in_mo[] = ++{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; ++ ++static unsigned char rtcframe[16]; ++ ++static void read_rtcframe(void) ++{ ++ i2c_open(); ++ i2c_read(0x51, rtcframe, 0, 16); ++ i2c_close(); ++} ++ ++static void write_rtcframe(void) ++{ ++ i2c_open(); ++ i2c_write(0x51, rtcframe, 0, 16); ++ i2c_close(); ++} ++ ++static void write_rtc(unsigned char addr, unsigned char val) ++{ ++ volatile unsigned char v = val; ++ i2c_open(); ++ i2c_write(0x51, (unsigned char *)&v, addr, 1); ++ i2c_close(); ++} ++ ++static unsigned char read_rtc(unsigned char addr) ++{ ++ volatile unsigned char v; ++ i2c_open(); ++ i2c_read(0x51, (unsigned char *)&v, addr, 1); ++ i2c_close(); ++ return v; ++} ++ ++static void CMOS_WRITE(unsigned char addr, unsigned char val) ++{ ++ rtcframe[addr] = val; ++} ++ ++static unsigned char CMOS_READ(unsigned char addr) ++{ ++ return rtcframe[addr]; ++} ++ ++static void get_rtc_time(struct rtc_time *rtc_tm) ++{ ++ unsigned char sec,mon,mday,wday,year,hour,min; ++ ++ /* ++ * Only the values that we read from the RTC are set. We leave ++ * tm_wday, tm_yday and tm_isdst untouched. Even though the ++ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated ++ * by the RTC when initially set to a non-zero value. ++ */ ++ ++ spin_lock_irq(&rtc_lock); ++ read_rtcframe(); ++ sec = CMOS_READ(RTC_SECONDS) & ~0x80; ++ min = CMOS_READ(RTC_MINUTES) & ~0x80; ++ hour = CMOS_READ(RTC_HOURS) & ~0xc0; ++ mday = CMOS_READ(RTC_DAY_OF_MONTH) & ~0xc0; ++ wday = CMOS_READ(RTC_DAY_OF_WEEK) & ~0xf8; ++ mon = CMOS_READ(RTC_MONTH) & ~0xe0; ++ year = CMOS_READ(RTC_YEAR) ; ++ ++ rtc_tm->tm_sec = BCD2BIN(sec); ++ rtc_tm->tm_min = BCD2BIN(min); ++ rtc_tm->tm_hour = BCD2BIN(hour); ++ rtc_tm->tm_mday = BCD2BIN(mday); ++ rtc_tm->tm_wday = wday; ++ /* Don't use centry, but start from year 1970 */ ++ rtc_tm->tm_mon = BCD2BIN(mon); ++ year = BCD2BIN(year); ++ if ((year += (epoch - 1900)) <= 69) ++ year += 100; ++ rtc_tm->tm_year = year; ++ ++ spin_unlock_irq(&rtc_lock); ++ ++ ++ /* ++ * Account for differences between how the RTC uses the values ++ * and how they are defined in a struct rtc_time; ++ */ ++ rtc_tm->tm_mon--; ++} ++ ++static void get_rtc_alm_time(struct rtc_time *alm_tm) ++{ ++ unsigned char sec, min, hour; ++ ++ /* ++ * Only the values that we read from the RTC are set. That ++ * means only tm_hour, tm_min, and tm_sec. ++ */ ++ spin_lock_irq(&rtc_lock); ++ read_rtcframe(); ++ sec = 0; ++ min = CMOS_READ(RTC_MINUTES_ALARM); ++ hour = CMOS_READ(RTC_HOURS_ALARM); ++ ++ alm_tm->tm_sec = sec;//not set sec ++ alm_tm->tm_min = BCD2BIN(min); ++ alm_tm->tm_hour = BCD2BIN(hour); ++ ++ spin_unlock_irq(&rtc_lock); ++} ++ ++static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct rtc_time wtime; ++ switch (cmd) { ++ case RTC_ALM_READ: /* Read the present alarm time */ ++ { ++ /* ++ * This returns a struct rtc_time. Reading >= 0xc0 ++ * means "don't care" or "match all". Only the tm_hour, ++ * tm_min, and tm_sec values are filled in. ++ */ ++ ++ get_rtc_alm_time(&wtime); ++ break; ++ } ++ case RTC_ALM_SET: /* Store a time into the alarm */ ++ { ++ unsigned char hrs, min, sec; ++ struct rtc_time alm_tm; ++ ++ if (copy_from_user(&alm_tm, (struct rtc_time*)arg, ++ sizeof(struct rtc_time))) ++ return -EFAULT; ++ ++ hrs = alm_tm.tm_hour; ++ min = alm_tm.tm_min; ++ sec = alm_tm.tm_sec; ++ ++ ++ ++ if (hrs >= 24) ++ return -EINVAL; ++ ++ hrs = BIN2BCD(hrs); ++ ++ if (min >= 60) ++ return -EINVAL; ++ ++ min = BIN2BCD(min); ++ ++ if (sec >= 60) ++ return -EINVAL; ++ ++ spin_lock_irq(&rtc_lock); ++ read_rtcframe(); ++ CMOS_WRITE(RTC_HOURS_ALARM, hrs | 0x80); ++ CMOS_WRITE(RTC_MINUTES_ALARM, min | 0x80); ++ ++ CMOS_WRITE(RTC_DAY_ALARM, CMOS_READ(RTC_DAY_ALARM) | 0x80); ++ CMOS_WRITE(RTC_WEEKDAY_ALARM, CMOS_READ(RTC_WEEKDAY_ALARM) | 0x80); ++ CMOS_WRITE(RTC_STATUS, CMOS_READ(RTC_STATUS) | 0x02);/*open alarm int*/ ++ write_rtcframe(); ++ spin_unlock_irq(&rtc_lock); ++ break; ++ } ++ case RTC_RD_TIME: /* Read the time/date from RTC */ ++ { ++ get_rtc_time(&wtime); ++ break; ++ } ++ case RTC_SET_TIME: /* Set the RTC */ ++ { ++ struct rtc_time rtc_tm; ++ unsigned char mon, day, hrs, min, sec, leap_yr, date; ++ unsigned int yrs; ++// unsigned char ctr; ++ ++ if (!capable(CAP_SYS_TIME)) ++ return -EACCES; ++ ++ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, ++ sizeof(struct rtc_time))) ++ return -EFAULT; ++ ++ ++ yrs = rtc_tm.tm_year + 1900; ++ mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ ++ day = rtc_tm.tm_wday; ++ date = rtc_tm.tm_mday; ++ hrs = rtc_tm.tm_hour; ++ min = rtc_tm.tm_min; ++ sec = rtc_tm.tm_sec; ++ ++ ++ if (yrs < 1970) ++ return -EINVAL; ++ ++ leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); ++ ++ if ((mon > 12) || (date == 0)) ++ return -EINVAL; ++ ++ if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr))) ++ return -EINVAL; ++ ++ if ((hrs >= 24) || (min >= 60) || (sec >= 60)) ++ return -EINVAL; ++ ++ if ((yrs -= epoch) > 255) /* They are unsigned */ ++ return -EINVAL; ++ ++ spin_lock_irq(&rtc_lock); ++ /* These limits and adjustments are independant of ++ * whether the chip is in binary mode or not. ++ */ ++ if (yrs > 169) { ++ spin_unlock_irq(&rtc_lock); ++ return -EINVAL; ++ } ++ ++ if (yrs >= 100) ++ yrs -= 100; ++ ++ min = BIN2BCD(min); ++ sec = BIN2BCD(sec); ++ hrs = BIN2BCD(hrs); ++ mon = BIN2BCD(mon); ++ yrs = BIN2BCD(yrs); ++ date = BIN2BCD(date); ++ ++ read_rtcframe(); ++ CMOS_WRITE(RTC_SECONDS, sec ); ++ CMOS_WRITE(RTC_MINUTES, min); ++ CMOS_WRITE(RTC_HOURS, hrs); ++ CMOS_WRITE(RTC_DAY_OF_MONTH, date); ++ CMOS_WRITE(RTC_DAY_OF_WEEK, day); ++ CMOS_WRITE(RTC_MONTH, mon); ++ CMOS_WRITE(RTC_YEAR, yrs); ++ write_rtcframe(); ++ ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ } ++ case RTC_EPOCH_READ: /* Read the epoch. */ ++ { ++ return put_user (epoch, (unsigned long *)arg); ++ } ++ case RTC_EPOCH_SET: /* Set the epoch. */ ++ { ++ /* ++ * There were no RTC clocks before 1900. ++ */ ++ if (arg < 1900) ++ return -EINVAL; ++ ++ if (!capable(CAP_SYS_TIME)) ++ return -EACCES; ++ ++ epoch = arg; ++ return 0; ++ } ++ default: ++ return -EINVAL; ++ } ++ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; ++} ++ ++/* ++ * We enforce only one user at a time here with the open/close. ++ * Also clear the previous interrupt data on an open, and clean ++ * up things on a close. ++ */ ++ ++/* We use rtc_lock to protect against concurrent opens. So the BKL is not ++ * needed here. Or anywhere else in this driver. */ ++static int rtc_open(struct inode *inode, struct file *file) ++{ ++ spin_lock_irq (&rtc_lock); ++ ++ if(rtc_status) ++ goto out_busy; ++ ++ rtc_status = 1; ++ ++ spin_unlock_irq (&rtc_lock); ++ return 0; ++ ++out_busy: ++ spin_unlock_irq (&rtc_lock); ++ return -EBUSY; ++} ++ ++static int rtc_release(struct inode *inode, struct file *file) ++{ ++ ++ ++ /* No need for locking -- nobody else can do anything until this rmw is ++ * committed, and no timer is running. */ ++ rtc_status = 0; ++ return 0; ++} ++ ++/* ++ * The various file operations we support. ++ */ ++ ++static struct file_operations rtc_fops = { ++ owner: THIS_MODULE, ++ llseek: no_llseek, ++ ioctl: rtc_ioctl, ++ open: rtc_open, ++ release: rtc_release, ++}; ++ ++#define RTC_MINOR 135 ++ ++static struct miscdevice rtc_dev= ++{ ++ RTC_MINOR, ++ "rtc", ++ &rtc_fops ++}; ++ ++int __init pcf_rtc_init(void) ++{ ++ int r; ++ unsigned char ctr; ++ r = misc_register(&rtc_dev); ++ ++ ctr = read_rtc(RTC_CONTROL); ++ write_rtc(RTC_CONTROL,0x00 ); ++ ++ read_rtcframe(); ++ CMOS_WRITE(RTC_STATUS, 0x00); ++ CMOS_WRITE(RTC_CLKOUT, 0x80); ++ /* RTC clock out, 32.768k */ ++ ++ CMOS_WRITE(RTC_TIMERCTL, 0x00); ++ CMOS_WRITE(RTC_TIMERCOUNTDOWN, 0x00); ++ write_rtcframe(); ++ ++ printk("PCF8563 RTC installed !!!\n"); ++ return 0; ++ ++} ++ ++void __exit pcf_rtc_exit (void) ++{ ++ misc_deregister(&rtc_dev); ++} ++ ++module_init(pcf_rtc_init); ++module_exit(pcf_rtc_exit); +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index 8206442..d704743 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -7,6 +7,14 @@ menu "I2C Hardware Bus support" + comment "PC SMBus host controller drivers" + depends on PCI + ++config I2C_JZ47XX ++ tristate "JZ47XX I2C Interface support" ++ depends on SOC_JZ4730 || SOC_JZ4740 ++ help ++ If you have devices in the Ingenic JZ4730/JZ4740 I2C bus, say yes to ++ this option. This driver can also be built as a module. If so, the ++ module will be called i2c-jz47xx. ++ + config I2C_ALI1535 + tristate "ALI 1535" + depends on PCI +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index e654263..73960cd 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o + obj-$(CONFIG_I2C_IMX) += i2c-imx.o + obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o + obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o ++obj-$(CONFIG_I2C_JZ47XX) += i2c-jz47xx.o + obj-$(CONFIG_I2C_MPC) += i2c-mpc.o + obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o + obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o +diff --git a/drivers/i2c/busses/i2c-jz47xx.c b/drivers/i2c/busses/i2c-jz47xx.c +new file mode 100644 +index 0000000..16f947e +--- /dev/null ++++ b/drivers/i2c/busses/i2c-jz47xx.c +@@ -0,0 +1,330 @@ ++/* ++ * i2c_jz47xx.c ++ * I2C adapter for the INGENIC I2C bus access. ++ * ++ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include "i2c-jz47xx.h" ++ ++/* I2C protocol */ ++#define I2C_READ 1 ++#define I2C_WRITE 0 ++ ++#define TIMEOUT 1000 ++unsigned short sub_addr = 0; ++int addr_val = 0; ++struct jz_i2c { ++ spinlock_t lock; ++ wait_queue_head_t wait; ++ struct i2c_msg *msg; ++ unsigned int msg_num; ++ unsigned int slave_addr; ++ struct i2c_adapter adap; ++ struct clk *clk; ++}; ++ ++/* ++ * I2C bus protocol basic routines ++ */ ++static int i2c_put_data(unsigned char data) ++{ ++ unsigned int timeout = TIMEOUT*10; ++ ++ __i2c_write(data); ++ __i2c_set_drf(); ++ while (__i2c_check_drf() != 0); ++ while (!__i2c_transmit_ended()); ++ while (!__i2c_received_ack() && timeout) ++ timeout--; ++ ++ if (timeout) ++ return 0; ++ else ++ return -ETIMEDOUT; ++} ++ ++static int i2c_get_data(unsigned char *data, int ack) ++{ ++ int timeout = TIMEOUT*10; ++ ++ if (!ack) ++ __i2c_send_nack(); ++ else ++ __i2c_send_ack(); ++ ++ while (__i2c_check_drf() == 0 && timeout) ++ timeout--; ++ ++ if (timeout) { ++ if (!ack) ++ __i2c_send_stop(); ++ *data = __i2c_read(); ++ __i2c_clear_drf(); ++ return 0; ++ } else ++ return -ETIMEDOUT; ++} ++ ++/* ++ * I2C interface ++ */ ++void i2c_jz_setclk(unsigned int i2cclk) ++{ ++ __i2c_set_clk(jz_clocks.extalclk, i2cclk); ++} ++ ++static int xfer_read(unsigned char device, struct i2c_adapter *adap, unsigned char *buf, int length) ++{ ++ int cnt = length; ++ int timeout = 5; ++ ++ device = (0xa << 3) | ((sub_addr & 0x0700) >> 8); ++ sub_addr = sub_addr & 0xff; ++ ++L_try_again: ++ ++ if (timeout < 0) ++ goto L_timeout; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ ++ if (addr_val) { ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_werr; ++ if (i2c_put_data(sub_addr) < 0) ++ goto address_err; ++ } ++ __i2c_send_start(); ++ ++ if (i2c_put_data((device << 1) | I2C_READ ) < 0) ++ goto device_rerr; ++ ++ __i2c_send_ack(); /* Master sends ACK for continue reading */ ++ __i2c_send_start(); ++ ++ while (cnt) { ++ if (cnt == 1) { ++ if (i2c_get_data(buf, 0) < 0) ++ break; ++ } else { ++ if (i2c_get_data(buf, 1) < 0) ++ break; ++ } ++ cnt--; ++ buf++; ++ } ++ addr_val = 0; ++ return length - cnt; ++ device_rerr: ++ device_werr: ++ address_err: ++ timeout --; ++ __i2c_send_stop(); ++ goto L_try_again; ++ ++L_timeout: ++ __i2c_send_stop(); ++ printk("Read I2C device 0x%2x failed.\n", device); ++ return -ENODEV; ++} ++ ++static int xfer_write(unsigned char device, struct i2c_adapter *adap, unsigned char *buf, int length) ++{ ++ int cnt = length; ++ int cnt_in_pg; ++ int timeout = 5; ++ unsigned char *tmpbuf; ++ unsigned char tmpaddr; ++ ++ device = (0xa << 3) | ((sub_addr & 0x0700) >> 8); ++ sub_addr = sub_addr & 0xff; ++ ++ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ ++ ++ W_try_again: ++ if (timeout < 0) ++ goto W_timeout; ++ ++ cnt = length; ++ tmpbuf = (unsigned char *)buf; ++ tmpaddr = device; ++ start_write_page: ++ cnt_in_pg = 0; ++ __i2c_send_start(); ++ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) ++ goto device_err; ++ if (addr_val) { ++ if (i2c_put_data(sub_addr) < 0) ++ goto address_err; ++ } ++ while (cnt) { ++ if (++cnt_in_pg > 8) { ++ __i2c_send_stop(); ++ mdelay(1); ++ sub_addr += 8; ++ goto start_write_page; ++ } ++ if (i2c_put_data(*tmpbuf) < 0) ++ break; ++ cnt--; ++ tmpbuf++; ++ } ++ __i2c_send_stop(); ++ addr_val = 0; ++ return length - cnt; ++ device_err: ++ address_err: ++ timeout--; ++ __i2c_send_stop(); ++ goto W_try_again; ++ ++W_timeout: ++ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); ++ __i2c_send_stop(); ++ return -ENODEV; ++} ++ ++static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) ++{ ++ int ret, i; ++ ++ dev_dbg(&adap->dev, "jz47xx_xfer: processing %d messages:\n", num); ++ for (i = 0; i < num; i++) { ++ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, ++ pmsg->flags & I2C_M_RD ? "read" : "writ", ++ pmsg->len, pmsg->len > 1 ? "s" : "", ++ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); ++ if (pmsg->len && pmsg->buf) { /* sanity check */ ++ if (pmsg->flags & I2C_M_RD) ++ ret = xfer_read(pmsg->addr, adap, pmsg->buf, pmsg->len); ++ else ++ ret = xfer_write(pmsg->addr, adap, pmsg->buf, pmsg->len); ++ ++ if (ret) ++ return ret; ++ /* Wait until transfer is finished */ ++ } ++ dev_dbg(&adap->dev, "transfer complete\n"); ++ pmsg++; /* next message */ ++ } ++ return i; ++} ++ ++static u32 i2c_jz_functionality(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; ++} ++ ++static const struct i2c_algorithm i2c_jz_algorithm = { ++ .master_xfer = i2c_jz_xfer, ++ .functionality = i2c_jz_functionality, ++}; ++ ++static int i2c_jz_probe(struct platform_device *dev) ++{ ++ struct jz_i2c *i2c; ++ struct i2c_jz_platform_data *plat = dev->dev.platform_data; ++ int ret; ++ ++ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ ++ __i2c_enable(); ++ ++ i2c = kzalloc(sizeof(struct jz_i2c), GFP_KERNEL); ++ if (!i2c) { ++ printk("There is no enough memory\n"); ++ ret = -ENOMEM; ++ goto emalloc; ++ } ++ ++ i2c->adap.owner = THIS_MODULE; ++ i2c->adap.algo = &i2c_jz_algorithm; ++ i2c->adap.retries = 5; ++ spin_lock_init(&i2c->lock); ++ init_waitqueue_head(&i2c->wait); ++ sprintf(i2c->adap.name, "jz_i2c-i2c.%u", dev->id); ++ i2c->adap.algo_data = i2c; ++ i2c->adap.dev.parent = &dev->dev; ++ ++ if (plat) { ++ i2c->adap.class = plat->class; ++ } ++ ++ /* ++ * If "dev->id" is negative we consider it as zero. ++ * The reason to do so is to avoid sysfs names that only make ++ * sense when there are multiple adapters. ++ */ ++ i2c->adap.nr = dev->id != -1 ? dev->id : 0; ++ /* ret = i2c_add_adapter(&i2c->adap); */ ++ ret = i2c_add_numbered_adapter(&i2c->adap); ++ if (ret < 0) { ++ printk(KERN_INFO "I2C: Failed to add bus\n"); ++ goto eadapt; ++ } ++ ++ platform_set_drvdata(dev, i2c); ++ dev_info(&dev->dev, "JZ47xx i2c bus driver.\n"); ++ return 0; ++eadapt: ++ __i2c_disable(); ++emalloc: ++ return ret; ++} ++ ++static int i2c_jz_remove(struct platform_device *dev) ++{ ++ struct i2c_adapter *adapter = platform_get_drvdata(dev); ++ int rc; ++ ++ rc = i2c_del_adapter(adapter); ++ platform_set_drvdata(dev, NULL); ++ return rc; ++} ++ ++static struct platform_driver i2c_jz_driver = { ++ .probe = i2c_jz_probe, ++ .remove = i2c_jz_remove, ++ .driver = { ++ .name = "jz_i2c", ++ }, ++}; ++ ++static int __init i2c_adap_jz_init(void) ++{ ++ return platform_driver_register(&i2c_jz_driver); ++} ++ ++static void __exit i2c_adap_jz_exit(void) ++{ ++ return platform_driver_unregister(&i2c_jz_driver); ++} ++ ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_adap_jz_init); ++module_exit(i2c_adap_jz_exit); +diff --git a/drivers/i2c/busses/i2c-jz47xx.h b/drivers/i2c/busses/i2c-jz47xx.h +new file mode 100644 +index 0000000..eb86110 +--- /dev/null ++++ b/drivers/i2c/busses/i2c-jz47xx.h +@@ -0,0 +1,20 @@ ++/* ++ * i2c_jz47xx.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _I2C_JZ_H_ ++#define _I2C_JZ_H_ ++ ++struct i2c_slave_client; ++ ++struct i2c_jz_platform_data { ++ unsigned int slave_addr; ++ struct i2c_slave_client *slave; ++ unsigned int class; ++}; ++ ++extern void jz_set_i2c_info(struct i2c_jz_platform_data *info); ++#endif +diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c +index 7e13d2d..0b0986b 100644 +--- a/drivers/i2c/i2c-dev.c ++++ b/drivers/i2c/i2c-dev.c +@@ -38,8 +38,9 @@ + #include + #include + ++extern unsigned short sub_addr; ++extern int addr_val; + static struct i2c_driver i2cdev_driver; +- + /* + * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a + * slave (i2c_client) with which messages will be exchanged. It's coupled +@@ -428,6 +429,14 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + */ + client->adapter->timeout = msecs_to_jiffies(arg * 10); + break; ++ case I2C_SET_SUB_ADDRESS: ++ addr_val = 1; ++ sub_addr = arg; ++ break; ++ case I2C_SET_CLOCK: ++ i2c_jz_setclk(arg); ++ break; ++ + default: + /* NOTE: returning a fault code here could cause trouble + * in buggy userspace code. Some old kernel bugs returned +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index a6b989a..a2c9ff9 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -146,8 +146,8 @@ config KEYBOARD_EP93XX + module will be called ep93xx_keypad. + + config KEYBOARD_GPIO +- tristate "GPIO Buttons" +- depends on GENERIC_GPIO ++ tristate "JZ GPIO Buttons support" ++# depends on GENERIC_GPIO + help + This driver implements support for buttons connected + to GPIO pins of various CPUs (and some other chips). +diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c +index efed0c9..4c8d358 100644 +--- a/drivers/input/keyboard/gpio_keys.c ++++ b/drivers/input/keyboard/gpio_keys.c +@@ -1,7 +1,13 @@ + /* +- * Driver for keys on GPIO lines capable of generating interrupts. ++ * linux/drivers/input/keyboard/gpio_keys.c + * +- * Copyright 2005 Phil Blundell ++ * JZ GPIO Buttons driver for JZ4740 PAVO ++ * ++ * User applications can access to this device via /dev/input/eventX. ++ * ++ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: Richard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -225,7 +231,7 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup) { +- int irq = gpio_to_irq(button->gpio); ++ int irq = button->gpio + IRQ_GPIO_0; + enable_irq_wake(irq); + } + } +@@ -243,7 +249,7 @@ static int gpio_keys_resume(struct platform_device *pdev) + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup) { +- int irq = gpio_to_irq(button->gpio); ++ int irq = button->gpio + IRQ_GPIO_0; + disable_irq_wake(irq); + } + } +@@ -269,11 +275,13 @@ static struct platform_driver gpio_keys_device_driver = { + + static int __init gpio_keys_init(void) + { ++ pavo_board_init(); + return platform_driver_register(&gpio_keys_device_driver); + } + + static void __exit gpio_keys_exit(void) + { ++ platform_device_unregister(&pavo_button_device); + platform_driver_unregister(&gpio_keys_device_driver); + } + +diff --git a/drivers/input/keyboard/jz_keypad.c b/drivers/input/keyboard/jz_keypad.c +new file mode 100644 +index 0000000..3e6e309 +--- /dev/null ++++ b/drivers/input/keyboard/jz_keypad.c +@@ -0,0 +1,357 @@ ++/* ++ * linux/drivers/input/keyboard/jz_keypad.c ++ * ++ * JZ Keypad Driver ++ * ++ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: Richard ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define KB_ROWS 3 ++#define KB_COLS 3 ++ ++#define SCAN_INTERVAL (10) ++ ++static unsigned short col[KB_COLS] = {85,87,91}; ++static unsigned short row[KB_ROWS] = {60,61,62}; ++static unsigned short s0[KB_COLS]; ++static unsigned short s1[KB_COLS]={7,7,7}; ++static unsigned short precol,prerow; ++ ++static const unsigned int jz_kbd_keycode[KB_COLS * KB_ROWS] = { ++ KEY_1, KEY_4, KEY_7, ++ KEY_2, KEY_5, 0, ++ KEY_3, KEY_6, 0, ++}; ++ ++struct jz_kbd { ++ unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)]; ++ struct input_dev *input; ++ char phys[32]; ++ ++ spinlock_t lock; ++ struct timer_list timer; ++ ++ unsigned int suspended; ++ unsigned long suspend_jiffies; ++}; ++ ++static struct jz_kbd g_jz_kbd; ++ ++static inline void jz_scan_kbd(unsigned short *s) ++{ ++ int i; ++ ++ if (!s) ++ return; ++ ++ for (i = 0; i < KB_COLS; i++) { ++ ++ __gpio_as_input(85); /* row */ ++ __gpio_as_input(87); /* row */ ++ __gpio_as_input(91); /* row */ ++ ++ __gpio_as_input(60); /* col */ ++ __gpio_as_input(61); /* col */ ++ __gpio_as_input(62); /* col */ ++ ++ __gpio_clear_pin(col[i]); ++ __gpio_as_output(col[i]); ++ ++ udelay(1000); ++ s[i]=(__gpio_get_pin(60) << 0) | (__gpio_get_pin(61) << 1) | ++ (__gpio_get_pin(62) << 2); ++ } ++} ++ ++static void jz_kbd_scankeyboard(struct jz_kbd *kbd_data) ++{ ++ unsigned int row,col; ++ unsigned long flags; ++ unsigned int num_pressed; ++ ++ if (kbd_data->suspended) ++ return; ++ ++ spin_lock_irqsave(&kbd_data->lock, flags); ++ ++ num_pressed = 0; ++ jz_scan_kbd(s0); ++ ++ /* look for key if pressed down on not, col & row */ ++ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 7) { ++ if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) { ++ /* up */ ++ input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0); ++ input_sync(kbd_data->input); ++ } ++ precol = prerow = -1; ++ s1[0] = s1[1] = s1[2] = 7; ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ return; ++ } ++ ++ if (s0[0] == 6 && s0[1] == 7 && s0[2] == 7) { ++ row = 0;//K7 ++ col = 2; ++ goto find_row_col; ++ } ++ if (s0[0] == 7 && s0[1] == 3 && s0[2] == 7) { ++ row = 2;//k6 ++ col = 1; ++ goto find_row_col; ++ } ++ if (s0[0] == 7 && s0[1] == 5 && s0[2] == 7) { ++ row = 1;//k5 ++ col = 1; ++ goto find_row_col; ++ } ++ if (s0[0] == 7 && s0[1] == 6 && s0[2] == 7) { ++ row = 0;//k4 ++ col = 1; ++ goto find_row_col; ++ } ++ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 3) { ++ row = 2;//k3 ++ col = 0; ++ goto find_row_col; ++ } ++ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 5) { ++ row = 1;//k2 ++ col = 0; ++ goto find_row_col; ++ } ++ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 6) { ++ row = 0;//k1 ++ col = 0; ++ goto find_row_col; ++ } ++ /* 2 or 3 buttons are pressed */ ++ s0[0] = s0[1] = s0[2] = 7; ++ s1[0] = s1[1] = s1[2] = 7; ++ prerow = precol = -1; ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ return; ++find_row_col: ++ if (s1[0] == 7 && s1[1] == 7 && s1[2] == 7) { ++ /* down */ ++ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); ++ input_sync(kbd_data->input); ++ s1[0] = s0[0]; ++ s1[1] = s0[1]; ++ s1[2] = s0[2]; ++ ++ precol = col; ++ prerow = row; ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ return; ++ } ++ if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) { ++ /* is the same as the preview key */ ++ if (s0[0] == s1[0] && s0[1] == s1[1] && s0[2] == s1[2]) { ++ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); ++ input_sync(kbd_data->input); ++ s1[0] = s0[0]; ++ s1[1] = s0[1]; ++ s1[2] = s0[2]; ++ ++ precol = col; ++ prerow = row; ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ return; ++ } else { ++ /* the preview key is up and other key is down */ ++ if (s0[0] != s1[0] || s0[1] != s1[1] || s0[2] != s1[2]) { ++ input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0); ++ input_sync(kbd_data->input); ++ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); ++ input_sync(kbd_data->input); ++ s1[0] = s0[0]; ++ s1[1] = s0[1]; ++ s1[2] = s0[2]; ++ precol = col; ++ prerow = row; ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ return; ++ } ++ } ++ } ++} ++ ++static void jz_kbd_timer_callback(unsigned long data) ++{ ++ jz_kbd_scankeyboard(&g_jz_kbd); ++ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); ++} ++ ++#ifdef CONFIG_PM ++static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); ++ jz_kbd->suspended = 1; ++ ++ return 0; ++} ++ ++static int jz_kbd_resume(struct platform_device *dev) ++{ ++ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); ++ ++ jz_kbd->suspend_jiffies = jiffies; ++ jz_kbd->suspended = 0; ++ ++ return 0; ++} ++#else ++#define jz_kbd_suspend NULL ++#define jz_kbd_resume NULL ++#endif ++ ++static int __init jz_kbd_probe(struct platform_device *dev) ++{ ++ struct input_dev *input_dev; ++ int i, error; ++ ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ return -ENOMEM; ++ ++ platform_set_drvdata(dev, &g_jz_kbd); ++ ++ strcpy(g_jz_kbd.phys, "input/kbd0"); ++ ++ spin_lock_init(&g_jz_kbd.lock); ++ ++ g_jz_kbd.suspend_jiffies = jiffies; ++ g_jz_kbd.input = input_dev; ++ ++ input_dev->private = &g_jz_kbd; ++ input_dev->name = "JZ Keypad"; ++ input_dev->phys = g_jz_kbd.phys; ++ input_dev->cdev.dev = &dev->dev; ++ ++ input_dev->id.bustype = BUS_PARPORT; ++ input_dev->id.vendor = 0x0001; ++ input_dev->id.product = 0x0001; ++ input_dev->id.version = 0x0100; ++ ++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN); ++ input_dev->keycode = g_jz_kbd.keycode; /* keycode array address */ ++ input_dev->keycodesize = sizeof(unsigned int); ++ input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode); ++ ++ memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode)); ++ ++ for (i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++) ++ set_bit(g_jz_kbd.keycode[i], input_dev->keybit); ++ ++ //clear_bit(0, input_dev->keybit); ++ ++ __gpio_as_input(85); ++ __gpio_as_input(87); ++ __gpio_as_input(91); ++ ++#if 0 ++ __gpio_as_input(60); ++ __gpio_as_input(61); ++ __gpio_as_input(62); ++#endif ++ ++ /* Init Keyboard rescan timer */ ++ init_timer(&g_jz_kbd.timer); ++ g_jz_kbd.timer.function = jz_kbd_timer_callback; ++ g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd; ++ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); ++ ++ error = input_register_device(input_dev); ++ if (error) { ++ pr_err("gpio-keys: Unable to register input device, " ++ "error: %d\n", error); ++ } ++ printk("input: JZ Keypad Registered\n"); ++ ++ return 0; ++} ++ ++static int jz_kbd_remove(struct platform_device *dev) ++{ ++ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); ++ ++ del_timer_sync(&jz_kbd->timer); ++ ++ __gpio_as_input(85); ++ __gpio_as_input(87); ++ __gpio_as_input(91); ++ ++ /* These pins is conficting with cs8900a's CS RD WE pins on JZ4740-PAVO board */ ++ __gpio_as_input(60); ++ __gpio_as_input(61); ++ __gpio_as_input(62); ++ ++ input_unregister_device(jz_kbd->input); ++ ++ return 0; ++} ++ ++static struct platform_driver jz_kbd_driver = { ++ .probe = jz_kbd_probe, ++ .remove = jz_kbd_remove, ++ .suspend = jz_kbd_suspend, ++ .resume = jz_kbd_resume, ++ .driver = { ++ .name = "jz-keypad", ++ }, ++}; ++ ++/* ++ * Jz Keyboard Device ++ */ ++static struct platform_device jzkbd_device = { ++ .name = "jz-keypad", ++ .id = -1, ++}; ++ ++static int __init jz_kbd_init(void) ++{ ++ platform_device_register(&jzkbd_device); ++ return platform_driver_register(&jz_kbd_driver); ++} ++ ++static void __exit jz_kbd_exit(void) ++{ ++ platform_device_unregister(&jzkbd_device); ++ platform_driver_unregister(&jz_kbd_driver); ++} ++ ++module_init(jz_kbd_init); ++module_exit(jz_kbd_exit); ++ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("JZ keypad driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/input/keyboard/jz_keypad_5x5.c b/drivers/input/keyboard/jz_keypad_5x5.c +new file mode 100644 +index 0000000..eb1502b +--- /dev/null ++++ b/drivers/input/keyboard/jz_keypad_5x5.c +@@ -0,0 +1,329 @@ ++/* ++ * JZ Keypad ( 5 x 5 ) Driver ++ * ++ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: Jason 20090210 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define KB_ROWS 5 ++#define KB_COLS 5 ++ ++#define SCAN_INTERVAL (10) ++ ++#define ROW_KEYBIT_MASK 0xFFE0 ++ ++#define SET_GPIOS_AS_INPUT() \ ++do { \ ++ unsigned short i; \ ++ \ ++ for (i = 0; i < KB_ROWS; i++) { \ ++ __gpio_as_input(jz_row_gpios[i]); \ ++ __gpio_as_input(jz_col_gpios[i]); \ ++ } \ ++} while (0) ++ ++ ++#define GET_ROW_GPIO_PINS() \ ++({ \ ++ unsigned short _pins = 0, i; \ ++ for (i = 0; \ ++ i < KB_ROWS; \ ++ _pins |= __gpio_get_pin(jz_row_gpios[i]) << i, i++) \ ++ ; \ ++ _pins; \ ++}) ++ ++#define CHECK_IF_KEY_PRESSED(s) \ ++({ \ ++ unsigned short i; \ ++ for (i = 0; i < KB_COLS && s[i] == 0x1F ; i++) \ ++ ; \ ++ i != KB_ROWS; \ ++}) ++ ++#define CLEAN_SCAN_RESULT(s) \ ++do { \ ++ unsigned short i; \ ++ for (i = 0; i < KB_COLS; s[i++] = 0x1F) \ ++ ; \ ++} while (0) ++ ++ ++static const unsigned short jz_col_gpios[KB_ROWS] = {76, 75, 74, 73, 72}; ++static const unsigned short jz_row_gpios[KB_COLS] = {181, 182, 79, 78, 77}; ++ ++static const unsigned int jz_kbd_keycode[KB_ROWS * KB_COLS] = { ++ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, ++ KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, ++ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, ++ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, ++ KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_SPACE, KEY_BACKSPACE, KEY_Y ++}; ++ ++struct jz_kbd { ++ unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)]; ++ struct input_dev *input; ++ char phys[32]; ++ ++ spinlock_t lock; ++ struct timer_list timer; ++ ++ unsigned int suspended; ++ unsigned long suspend_jiffies; ++}; ++static struct jz_kbd g_jz_kbd; ++ ++static unsigned short scan_result[KB_COLS]; ++static unsigned short pre_scan_result[KB_COLS] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; ++static unsigned short pre_col, pre_row; ++ ++/** ++ * Scan keypad by reading GPIO pins. ++ */ ++static inline void jz_do_scan(unsigned short *s) ++{ ++ unsigned short i; ++ ++ if (!s) ++ return ; ++ ++ for (i = 0; i < KB_COLS; i++) { ++ ++ SET_GPIOS_AS_INPUT(); ++ __gpio_clear_pin(jz_col_gpios[i]); ++ __gpio_as_output(jz_col_gpios[i]); ++ ++ udelay(1000); ++ ++ s[i] = GET_ROW_GPIO_PINS(); ++ } ++} ++ ++/** ++ * Call scan function and handle 'GPIO event'(like key down, key up), ++ * and report it to upper layer of input subsystem ... if necessary ++ */ ++static void jz_kbd_scan(struct jz_kbd *kbd_data) ++{ ++ unsigned short row, col, i; ++ unsigned long flags; ++ ++ if (kbd_data->suspended) ++ return; ++ ++ spin_lock_irqsave(&kbd_data->lock, flags); ++ ++ jz_do_scan(scan_result); ++ ++ /* check if any key was pressed or not */ ++ if (!CHECK_IF_KEY_PRESSED(scan_result)) { ++ ++ /* key up */ ++ if (CHECK_IF_KEY_PRESSED(pre_scan_result)) { ++ input_report_key(kbd_data->input, kbd_data->keycode[pre_row * KB_COLS + pre_col], 0); ++ input_sync(kbd_data->input); ++ } ++ pre_col = pre_row = 0xFFFF; ++ CLEAN_SCAN_RESULT(pre_scan_result); ++ ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ return; ++ } ++ ++ /* find the key */ ++ for (row = 0; row < KB_ROWS; row++) { ++ for (i = scan_result[row], col = 0; col < KB_COLS; col++) { ++ if ( !(i & 0x01) ) ++ break; ++ i >>= 1; ++ } ++ if (col != KB_COLS) ++ break; ++ } ++ ++ //printk("[DRIVER] row = %d, col = %d, key code: 0x%02X\n", row, col, kbd_data->keycode[row * KB_COLS + col]); ++ ++ /* the same as the preview one || new key */ ++ if ( (col == pre_col && row == pre_row) ++ || (pre_col == 0xFFFF && pre_row == 0xFFFF) ) { ++ ++ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); ++ input_sync(kbd_data->input); ++ ++ } else { ++ /* the preview key is up and other key is down */ ++ input_report_key(kbd_data->input, kbd_data->keycode[pre_row * KB_COLS + col], 0); ++ input_sync(kbd_data->input); ++ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); ++ input_sync(kbd_data->input); ++ } ++ ++ for (i = 0; i < KB_ROWS; i++) { ++ pre_scan_result[i] = scan_result[i]; ++ } ++ ++ pre_col = col; ++ pre_row = row; ++ ++ spin_unlock_irqrestore(&kbd_data->lock, flags); ++ ++ return; ++} ++ ++static void jz_kbd_timer_callback(unsigned long data) ++{ ++ jz_kbd_scan(&g_jz_kbd); ++ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); ++} ++ ++#ifdef CONFIG_PM ++static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); ++ jz_kbd->suspended = 1; ++ ++ return 0; ++} ++ ++static int jz_kbd_resume(struct platform_device *dev) ++{ ++ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); ++ ++ jz_kbd->suspend_jiffies = jiffies; ++ jz_kbd->suspended = 0; ++ ++ return 0; ++} ++ ++#else ++#define jz_kbd_suspend NULL ++#define jz_kbd_resume NULL ++#endif ++ ++/** ++ * Driver init ++ */ ++static int __init jz_kbd_probe(struct platform_device *dev) ++{ ++ struct input_dev *input_dev; ++ int i, error; ++ ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ return -ENOMEM; ++ ++ platform_set_drvdata(dev, &g_jz_kbd); ++ ++ strcpy(g_jz_kbd.phys, "input/kbd0"); ++ ++ spin_lock_init(&g_jz_kbd.lock); ++ ++ g_jz_kbd.suspend_jiffies = jiffies; ++ g_jz_kbd.input = input_dev; ++ ++ input_dev->private = &g_jz_kbd; ++ input_dev->name = "JZ 5x5 Keypad"; ++ input_dev->phys = g_jz_kbd.phys; ++ input_dev->cdev.dev = &dev->dev; ++ ++ input_dev->id.bustype = BUS_PARPORT; ++ input_dev->id.vendor = 0x0001; ++ input_dev->id.product = 0x0001; ++ input_dev->id.version = 0x0100; ++ ++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN); ++ input_dev->keycode = g_jz_kbd.keycode; ++ input_dev->keycodesize = sizeof(unsigned int); ++ input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode); ++ ++ memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode)); ++ ++ for ( i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++) ++ set_bit(g_jz_kbd.keycode[i], input_dev->keybit); ++ ++ init_timer(&g_jz_kbd.timer); ++ g_jz_kbd.timer.function = jz_kbd_timer_callback; ++ g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd; ++ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); ++ ++ error = input_register_device(input_dev); ++ if (error) { ++ pr_err("gpio-keys: Unable to register input device, " ++ "error: %d\n", error); ++ } ++ printk("input: JZ 5x5 Keypad Registered.\n"); ++ ++ return 0; ++} ++ ++static int jz_kbd_remove(struct platform_device *dev) ++{ ++ struct jz_kbd *kbd = platform_get_drvdata(dev); ++ ++ del_timer_sync(&kbd->timer); ++ ++ SET_GPIOS_AS_INPUT(); ++ ++ input_unregister_device(kbd->input); ++ ++ return 0; ++} ++ ++static struct platform_driver jz_kbd_driver = { ++ .probe = jz_kbd_probe, ++ .remove = jz_kbd_remove, ++ .suspend= jz_kbd_suspend, ++ .resume = jz_kbd_resume, ++ .driver = { ++ .name = "jz-5x5-keypad", ++ }, ++}; ++ ++static struct platform_device jzkbd_device = { ++ .name = "jz-5x5-keypad", ++ .id = -1, ++}; ++ ++static int __init jz_kbd_init(void) ++{ ++ platform_device_register(&jzkbd_device); ++ return platform_driver_register(&jz_kbd_driver); ++} ++ ++static void __exit jz_kbd_exit(void) ++{ ++ platform_device_unregister(&jzkbd_device); ++ platform_driver_unregister(&jz_kbd_driver); ++} ++ ++module_init(jz_kbd_init); ++module_exit(jz_kbd_exit); ++ ++MODULE_AUTHOR("Jason "); ++MODULE_DESCRIPTION("JZ 5x5 keypad driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig +index 84b6fc1..16c0f2e 100644 +--- a/drivers/media/video/Kconfig ++++ b/drivers/media/video/Kconfig +@@ -615,6 +615,24 @@ config VIDEO_VINO + Say Y here to build in support for the Vino video input system found + on SGI Indy machines. + ++config VIDEO_JZ4730_CIM ++ tristate 'JzSOC Camera Interface Module (CIM) support' ++ depends on VIDEO_V4L2 && FB_JZSOC && SOC_JZ4730 ++ select VIDEO_JZ_SENSOR ++ ++config VIDEO_JZ4740_CIM ++ tristate 'JzSOC Camera Interface Module (CIM) support' ++ depends on VIDEO_V4L2 && FB_JZSOC && SOC_JZ4740 ++ select VIDEO_JZ_SENSOR ++ ++config VIDEO_JZ4750_CIM ++ tristate 'JzSOC Camera Interface Module (CIM) support' ++ depends on VIDEO_V4L2 && FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D) ++ select VIDEO_JZ_SENSOR ++ ++config VIDEO_JZ_SENSOR ++ tristate "Jz generic camera sensor driver" ++ + config VIDEO_STRADIS + tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)" + depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS +diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile +index 9f2e321..77a2944 100644 +--- a/drivers/media/video/Makefile ++++ b/drivers/media/video/Makefile +@@ -80,6 +80,11 @@ obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o + + # And now the v4l2 drivers: + ++obj-$(CONFIG_VIDEO_JZ4730_CIM) += jz4730_cim.o ++obj-$(CONFIG_VIDEO_JZ4740_CIM) += jz4740_cim.o ++obj-$(CONFIG_VIDEO_JZ4750_CIM) += jz4750_cim.o ++obj-$(CONFIG_VIDEO_JZ_SENSOR) += jz_sensor.o ++ + obj-$(CONFIG_VIDEO_BT848) += bt8xx/ + obj-$(CONFIG_VIDEO_ZORAN) += zoran/ + obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o +diff --git a/drivers/media/video/jz4730_cim.c b/drivers/media/video/jz4730_cim.c +new file mode 100644 +index 0000000..4ea0594 +--- /dev/null ++++ b/drivers/media/video/jz4730_cim.c +@@ -0,0 +1,622 @@ ++/* ++ * linux/drivers/char/jzchar/cim.c ++ * ++ * Camera Interface Module (CIM) driver for JzSOC ++ * This driver is independent of the camera sensor ++ * ++ * Copyright (C) 2005 JunZheng semiconductor ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define CIM_NAME "cim" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("JzSOC Camera Interface Module driver"); ++MODULE_LICENSE("GPL"); ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++/* ++ * Define the Max Image Size ++ */ ++#define MAX_IMAGE_WIDTH 2048 ++#define MAX_IMAGE_HEIGHT 2048 ++#define MAX_IMAGE_BPP 16 ++#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8) ++#define CIM_RAM_ADDR (CIM_BASE + 0x1000) ++ ++typedef struct ++{ ++ u32 width; ++ u32 height; ++ u32 bpp; ++} img_param_t; ++ ++typedef struct ++{ ++ u32 cfg; ++ u32 ctrl; ++ u32 mclk; ++} cim_config_t; ++ ++/* ++ * IOCTL_XXX commands ++ */ ++#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t * ++#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t * ++#define IOCTL_STOP_CIM 2 // arg type: void ++#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t * ++#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t * ++#define IOCTL_TEST_CIM_RAM 5 // no arg type * ++ ++/* ++ * CIM DMA descriptor ++ */ ++struct cim_desc { ++ u32 nextdesc; /* Physical address of next desc */ ++ u32 framebuf; /* Physical address of frame buffer */ ++ u32 frameid; /* Frame ID */ ++ u32 dmacmd; /* DMA command */ ++ u32 pagenum; ++}; ++ ++/* ++ * CIM device structure ++ */ ++struct cim_device { ++ struct video_device *jz_cim; ++ unsigned char *framebuf; ++ unsigned int frame_size; ++ unsigned int page_order; ++ wait_queue_head_t wait_queue; ++ struct cim_desc *frame_desc __attribute__ ((aligned (16))); ++}; ++ ++/* global*/ ++static struct cim_device *cim_dev; ++ ++/*========================================================================== ++ * CIM init routines ++ *========================================================================*/ ++#if defined(CONFIG_SOC_JZ4750) ++static void cim_image_area(img_param_t *c) { ++ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/ ++ REG_CIM_SIZE = 0; ++ REG_CIM_OFFSET = 0; ++ if (REG_CIM_CTRL & CIM_CTRL_SIZEEN_MASK) { ++ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT); ++ REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT); ++// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT); ++ } ++} ++#endif ++ ++static void cim_config(cim_config_t *c) ++{ ++ REG_CIM_CFG = c->cfg; ++ REG_CIM_CTRL = c->ctrl; ++ ++ /*Set the master clock output*/ ++#if defined(CONFIG_SOC_JZ4730) ++ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); ++#elif defined(CONFIG_SOC_JZ4740) ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#elif defined(CONFIG_SOC_JZ4750) ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#else ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#endif ++ /* Enable sof, eof and stop interrupts*/ ++ __cim_enable_sof_intr(); ++ __cim_enable_eof_intr(); ++ __cim_enable_stop_intr(); ++} ++ ++/*========================================================================== ++ * CIM start/stop operations ++ *========================================================================*/ ++static int cim_start_dma(char *ubuf) ++{ ++ struct cim_desc *jz_frame_desc; ++ int cim_frame_size = 0; ++ jz_frame_desc = cim_dev->frame_desc; ++ dprintk("framedesc = %x\n", (u32) jz_frame_desc); ++ __cim_disable(); ++ dprintk("__cim_disable\n"); ++ __cim_set_da(virt_to_phys(cim_dev->frame_desc)); ++ __cim_clear_state(); // clear state register ++ __cim_reset_rxfifo(); // resetting rxfifo ++ __cim_unreset_rxfifo(); ++ __cim_enable_dma(); // enable dma ++ __cim_enable(); ++ ++ dprintk("__cim_enable\n"); ++// while(1) { ++// mdelay(10); ++// dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); ++// dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); ++// dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); ++// dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); ++// dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); ++// dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); ++// dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); ++// dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); ++// dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); ++// mdelay(100); ++// } ++ // wait for interrupts ++ interruptible_sleep_on(&cim_dev->wait_queue); ++ dprintk("interruptible_sleep_on\n"); ++ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); ++ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); ++ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); ++ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); ++ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); ++ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); ++ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); ++ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); ++ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); ++ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD); ++ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA); ++ /* copy frame data to user buffer */ ++ jz_frame_desc = cim_dev->frame_desc; ++ ++ while(jz_frame_desc != NULL) ++ { ++ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff); ++ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4)); ++ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; ++ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; ++ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); ++ } ++ return cim_dev->frame_size; ++} ++static void cim_stop(void) ++{ ++ __cim_disable(); ++ __cim_clear_state(); ++} ++ ++/*========================================================================== ++ * Framebuffer allocation and destroy ++ *========================================================================*/ ++static void cim_fb_destroy(void) ++{ ++ int pages; ++ struct cim_desc *jz_frame_desc, *p_desc; ++ if (cim_dev->frame_desc == NULL) { ++ printk("Original memory is NULL\n"); ++ return; ++ } ++ jz_frame_desc = cim_dev->frame_desc; ++ while (jz_frame_desc != NULL) { ++ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4); ++ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); ++ pages = jz_frame_desc->pagenum; ++ dprintk("page_order = %d\n", pages); ++ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages); ++ kfree(jz_frame_desc); ++ jz_frame_desc = p_desc; ++ } ++ cim_dev->frame_desc = NULL; ++} ++ ++static struct cim_desc *get_desc_list(int page_order) ++{ ++ int num, page_nums = 0; ++ unsigned char *p_buf; ++ struct cim_desc *desc_list_head __attribute__ ((aligned (16))); ++ struct cim_desc *desc_list_tail __attribute__ ((aligned (16))); ++ struct cim_desc *p_desc; ++// num = page_order - 1; ++ num = page_order; ++ desc_list_head = desc_list_tail = NULL; ++ ++ while(page_nums < (1 << page_order)) { ++ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL); ++ if (NULL == p_desc) ++ return NULL; ++ //return -ENOMEM; ++ cim_realloc_pages: ++ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num); ++ if ( !(p_buf) && num != 0) { ++ num --; ++ goto cim_realloc_pages; ++ } ++ else if ( !(p_buf) && num == 0) { ++ printk("No memory can be alloc!\n"); ++ //return -ENOMEM; ++ return NULL; ++ } ++ else { ++ if (desc_list_head == NULL) { ++ dprintk("Page_list_head\n"); ++ desc_list_head = p_desc; ++ } ++ ++ else ++ desc_list_tail->nextdesc = virt_to_phys(p_desc); ++ ++ desc_list_tail = p_desc; ++ desc_list_tail->framebuf = virt_to_phys(p_buf); ++ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf); ++ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail)); ++ ++ desc_list_tail->frameid = 0x52052018; ++ desc_list_tail->pagenum = num; ++ if ((page_nums + (1<< num)) < (1 << page_order)) { ++ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ; ++ } ++ else ++ desc_list_tail->dmacmd = ++ (cim_dev->frame_size - page_nums * 4096) >> 2 ; ++ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); ++ page_nums += (1 << num); ++ dprintk("the pages_num is %d\n", page_nums); ++ } ++ } ++ ++ desc_list_tail->nextdesc = virt_to_phys(NULL); ++ /* stop after capturing a frame */ ++ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT); ++ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); ++ ++ return desc_list_head; ++} ++ ++static int cim_fb_alloc(int img_width, int img_height, int img_bpp) ++{ ++#if defined(CONFIG_SOC_JZ4750) ++ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0) ++ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8); ++ else ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++#else ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++#endif ++ cim_dev->page_order = get_order(cim_dev->frame_size); ++ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order); ++ /* frame buffer ?? need large mem ??*/ ++ cim_dev->frame_desc = get_desc_list(cim_dev->page_order); ++ if (cim_dev->frame_desc == NULL) ++ return -ENOMEM; ++ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16); ++ return 0; ++} ++ ++/*========================================================================== ++ * File operations ++ *========================================================================*/ ++ ++static int cim_open(struct inode *inode, struct file *filp); ++static int cim_release(struct inode *inode, struct file *filp); ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++static int cim_mmap(struct file *file, struct vm_area_struct *vma); ++ ++static struct file_operations cim_fops = ++{ ++ open: cim_open, ++ release: cim_release, ++ read: cim_read, ++ write: cim_write, ++ ioctl: cim_ioctl, ++ compat_ioctl: v4l_compat_ioctl32, ++ mmap: cim_mmap ++}; ++ ++static struct video_device jz_v4l_device = { ++ .name = "jz cim", ++ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | ++ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY ++ .fops = &cim_fops, ++ .minor = -1, ++ .owner = THIS_MODULE, ++ .release = video_device_release, ++}; ++ ++static int cim_open(struct inode *inode, struct file *filp) ++{ ++ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int cim_release(struct inode *inode, struct file *filp) ++{ ++ cim_fb_destroy(); ++ cim_stop(); ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ if (size < cim_dev->frame_size) ++ return -EINVAL; ++ dprintk("read cim\n"); ++ return cim_start_dma(buf); ++} ++ ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("cim error: write is not implemented\n"); ++ return -1; ++} ++ ++static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ switch (cmd) { ++ case IOCTL_GET_IMG_PARAM: ++ { ++ img_param_t i; ++ return copy_to_user(argp, &i, sizeof(img_param_t)) ? -EFAULT : 0; ++ } ++ case IOCTL_SET_IMG_PARAM: ++ { ++ img_param_t i; ++ int img_width, img_height, img_bpp; ++ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) ++ return -EFAULT; ++#if defined(CONFIG_SOC_JZ4750) ++ cim_image_area(&i); ++#endif ++ img_width = i.width; ++ img_height = i.height; ++ img_bpp = i.bpp; ++ dprintk("ioctl_set_cim_param\n"); ++ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){ ++ printk("ERROR! Image is too large!\n"); ++ return -EINVAL; ++ } ++ /* allocate frame buffers */ ++ if (cim_dev->frame_desc == NULL){ ++ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ ++ printk("ERROR! Init & alloc cim fail!\n"); ++ return -ENOMEM; ++ } ++ } ++ else ++ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){ ++ /* realloc the buffer */ ++ cim_fb_destroy(); ++ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ ++ printk("ERRROR! Init & alloc cim fail!\n"); ++ return -ENOMEM; ++ } ++ } ++ break; ++ } ++ case IOCTL_CIM_CONFIG: ++ { ++ cim_config_t c; ++ ++ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t))) ++ return -EFAULT; ++ ++ cim_config(&c); ++ ++ break; ++ } ++ case IOCTL_TEST_CIM_RAM: ++ { ++ ++ int i; ++ volatile unsigned int *ptr; ++ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); ++ printk("RAM test!\n"); ++ printk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR); ++ for (i = 0; i < 1024; ptr++, i++) ++ *ptr = i; ++ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); ++ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc); ++ ++ for (i = 0; i < 1024; i++) { ++ if (i != *ptr) ++ printk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i); ++ if (i%32 == 0) { ++ if (i%128 == 0) ++ printk("\n"); ++ printk("*ptr=%04d, i=%04d | ", *ptr, i); ++ } ++ ptr++; ++ } ++ printk("\n"); ++ break; ++ } ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return 0; ++} ++ ++/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ ++static int cim_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); ++ ++ /* frame buffer memory */ ++ start = cim_dev->frame_desc->framebuf; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK)); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ ++#if defined(CONFIG_MIPS32) ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NO_WA; /* WT cachable */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; ++#endif ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) ++ vma->vm_flags |= VM_IO; ++ return -EAGAIN; ++ ++ return 0; ++} ++/*========================================================================== ++ * Interrupt handler ++ *========================================================================*/ ++ ++static irqreturn_t cim_irq_handler(int irq, void *dev_id) ++{ ++ u32 state = REG_CIM_STATE; ++ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE); ++ dprintk("REG_CIM_CTRL = %x\n", REG_CIM_CTRL); ++#if 1 ++ if (state & CIM_STATE_RXF_OF) { ++ dprintk("OverFlow interrupt!\n"); ++ } ++#endif ++ if (state & CIM_STATE_DMA_EOF) { ++ dprintk("EOF interrupt!\n"); ++ __cim_disable_dma(); ++ __cim_disable(); ++ wake_up_interruptible(&cim_dev->wait_queue); ++ dprintk("EOF interrupt wake up!\n"); ++ } ++ ++ if (state & CIM_STATE_DMA_STOP) { ++ // Got a frame, wake up wait routine ++ __cim_disable_dma(); ++ __cim_disable(); ++ dprintk("Stop interrupt!\n"); ++ wake_up_interruptible(&cim_dev->wait_queue); ++ } ++#if 1 ++ if (state & CIM_STATE_RXF_TRIG) { ++ dprintk("Trig!\n"); ++ } ++#endif ++ ++ /* clear status flags*/ ++ REG_CIM_STATE = 0; ++ return IRQ_HANDLED; ++} ++ ++static int v4l_device_init(void) ++{ ++ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL); ++ if (!cim_dev) return -ENOMEM; ++ cim_dev->jz_cim = video_device_alloc(); ++ if (!cim_dev->jz_cim) { ++ return -ENOMEM; ++ } ++ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device)); ++ cim_dev->frame_desc = NULL; ++ cim_dev->frame_size = 0; ++ cim_dev->page_order = 0; ++ return 0; ++} ++/*========================================================================== ++ * Module init and exit ++ *========================================================================*/ ++ ++static int __init jz_cim_init(void) ++{ ++ struct cim_device *dev; ++ int ret; ++ /* allocate device */ ++ ret = v4l_device_init(); ++ if (ret) ++ return ret; ++ /* record device */ ++ dev = cim_dev; ++ init_waitqueue_head(&dev->wait_queue); ++ ++ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1); ++ if (ret < 0) { ++ printk(KERN_ERR "CIM Video4Linux-device " ++ "registration failed\n"); ++ return -EINVAL; ++ } ++ ++ if (ret < 0) { ++ cim_fb_destroy(); ++ kfree(dev); ++ return ret; ++ } ++ ++ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, ++ CIM_NAME, dev))) { ++ printk(KERN_ERR "request_irq return error, ret=%d\n", ret); ++ cim_fb_destroy(); ++ kfree(dev); ++ printk(KERN_ERR "CIM could not get IRQ\n"); ++ return ret; ++ } ++ ++ printk("JzSOC Camera Interface Module (CIM) driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit jz_cim_exit(void) ++{ ++ free_irq(IRQ_CIM, cim_dev); ++ kfree(cim_dev); ++ video_unregister_device(cim_dev->jz_cim); ++} ++ ++module_init(jz_cim_init); ++module_exit(jz_cim_exit); +diff --git a/drivers/media/video/jz4740_cim.c b/drivers/media/video/jz4740_cim.c +new file mode 100644 +index 0000000..4ea0594 +--- /dev/null ++++ b/drivers/media/video/jz4740_cim.c +@@ -0,0 +1,622 @@ ++/* ++ * linux/drivers/char/jzchar/cim.c ++ * ++ * Camera Interface Module (CIM) driver for JzSOC ++ * This driver is independent of the camera sensor ++ * ++ * Copyright (C) 2005 JunZheng semiconductor ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define CIM_NAME "cim" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("JzSOC Camera Interface Module driver"); ++MODULE_LICENSE("GPL"); ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++/* ++ * Define the Max Image Size ++ */ ++#define MAX_IMAGE_WIDTH 2048 ++#define MAX_IMAGE_HEIGHT 2048 ++#define MAX_IMAGE_BPP 16 ++#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8) ++#define CIM_RAM_ADDR (CIM_BASE + 0x1000) ++ ++typedef struct ++{ ++ u32 width; ++ u32 height; ++ u32 bpp; ++} img_param_t; ++ ++typedef struct ++{ ++ u32 cfg; ++ u32 ctrl; ++ u32 mclk; ++} cim_config_t; ++ ++/* ++ * IOCTL_XXX commands ++ */ ++#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t * ++#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t * ++#define IOCTL_STOP_CIM 2 // arg type: void ++#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t * ++#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t * ++#define IOCTL_TEST_CIM_RAM 5 // no arg type * ++ ++/* ++ * CIM DMA descriptor ++ */ ++struct cim_desc { ++ u32 nextdesc; /* Physical address of next desc */ ++ u32 framebuf; /* Physical address of frame buffer */ ++ u32 frameid; /* Frame ID */ ++ u32 dmacmd; /* DMA command */ ++ u32 pagenum; ++}; ++ ++/* ++ * CIM device structure ++ */ ++struct cim_device { ++ struct video_device *jz_cim; ++ unsigned char *framebuf; ++ unsigned int frame_size; ++ unsigned int page_order; ++ wait_queue_head_t wait_queue; ++ struct cim_desc *frame_desc __attribute__ ((aligned (16))); ++}; ++ ++/* global*/ ++static struct cim_device *cim_dev; ++ ++/*========================================================================== ++ * CIM init routines ++ *========================================================================*/ ++#if defined(CONFIG_SOC_JZ4750) ++static void cim_image_area(img_param_t *c) { ++ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/ ++ REG_CIM_SIZE = 0; ++ REG_CIM_OFFSET = 0; ++ if (REG_CIM_CTRL & CIM_CTRL_SIZEEN_MASK) { ++ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT); ++ REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT); ++// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT); ++ } ++} ++#endif ++ ++static void cim_config(cim_config_t *c) ++{ ++ REG_CIM_CFG = c->cfg; ++ REG_CIM_CTRL = c->ctrl; ++ ++ /*Set the master clock output*/ ++#if defined(CONFIG_SOC_JZ4730) ++ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); ++#elif defined(CONFIG_SOC_JZ4740) ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#elif defined(CONFIG_SOC_JZ4750) ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#else ++ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++#endif ++ /* Enable sof, eof and stop interrupts*/ ++ __cim_enable_sof_intr(); ++ __cim_enable_eof_intr(); ++ __cim_enable_stop_intr(); ++} ++ ++/*========================================================================== ++ * CIM start/stop operations ++ *========================================================================*/ ++static int cim_start_dma(char *ubuf) ++{ ++ struct cim_desc *jz_frame_desc; ++ int cim_frame_size = 0; ++ jz_frame_desc = cim_dev->frame_desc; ++ dprintk("framedesc = %x\n", (u32) jz_frame_desc); ++ __cim_disable(); ++ dprintk("__cim_disable\n"); ++ __cim_set_da(virt_to_phys(cim_dev->frame_desc)); ++ __cim_clear_state(); // clear state register ++ __cim_reset_rxfifo(); // resetting rxfifo ++ __cim_unreset_rxfifo(); ++ __cim_enable_dma(); // enable dma ++ __cim_enable(); ++ ++ dprintk("__cim_enable\n"); ++// while(1) { ++// mdelay(10); ++// dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); ++// dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); ++// dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); ++// dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); ++// dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); ++// dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); ++// dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); ++// dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); ++// dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); ++// mdelay(100); ++// } ++ // wait for interrupts ++ interruptible_sleep_on(&cim_dev->wait_queue); ++ dprintk("interruptible_sleep_on\n"); ++ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); ++ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); ++ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); ++ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); ++ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); ++ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); ++ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); ++ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); ++ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); ++ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD); ++ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA); ++ /* copy frame data to user buffer */ ++ jz_frame_desc = cim_dev->frame_desc; ++ ++ while(jz_frame_desc != NULL) ++ { ++ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff); ++ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4)); ++ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; ++ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; ++ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); ++ } ++ return cim_dev->frame_size; ++} ++static void cim_stop(void) ++{ ++ __cim_disable(); ++ __cim_clear_state(); ++} ++ ++/*========================================================================== ++ * Framebuffer allocation and destroy ++ *========================================================================*/ ++static void cim_fb_destroy(void) ++{ ++ int pages; ++ struct cim_desc *jz_frame_desc, *p_desc; ++ if (cim_dev->frame_desc == NULL) { ++ printk("Original memory is NULL\n"); ++ return; ++ } ++ jz_frame_desc = cim_dev->frame_desc; ++ while (jz_frame_desc != NULL) { ++ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4); ++ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); ++ pages = jz_frame_desc->pagenum; ++ dprintk("page_order = %d\n", pages); ++ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages); ++ kfree(jz_frame_desc); ++ jz_frame_desc = p_desc; ++ } ++ cim_dev->frame_desc = NULL; ++} ++ ++static struct cim_desc *get_desc_list(int page_order) ++{ ++ int num, page_nums = 0; ++ unsigned char *p_buf; ++ struct cim_desc *desc_list_head __attribute__ ((aligned (16))); ++ struct cim_desc *desc_list_tail __attribute__ ((aligned (16))); ++ struct cim_desc *p_desc; ++// num = page_order - 1; ++ num = page_order; ++ desc_list_head = desc_list_tail = NULL; ++ ++ while(page_nums < (1 << page_order)) { ++ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL); ++ if (NULL == p_desc) ++ return NULL; ++ //return -ENOMEM; ++ cim_realloc_pages: ++ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num); ++ if ( !(p_buf) && num != 0) { ++ num --; ++ goto cim_realloc_pages; ++ } ++ else if ( !(p_buf) && num == 0) { ++ printk("No memory can be alloc!\n"); ++ //return -ENOMEM; ++ return NULL; ++ } ++ else { ++ if (desc_list_head == NULL) { ++ dprintk("Page_list_head\n"); ++ desc_list_head = p_desc; ++ } ++ ++ else ++ desc_list_tail->nextdesc = virt_to_phys(p_desc); ++ ++ desc_list_tail = p_desc; ++ desc_list_tail->framebuf = virt_to_phys(p_buf); ++ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf); ++ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail)); ++ ++ desc_list_tail->frameid = 0x52052018; ++ desc_list_tail->pagenum = num; ++ if ((page_nums + (1<< num)) < (1 << page_order)) { ++ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ; ++ } ++ else ++ desc_list_tail->dmacmd = ++ (cim_dev->frame_size - page_nums * 4096) >> 2 ; ++ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); ++ page_nums += (1 << num); ++ dprintk("the pages_num is %d\n", page_nums); ++ } ++ } ++ ++ desc_list_tail->nextdesc = virt_to_phys(NULL); ++ /* stop after capturing a frame */ ++ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT); ++ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); ++ ++ return desc_list_head; ++} ++ ++static int cim_fb_alloc(int img_width, int img_height, int img_bpp) ++{ ++#if defined(CONFIG_SOC_JZ4750) ++ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0) ++ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8); ++ else ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++#else ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++#endif ++ cim_dev->page_order = get_order(cim_dev->frame_size); ++ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order); ++ /* frame buffer ?? need large mem ??*/ ++ cim_dev->frame_desc = get_desc_list(cim_dev->page_order); ++ if (cim_dev->frame_desc == NULL) ++ return -ENOMEM; ++ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16); ++ return 0; ++} ++ ++/*========================================================================== ++ * File operations ++ *========================================================================*/ ++ ++static int cim_open(struct inode *inode, struct file *filp); ++static int cim_release(struct inode *inode, struct file *filp); ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++static int cim_mmap(struct file *file, struct vm_area_struct *vma); ++ ++static struct file_operations cim_fops = ++{ ++ open: cim_open, ++ release: cim_release, ++ read: cim_read, ++ write: cim_write, ++ ioctl: cim_ioctl, ++ compat_ioctl: v4l_compat_ioctl32, ++ mmap: cim_mmap ++}; ++ ++static struct video_device jz_v4l_device = { ++ .name = "jz cim", ++ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | ++ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY ++ .fops = &cim_fops, ++ .minor = -1, ++ .owner = THIS_MODULE, ++ .release = video_device_release, ++}; ++ ++static int cim_open(struct inode *inode, struct file *filp) ++{ ++ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int cim_release(struct inode *inode, struct file *filp) ++{ ++ cim_fb_destroy(); ++ cim_stop(); ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ if (size < cim_dev->frame_size) ++ return -EINVAL; ++ dprintk("read cim\n"); ++ return cim_start_dma(buf); ++} ++ ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("cim error: write is not implemented\n"); ++ return -1; ++} ++ ++static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ switch (cmd) { ++ case IOCTL_GET_IMG_PARAM: ++ { ++ img_param_t i; ++ return copy_to_user(argp, &i, sizeof(img_param_t)) ? -EFAULT : 0; ++ } ++ case IOCTL_SET_IMG_PARAM: ++ { ++ img_param_t i; ++ int img_width, img_height, img_bpp; ++ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) ++ return -EFAULT; ++#if defined(CONFIG_SOC_JZ4750) ++ cim_image_area(&i); ++#endif ++ img_width = i.width; ++ img_height = i.height; ++ img_bpp = i.bpp; ++ dprintk("ioctl_set_cim_param\n"); ++ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){ ++ printk("ERROR! Image is too large!\n"); ++ return -EINVAL; ++ } ++ /* allocate frame buffers */ ++ if (cim_dev->frame_desc == NULL){ ++ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ ++ printk("ERROR! Init & alloc cim fail!\n"); ++ return -ENOMEM; ++ } ++ } ++ else ++ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){ ++ /* realloc the buffer */ ++ cim_fb_destroy(); ++ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ ++ printk("ERRROR! Init & alloc cim fail!\n"); ++ return -ENOMEM; ++ } ++ } ++ break; ++ } ++ case IOCTL_CIM_CONFIG: ++ { ++ cim_config_t c; ++ ++ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t))) ++ return -EFAULT; ++ ++ cim_config(&c); ++ ++ break; ++ } ++ case IOCTL_TEST_CIM_RAM: ++ { ++ ++ int i; ++ volatile unsigned int *ptr; ++ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); ++ printk("RAM test!\n"); ++ printk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR); ++ for (i = 0; i < 1024; ptr++, i++) ++ *ptr = i; ++ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); ++ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc); ++ ++ for (i = 0; i < 1024; i++) { ++ if (i != *ptr) ++ printk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i); ++ if (i%32 == 0) { ++ if (i%128 == 0) ++ printk("\n"); ++ printk("*ptr=%04d, i=%04d | ", *ptr, i); ++ } ++ ptr++; ++ } ++ printk("\n"); ++ break; ++ } ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return 0; ++} ++ ++/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ ++static int cim_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); ++ ++ /* frame buffer memory */ ++ start = cim_dev->frame_desc->framebuf; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK)); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ ++#if defined(CONFIG_MIPS32) ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NO_WA; /* WT cachable */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; ++#endif ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) ++ vma->vm_flags |= VM_IO; ++ return -EAGAIN; ++ ++ return 0; ++} ++/*========================================================================== ++ * Interrupt handler ++ *========================================================================*/ ++ ++static irqreturn_t cim_irq_handler(int irq, void *dev_id) ++{ ++ u32 state = REG_CIM_STATE; ++ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE); ++ dprintk("REG_CIM_CTRL = %x\n", REG_CIM_CTRL); ++#if 1 ++ if (state & CIM_STATE_RXF_OF) { ++ dprintk("OverFlow interrupt!\n"); ++ } ++#endif ++ if (state & CIM_STATE_DMA_EOF) { ++ dprintk("EOF interrupt!\n"); ++ __cim_disable_dma(); ++ __cim_disable(); ++ wake_up_interruptible(&cim_dev->wait_queue); ++ dprintk("EOF interrupt wake up!\n"); ++ } ++ ++ if (state & CIM_STATE_DMA_STOP) { ++ // Got a frame, wake up wait routine ++ __cim_disable_dma(); ++ __cim_disable(); ++ dprintk("Stop interrupt!\n"); ++ wake_up_interruptible(&cim_dev->wait_queue); ++ } ++#if 1 ++ if (state & CIM_STATE_RXF_TRIG) { ++ dprintk("Trig!\n"); ++ } ++#endif ++ ++ /* clear status flags*/ ++ REG_CIM_STATE = 0; ++ return IRQ_HANDLED; ++} ++ ++static int v4l_device_init(void) ++{ ++ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL); ++ if (!cim_dev) return -ENOMEM; ++ cim_dev->jz_cim = video_device_alloc(); ++ if (!cim_dev->jz_cim) { ++ return -ENOMEM; ++ } ++ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device)); ++ cim_dev->frame_desc = NULL; ++ cim_dev->frame_size = 0; ++ cim_dev->page_order = 0; ++ return 0; ++} ++/*========================================================================== ++ * Module init and exit ++ *========================================================================*/ ++ ++static int __init jz_cim_init(void) ++{ ++ struct cim_device *dev; ++ int ret; ++ /* allocate device */ ++ ret = v4l_device_init(); ++ if (ret) ++ return ret; ++ /* record device */ ++ dev = cim_dev; ++ init_waitqueue_head(&dev->wait_queue); ++ ++ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1); ++ if (ret < 0) { ++ printk(KERN_ERR "CIM Video4Linux-device " ++ "registration failed\n"); ++ return -EINVAL; ++ } ++ ++ if (ret < 0) { ++ cim_fb_destroy(); ++ kfree(dev); ++ return ret; ++ } ++ ++ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, ++ CIM_NAME, dev))) { ++ printk(KERN_ERR "request_irq return error, ret=%d\n", ret); ++ cim_fb_destroy(); ++ kfree(dev); ++ printk(KERN_ERR "CIM could not get IRQ\n"); ++ return ret; ++ } ++ ++ printk("JzSOC Camera Interface Module (CIM) driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit jz_cim_exit(void) ++{ ++ free_irq(IRQ_CIM, cim_dev); ++ kfree(cim_dev); ++ video_unregister_device(cim_dev->jz_cim); ++} ++ ++module_init(jz_cim_init); ++module_exit(jz_cim_exit); +diff --git a/drivers/media/video/jz4750_cim.c b/drivers/media/video/jz4750_cim.c +new file mode 100644 +index 0000000..7edf285 +--- /dev/null ++++ b/drivers/media/video/jz4750_cim.c +@@ -0,0 +1,734 @@ ++/* ++ * linux/drivers/char/jzchar/cim.c ++ * ++ * Camera Interface Module (CIM) driver for JzSOC ++ * This driver is independent of the camera sensor ++ * ++ * Copyright (C) 2005 JunZheng semiconductor ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "jz4750_cim.h" ++ ++#define CIM_NAME "cim" ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("JzSOC Camera Interface Module driver"); ++MODULE_LICENSE("GPL"); ++ ++#if defined(CONFIG_SOC_JZ4750D) ++//#define USE_CIM_OFRCV 1 /* Test overflow recovery */ ++#define USE_CIM_DMA_SYNC 1 //set da every time ++#endif ++ ++//#define CIM_DEBUG ++#undef CIM_DEBUG ++#ifdef CIM_DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++/* ++ * Define the Max Image Size ++ */ ++#define MAX_IMAGE_WIDTH 2048 ++#define MAX_IMAGE_HEIGHT 2048 ++#define MAX_IMAGE_BPP 16 ++#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8) ++#define CIM_RAM_ADDR (CIM_BASE + 0x1000) ++ ++typedef struct ++{ ++ u32 width; ++ u32 height; ++ u32 bpp; ++} img_param_t; ++ ++typedef struct ++{ ++ u32 cfg; ++ u32 ctrl; ++ u32 mclk; ++ u32 size; ++ u32 offs; ++} cim_config_t; ++ ++/* ++ * IOCTL_XXX commands ++ */ ++#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t * ++#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t * ++#define IOCTL_STOP_CIM 2 // arg type: void ++#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t * ++#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t * ++#define IOCTL_TEST_CIM_RAM 5 // no arg type * ++#define IOCTL_START_CIM 6 // arg type: void ++ ++/* ++ * CIM DMA descriptor ++ */ ++struct cim_desc { ++ u32 nextdesc; /* Physical address of next desc */ ++ u32 framebuf; /* Physical address of frame buffer */ ++ u32 frameid; /* Frame ID */ ++ u32 dmacmd; /* DMA command */ ++ u32 pagenum; ++}; ++ ++/* ++ * CIM device structure ++ */ ++struct cim_device { ++ struct video_device *jz_cim; ++ unsigned char *framebuf; ++ unsigned int frame_size; ++ unsigned int page_order; ++ wait_queue_head_t wait_queue; ++ struct cim_desc *frame_desc __attribute__ ((aligned (16))); ++}; ++ ++/* global*/ ++static struct cim_device *cim_dev; ++static int start_init = 1; ++static int irq_sleep; ++/*========================================================================== ++ * CIM init routines ++ *========================================================================*/ ++ ++static void cim_image_area(img_param_t *c) { ++ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/ ++ REG_CIM_SIZE = 0; ++ REG_CIM_OFFSET = 0; ++#if defined(CONFIG_SOC_JZ4750D) ++ if (REG_CIM_CTRL & CIM_CTRL_WIN_EN) { ++ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT); ++// REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT); ++// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT); ++ REG_CIM_OFFSET = (200 << CIM_OFFSET_V_BIT) | (300 << CIM_OFFSET_H_BIT); ++ } ++#endif ++} ++ ++ ++static void cim_config(cim_config_t *c) ++{ ++ REG_CIM_CFG = c->cfg; ++ REG_CIM_CTRL = c->ctrl; ++ REG_CIM_SIZE = c->size; ++ REG_CIM_OFFSET = c->offs; ++ ++ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); ++ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); ++ /* Set the master clock output */ ++ /* If use pll clock, enable it */ ++// __cim_set_master_clk(__cpm_get_hclk(), c->mclk); ++ ++ /* Enable sof, eof and stop interrupts*/ ++ ++// __cim_enable_sof_intr(); ++ __cim_enable_eof_intr(); ++#if defined(USE_CIM_EEOFINT) ++ __cim_enable_eeof_intr(); ++#endif ++// __cim_enable_stop_intr(); ++// __cim_enable_trig_intr(); ++// __cim_enable_rxfifo_overflow_intr(); ++// __cim_enable_vdd_intr(); ++// printk("hclk=%d, mclk = %d\n", __cpm_get_hclk(),c->mclk); ++ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); ++} ++ ++/*========================================================================== ++ * CIM start/stop operations ++ *========================================================================*/ ++static int cim_start_dma(char *ubuf) ++{ ++ ++ struct cim_desc *jz_frame_desc; ++ int cim_frame_size = 0; ++ dprintk("==========start_init = %d\n", start_init); ++ __cim_disable(); ++ __cim_set_da(virt_to_phys(cim_dev->frame_desc)); ++ __cim_clear_state(); // clear state register ++ __cim_reset_rxfifo(); // resetting rxfifo ++ __cim_unreset_rxfifo(); ++ __cim_enable_dma(); // enable dma ++ __cim_enable(); ++ interruptible_sleep_on(&cim_dev->wait_queue); ++ ++#if 1 ++ dprintk("interruptible_sleep_on\n"); ++ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); ++ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); ++ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); ++ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); ++ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); ++ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); ++ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); ++ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); ++ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); ++ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD); ++ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA); ++#endif ++ /* copy frame data to user buffer */ ++#if 0 ++ jz_frame_desc = cim_dev->frame_desc; ++ ++ while (jz_frame_desc != NULL) ++ { ++ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff); ++ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4)); ++ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; ++ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; ++ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); ++ } ++#endif ++ dprintk("---------**********-----\n"); ++ return cim_dev->frame_size; ++} ++static void cim_stop(void) ++{ ++ __cim_disable(); ++ __cim_clear_state(); ++} ++ ++/*========================================================================== ++ * Framebuffer allocation and destroy ++ *========================================================================*/ ++static void cim_fb_destroy(void) ++{ ++ int pages; ++ struct cim_desc *jz_frame_desc, *p_desc; ++ __cim_disable_dma(); ++ __cim_disable(); ++ ++ dprintk("cim_dev->frame_desc = %x\n", (u32)cim_dev->frame_desc); ++ if (cim_dev->frame_desc == NULL) { ++ printk("Original memory is NULL\n"); ++ return; ++ } ++ jz_frame_desc = cim_dev->frame_desc; ++// while (jz_frame_desc != NULL) { ++// while (jz_frame_desc != cim_dev->frame_desc) { ++ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4); ++ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); ++ pages = jz_frame_desc->pagenum; ++ dprintk("page_order = %d\n", pages); ++ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages); ++ kfree(jz_frame_desc); ++ jz_frame_desc = p_desc; ++// } ++ cim_dev->frame_desc = NULL; ++ start_init = 1; ++} ++ ++static struct cim_desc *get_desc_list(int page_order) ++{ ++ int num, page_nums = 0; ++ unsigned char *p_buf; ++ struct cim_desc *desc_list_head __attribute__ ((aligned (16))); ++ struct cim_desc *desc_list_tail __attribute__ ((aligned (16))); ++ struct cim_desc *p_desc; ++// num = page_order - 1; ++ num = page_order; ++ desc_list_head = desc_list_tail = NULL; ++ ++ while(page_nums < (1 << page_order)) { ++ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL); ++ if (NULL == p_desc) ++ return NULL; ++ //return -ENOMEM; ++ cim_realloc_pages: ++ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num); ++ if ( !(p_buf) && num != 0) { ++ num --; ++ goto cim_realloc_pages; ++ } ++ else if ( !(p_buf) && num == 0) { ++ printk("No memory can be alloc!\n"); ++ //return -ENOMEM; ++ return NULL; ++ } ++ else { ++ if (desc_list_head == NULL) { ++ dprintk("Page_list_head\n"); ++ desc_list_head = p_desc; ++ } ++ ++ else ++ desc_list_tail->nextdesc = virt_to_phys(p_desc); ++ ++ desc_list_tail = p_desc; ++ desc_list_tail->framebuf = virt_to_phys(p_buf); ++ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf); ++ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail)); ++ ++ desc_list_tail->frameid = 0x52052018; ++ desc_list_tail->pagenum = num; ++ if ((page_nums + (1<< num)) < (1 << page_order)) { ++ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ; ++ } ++ else ++ desc_list_tail->dmacmd = ++ (cim_dev->frame_size - page_nums * 4096) >> 2 ; ++ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); ++ page_nums += (1 << num); ++ dprintk("the pages_num is %d\n", page_nums); ++ dma_cache_wback((unsigned long)(desc_list_tail), 16); ++ } ++ } ++ ++// desc_list_tail->nextdesc = virt_to_phys(NULL); ++ desc_list_tail->nextdesc = virt_to_phys(desc_list_head); ++ desc_list_tail->dmacmd |= CIM_CMD_EOFINT; ++#if defined(CONFIG_SOC_JZ4750D) ++#if defined(USE_CIM_OFRCV) ++ desc_list_tail->dmacmd |= (CIM_CMD_EOFINT | CIM_CMD_OFRCV); ++#endif ++#if defined(USE_CIM_DMA_SYNC) /* wake ervry time */ ++ desc_list_tail->nextdesc = virt_to_phys(NULL); ++ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT | CIM_CMD_OFRCV); ++#endif ++#if defined(USE_CIM_EEOFINT) ++// desc_list_tail->dmacmd |= CIM_CMD_EEOFINT; ++ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT | CIM_CMD_EEOFINT); ++#endif ++#endif ++ /* stop after capturing a frame */ ++// desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT | CIM_CMD_SOFINT); ++ ++ ++ ++ ++ dma_cache_wback((unsigned long)(desc_list_tail), 16); ++ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); ++ ++ return desc_list_head; ++} ++ ++static int cim_fb_alloc(int img_width, int img_height, int img_bpp) ++{ ++ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0) ++ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8); ++ else ++ cim_dev->frame_size = img_width * img_height * (img_bpp/8); ++ ++ cim_dev->page_order = get_order(cim_dev->frame_size); ++ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order); ++ /* frame buffer ?? need large mem ??*/ ++ cim_dev->frame_desc = get_desc_list(cim_dev->page_order); ++ if (cim_dev->frame_desc == NULL) ++ return -ENOMEM; ++ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16); ++ return 0; ++} ++ ++/*========================================================================== ++ * File operations ++ *========================================================================*/ ++ ++static int cim_open(struct inode *inode, struct file *filp); ++static int cim_release(struct inode *inode, struct file *filp); ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++static int cim_mmap(struct file *file, struct vm_area_struct *vma); ++ ++static struct file_operations cim_fops = ++{ ++ open: cim_open, ++ release: cim_release, ++ read: cim_read, ++ write: cim_write, ++ ioctl: cim_ioctl, ++ compat_ioctl: v4l_compat_ioctl32, ++ mmap: cim_mmap ++}; ++ ++static struct video_device jz_v4l_device = { ++ .name = "jz cim", ++ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | ++ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY ++ .fops = &cim_fops, ++ .minor = -1, ++ .owner = THIS_MODULE, ++ .release = video_device_release, ++}; ++ ++static int cim_open(struct inode *inode, struct file *filp) ++{ ++ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int cim_release(struct inode *inode, struct file *filp) ++{ ++ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); ++ cim_fb_destroy(); ++ cim_stop(); ++ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ printk("============cim error: write is not implemented\n"); ++ if (size < cim_dev->frame_size) ++ return -EINVAL; ++ return cim_start_dma(buf); ++} ++ ++static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("cim error: write is not implemented\n"); ++ return -1; ++} ++ ++static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ switch (cmd) { ++ case IOCTL_GET_IMG_PARAM: ++ { ++ unsigned int i; ++ i = cim_dev->frame_desc->framebuf; ++// printk("cim_dev->frame_desc->framebuf = 0x%08x\n", cim_dev->frame_desc->framebuf); ++ dprintk("&&cim_dev->frame_desc->framebuf = 0x%08x\n", i); ++ ++ return copy_to_user(argp, &i, sizeof(unsigned int)) ? -EFAULT : 0; ++ } ++ case IOCTL_STOP_CIM: ++ { ++ __cim_disable_dma(); // enable dma ++ __cim_disable(); ++ ++// cim_fb_destroy(); ++ return 0; ++ } ++ case IOCTL_START_CIM: ++ { ++ __cim_set_da(virt_to_phys(cim_dev->frame_desc)); ++ __cim_clear_state(); // clear state register ++ __cim_reset_rxfifo(); // resetting rxfifo ++ __cim_unreset_rxfifo(); ++ __cim_enable_dma(); // enable dma ++ __cim_enable(); ++ return 0; ++ } ++ case IOCTL_SET_IMG_PARAM: ++ { ++ img_param_t i; ++ int img_width, img_height, img_bpp; ++ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) ++ return -EFAULT; ++ img_width = i.width; ++ img_height = i.height; ++ img_bpp = i.bpp; ++ printk("ALLOC =========\n"); ++ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){ ++ printk("ERROR! Image is too large!\n"); ++ return -EINVAL; ++ } ++ /* allocate frame buffers */ ++ if (cim_dev->frame_desc == NULL){ ++ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ ++ printk("ERROR! Init & alloc cim fail!\n"); ++ return -ENOMEM; ++ } ++ } ++ else ++ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){ ++ /* realloc the buffer */ ++ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); ++ cim_fb_destroy(); ++ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ ++ printk("ERRROR! Init & alloc cim fail!\n"); ++ return -ENOMEM; ++ } ++ } ++ break; ++ } ++ case IOCTL_CIM_CONFIG: ++ { ++ cim_config_t c; ++ ++ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t))) ++ return -EFAULT; ++ cim_config(&c); ++ ++ break; ++ } ++ case IOCTL_TEST_CIM_RAM: ++ { ++ ++ int i; ++ volatile unsigned int *ptr; ++ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); ++ dprintk("RAM test!\n"); ++ dprintk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR); ++ for (i = 0; i < 1024; ptr++, i++) ++ *ptr = i; ++ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); ++ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc); ++ ++ for (i = 0; i < 1024; i++) { ++ if (i != *ptr) ++ dprintk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i); ++ if (i%32 == 0) { ++ if (i%128 == 0) ++ dprintk("\n"); ++ dprintk("*ptr=%04d, i=%04d | ", *ptr, i); ++ } ++ ptr++; ++ } ++ dprintk("\n"); ++ break; ++ } ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return 0; ++} ++ ++/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ ++static int cim_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ ++ /* frame buffer memory */ ++ start = cim_dev->frame_desc->framebuf; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK)*4); ++ start &= PAGE_MASK; ++ printk("vma->vm_end = 0x%08lx,\nvma->vm_start = 0x%08lx,\noff = 0x%08lx,\n len = 0x%08x\n\n", vma->vm_end, vma->vm_start, off, len); ++ if ((vma->vm_end - vma->vm_start + off) > len) { ++ printk("Error: vma is larger than memory length\n"); ++ return -EINVAL; ++ } ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ ++ ++#if defined(CONFIG_MIPS32) ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ ++#endif ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++/*========================================================================== ++ * Interrupt handler ++ *========================================================================*/ ++ ++static irqreturn_t cim_irq_handler(int irq, void *dev_id) ++{ ++ u32 state = REG_CIM_STATE; ++ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE); ++ dprintk("IRQ:REG_CIM_CTRL = %x\n", REG_CIM_CTRL); ++ ++#if 0 //sof ++ /* recommed don't open it */ ++ if ((REG_CIM_CTRL & CIM_CTRL_DMA_SOFM) && (state & CIM_STATE_DMA_SOF)) { ++ dprintk("SOF interrupt!\n"); ++ REG_CIM_STATE &= ~CIM_STATE_DMA_SOF; ++ } ++#endif ++#if 0 //eeof ++ if ((REG_CIM_CTRL & CIM_CTRL_DMA_EEOFM) && (state & CIM_STATE_DMA_EEOF)) { ++ dprintk("EEOF interrupt!\n"); ++ __cim_disable_dma(); ++ __cim_disable(); ++ wake_up_interruptible(&cim_dev->wait_queue); ++ REG_CIM_STATE &= ~CIM_STATE_DMA_EEOF; ++ } ++#endif ++ ++#if 1 //eof ++ if ((REG_CIM_CTRL & CIM_CTRL_DMA_EOFM) && (state & CIM_STATE_DMA_EOF)) { ++// if (state & CIM_STATE_DMA_EOF) { ++ dprintk("EOF interrupt!\n"); ++ ++#if defined(USE_CIM_DMA_SYNC) /* wake ervry time */ ++// __cim_disable_dma(); ++// __cim_disable(); ++ wake_up_interruptible(&cim_dev->wait_queue); ++#else ++// if(irq_sleep == 1) ++ wake_up_interruptible(&cim_dev->wait_queue); ++#endif ++ REG_CIM_STATE &= ~CIM_STATE_DMA_EOF; ++ return IRQ_HANDLED; ++ } ++#endif ++#if 0 //overflow ++ if (state & CIM_STATE_RXF_OF) { ++ printk("OverFlow interrupt!\n"); ++ REG_CIM_STATE &= ~CIM_STATE_RXF_OF; ++// dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE); ++ return IRQ_HANDLED; ++ } ++#endif ++#if 1 // stop ++ if ((REG_CIM_CTRL & CIM_CTRL_DMA_STOPM) && (state & CIM_STATE_DMA_STOP)) { ++ // Got a frame, wake up wait routine ++//#if defined(USE_CIM_DMA_SYNC) /* wake ervry time */ ++ __cim_disable_dma(); ++// __cim_disable(); ++ ++ dprintk("Stop interrupt!\n"); ++// wake_up_interruptible(&cim_dev->wait_queue); ++ REG_CIM_STATE &= ~CIM_STATE_DMA_STOP; ++ } ++#endif ++ ++#if 0 //trig ++ if ((REG_CIM_CTRL & CIM_CTRL_RXF_TRIGM) && (state & CIM_STATE_RXF_TRIG)) { ++ REG_CIM_STATE &= ~CIM_STATE_RXF_TRIG; ++ dprintk("Trig interrupt!\n"); ++ } ++#endif ++ ++#if 0 //vdd ++ /* only happen disable cim during DMA transfer*/ ++ if ((REG_CIM_CTRL & CIM_CTRL_VDDM) && (state & CIM_STATE_VDD)) { ++ dprintk(">>CIM Disable Done Interrupt!\n"); ++ REG_CIM_STATE &= ~CIM_STATE_VDD; ++ } ++#endif ++ /* clear status flags*/ ++ dprintk("before clear REG_CIM_STATE = %x\n", REG_CIM_STATE); ++// REG_CIM_STATE = 0; ++ ++ return IRQ_HANDLED; ++} ++ ++/*Camera gpio init, different operationg according sensor*/ ++static void camera_gpio_init(void) { ++ ++ __gpio_as_cim(); ++ __gpio_as_i2c(); ++ __sensor_gpio_init(); ++} ++ ++static int v4l_device_init(void) ++{ ++ camera_gpio_init(); ++ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL); ++ if (!cim_dev) return -ENOMEM; ++ cim_dev->jz_cim = video_device_alloc(); ++ if (!cim_dev->jz_cim) { ++ return -ENOMEM; ++ } ++ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device)); ++ cim_dev->frame_desc = NULL; ++ cim_dev->frame_size = 0; ++ cim_dev->page_order = 0; ++ return 0; ++} ++/*========================================================================== ++ * Module init and exit ++ *========================================================================*/ ++ ++static int __init jz4750_cim_init(void) ++{ ++ struct cim_device *dev; ++ int ret; ++ /* allocate device */ ++ ret = v4l_device_init(); ++ if (ret) ++ return ret; ++ /* record device */ ++ dev = cim_dev; ++ init_waitqueue_head(&dev->wait_queue); ++ ++ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1); ++ if (ret < 0) { ++ printk(KERN_ERR "CIM Video4Linux-device " ++ "registration failed\n"); ++ return -EINVAL; ++ } ++ ++ if (ret < 0) { ++ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); ++ cim_fb_destroy(); ++ kfree(dev); ++ return ret; ++ } ++ ++ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, ++ CIM_NAME, dev))) { ++ printk(KERN_ERR "request_irq return error, ret=%d\n", ret); ++ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); ++ cim_fb_destroy(); ++ kfree(dev); ++ printk(KERN_ERR "CIM could not get IRQ\n"); ++ return ret; ++ } ++ ++ printk("JzSOC Camera Interface Module (CIM) driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit jz4750_cim_exit(void) ++{ ++ free_irq(IRQ_CIM, cim_dev); ++ kfree(cim_dev); ++ video_unregister_device(cim_dev->jz_cim); ++} ++ ++module_init(jz4750_cim_init); ++module_exit(jz4750_cim_exit); +diff --git a/drivers/media/video/jz4750_cim.h b/drivers/media/video/jz4750_cim.h +new file mode 100644 +index 0000000..7e73c7c +--- /dev/null ++++ b/drivers/media/video/jz4750_cim.h +@@ -0,0 +1,49 @@ ++/* ++ * linux/drivers/media/video/jz4750_cim.h -- Ingenic Jz4750 On-Chip CIM driver ++ * ++ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef __JZ4750_CIM_H__ ++#define __JZ4750_CIM_H__ ++ ++/* gpio init */ ++#if defined(CONFIG_JZ4750_APUS) || defined(CONFIG_JZ4750D_FUWA1) /* board pavo */ ++#define GPIO_CAMERA_RST (32*4+8) /* CIM_MCLK as reset */ ++#else ++#error "driver/video/Jzlcd.h, please define SPI pins on your board." ++#endif ++ ++#define CONFIG_OV9650 1 ++ ++#if defined(CONFIG_OV9650) || defined(CONFIG_OV2640) ++#if defined(CONFIG_JZ4750_APUS) /* board pavo */ ++#define __sensor_gpio_init() \ ++do {\ ++ __gpio_as_output(GPIO_CAMERA_RST); \ ++ __gpio_set_pin(GPIO_CAMERA_RST); \ ++ mdelay(50); \ ++ __gpio_clear_pin(GPIO_CAMERA_RST);\ ++} while(0) ++ ++#elif defined(CONFIG_JZ4750D_FUWA1) /* board pavo */ ++#define __sensor_gpio_init() \ ++do {\ ++ __gpio_as_output(GPIO_CAMERA_RST); \ ++ __gpio_set_pin(GPIO_CAMERA_RST); \ ++ mdelay(50); \ ++ __gpio_clear_pin(GPIO_CAMERA_RST);\ ++} while(0) ++#endif ++#endif ++ ++#ifndef __sensor_gpio_init ++#define __sensor_gpio_init() ++#endif ++#endif /* __JZ4750_CIM_H__ */ ++ +diff --git a/drivers/media/video/jz_cim.h b/drivers/media/video/jz_cim.h +new file mode 100644 +index 0000000..f72cfa4 +--- /dev/null ++++ b/drivers/media/video/jz_cim.h +@@ -0,0 +1,36 @@ ++/* ++ * JzSOC CIM driver ++ * ++ * Copyright (C) 2005 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef __JZ_CIM_H__ ++#define __JZ_CIM_H__ ++ ++typedef struct ++{ ++ u32 width; ++ u32 height; ++ u32 bpp; ++} IMG_PARAM; ++ ++/* ++ * IOCTL_XXX commands ++ */ ++#define IOCTL_SET_IMG_PARAM 0 // arg type: IMG_PARAM * ++ ++#endif /* __JZ__CIM_H__ */ +diff --git a/drivers/media/video/jz_sensor.c b/drivers/media/video/jz_sensor.c +new file mode 100644 +index 0000000..2d6005f +--- /dev/null ++++ b/drivers/media/video/jz_sensor.c +@@ -0,0 +1,202 @@ ++/* ++ * linux/drivers/char/jzchar/sensor.c ++ * ++ * Common CMOS Camera Sensor Driver ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++//#include "jz-chars.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jianli Wei"); ++MODULE_DESCRIPTION("Common CMOS Camera Sensor Driver"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * ioctl commands ++ */ ++#define IOCTL_SET_ADDR 0 /* set i2c address */ ++#define IOCTL_SET_CLK 1 /* set i2c clock */ ++#define IOCTL_WRITE_REG 2 /* write sensor register */ ++#define IOCTL_READ_REG 3 /* read sensor register */ ++ ++/* ++ * i2c related ++ */ ++static unsigned int i2c_addr = 0x42; ++static unsigned int i2c_clk = 100000; ++ ++struct video_device *jz_sensor; ++ ++static void write_reg(u8 reg, u8 val) ++{ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_write((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++} ++ ++static u8 read_reg(u8 reg) ++{ ++ u8 val; ++ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_read((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++ return val; ++} ++ ++/* ++ * fops routines ++ */ ++ ++static int sensor_open(struct inode *inode, struct file *filp); ++static int sensor_release(struct inode *inode, struct file *filp); ++static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l); ++static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l); ++static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ++ ++static struct file_operations sensor_fops = ++{ ++ open: sensor_open, ++ release: sensor_release, ++ read: sensor_read, ++ write: sensor_write, ++ ioctl: sensor_ioctl, ++}; ++ ++static int sensor_open(struct inode *inode, struct file *filp) ++{ ++ try_module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int sensor_release(struct inode *inode, struct file *filp) ++{ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l) ++{ ++ printk("sensor: read is not implemented\n"); ++ return -1; ++} ++ ++static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l) ++{ ++ printk("sensor: write is not implemented\n"); ++ return -1; ++} ++ ++static int sensor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ ++ switch (cmd) { ++ case IOCTL_SET_ADDR: ++ if (copy_from_user(&i2c_addr, (void *)arg, 4)) ++ return -EFAULT; ++ break; ++ case IOCTL_SET_CLK: ++ if (copy_from_user(&i2c_clk, (void *)arg, 4)) ++ return -EFAULT; ++ break; ++ case IOCTL_WRITE_REG: ++ { ++ u8 regval[2]; ++ ++ if (copy_from_user(regval, (void *)arg, 2)) ++ return -EFAULT; ++ ++ write_reg(regval[0], regval[1]); ++ break; ++ } ++ case IOCTL_READ_REG: ++ { ++ u8 reg, val; ++ ++ if (copy_from_user(®, (void *)arg, 1)) ++ return -EFAULT; ++ ++ val = read_reg(reg); ++ ++ if (copy_to_user((void *)(arg + 1), &val, 1)) ++ return -EFAULT; ++ break; ++ } ++ default: ++ printk("Not supported command: 0x%x\n", cmd); ++ return -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static struct video_device jz_v4l_device = { ++ .name = "jz sensor", ++ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | ++ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY ++ .fops = &sensor_fops, ++ .minor = -1, ++}; ++ ++/* ++ * Module init and exit ++ */ ++ ++static int __init jz_sensor_init(void) ++{ ++ int ret; ++// cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL); ++ jz_sensor = video_device_alloc(); ++ memcpy(jz_sensor, &jz_v4l_device, sizeof(struct video_device)); ++ jz_sensor->release = video_device_release; ++// ret = jz_register_chrdev(SENSOR_MINOR, "sensor", &sensor_fops, NULL); ++ ret = video_register_device(jz_sensor, VFL_TYPE_GRABBER, -1); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ printk("Ingenic CMOS camera sensor driver registered\n"); ++ ++ return 0; ++} ++ ++static void __exit jz_sensor_exit(void) ++{ ++// jz_unregister_chrdev(SENSOR_MINOR, "sensor"); ++ video_unregister_device(jz_sensor); ++} ++ ++module_init(jz_sensor_init); ++module_exit(jz_sensor_exit); +diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c +index 06084db..1185e08 100644 +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -140,8 +140,13 @@ static int mmc_decode_csd(struct mmc_card *card) + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); +- csd->capacity = (1 + m) << (e + 2); + ++#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 ++ csd->capacity = (1 + m) << (e + 2); ++ csd->capacity -= 16384; ++#else ++ csd->capacity = (1 + m) << (e + 2); ++#endif + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); +diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c +index cd81c39..47033d7 100644 +--- a/drivers/mmc/core/sd.c ++++ b/drivers/mmc/core/sd.c +@@ -109,8 +109,13 @@ static int mmc_decode_csd(struct mmc_card *card) + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); +- csd->capacity = (1 + m) << (e + 2); + ++#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 ++ csd->capacity = (1 + m) << (e + 2); ++ csd->capacity -= 16384; ++#else ++ csd->capacity = (1 + m) << (e + 2); ++#endif + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); +@@ -137,8 +142,13 @@ static int mmc_decode_csd(struct mmc_card *card) + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + m = UNSTUFF_BITS(resp, 48, 22); +- csd->capacity = (1 + m) << 10; + ++#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 ++ csd->capacity = (1 + m) << 10; ++ csd->capacity -= 16384; ++#else ++ csd->capacity = (1 + m) << 10; ++#endif + csd->read_blkbits = 9; + csd->read_partial = 0; + csd->write_misalign = 0; +@@ -268,9 +278,11 @@ static int mmc_switch_hs(struct mmc_card *card) + goto out; + + if ((status[16] & 0xF) != 1) { ++#if 0 + printk(KERN_WARNING "%s: Problem switching card " + "into high-speed mode!\n", + mmc_hostname(card->host)); ++#endif + } else { + mmc_card_set_highspeed(card); + mmc_set_timing(card->host, MMC_TIMING_SD_HS); +@@ -417,6 +429,9 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, + goto free_card; + + mmc_decode_cid(card); ++ ++ /* set 24MHz clock again, why?? */ ++ mmc_set_clock(host, 24000000); + } + + /* +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 891ef18..c774b9a 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -4,6 +4,104 @@ + + comment "MMC/SD/SDIO Host Controller Drivers" + ++config MMC_JZ ++ tristate "JZ SD/Multimedia Card Interface support" ++ depends on SOC_JZ4730 || SOC_JZ4740 ++ help ++ This selects the Ingenic JZ4730/JZ4740 SD/Multimedia card Interface. ++ If you have abIngenic platform with a Multimedia Card slot, ++ say Y or M here. ++ ++ If unsure, say N. ++choice ++ depends on MMC_JZ ++ prompt "MMC BUS Width" ++ default JZ_MMC_BUS_4 ++ help ++ This defines the BUS Width of the Ingenic JZ4730/JZ4740 SD/Multimedia card Interface. ++ ++config JZ_MMC_BUS_1 ++ bool "1 Bit Bus" ++ help ++ 1 Bit SD/Multimedia Card Bus ++ ++config JZ_MMC_BUS_4 ++ bool "4 Bit Bus" ++ help ++ 4 Bit SD/Multimedia Card Bus ++ ++endchoice ++ ++config MSC0_JZ4750 ++ tristate "JZ4750 SD/Multimedia Card 0 Interface support" ++ depends on SOC_JZ4750 || SOC_JZ4750D ++ help ++ This selects the Ingenic JZ4750 SD/Multimedia card 0 Interface. ++ If you have a Ingenic platform with a Multimedia Card slot, ++ say Y or M here. ++ ++ If unsure, say N. ++ ++choice ++ depends on MSC0_JZ4750 ++ prompt "MSC0 BUS Width" ++ default JZ4750_MSC0_BUS_4 ++ help ++ This defines the BUS Width of the Ingenic JZ4750 SD/Multimedia card Interface. ++ ++config JZ4750_MSC0_BUS_1 ++ bool "1 Bit Bus" ++ help ++ 1 Bit SD/Multimedia Card Bus ++ ++config JZ4750_MSC0_BUS_4 ++ bool "4 Bit Bus" ++ help ++ 4 Bit SD/Multimedia Card Bus ++ ++config JZ4750_MSC0_BUS_8 ++ bool "8 Bit Bus" ++ help ++ 8 Bit Multimedia Card Bus ++ ++endchoice ++ ++config MSC1_JZ4750 ++ tristate "JZ4750 SD/Multimedia Card 1 Interface support" ++ depends on SOC_JZ4750 || SOC_JZ4750D ++ help ++ This selects the Ingenic JZ4750 SD/Multimedia card 1 Interface. ++ If you have a Ingenic platform with a Multimedia Card slot, ++ say Y or M here. ++ ++ If unsure, say N. ++ ++choice ++ depends on MSC1_JZ4750 ++ prompt "MSC1 BUS Width" ++ default JZ4750_MSC1_BUS_4 ++ help ++ This defines the BUS Width of the Ingenic JZ4750 SD/Multimedia card Interface. ++ ++config JZ4750_MSC1_BUS_1 ++ bool "1 Bit Bus" ++ help ++ 1 Bit SD/Multimedia Card Bus ++ ++config JZ4750_MSC1_BUS_4 ++ bool "4 Bit Bus" ++ help ++ 4 Bit SD/Multimedia Card Bus ++endchoice ++ ++config JZ4750_BOOT_FROM_MSC0 ++ tristate "JZ4750 Boot from SD/Multimedia Card Interface support" ++ depends on SOC_JZ4750 || SOC_JZ4750D ++ help ++ This selects boot from the Sd/Multimedia Card. ++ ++ If unsure,say N. ++ + config MMC_ARMMMCI + tristate "ARM AMBA Multimedia Card Interface support" + depends on ARM_AMBA +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index cf153f6..92d76ab 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -6,6 +6,9 @@ ifeq ($(CONFIG_MMC_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG + endif + ++obj-$(CONFIG_MMC_JZ) += jz_mmc.o ++obj-$(CONFIG_MSC0_JZ4750) += jz4750_mmc.o ++obj-$(CONFIG_MSC1_JZ4750) += jz4750_mmc.o + obj-$(CONFIG_MMC_ARMMMCI) += mmci.o + obj-$(CONFIG_MMC_PXA) += pxamci.o + obj-$(CONFIG_MMC_IMX) += imxmmc.o +diff --git a/drivers/mmc/host/jz4750_mmc.c b/drivers/mmc/host/jz4750_mmc.c +new file mode 100644 +index 0000000..94004fa +--- /dev/null ++++ b/drivers/mmc/host/jz4750_mmc.c +@@ -0,0 +1,1051 @@ ++/* ++ * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver ++ * ++ * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "jz4750_mmc.h" ++ ++#define DRIVER_NAME "jz-mmc" ++ ++#define USE_DMA ++ ++static int r_type = 0; ++static int rxdmachan = 0; ++static int txdmachan = 0; ++static int mmc_slot_enable = 0; ++static int auto_select_bus = MSC_4BIT_BUS; /* default 4 bit bus*/ ++ ++/* Start the MMC clock and operation */ ++static inline int jz_mmc_start_op(void) ++{ ++ REG_MSC_STRPCL(MSC_ID) = MSC_STRPCL_START_OP; ++ ++ return MMC_NO_ERROR; ++} ++ ++static inline u32 jz_mmc_calc_clkrt(int is_low, u32 rate) ++{ ++ u32 clkrt; ++ u32 clk_src = is_low ? 24000000 : 48000000; ++ ++ clkrt = 0; ++ while (rate < clk_src) { ++ clkrt++; ++ clk_src >>= 1; ++ } ++ return clkrt; ++} ++ ++/* Select the MMC clock frequency */ ++static int jz_mmc_set_clock(u32 rate) ++{ ++ int clkrt; ++ ++ /* __cpm_select_msc_clk_high will select 48M clock for MMC/SD card ++ * perhaps this will made some card with bad quality init fail,or ++ * bad stabilization. ++ */ ++ if (rate > SD_CLOCK_FAST) { ++ __cpm_select_msc_clk_high(MSC_ID,1); /* select clock source from CPM */ ++ clkrt = jz_mmc_calc_clkrt(0, rate); ++ } else { ++ __cpm_select_msc_clk(MSC_ID,1); /* select clock source from CPM */ ++ clkrt = jz_mmc_calc_clkrt(1, rate); ++ } ++ ++#ifndef CONFIG_FPGA ++ REG_MSC_CLKRT(MSC_ID) = clkrt; ++#else ++ REG_MSC_CLKRT(MSC_ID) = 7; ++#endif ++ return MMC_NO_ERROR; ++} ++ ++static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->imask &= ~mask; ++ REG_MSC_IMASK(MSC_ID) = host->imask; ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->imask |= mask; ++ REG_MSC_IMASK(MSC_ID) = host->imask; ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++void jz_set_dma_block_size(int dmanr, int nbyte); ++ ++#ifdef USE_DMA ++static inline void ++jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode) ++{ ++ unsigned long flags; ++ ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ jz_set_dma_block_size(chan, 32); ++ set_dma_mode(chan, mode); ++ set_dma_addr(chan, phyaddr); ++ set_dma_count(chan, count + 31); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid) ++{ ++ int chan = rxdmachan; ++ ++ disable_dma(chan); ++ if (__dmac_channel_address_error_detected(chan)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", ++ __FUNCTION__); ++ __dmac_channel_clear_address_error(chan); ++ } ++ if (__dmac_channel_transmit_end_detected(chan)) { ++ __dmac_channel_clear_transmit_end(chan); ++ } ++ return IRQ_HANDLED; ++} ++static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid) ++{ ++ int chan = txdmachan; ++ ++ disable_dma(chan); ++ if (__dmac_channel_address_error_detected(chan)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", ++ __FUNCTION__); ++ __dmac_channel_clear_address_error(chan); ++ } ++ if (__dmac_channel_transmit_end_detected(chan)) { ++ __dmac_channel_clear_transmit_end(chan); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* Prepare DMA to start data transfer from the MMC card */ ++static void jz_mmc_rx_setup_data(struct jz_mmc_host *host, ++ struct mmc_data *data) ++{ ++ unsigned int nob = data->blocks; ++ int channelrx = rxdmachan; ++ int i; ++ u32 size; ++ ++ if (data->flags & MMC_DATA_STREAM) ++ nob = 0xffff; ++ ++ REG_MSC_NOB(MSC_ID) = nob; ++ REG_MSC_BLKLEN(MSC_ID) = data->blksz; ++ size = nob * data->blksz; ++ ++ if (data->flags & MMC_DATA_READ) { ++ host->dma.dir = DMA_FROM_DEVICE; ++ } else { ++ host->dma.dir = DMA_TO_DEVICE; ++ } ++ ++ host->dma.len = ++ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, ++ host->dma.dir); ++ ++ for (i = 0; i < host->dma.len; i++) { ++ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); ++ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); ++ dma_cache_wback_inv((unsigned long) ++ CKSEG0ADDR(sg_dma_address(data->sg)) + ++ data->sg->offset, ++ host->sg_cpu[i].dcmd); ++ jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr, ++ host->sg_cpu[i].dcmd, DMA_MODE_READ); ++ } ++} ++ ++/* Prepare DMA to start data transfer from the MMC card */ ++static void jz_mmc_tx_setup_data(struct jz_mmc_host *host, ++ struct mmc_data *data) ++{ ++ unsigned int nob = data->blocks; ++ int channeltx = txdmachan; ++ int i; ++ u32 size; ++ ++ if (data->flags & MMC_DATA_STREAM) ++ nob = 0xffff; ++ ++ REG_MSC_NOB(MSC_ID) = nob; ++ REG_MSC_BLKLEN(MSC_ID) = data->blksz; ++ size = nob * data->blksz; ++ ++ if (data->flags & MMC_DATA_READ) { ++ host->dma.dir = DMA_FROM_DEVICE; ++ } else { ++ host->dma.dir = DMA_TO_DEVICE; ++ } ++ ++ host->dma.len = ++ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, ++ host->dma.dir); ++ ++ for (i = 0; i < host->dma.len; i++) { ++ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); ++ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); ++ dma_cache_wback_inv((unsigned long) ++ CKSEG0ADDR(sg_dma_address(data->sg)) + ++ data->sg->offset, ++ host->sg_cpu[i].dcmd); ++ jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr, ++ host->sg_cpu[i].dcmd, DMA_MODE_WRITE); ++ } ++} ++#else ++static void jz_mmc_receive_pio(struct jz_mmc_host *host) ++{ ++ ++ struct mmc_data *data = 0; ++ int sg_len = 0, max = 0, count = 0; ++ u32 *buf = 0; ++ struct scatterlist *sg; ++ unsigned int nob; ++ ++ data = host->mrq->data; ++ nob = data->blocks; ++ REG_MSC_NOB(MSC_ID) = nob; ++ REG_MSC_BLKLEN(MSC_ID) = data->blksz; ++ ++ max = host->pio.len; ++ if (host->pio.index < host->dma.len) { ++ sg = &data->sg[host->pio.index]; ++ buf = sg_virt(sg) + host->pio.offset; ++ ++ /* This is the space left inside the buffer */ ++ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; ++ /* Check to if we need less then the size of the sg_buffer */ ++ if (sg_len < max) max = sg_len; ++ } ++ max = max / 4; ++ for(count = 0; count < max; count++) { ++ while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_EMPTY) ++ ; ++ *buf++ = REG_MSC_RXFIFO(MSC_ID); ++ } ++ host->pio.len -= count; ++ host->pio.offset += count; ++ ++ if (sg_len && count == sg_len) { ++ host->pio.index++; ++ host->pio.offset = 0; ++ } ++} ++ ++static void jz_mmc_send_pio(struct jz_mmc_host *host) ++{ ++ ++ struct mmc_data *data = 0; ++ int sg_len, max, count = 0; ++ u32 *wbuf = 0; ++ struct scatterlist *sg; ++ unsigned int nob; ++ ++ data = host->mrq->data; ++ nob = data->blocks; ++ ++ REG_MSC_NOB(MSC_ID) = nob; ++ REG_MSC_BLKLEN(MSC_ID) = data->blksz; ++ ++ /* This is the pointer to the data buffer */ ++ sg = &data->sg[host->pio.index]; ++ wbuf = sg_virt(sg) + host->pio.offset; ++ ++ /* This is the space left inside the buffer */ ++ sg_len = data->sg[host->pio.index].length - host->pio.offset; ++ ++ /* Check to if we need less then the size of the sg_buffer */ ++ max = (sg_len > host->pio.len) ? host->pio.len : sg_len; ++ max = max / 4; ++ for(count = 0; count < max; count++ ) { ++ while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_FULL) ++ ; ++ REG_MSC_TXFIFO(MSC_ID) = *wbuf++; ++ } ++ ++ host->pio.len -= count; ++ host->pio.offset += count; ++ ++ if (count == sg_len) { ++ host->pio.index++; ++ host->pio.offset = 0; ++ } ++} ++ ++static int ++jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data) ++{ ++ int datalen = data->blocks * data->blksz; ++ ++ host->dma.dir = DMA_BIDIRECTIONAL; ++ host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, ++ data->sg_len, host->dma.dir); ++ if (host->dma.len == 0) ++ return -ETIMEDOUT; ++ ++ host->pio.index = 0; ++ host->pio.offset = 0; ++ host->pio.len = datalen; ++ return 0; ++} ++#endif ++ ++static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat); ++ ++static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq) ++{ ++ host->mrq = NULL; ++ host->cmd = NULL; ++ host->data = NULL; ++ mmc_request_done(host->mmc, mrq); ++} ++ ++static void jz_mmc_start_cmd(struct jz_mmc_host *host, ++ struct mmc_command *cmd, unsigned int cmdat) ++{ ++ u32 timeout = 0x3fffff; ++ unsigned int stat; ++ struct jz_mmc_host *hst = host; ++ WARN_ON(host->cmd != NULL); ++ host->cmd = cmd; ++ ++ /* mask interrupts */ ++ REG_MSC_IMASK(MSC_ID) = 0xffff; ++ ++ /* clear status */ ++ REG_MSC_IREG(MSC_ID) = 0xffff; ++ ++ if (cmd->flags & MMC_RSP_BUSY) ++ cmdat |= MSC_CMDAT_BUSY; ++ ++#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) ++ switch (RSP_TYPE(mmc_resp_type(cmd))) { ++ case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */ ++ cmdat |= MSC_CMDAT_RESPONSE_R1; ++ r_type = 1; ++ break; ++ case RSP_TYPE(MMC_RSP_R3): ++ cmdat |= MSC_CMDAT_RESPONSE_R3; ++ r_type = 1; ++ break; ++ case RSP_TYPE(MMC_RSP_R2): ++ cmdat |= MSC_CMDAT_RESPONSE_R2; ++ r_type = 2; ++ break; ++ default: ++ break; ++ } ++ ++ REG_MSC_CMD(MSC_ID) = cmd->opcode; ++ ++ /* Set argument */ ++#ifdef CONFIG_MSC0_JZ4750 ++#ifdef CONFIG_JZ4750_MSC0_BUS_1 ++ if (cmd->opcode == 6) { ++ /* set 1 bit sd card bus*/ ++ if (cmd->arg ==2) ++ REG_MSC_ARG(MSC_ID) = 0; ++ ++ /* set 1 bit mmc card bus*/ ++ if (cmd->arg == 0x3b70101) { ++ REG_MSC_ARG(MSC_ID) = 0x3b70001; ++ } ++ } else ++ REG_MSC_ARG(MSC_ID) = cmd->arg; ++ ++#elif defined CONFIG_JZ4750_MSC0_BUS_8 ++ if (cmd->opcode == 6) { ++ /* set 8 bit mmc card bus*/ ++ if (cmd->arg == 0x3b70101) ++ REG_MSC_ARG(MSC_ID) = 0x3b70201; ++ else ++ REG_MSC_ARG(MSC_ID) = cmd->arg; ++ ++ } else ++ REG_MSC_ARG(MSC_ID) = cmd->arg; ++#else ++ REG_MSC_ARG(MSC_ID) = cmd->arg; ++#endif /* CONFIG_JZ4750_MSC0_BUS_1 */ ++#else ++#ifdef CONFIG_JZ4750_MSC1_BUS_1 ++ if (cmd->opcode == 6) { ++ /* set 1 bit sd card bus*/ ++ if (cmd->arg ==2) ++ REG_MSC_ARG(MSC_ID) = 0; ++ ++ /* set 1 bit mmc card bus*/ ++ if (cmd->arg == 0x3b70101) { ++ REG_MSC_ARG(MSC_ID) = 0x3b70001; ++ } ++ } else ++ REG_MSC_ARG(MSC_ID) = cmd->arg; ++ ++#else ++ REG_MSC_ARG(MSC_ID) = cmd->arg; ++#endif /* CONFIG_JZ4750_MSC1_BUS_1 */ ++#endif /* CONFIG_MSC0_JZ4750*/ ++ ++ /* Set command */ ++ REG_MSC_CMDAT(MSC_ID) = cmdat; ++ ++ /* Send command */ ++ jz_mmc_start_op(); ++ ++ while (timeout-- && !(REG_MSC_STAT(MSC_ID) & MSC_STAT_END_CMD_RES)) ++ ; ++ ++ REG_MSC_IREG(MSC_ID) = MSC_IREG_END_CMD_RES; /* clear irq flag */ ++ if (cmd->opcode == 12) { ++ while (timeout-- && !(REG_MSC_IREG(MSC_ID) & MSC_IREG_PRG_DONE)) ++ ; ++ REG_MSC_IREG(MSC_ID) = MSC_IREG_PRG_DONE; /* clear status */ ++ } ++ if (!mmc_slot_enable) { ++ /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when ++ * card was removed. We force to return here. ++ */ ++ cmd->error = -ETIMEDOUT; ++ jz_mmc_finish_request(hst, hst->mrq); ++ return; ++ } ++ ++ if (SD_IO_SEND_OP_COND == cmd->opcode) { ++ /* ++ * Don't support SDIO card currently. ++ */ ++ cmd->error = -ETIMEDOUT; ++ jz_mmc_finish_request(hst, hst->mrq); ++ return; ++ } ++ ++ /* Check for status */ ++ stat = REG_MSC_STAT(MSC_ID); ++ jz_mmc_cmd_done(hst, stat); ++ if (host->data) { ++ if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) ++#ifdef USE_DMA ++ jz_mmc_tx_setup_data(host, host->data); ++#else ++ jz_mmc_send_pio(host); ++ else ++ jz_mmc_receive_pio(host); ++#endif ++ } ++} ++ ++static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat) ++{ ++ struct mmc_command *cmd = host->cmd; ++ int i, temp[16]; ++ u8 *buf; ++ u32 data, v, w1, w2; ++ ++ if (!cmd) ++ return 0; ++ ++ host->cmd = NULL; ++ buf = (u8 *) temp; ++ switch (r_type) { ++ case 1: ++ { ++ data = REG_MSC_RES(MSC_ID); ++ buf[0] = (data >> 8) & 0xff; ++ buf[1] = data & 0xff; ++ data = REG_MSC_RES(MSC_ID); ++ buf[2] = (data >> 8) & 0xff; ++ buf[3] = data & 0xff; ++ data = REG_MSC_RES(MSC_ID); ++ buf[4] = data & 0xff; ++ cmd->resp[0] = ++ buf[1] << 24 | buf[2] << 16 | buf[3] << 8 | ++ buf[4]; ++ break; ++ } ++ case 2: ++ { ++ data = REG_MSC_RES(MSC_ID); ++ v = data & 0xffff; ++ for (i = 0; i < 4; i++) { ++ data = REG_MSC_RES(MSC_ID); ++ w1 = data & 0xffff; ++ data = REG_MSC_RES(MSC_ID); ++ w2 = data & 0xffff; ++ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; ++ v = w2; ++ } ++ break; ++ } ++ case 0: ++ break; ++ } ++ if (stat & MSC_STAT_TIME_OUT_RES) { ++ printk("MSC_STAT_TIME_OUT_RES\n"); ++ cmd->error = -ETIMEDOUT; ++ } else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) { ++ printk("MSC_STAT_CRC\n"); ++ if (cmd->opcode == MMC_ALL_SEND_CID || ++ cmd->opcode == MMC_SEND_CSD || ++ cmd->opcode == MMC_SEND_CID) { ++ /* a bogus CRC error can appear if the msb of ++ the 15 byte response is a one */ ++ if ((cmd->resp[0] & 0x80000000) == 0) ++ cmd->error = -EILSEQ; ++ } ++ } ++ /* ++ * Did I mention this is Sick. We always need to ++ * discard the upper 8 bits of the first 16-bit word. ++ */ ++ if (host->data && cmd->error == 0) ++ jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE); ++ else ++ jz_mmc_finish_request(host, host->mrq); ++ ++ return 1; ++} ++ ++static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat) ++{ ++ struct mmc_data *data = host->data; ++ ++ if (!data) ++ return 0; ++ REG_MSC_IREG(MSC_ID) = MSC_IREG_DATA_TRAN_DONE; /* clear status */ ++ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, ++ host->dma_dir); ++ if (stat & MSC_STAT_TIME_OUT_READ) { ++ printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat); ++ data->error = -ETIMEDOUT; ++ } else if (REG_MSC_STAT(MSC_ID) & ++ (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) { ++ printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat); ++ data->error = -EILSEQ; ++ } ++ /* ++ * There appears to be a hardware design bug here. There seems to ++ * be no way to find out how much data was transferred to the card. ++ * This means that if there was an error on any block, we mark all ++ * data blocks as being in error. ++ */ ++ if (data->error == 0) ++ data->bytes_xfered = data->blocks * data->blksz; ++ else ++ data->bytes_xfered = 0; ++ ++ jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE); ++ host->data = NULL; ++ if (host->mrq->stop) { ++ jz_mmc_start_cmd(host, host->mrq->stop, 0); ++ } else { ++ jz_mmc_finish_request(host, host->mrq); ++ } ++ return 1; ++} ++ ++static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct jz_mmc_host *host = mmc_priv(mmc); ++ unsigned int cmdat; ++ ++ /* Save current request for the future processing */ ++ host->mrq = mrq; ++ host->data = mrq->data; ++ cmdat = host->cmdat; ++ host->cmdat &= ~MSC_CMDAT_INIT; ++ ++ if (mrq->data) { ++ cmdat &= ~MSC_CMDAT_BUSY; ++#ifdef USE_DMA ++ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) ++ ++ cmdat |= ++ MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | ++ MSC_CMDAT_DMA_EN; ++ else { ++#ifdef CONFIG_MSC0_JZ4750 ++#ifdef CONFIG_JZ4750_MSC0_BUS_1 ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | ++ MSC_CMDAT_DMA_EN; ++#elif defined CONFIG_JZ4750_MSC0_BUS_4 ++ if(auto_select_bus == MSC_1BIT_BUS) { ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | ++ MSC_CMDAT_DMA_EN; ++ } else { ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN | ++ MSC_CMDAT_DMA_EN; ++ } ++#else ++ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN; ++#endif /* CONFIG_JZ4750_MSC0_BUS_1 */ ++#else ++#ifdef CONFIG_JZ4750_MSC1_BUS_1 ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | ++ MSC_CMDAT_DMA_EN; ++#else ++ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN; ++#endif /* CONFIG_JZ4750_MSC1_BUS_1 */ ++#endif /* CONFIG_MSC0_JZ4750 */ ++ } ++ if (mrq->data->flags & MMC_DATA_WRITE) ++ cmdat |= MSC_CMDAT_WRITE; ++ ++ if (mrq->data->flags & MMC_DATA_STREAM) ++ cmdat |= MSC_CMDAT_STREAM_BLOCK; ++ if (mrq->cmd->opcode != MMC_WRITE_BLOCK ++ && mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) ++ jz_mmc_rx_setup_data(host, mrq->data); ++#else /*USE_DMA*/ ++ ++ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; ++ else { ++#ifdef CONFIG_MSC0_JZ4750 ++#ifdef CONFIG_JZ4750_MSC0_BUS_1 ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; ++#elif defined CONFIG_JZ4750_MSC0_BUS_4 ++ if(auto_select_bus == MSC_1BIT_BUS) { ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; ++ } else { ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN; ++ } ++#else ++ cmdat |= MSC_CMDAT_DATA_EN; ++#endif ++#else ++#ifdef CONFIG_JZ4750_MSC1_BUS_1 ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; ++#else ++ cmdat |= MSC_CMDAT_DATA_EN; ++#endif /* CONFIG_JZ4750_MSC1_BUS_1 */ ++#endif /* CONFIG_MSC0_JZ4750 */ ++ } ++ if (mrq->data->flags & MMC_DATA_WRITE) ++ cmdat |= MSC_CMDAT_WRITE; ++ ++ if (mrq->data->flags & MMC_DATA_STREAM) ++ cmdat |= MSC_CMDAT_STREAM_BLOCK; ++ jz_mmc_prepare_data(host, host->data); ++#endif /*USE_DMA*/ ++ } ++ jz_mmc_start_cmd(host, mrq->cmd, cmdat); ++} ++ ++static irqreturn_t jz_mmc_irq(int irq, void *devid) ++{ ++ struct jz_mmc_host *host = devid; ++ unsigned int ireg; ++ int handled = 0; ++ ++ ireg = REG_MSC_IREG(MSC_ID); ++ ++ if (ireg) { ++ unsigned stat = REG_MSC_STAT(MSC_ID); ++ if (ireg & MSC_IREG_DATA_TRAN_DONE) ++ handled |= jz_mmc_data_done(host, stat); ++ } ++ return IRQ_RETVAL(handled); ++} ++ ++/* Returns true if MMC slot is empty */ ++static int jz_mmc_slot_is_empty(int slot) ++{ ++ int empty; ++ ++#ifdef CONFIG_FPGA ++ return 0; ++#endif ++ ++#ifdef CONFIG_MSC1_JZ4750 ++ empty = (__msc1_card_detected(slot) == 0) ? 1 : 0; ++#else ++ empty = (__msc0_card_detected(slot) == 0) ? 1 : 0; ++ ++#endif ++ if (empty) { ++ /* wait for card insertion */ ++#ifdef CONFIG_MSC1_JZ4750 ++ __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_MSC1_JZ4750 ++ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); ++#else ++ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); ++#endif ++ } ++ ++ return empty; ++} ++ ++static irqreturn_t jz_mmc_detect_irq(int irq, void *devid) ++{ ++ struct jz_mmc_host *host = (struct jz_mmc_host *) devid; ++ ++ auto_select_bus = MSC_4BIT_BUS; ++ if (jz_mmc_slot_is_empty(0)) { ++ mmc_slot_enable = 0; ++ mmc_detect_change(host->mmc, 50); ++ } else { ++ mmc_slot_enable = 1; ++ mmc_detect_change(host->mmc, 50); ++ } ++ return IRQ_HANDLED; ++} ++ ++static int jz_mmc_get_ro(struct mmc_host *mmc) ++{ ++ struct jz_mmc_host *host = mmc_priv(mmc); ++ ++ if (host->pdata && host->pdata->get_ro) ++ return host->pdata->get_ro(mmc_dev(mmc)); ++ /* Host doesn't support read only detection so assume writeable */ ++ return 0; ++} ++ ++/* set clock and power */ ++static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct jz_mmc_host *host = mmc_priv(mmc); ++ ++ if (ios->clock) ++ jz_mmc_set_clock(ios->clock); ++ ++ if (host->power_mode != ios->power_mode) { ++ host->power_mode = ios->power_mode; ++ ++ if (ios->power_mode == MMC_POWER_ON) ++ host->cmdat |= CMDAT_INIT; ++ } ++ ++ if (ios->bus_width == MMC_BUS_WIDTH_4) { ++ auto_select_bus = MSC_4BIT_BUS; ++ host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; ++ } ++ else if (ios->bus_width == MMC_BUS_WIDTH_8) { ++ host->cmdat |= MSC_CMDAT_BUS_WIDTH_8BIT; ++ auto_select_bus = MSC_8BIT_BUS; ++ } else { ++ /* 1 bit bus*/ ++ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_8BIT; ++ auto_select_bus = MSC_1BIT_BUS; ++ } ++} ++ ++static const struct mmc_host_ops jz_mmc_ops = { ++ .request = jz_mmc_request, ++ .get_ro = jz_mmc_get_ro, ++ .set_ios = jz_mmc_set_ios, ++}; ++static int jz_mmc_pm_callback(struct pm_dev *pm_dev, ++ pm_request_t req, void *data); ++ ++static int jz_mmc_probe(struct platform_device *pdev) ++{ ++ int retval; ++ struct mmc_host *mmc; ++ struct jz_mmc_host *host = NULL; ++ int irq; ++ struct resource *r; ++ ++#ifdef CONFIG_MSC0_JZ4750 ++#ifdef CONFIG_SOC_JZ4750 ++ __gpio_as_msc0_8bit(); // for jz4750 ++#else ++ __gpio_as_msc0_4bit(); // for jz4750d ++#endif ++ __msc0_init_io(); ++ __msc0_enable_power(); ++#else ++ __gpio_as_msc1_4bit(); ++ __msc1_init_io(); ++ __msc1_enable_power(); ++#endif ++ __msc_reset(MSC_ID); ++ REG_MSC_LPM(MSC_ID) = 0x1; ++ ++ MMC_IRQ_MASK(); ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!r || irq < 0) ++ return -ENXIO; ++ ++ r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); ++ if (!r) ++ return -EBUSY; ++ ++ mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev); ++ if (!mmc) { ++ retval = -ENOMEM; ++ goto out; ++ } ++ mmc->ops = &jz_mmc_ops; ++ mmc->f_min = MMC_CLOCK_SLOW; ++ mmc->f_max = SD_CLOCK_HIGH; ++ /* ++ * We can do SG-DMA, but we don't because we never know how much ++ * data we successfully wrote to the card. ++ */ ++ mmc->max_phys_segs = NR_SG; ++ ++ mmc->max_seg_size = PAGE_SIZE * 16; ++ mmc->max_req_size = mmc->max_seg_size; ++ mmc->max_blk_size = 4095; ++ /* ++ * Block count register is 16 bits. ++ */ ++ mmc->max_blk_count = 65535; ++ host = mmc_priv(mmc); ++ host->mmc = mmc; ++ host->pdata = pdev->dev.platform_data; ++ mmc->ocr_avail = host->pdata ? ++ host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34; ++ host->mmc->caps = ++ MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SD_HIGHSPEED ++ | MMC_CAP_MMC_HIGHSPEED; ++ /* ++ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers ++ * ++ */ ++ host->sg_cpu = ++ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, ++ GFP_KERNEL); ++ if (!host->sg_cpu) { ++ retval = -ENOMEM; ++ goto out; ++ } ++ spin_lock_init(&host->lock); ++ host->irq = IRQ_MSC; /* is it useful ?*/ ++ host->imask = 0xffff; ++ /* ++ * Ensure that the host controller is shut down, and setup ++ * with our defaults. ++ */ ++ retval = request_irq(IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host); ++ if (retval) { ++ printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); ++ return retval; ++ } ++ ++ jz_mmc_slot_is_empty(0); ++ /* Request card detect interrupt */ ++ ++ retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT, ++ "MMC card detect", host); ++ if (retval) { ++ printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n"); ++ goto err1; ++ } ++#ifdef USE_DMA ++ /* Request MMC Rx DMA channel */ ++ rxdmachan = ++ jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback, ++ 0, host); ++ if (rxdmachan < 0) { ++ printk(KERN_ERR "jz_request_dma failed for MMC Rx\n"); ++ goto err2; ++ } ++ ++ if (rxdmachan < HALF_DMA_NUM) ++ REG_DMAC_DMACR(0) |= DMAC_DMACR_FMSC; ++ else ++ REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC; ++ ++ /* Request MMC Tx DMA channel */ ++ txdmachan = ++ jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback, ++ 0, host); ++ if (txdmachan < 0) { ++ printk(KERN_ERR "jz_request_dma failed for MMC Tx\n"); ++ goto err3; ++ } ++ ++ if (txdmachan < HALF_DMA_NUM) ++ REG_DMAC_DMACR(0) |= DMAC_DMACR_FMSC; ++ else ++ REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC; ++ ++#endif ++ platform_set_drvdata(pdev, mmc); ++ mmc_add_host(mmc); ++#ifdef CONFIG_PM ++ /* Register MMC slot as as power-managed device */ ++ pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, jz_mmc_pm_callback); ++#endif ++ printk("JZ SD/MMC card driver registered\n"); ++ ++ /* Detect card during initialization */ ++#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++ if (!jz_mmc_slot_is_empty(0)) { ++ mmc_slot_enable = 1; ++ mmc_detect_change(host->mmc, 0); ++ } ++#endif ++ return 0; ++ ++err1:free_irq(IRQ_MSC, &host); ++#ifdef USE_DMA ++ err2:jz_free_dma(rxdmachan); ++ err3:jz_free_dma(txdmachan); ++#endif ++out: ++ if (host) { ++ if (host->sg_cpu) ++ dma_free_coherent(&pdev->dev, PAGE_SIZE, ++ host->sg_cpu, host->sg_dma); ++ } ++ if (mmc) ++ mmc_free_host(mmc); ++ return -1; ++} ++ ++static int jz_mmc_remove(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(pdev); ++ long flags; ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ if (mmc) { ++ struct jz_mmc_host *host = mmc_priv(mmc); ++ ++ if (host->pdata && host->pdata->exit) ++ host->pdata->exit(&pdev->dev, mmc); ++ ++ mmc_remove_host(mmc); ++ ++ local_irq_save(flags); ++ __msc0_disable_power(); ++ jz_free_dma(rxdmachan); ++ jz_free_dma(txdmachan); ++ free_irq(IRQ_MSC, host); ++ local_irq_restore(flags); ++ mmc_free_host(mmc); ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++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; ++ ++ if (mmc) ++ ret = mmc_suspend_host(mmc, state); ++ ++ return ret; ++} ++ ++static int jz_mmc_resume(struct platform_device *dev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(dev); ++ int ret = 0; ++ ++ if (mmc) ++ ret = mmc_resume_host(mmc); ++ ++ return ret; ++} ++static int jz_mmc_pm_callback(struct pm_dev *pm_dev, ++ pm_request_t req, void *data) ++{ ++ struct platform_device *pdev = (struct platform_device *)pm_dev; ++ ++ switch(req) { ++ case PM_RESUME: ++ jz_mmc_resume(pdev); ++ break; ++ case PM_SUSPEND: ++ /* state has no use */ ++ jz_mmc_suspend(pdev,state); ++ break; ++ default: ++ printk("MMC/SD: invalid PM request %d\n", req); ++ break; ++ } ++ return 0; ++} ++#else ++#define jz_mmc_suspend NULL ++#define jz_mmc_resume NULL ++#endif ++ ++static struct platform_driver jz_mmc_driver = { ++ .probe = jz_mmc_probe, ++ .remove = jz_mmc_remove, ++ .suspend = jz_mmc_suspend, ++ .resume = jz_mmc_resume, ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++static int __init jz_mmc_init(void) ++{ ++ return platform_driver_register(&jz_mmc_driver); ++} ++ ++static void __exit jz_mmc_exit(void) ++{ ++ platform_driver_unregister(&jz_mmc_driver); ++} ++ ++module_init(jz_mmc_init); ++module_exit(jz_mmc_exit); ++ ++MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mmc/host/jz4750_mmc.h b/drivers/mmc/host/jz4750_mmc.h +new file mode 100644 +index 0000000..8577db6 +--- /dev/null ++++ b/drivers/mmc/host/jz4750_mmc.h +@@ -0,0 +1,88 @@ ++#ifndef __JZ4750_MMC_H__ ++#define __JZ4750_MMC_H__ ++ ++#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ ++#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ ++#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ ++#define SD_CLOCK_HIGH 24000000 /* 24 MHz for SD Cards */ ++#define MMC_NO_ERROR 0 ++ ++#define NR_SG 1 ++ ++#ifdef CONFIG_MSC0_JZ4750 ++#define MSC_ID 0 ++#define MSC_HOTPLUG_IRQ MSC0_HOTPLUG_IRQ ++#define IRQ_MSC IRQ_MSC0 ++#define DMA_ID_MSC_RX DMA_ID_MSC0_RX ++#define DMA_ID_MSC_TX DMA_ID_MSC0_TX ++#define MSC_HOTPLUG_PIN MSC0_HOTPLUG_PIN ++#else ++#define MSC_ID 1 ++#define MSC_HOTPLUG_IRQ MSC1_HOTPLUG_IRQ ++#define IRQ_MSC IRQ_MSC1 ++#define DMA_ID_MSC_RX DMA_ID_MSC1_RX ++#define DMA_ID_MSC_TX DMA_ID_MSC1_TX ++#define MSC_HOTPLUG_PIN MSC1_HOTPLUG_PIN ++#endif ++ ++#define MSC_1BIT_BUS 0 ++#define MSC_4BIT_BUS 1 ++#define MSC_8BIT_BUS 2 ++ ++#define SZ_4K 0x00001000 ++ ++struct jz_mmc_host { ++ struct mmc_host *mmc; ++ spinlock_t lock; ++ struct { ++ int len; ++ int dir; ++ } dma; ++ struct { ++ int index; ++ int offset; ++ int len; ++ } pio; ++ int irq; ++ unsigned int clkrt; ++ unsigned int cmdat; ++ unsigned int imask; ++ unsigned int power_mode; ++ struct jz_mmc_platform_data *pdata; ++ struct mmc_request *mrq; ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ dma_addr_t sg_dma; ++ struct jzsoc_dma_desc *sg_cpu; ++ unsigned int dma_len; ++ unsigned int dma_dir; ++}; ++ ++#define MMC_IRQ_MASK() \ ++do { \ ++ REG_MSC_IMASK(MSC_ID) = 0xffff; \ ++ REG_MSC_IREG(MSC_ID) = 0xffff; \ ++} while (0) ++ ++typedef struct jzsoc_dma_desc { ++ volatile u32 ddadr; /* Points to the next descriptor + flags */ ++ volatile u32 dsadr; /* DSADR value for the current transfer */ ++ volatile u32 dtadr; /* DTADR value for the current transfer */ ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++} jzsoc_dma_desc; ++ ++#include ++ ++struct device; ++struct mmc_host; ++ ++struct jz_mmc_platform_data { ++ unsigned int ocr_mask; /* available voltages */ ++ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ ++ int (*init)(struct device *, irq_handler_t , void *); ++ int (*get_ro)(struct device *); ++ void (*setpower)(struct device *, unsigned int); ++ void (*exit)(struct device *, void *); ++}; ++ ++#endif /* __JZ4750_MMC_H__ */ +diff --git a/drivers/mmc/host/jz_mmc.c b/drivers/mmc/host/jz_mmc.c +new file mode 100644 +index 0000000..29ab9bb +--- /dev/null ++++ b/drivers/mmc/host/jz_mmc.c +@@ -0,0 +1,1026 @@ ++/* ++ * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver ++ * ++ * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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_pm_callback(struct pm_dev *pm_dev, ++ pm_request_t req, void *data); ++ ++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_MULTIWRITE | 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); ++#ifdef CONFIG_PM ++ /* Register MMC slot as as power-managed device */ ++ host->pmdev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, jz_mmc_pm_callback); ++ if (host->pmdev) ++ host->pmdev->data = pdev; ++#endif ++ 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); ++ long flags; ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ if (mmc) { ++ struct jz_mmc_host *host = mmc_priv(mmc); ++ ++ if (host->pdata && host->pdata->exit) ++ host->pdata->exit(&pdev->dev, mmc); ++ ++ mmc_remove_host(mmc); ++ ++ local_irq_save(flags); ++ jz_mmc_stop_clock(); ++ __msc_disable_power(); ++ jz_free_dma(rxdmachan); ++ jz_free_dma(txdmachan); ++ free_irq(IRQ_MSC, host); ++ local_irq_restore(flags); ++ mmc_free_host(mmc); ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++pm_message_t state; ++static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(dev); ++ int ret = 0; ++ ++ __msc_disable_power(); ++ if (mmc) ++ ret = mmc_suspend_host(mmc, state); ++ ++ return ret; ++} ++ ++static int jz_mmc_resume(struct platform_device *dev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(dev); ++ int ret = 0; ++#if 0 ++ /*for sandisk BB0807011816D and other strange cards*/ ++ int i; ++ ++ for(i = 104; i < 110; i++) ++ __gpio_as_input(i); ++ ++ /* perhaps you should mdelay more */ ++ mdelay(1000); ++ __gpio_as_msc(); ++#endif ++ __msc_init_io(); ++ __msc_enable_power(); ++ __msc_reset(); ++ ++ if (!jz_mmc_slot_is_empty(0)) { ++ mmc_slot_enable = 1; ++ mmc_detect_change(mmc, 10); ++ } ++ ++ if (mmc) ++ ret = mmc_resume_host(mmc); ++ ++ return ret; ++} ++static int jz_mmc_pm_callback(struct pm_dev *pm_dev, ++ pm_request_t req, void *data) ++{ ++ struct platform_device *pdev = (struct platform_device *)pm_dev->data; ++ ++ switch(req) { ++ case PM_RESUME: ++ jz_mmc_resume(pdev); ++ break; ++ case PM_SUSPEND: ++ /* state has no use */ ++ jz_mmc_suspend(pdev, state); ++ break; ++ default: ++ printk("MMC/SD: invalid PM request %d\n", req); ++ break; ++ } ++ return 0; ++} ++#else ++#define jz_mmc_suspend NULL ++#define jz_mmc_resume NULL ++#endif ++ ++static struct platform_driver jz_mmc_driver = { ++ .probe = jz_mmc_probe, ++ .remove = jz_mmc_remove, ++ .suspend = jz_mmc_suspend, ++ .resume = jz_mmc_resume, ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++static int __init jz_mmc_init(void) ++{ ++ return platform_driver_register(&jz_mmc_driver); ++} ++ ++static void __exit jz_mmc_exit(void) ++{ ++ platform_driver_unregister(&jz_mmc_driver); ++} ++ ++module_init(jz_mmc_init); ++module_exit(jz_mmc_exit); ++ ++MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mmc/host/jz_mmc.h b/drivers/mmc/host/jz_mmc.h +new file mode 100644 +index 0000000..c733529 +--- /dev/null ++++ b/drivers/mmc/host/jz_mmc.h +@@ -0,0 +1,65 @@ ++#ifndef __JZ_MMC_H__ ++#define __JZ_MMC_H__ ++ ++#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ ++#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ ++#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ ++#define MMC_NO_ERROR 0 ++/* Extra MMC commands for state control */ ++/* Use negative numbers to disambiguate */ ++#define MMC_CIM_RESET -1 ++#define MMC_SET_CLOCK 100 ++ ++typedef struct jzsoc_dma_desc { ++ volatile u32 ddadr; /* Points to the next descriptor + flags */ ++ volatile u32 dsadr; /* DSADR value for the current transfer */ ++ volatile u32 dtadr; /* DTADR value for the current transfer */ ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++} jzsoc_dma_desc; ++ ++ ++ ++ ++#include ++ ++struct device; ++struct mmc_host; ++ ++struct jz_mmc_platform_data { ++ unsigned int ocr_mask; /* available voltages */ ++ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ ++ int (*init)(struct device *, irq_handler_t , void *); ++ int (*get_ro)(struct device *); ++ void (*setpower)(struct device *, unsigned int); ++ void (*exit)(struct device *, void *); ++}; ++ ++//extern void pxa_set_mci_info(struct pxamci_platform_data *info); ++ ++ ++ ++#define SZ_1K 0x00000400 ++#define SZ_4K 0x00001000 ++#define SZ_8K 0x00002000 ++#define SZ_16K 0x00004000 ++#define SZ_64K 0x00010000 ++#define SZ_128K 0x00020000 ++#define SZ_256K 0x00040000 ++#define SZ_512K 0x00080000 ++ ++#define SZ_1M 0x00100000 ++#define SZ_2M 0x00200000 ++#define SZ_4M 0x00400000 ++#define SZ_8M 0x00800000 ++#define SZ_16M 0x01000000 ++#define SZ_32M 0x02000000 ++#define SZ_64M 0x04000000 ++#define SZ_128M 0x08000000 ++#define SZ_256M 0x10000000 ++#define SZ_512M 0x20000000 ++ ++#define SZ_1G 0x40000000 ++#define SZ_2G 0x80000000 ++ ++ ++#endif /* __JZ_MMC_H__ */ +diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c +index 77db5ce..b9541ab 100644 +--- a/drivers/mtd/mtdblock.c ++++ b/drivers/mtd/mtdblock.c +@@ -13,7 +13,7 @@ + #include + #include + #include +- ++#include + #include + #include + #include +@@ -371,12 +371,27 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) + kfree(dev); + } + ++ ++static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) ++{ ++ struct gendisk *gd = dev->blkcore_priv; ++ memset(geo, 0, sizeof(*geo)); ++ geo->heads = 4; ++ geo->sectors = 16; ++ geo->cylinders = dev->size/(4*16); ++ ++ printk("cylinders: %x \n", geo->cylinders); ++ printk("sects: %x\n", dev->size); ++ return 0; ++} ++ + static struct mtd_blktrans_ops mtdblock_tr = { + .name = "mtdblock", + .major = 31, + .part_bits = 0, + .blksize = 512, + .open = mtdblock_open, ++ .getgeo = mtdblock_getgeo, + .flush = mtdblock_flush, + .release = mtdblock_release, + .readsect = mtdblock_readsect, +diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c +index 5b081cb..cdc69c0 100644 +--- a/drivers/mtd/mtdchar.c ++++ b/drivers/mtd/mtdchar.c +@@ -635,6 +635,73 @@ static int mtd_ioctl(struct inode *inode, struct file *file, + break; + } + ++ case MEMWRITEPAGE: ++ { ++ struct mtd_page_buf buf; ++ struct mtd_oob_ops ops; ++ ++ memset(&ops, 0, sizeof(ops)); ++#if 1 ++ if(!(file->f_mode & 2)) ++ return -EPERM; ++#endif ++ ++ if (copy_from_user(&buf, argp, sizeof(struct mtd_page_buf))) ++ return -EFAULT; ++ ++ if (buf.ooblength > mtd->oobsize) ++ return -EINVAL; ++ ++ if (!mtd->write_oob) ++ ret = -EOPNOTSUPP; ++ else ++ ret = access_ok(VERIFY_READ, buf.oobptr, ++ buf.ooblength) ? 0 : EFAULT; ++ ++ if (ret) ++ return ret; ++ ++ ops.len = mtd->writesize; ++ ops.ooblen = buf.ooblength; ++ ops.ooboffs = buf.start & (mtd->oobsize - 1); ++ ops.mode = MTD_OOB_PLACE; ++ ++ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) ++ return -EINVAL; ++ ++ /* alloc memory and copy oob data from user mode to kernel mode */ ++ ops.oobbuf = kmalloc(buf.ooblength, GFP_KERNEL); ++ if (!ops.oobbuf) ++ return -ENOMEM; ++ ++ if (copy_from_user(ops.oobbuf, buf.oobptr, buf.ooblength)) { ++ kfree(ops.oobbuf); ++ return -EFAULT; ++ } ++ ++ /* alloc memory and copy page data from user mode to kernel mode */ ++ ops.datbuf = kmalloc(mtd->writesize, GFP_KERNEL); ++ if (!ops.datbuf) ++ return -ENOMEM; ++ ++ if (copy_from_user(ops.datbuf, buf.datptr, mtd->writesize)) { ++ kfree(ops.datbuf); ++ return -EFAULT; ++ } ++ ++ buf.start &= ~(mtd->oobsize - 1); ++ ret = mtd->write_oob(mtd, buf.start, &ops); ++ ++ if (copy_to_user(argp + 2*sizeof(uint32_t), &ops.retlen, ++ sizeof(uint32_t))) ++ ret = -EFAULT; ++ ++ kfree(ops.oobbuf); ++ kfree(ops.datbuf); ++ break; ++ } ++ ++ + case MEMLOCK: + { + struct erase_info_user einfo; +diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c +index 349fcbe..69f511c 100644 +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -346,6 +346,10 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, + /* set up the MTD object for this partition */ + slave->mtd.type = master->type; + slave->mtd.flags = master->flags & ~part->mask_flags; ++ if (part[i].mtdblock_jz_invalid) ++ slave->mtd.flags |= MTD_MTDBLOCK_JZ_INVALID; ++ if (part[i].cpu_mode) ++ slave->mtd.flags |= MTD_NAND_CPU_MODE; + slave->mtd.size = part->size; + slave->mtd.writesize = master->writesize; + slave->mtd.oobsize = master->oobsize; +@@ -363,6 +367,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, + + slave->mtd.read = part_read; + slave->mtd.write = part_write; ++ slave->mtd.priv = master->priv; + + if (master->panic_write) + slave->mtd.panic_write = part_panic_write; +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index ce96c09..138afb0 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -452,4 +452,134 @@ config MTD_NAND_SOCRATES + help + Enables support for NAND Flash chips wired onto Socrates board. + ++config MTD_NAND_JZ4730 ++ tristate "Support NAND Flash device on Jz4730 board" ++ depends on SOC_JZ4730 ++ help ++ Support NAND Flash device on Jz4730 board ++ ++config MTD_NAND_JZ4740 ++ tristate "Support NAND Flash device on Jz4740 board" ++ depends on SOC_JZ4740 ++ help ++ Support NAND Flash device on Jz4740 board ++ ++config MTD_NAND_JZ4750 ++ tristate "Support NAND Flash device on Jz4750 board" ++ depends on SOC_JZ4750 || SOC_JZ4750D ++ help ++ Support NAND Flash device on Jz4750 board ++ ++config MTD_NAND_CS2 ++ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750 ++ bool 'Use NAND on CS2_N of JZSOC' ++ default n ++ ++config MTD_NAND_CS3 ++ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750 ++ bool 'Use NAND on CS3_N of JZSOC' ++ default n ++ ++config MTD_NAND_CS4 ++ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750 ++ bool 'Use NAND on CS4_N of JZSOC' ++ default n ++ ++config MTD_NAND_MULTI_PLANE ++ depends on MTD_NAND_JZ4730 || MTD_NAND_JZ4740 || MTD_NAND_JZ4750 ++ bool 'Use multiple planes if the NAND supports' ++ default y ++ help ++ It is just supported on jz4740 now. ++ ++if MTD_NAND_JZ4740 || MTD_NAND_JZ4730 || MTD_NAND_JZ4750 ++choice ++ prompt "ECC type" ++ default CONFIG_MTD_SW_HM_ECC ++ ++config MTD_HW_HM_ECC ++ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4730 ++ bool 'Select hardware HM ECC' ++ ++config MTD_SW_HM_ECC ++ bool 'Select software HM ECC' ++ ++config MTD_HW_RS_ECC ++ depends on MTD_NAND_JZ4740 ++ bool 'Select hardware RS ECC' ++ ++config MTD_HW_BCH_ECC ++ depends on MTD_NAND_JZ4750 ++ bool 'Select hardware BCH ECC' ++endchoice ++ ++choice ++ prompt "4 bit or 8 bit BCH ecc" ++ depends on MTD_HW_BCH_ECC ++ default CONFIG_MTD_HW_BCH_4BIT ++ ++config MTD_HW_BCH_4BIT ++ bool '4 bit' ++ ++config MTD_HW_BCH_8BIT ++ bool '8 bit' ++ ++endchoice ++ ++config MTD_NAND_DMA ++ depends on MTD_HW_BCH_ECC || MTD_HW_RS_ECC ++ bool 'Use DMA mode' ++ help ++ This enables using DMA for reading and writing NAND flash, if not selected, ++ then CPU mode is used. DMA is only used for two planes for jz4740. ++ ++config MTD_NAND_DMABUF ++ depends on MTD_NAND_DMA && MTD_HW_BCH_ECC ++ bool 'use DMA buffer in NAND driver' ++ help ++ It's better to say NO. If saying yes, DMA buffers will be allocated for ++ NAND reading and writing in NAND driver instead of upper layer. It's ++ slower. Just usable on CS1_N now. By saying NO, upper buffers will be ++ used as DMA buffer. It's faster, but kmalloc instead of vmalloc is required. ++endif ++ ++config ALLOCATE_MTDBLOCK_JZ_EARLY ++ bool "Allocate memory for mtdblock-jz early" ++ default n ++ help ++ Allocate memory (a nand block cache) for mtdblock-jz.c early in nand_base.c, ++ Especially for the vfat partition which will be used as USB disk by PC. ++ ++config MTD_MTDBLOCK_WRITE_VERIFY_ENABLE ++ bool "MTDBLOCK write verify enable" ++ default n ++ help ++ This will enable the write verification, which will read back data to check ++ after doing a write opetaion. ++ ++ It will be used by the JZ mtdblock driver (mtdblock-jz.c). ++ ++config MTD_OOB_COPIES ++ int "how many copies of the fs info in the oob area" ++ default 3 ++ range 0 128 ++ depends on MTD ++ help ++ This defines the copies of the fs info in the oob area inside a block. ++ Value ranges from 0 to (pages_per_block - 1). ++ ++ It will be used by the JZ mtdblock driver (mtdblock-jz.c). ++ ++config MTD_BADBLOCK_FLAG_PAGE ++ int "which page inside a block will store the badblock mark" ++ default 0 ++ range 0 127 ++ depends on MTD ++ help ++ This defines which page of a block will store the badblock mark. ++ Value ranges from 0 to (pages_per_block - 1). ++ ++ Old SLC NANDs store the badblock mark in the first page of a block, but ++ most modern MLC NANDs store it in the last page of a block. ++ + endif # MTD_NAND +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index f3a786b..748a92a 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -32,6 +32,9 @@ obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o + obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o + obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o + obj-$(CONFIG_MTD_ALAUDA) += alauda.o ++obj-$(CONFIG_MTD_NAND_JZ4730) += jz4730_nand.o ++obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o ++obj-$(CONFIG_MTD_NAND_JZ4750) += jz4750_nand.o + obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o + obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o + obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o +diff --git a/drivers/mtd/nand/jz4730_nand.c b/drivers/mtd/nand/jz4730_nand.c +new file mode 100644 +index 0000000..f3e57f7 +--- /dev/null ++++ b/drivers/mtd/nand/jz4730_nand.c +@@ -0,0 +1,367 @@ ++/* ++ * linux/drivers/mtd/nand/jz4730_nand.c ++ * ++ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Ingenic JZ4730 NAND driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define NAND_DATA_PORT 0xB4000000 /* read-write area */ ++#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff) ++#define __nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST) ++#define __nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE) ++ ++/* ++ * MTD structure for JzSOC board ++ */ ++static struct mtd_info *jz_mtd = NULL; ++ ++/* ++ * Define partitions for flash devices ++ */ ++#ifdef CONFIG_JZ4730_PMP ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 56 * 0x100000 }, ++ { name: "NAND SSFDC partition", ++ offset: 64 * 0x100000, ++ size: 64 * 0x100000 }, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[]= { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10}; /* reserved blocks of mtd3 */ ++#elif CONFIG_JZ4730_PMPV1 ++static struct mtd_partition partition_info[] = { ++ { name: "NAND ROOTFS partition", ++ offset: 3 * 0x100000, ++ size: (32-3) * 0x100000 }, ++ { name: "NAND DATAFS partition", ++ offset: 32 * 0x100000, ++ size: 32 * 0x100000 }, ++}; ++static int partition_reserved_badblocks[]={ ++ 10, ++ 10}; ++#else ++static struct mtd_partition partition_info[] = { ++ { name: "NAND ROOTFS partition", ++ offset: 3 * 0x100000, ++ size: (128-3) * 0x100000 }, ++}; ++static int partition_reserved_badblocks[]={ ++ 20}; ++#endif ++ ++/*------------------------------------------------------------------------- ++ * Following three functions are exported and used by the mtdblock-jz.c ++ * NAND FTL driver only. ++ */ ++ ++unsigned short get_mtdblock_write_verify_enable(void) ++{ ++#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE ++ return 1; ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(get_mtdblock_write_verify_enable); ++ ++unsigned short get_mtdblock_oob_copies(void) ++{ ++ return CONFIG_MTD_OOB_COPIES; ++} ++EXPORT_SYMBOL(get_mtdblock_oob_copies); ++ ++int *get_jz_badblock_table(void) ++{ ++ return partition_reserved_badblocks; ++} ++EXPORT_SYMBOL(get_jz_badblock_table); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz_hwcontrol(struct mtd_info *mtd, int dat, ++ unsigned int ctrl) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if ( ctrl & NAND_ALE ) ++ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00080000); ++ else ++ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00080000); ++ ++ if ( ctrl & NAND_CLE ) ++ nandaddr = nandaddr | 0x00040000; ++ else ++ nandaddr = nandaddr & ~0x00040000; ++ if ( ctrl & NAND_NCE ) ++ REG_EMC_NFCSR |= EMC_NFCSR_FCE; ++ else ++ REG_EMC_NFCSR &= ~EMC_NFCSR_FCE; ++ } ++ ++ this->IO_ADDR_W = (void __iomem *)nandaddr; ++ if (dat != NAND_CMD_NONE) ++ writeb(dat , this->IO_ADDR_W); ++ ++} ++ ++static int jz_device_ready(struct mtd_info *mtd) ++{ ++ int ready; ++ ready = (REG_EMC_NFCSR & EMC_NFCSR_RB) ? 1 : 0; ++ return ready; ++} ++ ++/* ++ * EMC setup ++ */ ++static void jz_device_setup(void) ++{ ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE; ++} ++ ++static void jzsoc_nand_enable_hwecc(struct mtd_info* mtd, int mode) ++{ ++ __nand_ecc_enable(); ++} ++ ++static int jzsoc_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat, ++ u_char* ecc_code) ++{ ++ unsigned int calc_ecc; ++ unsigned char *tmp; ++ ++ __nand_ecc_disable(); ++ ++ calc_ecc = ~(__nand_ecc()) | 0x00030000; ++ ++ tmp = (unsigned char *)&calc_ecc; ++ ++ ecc_code[0] = tmp[1]; ++ ecc_code[1] = tmp[0]; ++ ecc_code[2] = tmp[2]; ++ ++ return 0; ++} ++ ++/* ECC handling functions */ ++ ++static int jzsoc_nand_correct_data(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *calc_ecc) ++{ ++ u_char a, b, c, d1, d2, d3, add, bit, i; ++ ++ /* Do error detection */ ++ d1 = calc_ecc[0] ^ read_ecc[0]; ++ d2 = calc_ecc[1] ^ read_ecc[1]; ++ d3 = calc_ecc[2] ^ read_ecc[2]; ++ ++ if ((d1 | d2 | d3) == 0) { ++ /* No errors */ ++ return 0; ++ } ++ else { ++ a = (d1 ^ (d1 >> 1)) & 0x55; ++ b = (d2 ^ (d2 >> 1)) & 0x55; ++ c = (d3 ^ (d3 >> 1)) & 0x54; ++ ++ /* Found and will correct single bit error in the data */ ++ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { ++ c = 0x80; ++ add = 0; ++ a = 0x80; ++ for (i=0; i<4; i++) { ++ if (d1 & c) ++ add |= a; ++ c >>= 2; ++ a >>= 1; ++ } ++ c = 0x80; ++ for (i=0; i<4; i++) { ++ if (d2 & c) ++ add |= a; ++ c >>= 2; ++ a >>= 1; ++ } ++ bit = 0; ++ b = 0x04; ++ c = 0x80; ++ for (i=0; i<3; i++) { ++ if (d3 & c) ++ bit |= b; ++ c >>= 2; ++ b >>= 1; ++ } ++ b = 0x01; ++ a = dat[add]; ++ a ^= (b << bit); ++ dat[add] = a; ++ return 0; ++ } ++ else { ++ i = 0; ++ while (d1) { ++ if (d1 & 0x01) ++ ++i; ++ d1 >>= 1; ++ } ++ while (d2) { ++ if (d2 & 0x01) ++ ++i; ++ d2 >>= 1; ++ } ++ while (d3) { ++ if (d3 & 0x01) ++ ++i; ++ d3 >>= 1; ++ } ++ if (i == 1) { ++ /* ECC Code Error Correction */ ++ read_ecc[0] = calc_ecc[0]; ++ read_ecc[1] = calc_ecc[1]; ++ read_ecc[2] = calc_ecc[2]; ++ return 0; ++ } ++ else { ++ /* Uncorrectable Error */ ++ printk("uncorrectable ECC error\n"); ++ return -1; ++ } ++ } ++ } ++ ++ /* Should never happen */ ++ return -1; ++} ++ ++ ++/* ++ * Main initialization routine ++ */ ++int __init jznand_init(void) ++{ ++ struct nand_chip *this; ++ int nr_partitions; ++ ++ /* Allocate memory for MTD device structure and private data */ ++ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), ++ GFP_KERNEL); ++ if (!jz_mtd) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure.\n"); ++ return -ENOMEM; ++ } ++ ++ /* Get pointer to private data */ ++ this = (struct nand_chip *) (&jz_mtd[1]); ++ ++ /* Initialize structures */ ++ memset((char *) jz_mtd, 0, sizeof(struct mtd_info)); ++ memset((char *) this, 0, sizeof(struct nand_chip)); ++ ++ /* Link the private data with the MTD structure */ ++ jz_mtd->priv = this; ++ ++ /* Set & initialize NAND Flash controller */ ++ jz_device_setup(); ++ ++ /* Set address of NAND IO lines */ ++ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT; ++ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT; ++ this->cmd_ctrl = jz_hwcontrol; ++ this->dev_ready = jz_device_ready; ++ ++#ifdef CONFIG_MTD_HW_HM_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_ecc; ++ this->ecc.correct = jzsoc_nand_correct_data; ++ this->ecc.hwctl = jzsoc_nand_enable_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 256; ++ this->ecc.bytes = 3; ++ ++#endif ++ ++#ifdef CONFIG_MTD_SW_HM_ECC ++ this->eccmode = NAND_ECC_SOFT; ++#endif ++ ++ /* 20 us command delay time */ ++ this->chip_delay = 20; ++ ++ /* Scan to find existance of the device */ ++ if (nand_scan(jz_mtd, 1)) { ++ kfree (jz_mtd); ++ return -ENXIO; ++ } ++ ++ /* Register the partitions */ ++ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); ++ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); ++ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); ++ ++ return 0; ++} ++module_init(jznand_init); ++ ++/* ++ * Clean up routine ++ */ ++#ifdef MODULE ++static void __exit jznand_cleanup(void) ++{ ++ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1]; ++ ++ /* Unregister partitions */ ++ del_mtd_partitions(jz_mtd); ++ ++ /* Unregister the device */ ++ del_mtd_device (jz_mtd); ++ ++ /* Free internal data buffers */ ++ kfree (this->data_buf); ++ ++ /* Free the MTD device structure */ ++ kfree (jz_mtd); ++} ++module_exit(jznand_cleanup); ++#endif +diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c +new file mode 100644 +index 0000000..5269670 +--- /dev/null ++++ b/drivers/mtd/nand/jz4740_nand.c +@@ -0,0 +1,1123 @@ ++/* ++ * linux/drivers/mtd/nand/jz4740_nand.c ++ * ++ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Ingenic JZ4740 NAND driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ ++#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ ++#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ ++#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ ++ ++#define PAR_SIZE 9 ++ ++#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) ++#define __nand_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1) ++ ++#define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST ) ++#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) ++ ++#define __nand_select_hm_ecc() (REG_EMC_NFECR &= ~EMC_NFECR_RS ) ++#define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS) ++ ++#define __nand_read_hm_ecc() (REG_EMC_NFECC & 0x00ffffff) ++ ++#define __nand_rs_ecc_encoding() (REG_EMC_NFECR |= EMC_NFECR_RS_ENCODING) ++#define __nand_rs_ecc_decoding() (REG_EMC_NFECR &= ~EMC_NFECR_RS_ENCODING) ++#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF)) ++#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF)) ++ ++/* ++ * MTD structure for JzSOC board ++ */ ++static struct mtd_info *jz_mtd = NULL; ++extern struct mtd_info *jz_mtd1; ++extern char all_use_planes; ++extern int global_page; /* for two-plane operations */ ++ ++int nr_partitions; /* Number of partitions */ ++ ++/* ++ * Define partitions for flash devices ++ */ ++#ifdef CONFIG_JZ4740_PAVO ++struct mtd_partition partition_info[] = { ++ {name:"NAND BOOT partition", ++ offset:0 * 0x100000, ++ size:4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND KERNEL partition", ++ offset:4 * 0x100000, ++ size:4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND ROOTFS partition", ++ offset:8 * 0x100000, ++ size:504 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND VFAT partition", ++ offset:512 * 0x100000, ++ size:512 * 0x100000, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0}, ++}; ++ ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4740_PAVO */ ++ ++#ifdef CONFIG_JZ4740_LEO ++struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 56 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND VFAT partition", ++ offset: 64 * 0x100000, ++ size: 64 * 0x100000, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0 }, ++}; ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10}; /* reserved blocks of mtd3 */ ++#endif /* CONFIG_JZ4740_LEO */ ++ ++#ifdef CONFIG_JZ4740_LYRA ++struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 120 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND DATA1 partition", ++ offset: 128 * 0x100000, ++ size: 128 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND DATA2 partition", ++ offset: 256 * 0x100000, ++ size: 256 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND VFAT partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0 }, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4740_LYRA */ ++ ++#ifdef CONFIG_JZ4725_DIPPER ++struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 56 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND VFAT partition", ++ offset: 64 * 0x100000, ++ size: 64 * 0x100000, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0 }, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10}; /* reserved blocks of mtd3 */ ++#endif /* CONFIG_JZ4740_DIPPER */ ++ ++#ifdef CONFIG_JZ4720_VIRGO ++struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 120 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND DATA1 partition", ++ offset: 128 * 0x100000, ++ size: 128 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND DATA2 partition", ++ offset: 256 * 0x100000, ++ size: 256 * 0x100000, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1 }, ++ { name: "NAND VFAT partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0 }, ++}; ++ ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4720_VIRGO */ ++ ++#ifdef CONFIG_JZ4740_QI_LB60 ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 504 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND DATA1 partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++ { name: "NAND DATA2 partition", ++ offset: 1024 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++ { name: "NAND VFAT partition", ++ offset: (1024 + 512) * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 10, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4740_QI_LB60 */ ++ ++/*------------------------------------------------------------------------- ++ * Following three functions are exported and used by the mtdblock-jz.c ++ * NAND FTL driver only. ++ */ ++ ++unsigned short get_mtdblock_write_verify_enable(void) ++{ ++#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE ++ return 1; ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(get_mtdblock_write_verify_enable); ++ ++unsigned short get_mtdblock_oob_copies(void) ++{ ++ return CONFIG_MTD_OOB_COPIES; ++} ++EXPORT_SYMBOL(get_mtdblock_oob_copies); ++ ++int *get_jz_badblock_table(void) ++{ ++ return partition_reserved_badblocks; ++} ++EXPORT_SYMBOL(get_jz_badblock_table); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz_hwcontrol(struct mtd_info *mtd, int dat, ++ unsigned int ctrl) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; ++ extern u8 nand_nce; /* in nand_base.c, indicates which chip select is used for current nand chip */ ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_NCE) { ++ switch (nand_nce) { ++ case NAND_NCE1: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; ++ break; ++ case NAND_NCE2: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; ++ break; ++ case NAND_NCE3: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; ++ break; ++ case NAND_NCE4: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; ++ break; ++ default: ++ printk("error: no nand_nce 0x%x\n",nand_nce); ++ break; ++ } ++ } else { ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ } ++ ++ if ( ctrl & NAND_ALE ) ++ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00010000); ++ else ++ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00010000); ++ ++ if ( ctrl & NAND_CLE ) ++ nandaddr = nandaddr | 0x00008000; ++ else ++ nandaddr = nandaddr & ~0x00008000; ++ } ++ ++ this->IO_ADDR_W = (void __iomem *)nandaddr; ++ if (dat != NAND_CMD_NONE) ++ writeb(dat, this->IO_ADDR_W); ++} ++ ++static int jz_device_ready(struct mtd_info *mtd) ++{ ++ int ready, wait = 10; ++ while (wait--); ++ ready = __gpio_get_pin(94); ++ return ready; ++} ++ ++/* ++ * EMC setup ++ */ ++static void jz_device_setup(void) ++{ ++// PORT 0: ++// ... ++// PORT 1: ++// PIN/BIT N FUNC0 FUNC1 ++// 25 CS1# - ++// 26 CS2# - ++// 27 CS3# - ++// 28 CS4# - ++#define GPIO_CS2_N (32+26) ++#define GPIO_CS3_N (32+27) ++#define GPIO_CS4_N (32+28) ++#define SMCR_VAL 0x0d221200 ++ ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; ++ /* Read/Write timings */ ++ REG_EMC_SMCR1 = SMCR_VAL; ++ ++#if defined(CONFIG_MTD_NAND_CS2) ++ /* Set CS2# pin as function 0 */ ++ __gpio_as_func0(GPIO_CS2_N); ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; ++ REG_EMC_SMCR2 = SMCR_VAL; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS3) ++ __gpio_as_func0(GPIO_CS3_N); ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; ++ REG_EMC_SMCR3 = SMCR_VAL; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS4) ++ __gpio_as_func0(GPIO_CS4_N); ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; ++ REG_EMC_SMCR4 = SMCR_VAL; ++#endif ++} ++ ++#ifdef CONFIG_MTD_HW_HM_ECC ++ ++static int jzsoc_nand_calculate_hm_ecc(struct mtd_info* mtd, ++ const u_char* dat, u_char* ecc_code) ++{ ++ unsigned int calc_ecc; ++ unsigned char *tmp; ++ ++ __nand_ecc_disable(); ++ ++ calc_ecc = ~(__nand_read_hm_ecc()) | 0x00030000; ++ ++ tmp = (unsigned char *)&calc_ecc; ++ //adjust eccbytes order for compatible with software ecc ++ ecc_code[0] = tmp[1]; ++ ecc_code[1] = tmp[0]; ++ ecc_code[2] = tmp[2]; ++ ++ return 0; ++} ++ ++static void jzsoc_nand_enable_hm_hwecc(struct mtd_info* mtd, int mode) ++{ ++ __nand_ecc_enable(); ++ __nand_select_hm_ecc(); ++} ++ ++static int jzsoc_nand_hm_correct_data(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *calc_ecc) ++{ ++ u_char a, b, c, d1, d2, d3, add, bit, i; ++ ++ /* Do error detection */ ++ d1 = calc_ecc[0] ^ read_ecc[0]; ++ d2 = calc_ecc[1] ^ read_ecc[1]; ++ d3 = calc_ecc[2] ^ read_ecc[2]; ++ ++ if ((d1 | d2 | d3) == 0) { ++ /* No errors */ ++ return 0; ++ } ++ else { ++ a = (d1 ^ (d1 >> 1)) & 0x55; ++ b = (d2 ^ (d2 >> 1)) & 0x55; ++ c = (d3 ^ (d3 >> 1)) & 0x54; ++ ++ /* Found and will correct single bit error in the data */ ++ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { ++ c = 0x80; ++ add = 0; ++ a = 0x80; ++ for (i=0; i<4; i++) { ++ if (d1 & c) ++ add |= a; ++ c >>= 2; ++ a >>= 1; ++ } ++ c = 0x80; ++ for (i=0; i<4; i++) { ++ if (d2 & c) ++ add |= a; ++ c >>= 2; ++ a >>= 1; ++ } ++ bit = 0; ++ b = 0x04; ++ c = 0x80; ++ for (i=0; i<3; i++) { ++ if (d3 & c) ++ bit |= b; ++ c >>= 2; ++ b >>= 1; ++ } ++ b = 0x01; ++ a = dat[add]; ++ a ^= (b << bit); ++ dat[add] = a; ++ return 0; ++ } ++ else { ++ i = 0; ++ while (d1) { ++ if (d1 & 0x01) ++ ++i; ++ d1 >>= 1; ++ } ++ while (d2) { ++ if (d2 & 0x01) ++ ++i; ++ d2 >>= 1; ++ } ++ while (d3) { ++ if (d3 & 0x01) ++ ++i; ++ d3 >>= 1; ++ } ++ if (i == 1) { ++ /* ECC Code Error Correction */ ++ read_ecc[0] = calc_ecc[0]; ++ read_ecc[1] = calc_ecc[1]; ++ read_ecc[2] = calc_ecc[2]; ++ return 0; ++ } ++ else { ++ /* Uncorrectable Error */ ++ printk("NAND: uncorrectable ECC error\n"); ++ return -1; ++ } ++ } ++ } ++ ++ /* Should never happen */ ++ return -1; ++} ++ ++#endif /* CONFIG_MTD_HW_HM_ECC */ ++ ++#ifdef CONFIG_MTD_HW_RS_ECC ++ ++static void jzsoc_nand_enable_rs_hwecc(struct mtd_info* mtd, int mode) ++{ ++ REG_EMC_NFINTS = 0x0; ++ __nand_ecc_enable(); ++ __nand_select_rs_ecc(); ++ ++ if (mode == NAND_ECC_READ) ++ __nand_rs_ecc_decoding(); ++ ++ if (mode == NAND_ECC_WRITE) ++ __nand_rs_ecc_encoding(); ++} ++ ++static void jzsoc_rs_correct(unsigned char *dat, int idx, int mask) ++{ ++ int i; ++ ++ idx--; ++ ++ i = idx + (idx >> 3); ++ if (i >= 512) ++ return; ++ ++ mask <<= (idx & 0x7); ++ ++ dat[i] ^= mask & 0xff; ++ if (i < 511) ++ dat[i+1] ^= (mask >> 8) & 0xff; ++} ++ ++/* ++ * calc_ecc points to oob_buf for us ++ */ ++static int jzsoc_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *calc_ecc) ++{ ++ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; ++ short k; ++ u32 stat; ++ ++ /* Set PAR values */ ++ for (k = 0; k < PAR_SIZE; k++) { ++ *paraddr++ = read_ecc[k]; ++ } ++ ++ /* Set PRDY */ ++ REG_EMC_NFECR |= EMC_NFECR_PRDY; ++ ++ /* Wait for completion */ ++ __nand_ecc_decode_sync(); ++ __nand_ecc_disable(); ++ ++ /* Check decoding */ ++ stat = REG_EMC_NFINTS; ++ ++ if (stat & EMC_NFINTS_ERR) { ++ /* Error occurred */ ++ if (stat & EMC_NFINTS_UNCOR) { ++ printk("NAND: Uncorrectable ECC error\n"); ++ return -1; ++ } else { ++ u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; ++ switch (errcnt) { ++ case 4: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ /* FALL-THROUGH */ ++ case 3: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ /* FALL-THROUGH */ ++ case 2: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ /* FALL-THROUGH */ ++ case 1: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ return 0; ++ default: ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int jzsoc_nand_calculate_rs_ecc(struct mtd_info* mtd, const u_char* dat, ++ u_char* ecc_code) ++{ ++ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; ++ short i; ++ ++ __nand_ecc_encode_sync(); ++ __nand_ecc_disable(); ++ ++ for(i = 0; i < PAR_SIZE; i++) { ++ ecc_code[i] = *paraddr++; ++ } ++ ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_HW_RS_ECC */ ++ ++/* Nand optimized functions */ ++static int dma_chan; ++static unsigned int dma_src_phys_addr, dma_dst_phys_addr; ++extern int jz_request_dma(int dev_id, const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, void *irq_dev_id); ++ ++static void dma_setup(void) ++{ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", NULL, IRQF_DISABLED, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq for nand failed!\n"); ++ return; ++ } else ++ printk("Nand DMA request channel %d.\n",dma_chan); ++} ++ ++static void jz4740_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ++{ ++ int i; ++ struct nand_chip *chip = mtd->priv; ++ ++ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) ++ { ++ for (i = 0; i < len; i++) ++ buf[i] = readb(chip->IO_ADDR_R); ++ } else { ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ dma_src_phys_addr = CPHYSADDR(chip->IO_ADDR_R); ++ dma_dst_phys_addr = CPHYSADDR(buf); ++ dma_cache_inv((u32)buf, len); ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = len / 16; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_end(dma_chan); ++ } ++} ++ ++static void jz4740_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) ++{ ++ int i; ++ struct nand_chip *chip = mtd->priv; ++ ++ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) ++ { ++ for (i = 0; i < len; i++) ++ writeb(buf[i], chip->IO_ADDR_W); ++ } else { ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ dma_dst_phys_addr = CPHYSADDR(chip->IO_ADDR_R); ++ dma_src_phys_addr = CPHYSADDR(buf); ++ dma_cache_wback((unsigned long)buf, len); ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = len / 16; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_16BYTE ; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_end(dma_chan); ++ } ++} ++ ++static int nand_read_page_hwecc_rs_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps >> 1; ++ uint8_t *p; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *ecc_code = chip->buffers->ecccode; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ uint32_t page; ++ uint8_t flag = 0; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ int ecctotal = chip->ecc.total >> 1; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page */ ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ for (i = 0; i < ecctotal; i++) { ++ ecc_code[i] = chip->oob_poi[eccpos[i]]; ++ if (ecc_code[i] != 0xff) flag = 1; ++ } ++ ++ p = buf; ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); ++ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ int stat; ++ if (flag) { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ else { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ } ++ } ++ /* Read second page */ ++ page += ppb; ++ flag = 0; ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ chip->read_buf(mtd, chip->oob_poi + oobsize, oobsize); ++ for (i = 0; i < ecctotal; i++) { ++ ecc_code[i] = chip->oob_poi[oobsize + eccpos[i]]; ++ if (ecc_code[i] != 0xff) flag = 1; ++ } ++ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); ++ eccsteps = chip->ecc.steps >> 1; ++ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ int stat; ++ if (flag) { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ else { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ } ++ } ++ ++ return 0; ++} ++ ++static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page, int sndcmd) ++{ ++ int page; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page OOB */ ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ } ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ /* Read second page OOB */ ++ page += ppb; ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ sndcmd = 0; ++ } ++ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); ++ return 0; ++} ++ ++static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page) ++{ ++ int status = 0,page; ++ int pagesize = mtd->writesize >> 1; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ const uint8_t *buf = chip->oob_poi; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send first command to program the OOB data */ ++ chip->cmdfunc(mtd, 0x11, -1, -1); ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ page += ppb; ++ buf += oobsize; ++ chip->cmdfunc(mtd, 0x81, pagesize, page); ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send command to program the OOB data */ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ /* Wait long R/B */ ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ return status & NAND_STATUS_FAIL ? -EIO : 0; ++} ++ ++static void nand_write_page_hwecc_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps >> 1; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *p = (uint8_t *)buf; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ int ecctotal = chip->ecc.total >> 1; ++ int page; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ chip->write_buf(mtd, p, eccsize); ++ chip->ecc.calculate(mtd, p, &ecc_calc[i]); ++ } ++ for (i = 0; i < ecctotal; i++) ++ chip->oob_poi[eccpos[i]] = ecc_calc[i]; ++ ++ chip->write_buf(mtd, chip->oob_poi, oobsize); ++ ++ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ ++ ndelay(100); ++ while(!chip->dev_ready(mtd)); ++ ++ page += ppb; ++ chip->cmdfunc(mtd, 0x81, 0x00, page); /* send cmd 0x81 */ ++ eccsteps = chip->ecc.steps >> 1; ++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ chip->write_buf(mtd, p, eccsize); ++ chip->ecc.calculate(mtd, p, &ecc_calc[i]); ++ } ++ ++ for (i = 0; i < ecctotal; i++) ++ chip->oob_poi[eccpos[i]] = ecc_calc[i]; ++ ++ chip->write_buf(mtd, chip->oob_poi, oobsize); ++} ++ ++static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) ++{ ++ struct nand_chip *chip = mtd->priv; ++ ++ /* Send commands to erase a block */ ++ int page; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x60, -1, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ page += ppb; ++ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ ++ ++ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ ++ /* Do not need wait R/B or check status */ ++} ++ ++/* ++ * Main initialization routine ++ */ ++int __init jznand_init(void) ++{ ++ struct nand_chip *this; ++ int ret, i; ++ ++ /* Allocate memory for MTD device structure and private data */ ++ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), ++ GFP_KERNEL); ++ if (!jz_mtd) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure.\n"); ++ return -ENOMEM; ++ } ++ ++ jz_mtd1 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), ++ GFP_KERNEL); ++ if (!jz_mtd1) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); ++ kfree(jz_mtd); ++ return -ENOMEM; ++ } ++ ++ /* Get pointer to private data */ ++ this = (struct nand_chip *) (&jz_mtd[1]); ++ ++ /* Initialize structures */ ++ memset((char *) jz_mtd, 0, sizeof(struct mtd_info)); ++ memset((char *) this, 0, sizeof(struct nand_chip)); ++ ++ /* Link the private data with the MTD structure */ ++ jz_mtd->priv = this; ++ ++ /* Set & initialize NAND Flash controller */ ++ jz_device_setup(); ++ ++ /* Set address of NAND IO lines */ ++ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT1; ++ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT1; ++ this->cmd_ctrl = jz_hwcontrol; ++ this->dev_ready = jz_device_ready; ++ ++#ifdef CONFIG_MTD_HW_HM_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_hm_ecc; ++ this->ecc.correct = jzsoc_nand_hm_correct_data; ++ this->ecc.hwctl = jzsoc_nand_enable_hm_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 256; ++ this->ecc.bytes = 3; ++ ++#endif ++ ++#ifdef CONFIG_MTD_HW_RS_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_rs_ecc; ++ this->ecc.correct = jzsoc_nand_rs_correct_data; ++ this->ecc.hwctl = jzsoc_nand_enable_rs_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 512; ++ this->ecc.bytes = 9; ++#endif ++ ++#ifdef CONFIG_MTD_SW_HM_ECC ++ this->ecc.mode = NAND_ECC_SOFT; ++#endif ++ /* 20 us command delay time */ ++ this->chip_delay = 20; ++ ++#ifdef CONFIG_MTD_NAND_DMA ++ dma_setup(); ++#endif ++ /* Scan to find existance of the device */ ++ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); ++ if (!ret) { ++ if (this->planenum == 2) { ++ /* reset nand functions */ ++ this->erase_cmd = single_erase_cmd_planes; ++ this->ecc.read_page = nand_read_page_hwecc_rs_planes; //Muti planes read ++ this->ecc.write_page = nand_write_page_hwecc_planes; ++ this->ecc.read_oob = nand_read_oob_std_planes; ++ this->ecc.write_oob = nand_write_oob_std_planes; ++#ifdef CONFIG_MTD_NAND_DMA ++ this->write_buf = jz4740_nand_write_buf; ++ this->read_buf = jz4740_nand_read_buf; ++#endif ++ printk(KERN_INFO "Nand using two-plane mode, " ++ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", ++ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); ++ } ++ } ++ ++ /* Determine whether all the partitions will use multiple planes if supported */ ++ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); ++ all_use_planes = 1; ++ for (i = 0; i < nr_partitions; i++) { ++ all_use_planes &= partition_info[i].use_planes; ++ } ++ ++ if (!ret) ++ ret = nand_scan_tail(jz_mtd); ++ ++ if (ret){ ++ kfree (jz_mtd1); ++ kfree (jz_mtd); ++ return -ENXIO; ++ } ++ ++ /* Register the partitions */ ++ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); ++ ++ if ((this->planenum == 2) && !all_use_planes) { ++ for (i = 0; i < nr_partitions; i++) { ++ if (partition_info[i].use_planes) ++ add_mtd_partitions(jz_mtd, &partition_info[i], 1); ++ else ++ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); ++ } ++ } else { ++ kfree(jz_mtd1); ++ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); ++ } ++ return 0; ++} ++module_init(jznand_init); ++ ++/* ++ * Clean up routine ++ */ ++#ifdef MODULE ++static void __exit jznand_cleanup(void) ++{ ++ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1]; ++ ++ /* Unregister partitions */ ++ del_mtd_partitions(jz_mtd); ++ ++ /* Unregister the device */ ++ del_mtd_device (jz_mtd); ++ ++ /* Free internal data buffers */ ++ kfree (this->data_buf); ++ ++ /* Free the MTD device structure */ ++ if ((this->planenum == 2) && !all_use_planes) ++ kfree (jz_mtd1); ++ kfree (jz_mtd); ++} ++module_exit(jznand_cleanup); ++#endif +diff --git a/drivers/mtd/nand/jz4750_nand.c b/drivers/mtd/nand/jz4750_nand.c +new file mode 100644 +index 0000000..f50fe74 +--- /dev/null ++++ b/drivers/mtd/nand/jz4750_nand.c +@@ -0,0 +1,1857 @@ ++/* ++ * linux/drivers/mtd/nand/jz4750_nand.c ++ * ++ * JZ4750 NAND driver ++ * ++ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* 32bit instead of 16byte burst is used by DMA to read or ++ write NAND and BCH avoiding grabbing bus for too long */ ++#define DMAC_DCMD_DS_NAND DMAC_DCMD_DS_32BIT ++#define DIV_DS_NAND 4 ++ ++#define DMAC_DCMD_DS_BCH DMAC_DCMD_DS_32BIT ++#define DIV_DS_BCH 4 ++ ++#define DEBUG1 0 ++#if DEBUG1 ++#define dprintk(n,x...) printk(n,##x) ++#else ++#define dprintk(n,x...) ++#endif ++ ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++#define __ECC_ENCODING __ecc_encoding_8bit ++#define __ECC_DECODING __ecc_decoding_8bit ++#define ERRS_SIZE 5 /* 5 words */ ++#else ++#define __ECC_ENCODING __ecc_encoding_4bit ++#define __ECC_DECODING __ecc_decoding_4bit ++#define ERRS_SIZE 3 /* 3 words */ ++#endif ++ ++#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ ++#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ ++#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ ++#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ ++ ++#define NAND_ADDR_OFFSET0 0x00010000 /* address port offset for share mode */ ++#define NAND_CMD_OFFSET0 0x00008000 /* command port offset for share mode */ ++#define NAND_ADDR_OFFSET1 0x00000010 /* address port offset for unshare mode */ ++#define NAND_CMD_OFFSET1 0x00000008 /* command port offset for unshare mode */ ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++#define USE_IRQ 1 ++enum { ++ NAND_NONE, ++ NAND_PROG, ++ NAND_READ ++}; ++static volatile u8 nand_status; ++static volatile int dma_ack = 0; ++static volatile int dma_ack1 = 0; ++static char nand_dma_chan; /* automatically select a free channel */ ++static char bch_dma_chan = 0; /* fixed to channel 0 */ ++static u32 *errs; ++static jz_dma_desc_8word *dma_desc_enc, *dma_desc_enc1, *dma_desc_dec, *dma_desc_dec1, *dma_desc_dec2, ++ *dma_desc_nand_prog, *dma_desc_nand_read; ++static u32 *pval_nand_ddr; ++static u8 *pval_nand_cmd_pgprog; /* for sending 0x11 or 0x10 when programing*/ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++u8 *prog_buf, *read_buf; ++#endif ++DECLARE_WAIT_QUEUE_HEAD(nand_prog_wait_queue); ++DECLARE_WAIT_QUEUE_HEAD(nand_read_wait_queue); ++#endif ++ ++struct buf_be_corrected { ++ u8 *data; ++ u8 *oob; ++}; ++ ++static u32 addr_offset; ++static u32 cmd_offset; ++static int nand_chips = 1; /* Number of nand chips to be scanned */ ++extern int global_page; /* for two-plane operations */ ++ ++/* ++ * MTD structure for JzSOC board ++ */ ++static struct mtd_info *jz_mtd = NULL; ++extern struct mtd_info *jz_mtd1; ++extern char all_use_planes; ++ ++int nr_partitions; /* Number of partitions */ ++ ++/* ++ * Define partitions for flash devices ++ */ ++#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1) || defined(CONFIG_JZ4750D_CETUS) ++struct mtd_partition partition_info[] = { ++ {name:"NAND BOOT partition", ++ offset:0 * 0x100000, ++ size:4 * 0x100000, ++ cpu_mode: 1, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND KERNEL partition", ++ offset:4 * 0x100000, ++ size:4 * 0x100000, ++ cpu_mode: 1, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND ROOTFS partition", ++ offset:8 * 0x100000, ++ size:120 * 0x100000, ++ cpu_mode: 1, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND DATA1 partition", ++ offset:128 * 0x100000, ++ size:128 * 0x100000, ++ cpu_mode: 1, ++ use_planes: 1, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND DATA2 partition", ++ offset:256 * 0x100000, ++ size:256 * 0x100000, ++ cpu_mode: 1, ++ use_planes: 1, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND VFAT partition", ++ offset:512 * 0x100000, ++ size:512 * 0x100000, ++ cpu_mode: 0, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0}, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20 ++}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4750_FUWA */ ++ ++#if defined(CONFIG_JZ4750_APUS) ++struct mtd_partition partition_info[] = { ++ {name:"NAND BOOT partition", ++ offset:0 * 0x100000, ++ size:4 * 0x100000, ++ cpu_mode: 0, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND KERNEL partition", ++ offset:4 * 0x100000, ++ size:4 * 0x100000, ++ cpu_mode: 0, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND ROOTFS partition", ++ offset:8 * 0x100000, ++ size:504 * 0x100000, ++ cpu_mode: 1, ++ use_planes: 0, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND DATA partition", ++ offset:512 * 0x100000, ++ size:512 * 0x100000, ++ cpu_mode: 0, ++ use_planes: 1, ++ mtdblock_jz_invalid: 1}, ++ {name:"NAND VFAT partition", ++ offset:1024 * 0x100000, ++ size:1024 * 0x100000, ++ cpu_mode: 0, ++ use_planes: 1, ++ mtdblock_jz_invalid: 0}, ++}; ++ ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 10, /* reserved blocks of mtd4 */ ++}; ++#endif /* CONFIG_JZ4750_APUS */ ++ ++/*------------------------------------------------------------------------- ++ * Following three functions are exported and used by the mtdblock-jz.c ++ * NAND FTL driver only. ++ */ ++ ++unsigned short get_mtdblock_write_verify_enable(void) ++{ ++#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE ++ return 1; ++#endif ++ return 0; ++} ++ ++EXPORT_SYMBOL(get_mtdblock_write_verify_enable); ++ ++unsigned short get_mtdblock_oob_copies(void) ++{ ++ return CONFIG_MTD_OOB_COPIES; ++} ++ ++EXPORT_SYMBOL(get_mtdblock_oob_copies); ++ ++int *get_jz_badblock_table(void) ++{ ++ if (sizeof(partition_reserved_badblocks) / sizeof(int) != nr_partitions) ++ printk("partition_reserved_badblocks setting error!\n"); ++ ++ return partition_reserved_badblocks; ++} ++ ++EXPORT_SYMBOL(get_jz_badblock_table); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz_hwcontrol(struct mtd_info *mtd, int dat, u32 ctrl) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ u32 nandaddr = (u32)this->IO_ADDR_W; ++ extern u8 nand_nce; /* defined in nand_base.c, indicates which chip select is used for current nand chip */ ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_NCE) { ++ switch (nand_nce) { ++ case NAND_NCE1: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; ++ break; ++ case NAND_NCE2: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; ++ break; ++ case NAND_NCE3: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; ++ break; ++ case NAND_NCE4: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; ++ break; ++ default: ++ printk("error: no nand_nce 0x%x\n",nand_nce); ++ break; ++ } ++ } else { ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ } ++ ++ if (ctrl & NAND_ALE) ++ nandaddr = (u32)((u32)(this->IO_ADDR_W) | addr_offset); ++ else ++ nandaddr = (u32)((u32)(this->IO_ADDR_W) & ~addr_offset); ++ if (ctrl & NAND_CLE) ++ nandaddr = (u32)(nandaddr | cmd_offset); ++ else ++ nandaddr = (u32)(nandaddr & ~cmd_offset); ++ } ++ ++ this->IO_ADDR_W = (void __iomem *)nandaddr; ++ if (dat != NAND_CMD_NONE) { ++ writeb(dat, this->IO_ADDR_W); ++ /* printk("write cmd:0x%x to 0x%x\n",dat,(u32)this->IO_ADDR_W); */ ++ } ++} ++ ++static int jz_device_ready(struct mtd_info *mtd) ++{ ++ int ready, wait = 10; ++ while (wait--); ++ ready = __gpio_get_pin(91); ++ return ready; ++} ++ ++/* ++ * EMC setup ++ */ ++static void jz_device_setup(void) ++{ ++// PORT 0: ++// PORT 1: ++// PORT 2: ++// PIN/BIT N FUNC0 FUNC1 ++// 21 CS1# - ++// 22 CS2# - ++// 23 CS3# - ++// 24 CS4# - ++#define GPIO_CS2_N (32*2+22) ++#define GPIO_CS3_N (32*2+23) ++#define GPIO_CS4_N (32*2+24) ++#define SMCR_VAL 0x0d444400 ++ ++ __gpio_as_nand_8bit(1); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; ++ /* Read/Write timings */ ++ REG_EMC_SMCR1 = SMCR_VAL; ++ ++#if defined(CONFIG_MTD_NAND_CS2) ++ __gpio_as_func0(GPIO_CS2_N); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; ++ /* Read/Write timings */ ++ REG_EMC_SMCR2 = SMCR_VAL; ++ nand_chips++; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS3) ++ __gpio_as_func0(GPIO_CS3_N); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; ++ /* Read/Write timings */ ++ REG_EMC_SMCR3 = SMCR_VAL; ++ nand_chips++; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS4) ++ __gpio_as_func0(GPIO_CS4_N); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; ++ /* Read/Write timings */ ++ REG_EMC_SMCR4 = SMCR_VAL; ++ nand_chips++; ++#endif ++} ++ ++#ifdef CONFIG_MTD_HW_BCH_ECC ++ ++static void jzsoc_nand_enable_bch_hwecc(struct mtd_info *mtd, int mode) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccbytes = this->ecc.bytes; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int oob_per_eccsize = this->ecc.layout->eccpos[0] / eccsteps; ++ ++ REG_BCH_INTS = 0xffffffff; ++ if (mode == NAND_ECC_READ) { ++ __ECC_DECODING(); ++ __ecc_cnt_dec(eccsize + oob_per_eccsize + eccbytes); ++ ++ if (!(mtd->flags & MTD_NAND_CPU_MODE)) ++ __ecc_dma_enable(); ++ else ++ __ecc_dma_disable(); ++ } ++ ++ if (mode == NAND_ECC_WRITE) { ++ __ECC_ENCODING(); ++ __ecc_cnt_enc(eccsize + oob_per_eccsize); ++ ++ if (!(mtd->flags & MTD_NAND_CPU_MODE)) ++ __ecc_dma_enable(); ++ else ++ __ecc_dma_disable(); ++ } ++} ++ ++/** ++ * bch_correct ++ * @dat: data to be corrected ++ * @idx: the index of error bit in an eccsize ++ */ ++static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int ecc_pos = this->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int i, bit; /* the 'bit' of i byte is error */ ++ ++ i = (idx - 1) >> 3; ++ bit = (idx - 1) & 0x7; ++ ++ dprintk("error:i=%d, bit=%d\n",i,bit); ++ ++ if (i < eccsize){ ++ ((struct buf_be_corrected *)dat)->data[i] ^= (1 << bit); ++ } else if (i < eccsize + oob_per_eccsize) { ++ ((struct buf_be_corrected *)dat)->oob[i-eccsize] ^= (1 << bit); ++ } ++} ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ ++/** ++ * jzsoc_nand_bch_correct_data ++ * @mtd: mtd info structure ++ * @dat: data to be corrected ++ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and ++ * BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH) ++ * @calc_ecc: no used ++ */ ++static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * errs0, u_char * calc_ecc) ++{ ++ u32 stat; ++ u32 *errs = (u32 *)errs0; ++ ++ if (REG_DMAC_DCCSR(0) & DMAC_DCCSR_BERR) { ++ stat = errs[0]; ++ dprintk("stat=%x err0:%x err1:%x \n", stat, errs[1], errs[2]); ++ ++ if (stat & BCH_INTS_ERR) { ++ if (stat & BCH_INTS_UNCOR) { ++ printk("NAND: Uncorrectable ECC error\n"); ++ return -1; ++ } else { ++ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; ++ switch (errcnt) { ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ case 8: ++ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 7: ++ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ case 6: ++ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 5: ++ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++#endif ++ case 4: ++ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 3: ++ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ case 2: ++ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 1: ++ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ default: ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++/** ++ * jzsoc_nand_bch_correct_data_cpu ++ * @mtd: mtd info structure ++ * @dat: data to be corrected ++ * @read_ecc: pointer to ecc buffer calculated when nand writing ++ * @calc_ecc: no used ++ */ ++static int jzsoc_nand_bch_correct_data_cpu(struct mtd_info *mtd, u_char * dat, u_char * read_ecc, u_char * calc_ecc) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccbytes = this->ecc.bytes; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int ecc_pos = this->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ short k; ++ u32 stat; ++ ++ /* Write data to REG_BCH_DR */ ++ for (k = 0; k < eccsize; k++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[k]; ++ } ++ /* Write oob to REG_BCH_DR */ ++ for (k = 0; k < oob_per_eccsize; k++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[k]; ++ } ++ /* Write parities to REG_BCH_DR */ ++ for (k = 0; k < eccbytes; k++) { ++ REG_BCH_DR = read_ecc[k]; ++ } ++ ++ /* Wait for completion */ ++ __ecc_decode_sync(); ++ __ecc_disable(); ++ ++ /* Check decoding */ ++ stat = REG_BCH_INTS; ++ ++ if (stat & BCH_INTS_ERR) { ++ /* Error occurred */ ++ if (stat & BCH_INTS_UNCOR) { ++ printk("NAND: Uncorrectable ECC error--\n"); ++ return -1; ++ } else { ++ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; ++ switch (errcnt) { ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ case 8: ++ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 7: ++ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ /* FALL-THROUGH */ ++ case 6: ++ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 5: ++ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ /* FALL-THROUGH */ ++#endif ++ case 4: ++ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 3: ++ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ /* FALL-THROUGH */ ++ case 2: ++ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 1: ++ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ return 0; ++ default: ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccbytes = this->ecc.bytes; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int ecc_pos = this->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ volatile u8 *paraddr = (volatile u8 *)BCH_PAR0; ++ short i; ++ ++ /* Write data to REG_BCH_DR */ ++ for (i = 0; i < eccsize; i++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[i]; ++ } ++ /* Write oob to REG_BCH_DR */ ++ for (i = 0; i < oob_per_eccsize; i++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[i]; ++ } ++ __ecc_encode_sync(); ++ __ecc_disable(); ++ ++ for (i = 0; i < eccbytes; i++) { ++ ecc_code[i] = *paraddr++; ++ } ++ ++ return 0; ++} ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ ++/** ++ * nand_write_page_hwecc_bch - [REPLACABLE] hardware ecc based page write function ++ * @mtd: mtd info structure ++ * @chip: nand chip info structure ++ * @buf: data buffer ++ */ ++static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, u8 cmd_pgprog) ++{ ++ int eccsize = chip->ecc.size; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int eccbytes = chip->ecc.bytes; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int i, err, timeout; ++ const u8 *databuf; ++ u8 *oobbuf; ++ jz_dma_desc_8word *desc; ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ memcpy(prog_buf, buf, pagesize); ++ memcpy(prog_buf + pagesize, chip->oob_poi, oobsize); ++ dma_cache_wback_inv((u32)prog_buf, pagesize + oobsize); ++#else ++ databuf = buf; ++ oobbuf = chip->oob_poi; ++ ++ /* descriptors for encoding data blocks */ ++ desc = dma_desc_enc; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++ dprintk("dma_desc_enc:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for encoding oob blocks */ ++ desc = dma_desc_enc1; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++ dprintk("dma_desc_enc1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptor for nand programing data block */ ++ desc = dma_desc_nand_prog; ++ desc->dsadr = CPHYSADDR((u32)databuf); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ ++ dprintk("dma_desc_nand_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptor for nand programing oob block */ ++ desc++; ++ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ ++ dprintk("dma_desc_oob_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptor for __nand_cmd(CMD_PGPROG) */ ++ desc++; ++ *pval_nand_cmd_pgprog = cmd_pgprog; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ ++ if (cmd_pgprog == 0x10) ++ desc->dcmd |= DMAC_DCMD_LINK; /* __nand_sync() by a DMA descriptor */ ++ else if (cmd_pgprog == 0x11) ++ desc->dcmd &= ~DMAC_DCMD_LINK; /* __nand_sync() by polling */ ++ ++ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 1) * (sizeof(jz_dma_desc_8word))); ++ dma_cache_wback_inv((u32)databuf, pagesize); ++ dma_cache_wback_inv((u32)oobbuf, oobsize); ++ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ ++ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ ++#endif ++ ++ REG_DMAC_DCCSR(bch_dma_chan) = 0; ++ REG_DMAC_DCCSR(nand_dma_chan) = 0; ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_enc); ++ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_prog); ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_ENC; ++ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_AUTO; ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(bch_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; ++ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; ++ ++ /* Enable BCH encoding */ ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ ++ dma_ack1 = 0; ++ nand_status = NAND_PROG; ++ ++ /* DMA doorbell set -- start DMA now ... */ ++ __dmac_channel_set_doorbell(bch_dma_chan); ++ ++#if USE_IRQ ++ if (cmd_pgprog == 0x10) { ++ dprintk("nand prog before wake up\n"); ++ err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ); ++ nand_status = NAND_NONE; ++ dprintk("nand prog after wake up\n"); ++ if (!err) { ++ printk("*** NAND WRITE, Warning, wait event 3s timeout!\n"); ++ dump_jz_dma_channel(0); ++ dump_jz_dma_channel(nand_dma_chan); ++ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); ++ } ++ dprintk("timeout remain = %d\n", err); ++ } else if (cmd_pgprog == 0x11) { ++ timeout = 100000; ++ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); ++ if (timeout <= 0) ++ printk("two-plane prog 0x11 timeout!\n"); ++ } ++#else ++ timeout = 100000; ++ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); ++ while(!chip->dev_ready(mtd)); ++ if (timeout <= 0) ++ printk("not use irq, prog timeout!\n"); ++#endif ++} ++ ++static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) ++{ ++ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x10); ++} ++ ++static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) ++{ ++ int page; ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x11); ++ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); ++ nand_write_page_hwecc_bch0(mtd, chip, buf + pagesize, 0x10); ++} ++ ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++static void nand_write_page_hwecc_bch_cpu(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int oob_per_eccsize = chip->ecc.layout->eccpos[0] / eccsteps; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int ecctotal = chip->ecc.total / chip->planenum; ++ uint8_t *p = (uint8_t *)buf; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ static struct buf_be_corrected buf_calc0; ++ struct buf_be_corrected *buf_calc = &buf_calc0; ++ ++ for (i = 0; i < eccsteps; i++, p += eccsize) { ++ buf_calc->data = (u8 *)buf + eccsize * i; ++ buf_calc->oob = chip->oob_poi + oob_per_eccsize * i; ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ chip->ecc.calculate(mtd, (u8 *)buf_calc, &ecc_calc[eccbytes*i]); ++ chip->write_buf(mtd, p, eccsize); ++ } ++ ++ for (i = 0; i < ecctotal; i++) ++ chip->oob_poi[eccpos[i]] = ecc_calc[i]; ++ ++ chip->write_buf(mtd, chip->oob_poi, oobsize); ++} ++ ++/* nand write using two-plane mode with cpu mode */ ++static void nand_write_page_hwecc_bch_planes_cpu(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf) ++{ ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ int page; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ nand_write_page_hwecc_bch_cpu(mtd, chip, buf); ++ ++ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ ++ ndelay(100); ++ while(!chip->dev_ready(mtd)); ++ ++ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); /* send cmd 0x81 */ ++ nand_write_page_hwecc_bch_cpu(mtd, chip, buf + pagesize); ++} ++ ++/** ++ * nand_read_page_hwecc_bch - [REPLACABLE] hardware ecc based page read function ++ * @mtd: mtd info structure ++ * @chip: nand chip info structure ++ * @buf: buffer to store read data ++ * ++ * Not for syndrome calculating ecc controllers which need a special oob layout ++ */ ++#if defined(CONFIG_MTD_NAND_DMA) ++static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, u32 page) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int eccbytes = chip->ecc.bytes; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ u8 *databuf, *oobbuf; ++ jz_dma_desc_8word *desc; ++ int err; ++ u32 addrport, cmdport; ++ static struct buf_be_corrected buf_correct0; ++ ++ addrport = (u32)(chip->IO_ADDR_R) | addr_offset; ++ cmdport = (u32)(chip->IO_ADDR_R) | cmd_offset; ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ databuf = read_buf; ++ oobbuf = read_buf + pagesize; ++ ++ dma_cache_inv((u32)read_buf, pagesize + oobsize); // databuf should be invalidated. ++ memset(errs, 0, eccsteps * ERRS_SIZE * 4); ++ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); ++#else ++ ++ databuf = buf; ++ oobbuf = chip->oob_poi; ++ ++ /* descriptor for nand reading data block */ ++ desc = dma_desc_nand_read; ++ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ ++ desc->dtadr = CPHYSADDR((u32)databuf); /* DMA target address */ ++ ++ dprintk("desc_nand_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptor for nand reading oob block */ ++ desc++; ++ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ ++ dprintk("desc_oob_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptors for data to be written to bch */ ++ desc = dma_desc_dec; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ ++ dprintk("dma_desc_dec:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for oob to be written to bch */ ++ desc = dma_desc_dec1; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ ++ dprintk("dma_desc_dec1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for parities to be written to bch */ ++ desc = dma_desc_dec2; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ ++ dprintk("dma_desc_dec2:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); ++ ++ memset(errs, 0, eccsteps * ERRS_SIZE * 4); ++ dma_cache_inv((u32)databuf, pagesize); // databuf should be invalidated. ++ dma_cache_inv((u32)oobbuf, oobsize); // oobbuf should be invalidated too ++ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); ++#endif ++ REG_DMAC_DCCSR(bch_dma_chan) = 0; ++ REG_DMAC_DCCSR(nand_dma_chan) = 0; ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_read); ++ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_dec); ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_NAND; ++ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_DEC; ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; ++ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; ++ ++ /* Enable BCH decoding */ ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ ++ dma_ack = 0; ++ nand_status = NAND_READ; ++ /* DMA doorbell set -- start nand DMA now ... */ ++ __dmac_channel_set_doorbell(nand_dma_chan); ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(nand_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; ++ ++#define __nand_cmd(n) (REG8(cmdport) = (n)) ++#define __nand_addr(n) (REG8(addrport) = (n)) ++ ++ __nand_cmd(NAND_CMD_READ0); ++ ++ __nand_addr(0); ++ if (pagesize != 512) ++ __nand_addr(0); ++ ++ __nand_addr(page & 0xff); ++ __nand_addr((page >> 8) & 0xff); ++ ++ /* One more address cycle for the devices whose number of page address bits > 16 */ ++ if (((chip->chipsize >> chip->page_shift) >> 16) - 1 > 0) ++ __nand_addr((page >> 16) & 0xff); ++ ++ if (pagesize != 512) ++ __nand_cmd(NAND_CMD_READSTART); ++ ++#if USE_IRQ ++ do { ++ err = wait_event_interruptible_timeout(nand_read_wait_queue, dma_ack, 3 * HZ); ++ }while(err == -ERESTARTSYS); ++ nand_status = NAND_NONE; ++ ++ if (!err) { ++ printk("*** NAND READ, Warning, wait event 3s timeout!\n"); ++ dump_jz_dma_channel(0); ++ dump_jz_dma_channel(nand_dma_chan); ++ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); ++ printk("databuf[0]=%x\n", databuf[0]); ++ } ++ dprintk("timeout remain = %d\n", err); ++#else ++ int timeout; ++ timeout = 100000; ++ while ((!__dmac_channel_transmit_end_detected(bch_dma_chan)) && (timeout--)); ++ if (timeout <= 0) { ++ printk("not use irq, NAND READ timeout!\n"); ++ } ++#endif ++ ++ for (i = 0; i < eccsteps; i++) { ++ int stat; ++ struct buf_be_corrected *buf_correct = &buf_correct0; ++ ++ buf_correct->data = databuf + eccsize * i; ++ buf_correct->oob = oobbuf + oob_per_eccsize * i; ++ ++ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, (u8 *)&errs[i * ERRS_SIZE], NULL); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ memcpy(buf, read_buf, pagesize); ++ memcpy(chip->oob_poi, read_buf + pagesize, oobsize); ++#endif ++ return 0; ++} ++ ++static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ u32 page = global_page; ++ ++ nand_read_page_hwecc_bch0(mtd, chip, buf, page); ++ return 0; ++} ++ ++static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ u32 page; ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* read 1st page */ ++ nand_read_page_hwecc_bch0(mtd, chip, buf, page); ++ ++ /* read 2nd page */ ++ nand_read_page_hwecc_bch0(mtd, chip, buf + pagesize, page + ppb); ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++static int nand_read_page_hwecc_bch_cpu(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *ecc_code = chip->buffers->ecccode; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int ecctotal = chip->ecc.total / chip->planenum; ++ static struct buf_be_corrected buf_correct0; ++ ++ chip->read_buf(mtd, buf, pagesize); ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ ++ for (i = 0; i < ecctotal; i++) { ++ ecc_code[i] = chip->oob_poi[eccpos[i]]; ++ } ++ ++ for (i = 0; i < eccsteps; i++) { ++ int stat; ++ struct buf_be_corrected *buf_correct = &buf_correct0; ++ ++ buf_correct->data = buf + eccsize * i; ++ buf_correct->oob = chip->oob_poi + oob_per_eccsize * i; ++ ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, &ecc_code[eccbytes*i], &ecc_calc[eccbytes*i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ ++ return 0; ++} ++ ++static int nand_read_page_hwecc_bch_planes_cpu(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ uint32_t page; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page */ ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); ++ nand_read_page_hwecc_bch_cpu(mtd, chip, buf); ++ ++ /* Read 2nd page */ ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page + ppb); ++ nand_read_page_hwecc_bch_cpu(mtd, chip, buf+pagesize); ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_HW_BCH_ECC */ ++ ++/* read oob using two-plane mode */ ++static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page, int sndcmd) ++{ ++ int page; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page OOB */ ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ } ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ /* Read second page OOB */ ++ page += ppb; ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ sndcmd = 0; ++ } ++ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); ++ return 0; ++} ++ ++/* write oob using two-plane mode */ ++static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page) ++{ ++ int status = 0, page; ++ const uint8_t *buf = chip->oob_poi; ++ int pagesize = mtd->writesize >> 1; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send first command to program the OOB data */ ++ chip->cmdfunc(mtd, 0x11, -1, -1); ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ page += ppb; ++ buf += oobsize; ++ chip->cmdfunc(mtd, 0x81, pagesize, page); ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send command to program the OOB data */ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ /* Wait long R/B */ ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ return status & NAND_STATUS_FAIL ? -EIO : 0; ++} ++ ++/* nand erase using two-plane mode */ ++static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) ++{ ++ struct nand_chip *chip = mtd->priv; ++ int page, ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x60, -1, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ page += ppb; ++ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ ++ ++ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ ++ /* Do not need wait R/B or check status */ ++} ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ ++#if USE_IRQ ++static irqreturn_t nand_dma_irq(int irq, void *dev_id) ++{ ++ u8 dma_chan; ++ volatile int wakeup = 0; ++ ++ dma_chan = irq - IRQ_DMA_0; ++ ++ dprintk("jz4750_dma_irq %d, channel %d\n", irq, dma_chan); ++ ++ if (__dmac_channel_transmit_halt_detected(dma_chan)) { ++ __dmac_channel_clear_transmit_halt(dma_chan); ++ wakeup = 1; ++ printk("DMA HALT\n"); ++ } ++ ++ if (__dmac_channel_address_error_detected(dma_chan)) { ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_address_error(dma_chan); ++ ++ REG_DMAC_DSAR(dma_chan) = 0; /* reset source address register */ ++ REG_DMAC_DTAR(dma_chan) = 0; /* reset destination address register */ ++ ++ /* clear address error in DMACR */ ++ REG_DMAC_DMACR((dma_chan / HALF_DMA_NUM)) &= ~(1 << 2); ++ wakeup = 1; ++ printk("DMA address error!\n"); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { ++ __dmac_channel_clear_descriptor_invalid(dma_chan); ++ wakeup = 1; ++ printk("DMA DESC INVALID\n"); ++ } ++#if 1 ++ ++ while (!__dmac_channel_transmit_end_detected(dma_chan)); ++ ++ if (__dmac_channel_count_terminated_detected(dma_chan)) { ++ dprintk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(dma_chan); ++ wakeup = 0; ++ } ++#endif ++ ++ if (__dmac_channel_transmit_end_detected(dma_chan)) { ++ dprintk("DMA TT\n"); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_end(dma_chan); ++ wakeup = 1; ++ } ++ ++ if (wakeup) { ++ dprintk("ack %d irq , wake up dma_chan %d nand_status %d\n", dma_ack, dma_chan, nand_status); ++ /* wakeup wait event */ ++ if ((dma_chan == nand_dma_chan) && (nand_status == NAND_PROG)) { ++ dprintk("nand prog dma irq, wake up----\n"); ++ dma_ack1 = 1; ++ wake_up_interruptible(&nand_prog_wait_queue); ++ } ++ ++ if ((dma_chan == bch_dma_chan) && (nand_status == NAND_READ)) { ++ dprintk("nand read irq, wake up----\n"); ++ dma_ack = 1; ++ wake_up_interruptible(&nand_read_wait_queue); ++ } ++ wakeup = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++#endif /* USE_IRQ */ ++ ++static int jz4750_nand_dma_init(struct mtd_info *mtd) ++{ ++ struct nand_chip *chip = mtd->priv; ++ int eccsize = chip->ecc.size; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int eccbytes = chip->ecc.bytes; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int i, err; ++ jz_dma_desc_8word *desc, *dma_desc_bch_ddr, *dma_desc_nand_ddr, *dma_desc_nand_cmd_pgprog; ++ u32 *pval_nand_dcs, *pval_bch_ddr, *pval_bch_dcs, *dummy; ++ u32 next; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ u8 *oobbuf; ++#endif ++ ++#if USE_IRQ ++ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", nand_dma_irq, IRQF_DISABLED, NULL)) < 0) { ++ printk("can't reqeust DMA nand channel.\n"); ++ return 0; ++ } ++ dprintk("nand dma channel:%d----\n", nand_dma_chan); ++ ++ if ((err = request_irq(IRQ_DMA_0 + bch_dma_chan, nand_dma_irq, IRQF_DISABLED, "bch_dma", NULL))) { ++ printk("bch_dma irq request err\n"); ++ return 0; ++ } ++#else ++ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", NULL, IRQF_DISABLED, NULL)) < 0) { ++ printk("can't reqeust DMA nand channel.\n"); ++ return 0; ++ } ++ dprintk("nand dma channel:%d----\n", nand_dma_chan); ++#endif ++ ++ __dmac_channel_enable_clk(nand_dma_chan); ++ __dmac_channel_enable_clk(bch_dma_chan); ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ if (pagesize < 4096) { ++ read_buf = prog_buf = (u8 *) __get_free_page(GFP_KERNEL); ++ } else { ++ read_buf = prog_buf = (u8 *) __get_free_pages(GFP_KERNEL, 1); ++ } ++ if (!read_buf) ++ return -ENOMEM; ++#endif ++ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value ++ * of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */ ++ errs = (u32 *)kmalloc(4 * (2 + 2 + 5 * eccsteps), GFP_KERNEL); ++ if (!errs) ++ return -ENOMEM; ++ ++ pval_nand_ddr = errs + 5 * eccsteps; ++ pval_nand_dcs = pval_nand_ddr + 1; ++ pval_bch_ddr = pval_nand_dcs + 1; ++ pval_bch_dcs = pval_bch_ddr + 1; ++ /* space for nand prog waiting target, the content is useless */ ++ dummy = pval_bch_dcs + 1; ++ /* space to store CMD_PGPROG(0x10) or 0x11 */ ++ pval_nand_cmd_pgprog = (u8 *)(dummy + 1); ++ ++ /* desc can't across 4KB boundary, as desc base address is fixed */ ++ /* space of descriptors for nand reading data and oob blocks */ ++ dma_desc_nand_read = (jz_dma_desc_8word *) __get_free_page(GFP_KERNEL); ++ if (!dma_desc_nand_read) ++ return -ENOMEM; ++ ++ /* space of descriptors for bch decoding */ ++ dma_desc_dec = dma_desc_nand_read + 2; ++ dma_desc_dec1 = dma_desc_dec + eccsteps; ++ dma_desc_dec2 = dma_desc_dec + eccsteps * 2; ++ ++ /* space of descriptors for notifying bch channel */ ++ dma_desc_bch_ddr = dma_desc_dec2 + eccsteps; ++ ++ /* space of descriptors for bch encoding */ ++ dma_desc_enc = dma_desc_bch_ddr + 2; ++ dma_desc_enc1 = dma_desc_enc + eccsteps; ++ ++ /* space of descriptors for nand programing data and oob blocks */ ++ dma_desc_nand_prog = dma_desc_enc1 + eccsteps; ++ ++ /* space of descriptors for nand prog waiting, including pgprog and sync */ ++ dma_desc_nand_cmd_pgprog = dma_desc_nand_prog + 2; ++ ++ /* space of descriptors for notifying nand channel, including ddr and dcsr */ ++ dma_desc_nand_ddr = dma_desc_nand_cmd_pgprog + 2; ++ ++/************************************* ++ * Setup of nand programing descriptors ++ *************************************/ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ oobbuf = prog_buf + pagesize; ++#endif ++ /* set descriptor for encoding data blocks */ ++ desc = dma_desc_enc; ++ for (i = 0; i < eccsteps; i++) { ++ next = (CPHYSADDR((u32)dma_desc_enc1) + i * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | ++ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)prog_buf) + i * eccsize; /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ desc++; ++ } ++ ++ /* set descriptor for encoding oob blocks */ ++ desc = dma_desc_enc1; ++ for (i = 0; i < eccsteps; i++) { ++ next = (CPHYSADDR((u32)dma_desc_enc) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | ++ DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; /* size: 7 bytes -> 2 words */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ desc++; ++ } ++ ++ next = (CPHYSADDR((u32)dma_desc_nand_ddr)) >> 4; ++ desc--; ++ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; ++ ++ /* set the descriptor to set door bell of nand_dma_chan for programing nand */ ++ desc = dma_desc_nand_ddr; ++ *pval_nand_ddr = 1 << (nand_dma_chan - nand_dma_chan / HALF_DMA_NUM * HALF_DMA_NUM); ++ next = (CPHYSADDR((u32)dma_desc_nand_ddr) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(nand_dma_chan / HALF_DMA_NUM)); /* nand_dma_chan's descriptor addres register */ ++ desc->ddadr = (next << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("*pval_nand_ddr=0x%x\n", *pval_nand_ddr); ++ ++ /* set the descriptor to write dccsr of nand_dma_chan for programing nand, dccsr should be set at last */ ++ desc++; ++ *pval_nand_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* set value for writing ddr to enable channel nand_dma_chan */ ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_dcs); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DCCSR(nand_dma_chan)); /* address of dma door bell set register */ ++ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("*pval_nand_dcs=0x%x\n", *pval_nand_dcs); ++ ++ /* set descriptor for nand programing data block */ ++ desc = dma_desc_nand_prog; ++ next = (CPHYSADDR((u32)dma_desc_nand_prog) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)prog_buf); /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address */ ++ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for nand programing oob block */ ++ desc++; ++ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address: dataport */ ++ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for __nand_cmd(CMD_PGPROG) */ ++ desc = dma_desc_nand_cmd_pgprog; ++ *pval_nand_cmd_pgprog = NAND_CMD_PAGEPROG; ++ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ ++ desc->ddadr = (next << 24) + 1; /* size: 1 byte */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for __nand_sync() */ ++ desc++; ++#if USE_IRQ ++ desc->dcmd = ++ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE; ++#else ++ desc->dcmd = ++ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; ++#endif ++ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)dummy); /* DMA target address, the content is useless */ ++ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_NAND; ++ dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* eccsteps*2 + 2 + 2 + 2: ++ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr) ++ + dma_desc_nand_cmd_pgprog(sync) */ ++ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_dma_desc_8word))); ++ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ ++ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ ++ ++/************************************* ++ * Setup of nand reading descriptors ++ *************************************/ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ oobbuf = read_buf + pagesize; ++#endif ++ /* set descriptor for nand reading data block */ ++ desc = dma_desc_nand_read; ++ next = (CPHYSADDR((u32)dma_desc_nand_read) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dtadr = CPHYSADDR((u32)read_buf); /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_NAND; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for nand reading oob block */ ++ desc++; ++ next = (CPHYSADDR((u32)dma_desc_bch_ddr)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set the descriptor to set door bell for bch */ ++ desc = dma_desc_bch_ddr; ++ *pval_bch_ddr = DMAC_DMADBSR_DBS0; // set value for writing ddr to enable channel 0 ++ next = (CPHYSADDR((u32)dma_desc_bch_ddr) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)pval_bch_ddr); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(0)); /* channel 1's descriptor addres register */ ++ desc->ddadr = (next << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ ++ /* set descriptor for writing dcsr */ ++ desc++; ++ *pval_bch_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; // set value for writing ddr to enable channel 1 ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; ++ desc->dsadr = CPHYSADDR((u32)pval_bch_dcs); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DCCSR(bch_dma_chan)); /* address of dma door bell set register */ ++ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ ++ /* descriptors for data to be written to bch */ ++ desc = dma_desc_dec; ++ for (i = 0; i < eccsteps; i++) { ++ next = CPHYSADDR((u32)dma_desc_dec1 + i * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)read_buf) + i * eccsize; /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ ++ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; ++ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for oob to be written to bch */ ++ desc = dma_desc_dec1; ++ for (i = 0; i < eccsteps; i++) { ++ next = CPHYSADDR((u32)dma_desc_dec2 + i * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ ++ desc->ddadr = (next << 24) + oob_per_eccsize; /* size: 7 bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; ++ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for parities to be written to bch */ ++ desc = dma_desc_dec2; ++ for (i = 0; i < eccsteps; i++) { ++ next = (CPHYSADDR((u32)dma_desc_dec) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | ++ DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ ++ desc->ddadr = (next << 24) + (eccbytes + 15) / DIV_DS_BCH; /* size: eccbytes bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; ++ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ desc--; ++ desc->dcmd &= ~DMAC_DCMD_LINK; ++#if USE_IRQ ++ desc->dcmd |= DMAC_DCMD_TIE; ++#endif ++ ++ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + 2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); ++ dma_cache_wback_inv((u32)pval_bch_ddr, 4 * 2); /* two words */ ++ ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++void copy_to_cpu_mode(struct mtd_info *mtd_cpu, struct mtd_info *mtd_dma, char use_planes) ++{ ++ struct nand_chip *chip_cpu = (struct nand_chip *)(&mtd_cpu[1]); ++ struct nand_chip *chip_dma = (struct nand_chip *)(&mtd_dma[1]); ++ ++ memcpy(mtd_cpu, mtd_dma, sizeof(struct mtd_info)); ++ mtd_cpu->priv = chip_cpu; ++ memcpy(chip_cpu, chip_dma, sizeof(struct nand_chip)); ++ ++ chip_cpu->ecc.correct = jzsoc_nand_bch_correct_data_cpu; ++ ++ if (use_planes) { ++ chip_cpu->ecc.read_page = nand_read_page_hwecc_bch_planes_cpu; ++ chip_cpu->ecc.write_page = nand_write_page_hwecc_bch_planes_cpu; ++ } else { ++ chip_cpu->ecc.read_page = nand_read_page_hwecc_bch_cpu; ++ chip_cpu->ecc.write_page = nand_write_page_hwecc_bch_cpu; ++ } ++ ++ mtd_cpu->flags |= MTD_NAND_CPU_MODE; ++} ++ ++/* ++ * Main initialization routine ++ */ ++int __init jznand_init(void) ++{ ++ struct nand_chip *this; ++ struct mtd_info *jz_mtd_cpu, *jz_mtd_cpu1; /* jz_mtd_cpu for 2 planes, jz_mtd_cpu1 for 1 plane */ ++ int ret, i; ++ ++ printk("JZ NAND init:"); ++#if defined(CONFIG_MTD_NAND_DMA) ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ printk(" DMA mode, using DMA buffer in NAND driver, "); ++#else ++ printk(" DMA mode, using DMA buffer in upper layer, "); ++#endif ++#else ++ printk(KERN_INFO " CPU mode, "); ++#endif ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ printk(" 8bit BCH.\n"); ++#else ++ printk(" 4bit BCH.\n"); ++#endif ++ ++ /* Allocate memory for MTD device structure and private data */ ++ jz_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); ++ if (!jz_mtd) { ++ printk("Unable to allocate JzSOC NAND MTD device structure for dma mode using multi-planes.\n"); ++ return -ENOMEM; ++ } ++ ++ jz_mtd1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); ++ if (!jz_mtd1) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure for dma mode using 1 plane.\n"); ++ kfree(jz_mtd); ++ return -ENOMEM; ++ } ++ ++ jz_mtd_cpu = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); ++ if (!jz_mtd_cpu) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure for cpu mode using multi-planes.\n"); ++ kfree(jz_mtd); ++ kfree(jz_mtd1); ++ return -ENOMEM; ++ } ++ ++ jz_mtd_cpu1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); ++ if (!jz_mtd_cpu) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure for cpu mode using 1 plane.\n"); ++ kfree(jz_mtd); ++ kfree(jz_mtd1); ++ kfree(jz_mtd_cpu); ++ return -ENOMEM; ++ } ++ ++ /* Get pointer to private data */ ++ this = (struct nand_chip *)(&jz_mtd[1]); ++ ++ /* Initialize structures */ ++ memset((char *)jz_mtd, 0, sizeof(struct mtd_info)); ++ memset((char *)this, 0, sizeof(struct nand_chip)); ++ ++ /* Link the private data with the MTD structure */ ++ jz_mtd->priv = this; ++ ++ if (is_share_mode()) { ++ addr_offset = NAND_ADDR_OFFSET0; ++ cmd_offset = NAND_CMD_OFFSET0; ++ } else { ++ addr_offset = NAND_ADDR_OFFSET1; ++ cmd_offset = NAND_CMD_OFFSET1; ++ } ++ ++ /* Set & initialize NAND Flash controller */ ++ jz_device_setup(); ++ ++ /* Set address of NAND IO lines to static bank1 by default */ ++ this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; ++ this->IO_ADDR_W = (void __iomem *)NAND_DATA_PORT1; ++ this->cmd_ctrl = jz_hwcontrol; ++ this->dev_ready = jz_device_ready; ++ ++#ifdef CONFIG_MTD_HW_BCH_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_bch_ecc; ++ this->ecc.hwctl = jzsoc_nand_enable_bch_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 512; ++#if defined(CONFIG_MTD_NAND_DMA) ++ this->ecc.correct = jzsoc_nand_bch_correct_data; ++ this->ecc.read_page = nand_read_page_hwecc_bch; ++ this->ecc.write_page = nand_write_page_hwecc_bch; ++#else ++ this->ecc.correct = jzsoc_nand_bch_correct_data_cpu; ++ this->ecc.read_page = nand_read_page_hwecc_bch_cpu; ++ this->ecc.write_page = nand_write_page_hwecc_bch_cpu; ++#endif ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ this->ecc.bytes = 13; ++#else ++ this->ecc.bytes = 7; ++#endif ++#endif ++ ++#ifdef CONFIG_MTD_SW_HM_ECC ++ this->ecc.mode = NAND_ECC_SOFT; ++#endif ++ /* 20 us command delay time */ ++ this->chip_delay = 20; ++ /* Scan to find existance of the device */ ++ ret = nand_scan_ident(jz_mtd, nand_chips); ++ ++ if (!ret) { ++ if (this->planenum == 2) { ++ /* reset nand functions */ ++ this->erase_cmd = single_erase_cmd_planes; ++#if defined(CONFIG_MTD_NAND_DMA) ++ this->ecc.read_page = nand_read_page_hwecc_bch_planes; ++ this->ecc.write_page = nand_write_page_hwecc_bch_planes; ++#else ++ this->ecc.read_page = nand_read_page_hwecc_bch_planes_cpu; ++ this->ecc.write_page = nand_write_page_hwecc_bch_planes_cpu; ++#endif ++ this->ecc.read_oob = nand_read_oob_std_planes; ++ this->ecc.write_oob = nand_write_oob_std_planes; ++ ++ printk(KERN_INFO "Nand using two-plane mode, " ++ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", ++ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); ++ } ++ } ++ ++ /* Determine whether all the partitions will use multiple planes if supported */ ++ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); ++ all_use_planes = 1; ++ for (i = 0; i < nr_partitions; i++) { ++ all_use_planes &= partition_info[i].use_planes; ++ } ++ ++ if (!ret) ++ ret = nand_scan_tail(jz_mtd); ++ ++ if (ret){ ++ kfree (jz_mtd1); ++ kfree (jz_mtd); ++ return -ENXIO; ++ } ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ jz4750_nand_dma_init(jz_mtd); ++ ++ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch; ++ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch; ++#else ++ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch_cpu; ++ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch_cpu; ++#endif ++ ++ copy_to_cpu_mode(jz_mtd_cpu, jz_mtd, 1); ++ copy_to_cpu_mode(jz_mtd_cpu1, jz_mtd1, 0); ++ ++ /* Register the partitions */ ++ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); ++ ++ if ((this->planenum == 2) && !all_use_planes) { ++ for (i = 0; i < nr_partitions; i++) { ++ if (partition_info[i].use_planes) { ++ if (partition_info[i].cpu_mode) ++ add_mtd_partitions(jz_mtd_cpu, &partition_info[i], 1); ++ else ++ add_mtd_partitions(jz_mtd, &partition_info[i], 1); ++ } else { ++ if (partition_info[i].cpu_mode) ++ add_mtd_partitions(jz_mtd_cpu1, &partition_info[i], 1); ++ else ++ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); ++ } ++ } ++ } else { ++ kfree(jz_mtd1); ++ kfree(jz_mtd_cpu1); ++ for (i = 0; i < nr_partitions; i++) { ++ if (partition_info[i].cpu_mode) ++ add_mtd_partitions(jz_mtd_cpu, &partition_info[i], 1); ++ else ++ add_mtd_partitions(jz_mtd, &partition_info[i], 1); ++ } ++ } ++ return 0; ++} ++ ++module_init(jznand_init); ++ ++/* ++ * Clean up routine ++ */ ++#ifdef MODULE ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++static int jz4750_nand_dma_exit(struct mtd_info *mtd) ++{ ++ int pagesize = mtd->writesize / chip->planenum; ++ ++#if USE_IRQ ++ free_irq(IRQ_DMA_0 + nand_dma_chan, NULL); ++ free_irq(IRQ_DMA_0 + bch_dma_chan, NULL); ++#endif ++ ++ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), ++ * and the space for the value of ddr and dcs of channel 0 and channel ++ * nand_dma_chan (4 * (2 + 2) bytes) */ ++ kfree(errs); ++ ++ /* space for dma_desc_nand_read contains dma_desc_nand_prog, ++ * dma_desc_enc and dma_desc_dec */ ++ free_page((u32)dma_desc_nand_read); ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ if (pagesize < 4096) { ++ free_page((u32)prog_buf); ++ } else { ++ free_pages((u32)prog_buf, 1); ++ } ++#endif ++ ++ return 0; ++} ++#endif ++ ++static void __exit jznand_cleanup(void) ++{ ++#if defined(CONFIG_MTD_NAND_DMA) ++ jz4750_nand_dma_exit(jz_mtd); ++#endif ++ ++ /* Unregister partitions */ ++ del_mtd_partitions(jz_mtd); ++ ++ /* Unregister the device */ ++ del_mtd_device(jz_mtd); ++ ++ /* Free the MTD device structure */ ++ if ((this->planenum == 2) && !all_use_planes) ++ kfree (jz_mtd1); ++ kfree(jz_mtd); ++} ++ ++module_exit(jznand_cleanup); ++#endif +diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c +index 8c21b89..fbbcfdb 100644 +--- a/drivers/mtd/nand/nand_base.c ++++ b/drivers/mtd/nand/nand_base.c +@@ -52,6 +52,22 @@ + #include + #endif + ++#include ++ ++ ++u8 nand_nce; /* indicates which chip select on JZSOC is used for current nand chip */ ++int global_page; /* page index of large page used for nand with multiple planes */ ++struct mtd_info *jz_mtd1 = NULL; /* for 1 plane operation */ ++ ++/* indicates whether multiple planes operation is used by all partitions ++ if multiple planes is supported by NAND */ ++char all_use_planes = 1; ++ ++/* The pointer to the address of block cache for partitions which work ++ over mtdblock-jz */ ++extern struct mtd_partition partition_info[]; /* defined in jz47xx_nand.c */ ++unsigned char **jz_mtdblock_cache = NULL; /* used by mtdblock-jz.c */ ++ + /* Define default oob placement schemes for large and small page devices */ + static struct nand_ecclayout nand_oob_8 = { + .eccbytes = 3, +@@ -68,10 +84,35 @@ static struct nand_ecclayout nand_oob_16 = { + .eccpos = {0, 1, 2, 3, 6, 7}, + .oobfree = { + {.offset = 8, +- . length = 8}} ++ .length = 8}} + }; + + static struct nand_ecclayout nand_oob_64 = { ++#if defined(CONFIG_MTD_HW_RS_ECC) ++/* Reed-Solomon ECC */ ++ .eccbytes = 36, ++ .eccpos = { ++ 28, 29, 30, 31, ++ 32, 33, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, ++ 56, 57, 58, 59, 60, 61, 62, 63}, ++ .oobfree = { ++ {.offset = 2, ++ .length = 26}} ++#elif defined(CONFIG_MTD_HW_BCH_ECC) ++/* BCH ECC */ ++ .eccbytes = 28, ++ .eccpos = { ++ 24, 25, 26, 27, 28, 29, 30, 31, ++ 32, 33, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51}, ++ .oobfree = { ++ {.offset = 2, ++ .length = 22}} ++#else ++/* HW&SW Hamming ECC */ + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, +@@ -109,6 +150,35 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, + DEFINE_LED_TRIGGER(nand_led_trigger); + + /** ++ * ffs_ll - find first bit set in a 64bit word. ++ * @word: The word to search ++ */ ++static inline int ffs_ll(u64 word) ++{ ++ u32 low = word & 0xffffffff; ++ u32 high = word >> 32; ++ int i; ++ ++ for(i = 0; i < 32; i++) { ++ if (low & 0x1) ++ break; ++ low >>= 1; ++ } ++ if (i == 32) { ++ for(i = 0; i < 32; i++) { ++ if (high & 0x1) ++ break; ++ high >>= 1; ++ } ++ i += 32; ++ } ++ if (i == 64) ++ return 0; ++ else ++ return (i+1); ++} ++ ++/** + * nand_release_device - [GENERIC] release chip + * @mtd: MTD device structure + * +@@ -183,6 +253,20 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + break; + case 0: ++ nand_nce = NAND_NCE1; ++ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); ++ break; ++ case 1: ++ nand_nce = NAND_NCE2; ++ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); ++ break; ++ case 2: ++ nand_nce = NAND_NCE3; ++ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); ++ break; ++ case 3: ++ nand_nce = NAND_NCE4; ++ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + break; + + default: +@@ -314,11 +398,17 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) + */ + static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) + { +- int page, chipnr, res = 0; ++ int page, page1 = 0, chipnr, res = 0; + struct nand_chip *chip = mtd->priv; + u16 bad; + +- page = (int)(ofs >> chip->page_shift) & chip->pagemask; ++ if (chip->planenum > 1) { ++ page = ((int)(ofs >> chip->page_shift) * chip->planenum + CONFIG_MTD_BADBLOCK_FLAG_PAGE); ++ page1 = page + mtd->erasesize / mtd->writesize; ++ page &= chip->pagemask; ++ page1 &= chip->pagemask; ++ } else ++ page = ((int)(ofs >> chip->page_shift) + CONFIG_MTD_BADBLOCK_FLAG_PAGE) & chip->pagemask; + + if (getchip) { + chipnr = (int)(ofs >> chip->chip_shift); +@@ -341,6 +431,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); + if (chip->read_byte(mtd) != 0xff) + res = 1; ++ if (chip->planenum > 1) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page1); ++ if (chip->read_byte(mtd) != 0xff) ++ res = 1; ++ } + } + + if (getchip) +@@ -377,6 +472,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) + */ + nand_get_device(chip, mtd, FL_WRITING); + ofs += mtd->oobsize; ++ ofs += (CONFIG_MTD_BADBLOCK_FLAG_PAGE << chip->page_shift); + chip->ops.len = chip->ops.ooblen = 2; + chip->ops.datbuf = NULL; + chip->ops.oobbuf = buf; +@@ -568,7 +664,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { +- column += mtd->writesize; ++ if (chip->planenum > 1) ++ column += (mtd->writesize / chip->planenum); ++ else ++ column += mtd->writesize; + command = NAND_CMD_READ0; + } + +@@ -614,6 +713,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, + case NAND_CMD_RNDIN: + case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: ++ case 0x81: /* for two-plane page program */ ++ case 0x11: /* for two-plane page program */ + return; + + /* +@@ -935,6 +1036,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 + return 0; + } + ++#ifndef CONFIG_MTD_HW_RS_ECC /* HW&SW Hamming ECC */ + /** + * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function + * @mtd: mtd info structure +@@ -979,6 +1081,63 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + return 0; + } + ++#else /* CONFIG_MTD_HW_RS_ECC */ ++ ++/** ++ * nand_read_page_hwecc_rs - [REPLACABLE] hardware rs ecc based page read function ++ * @mtd: mtd info structure ++ * @chip: nand chip info structure ++ * @buf: buffer to store read data ++ * ++ * Not for syndrome calculating ecc controllers which need a special oob layout ++ */ ++static int nand_read_page_hwecc_rs(struct mtd_info *mtd, struct nand_chip *chip, ++ uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps; ++ uint8_t *p = buf; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *ecc_code = chip->buffers->ecccode; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ uint32_t page; ++ uint8_t flag = 0; ++ ++ page = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0]; ++ ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); ++ for (i = 0; i < chip->ecc.total; i++) { ++ ecc_code[i] = chip->oob_poi[eccpos[i]]; ++ if (ecc_code[i] != 0xff) flag = 1; ++ } ++ ++ eccsteps = chip->ecc.steps; ++ p = buf; ++ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); ++ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ int stat; ++ if (flag) { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ else { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ } ++ } ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_HW_RS_ECC */ ++ + /** + * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read + * @mtd: mtd info structure +@@ -1124,10 +1283,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, + if (realpage != chip->pagebuf || oob) { + bufpoi = aligned ? buf : chip->buffers->databuf; + ++ global_page = page; ++#if defined(CONFIG_MTD_HW_RS_ECC) ++ bufpoi[0] = (uint8_t)page; ++ bufpoi[1] = (uint8_t)(page >> 8); ++ bufpoi[2] = (uint8_t)(page >> 16); ++ bufpoi[3] = (uint8_t)(page >> 24); ++#elif defined(CONFIG_SOC_JZ4730) + if (likely(sndcmd)) { + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + sndcmd = 0; + } ++#else /* for jz4750 and later chip */ ++ if (mtd->flags & MTD_NAND_CPU_MODE) { ++ if (likely(sndcmd)) { ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); ++ sndcmd = 0; ++ } ++ } ++#endif + + /* Now read the page into the buffer */ + if (unlikely(ops->mode == MTD_OOB_RAW)) +@@ -1699,12 +1873,17 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, + { + int status; + +- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); +- +- if (unlikely(raw)) +- chip->ecc.write_page_raw(mtd, chip, buf); +- else ++ global_page = page; ++ if (chip->planenum > 1) + chip->ecc.write_page(mtd, chip, buf); ++ else { ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ++ ++ if (unlikely(raw)) ++ chip->ecc.write_page_raw(mtd, chip, buf); ++ else ++ chip->ecc.write_page(mtd, chip, buf); ++ } + + /* + * Cached progamming disabled for now, Not sure if its worth the +@@ -1713,9 +1892,19 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, + cached = 0; + + if (!cached || !(chip->options & NAND_CACHEPRG)) { +- +- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++/* ++* __nand_cmd(CMD_PAGEPROG) and __nand_sync() have been done by DMA for jz4750 and ++* later chip, status should still be read by "status = chip->waitfunc(mtd, chip)" ++*/ ++#if defined(CONFIG_SOC_JZ4730) || defined(CONFIG_SOC_JZ4740) ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++#else ++ if (mtd->flags & MTD_NAND_CPU_MODE) { ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ } ++#endif + status = chip->waitfunc(mtd, chip); ++ + /* + * See if operation failed and additional status checks are + * available +@@ -2485,7 +2674,21 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, + extid >>= 2; + /* Get buswidth information */ + busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; ++ /* The 5th id byte */ ++#if defined(CONFIG_MTD_NAND_MULTI_PLANE) ++ extid = chip->read_byte(mtd); ++ chip->realplanenum = 1 << ((extid & 0x0c) >> 2); ++#else ++ chip->realplanenum = 1; ++#endif + ++ if (chip->realplanenum > 1) { /* use muti planes mode */ ++ chip->planenum = 2; ++ mtd->writesize *= 2; /* two pages as one page */ ++ mtd->oobsize *= 2; ++ mtd->erasesize *= 2; /* two blocks as one block */ ++ } else ++ chip->planenum = 1; + } else { + /* + * Old devices have chip data hardcoded in the device id table +@@ -2558,8 +2761,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, + chip->cmdfunc = nand_command_lp; + + printk(KERN_INFO "NAND device: Manufacturer ID:" +- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, +- nand_manuf_ids[maf_idx].name, type->name); ++ " 0x%02x, Chip ID: 0x%02x (%s %s) planenum:%d\n", *maf_id, dev_id, ++ nand_manuf_ids[maf_idx].name, type->name, chip->realplanenum); + + return type; + } +@@ -2627,7 +2830,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) + */ + int nand_scan_tail(struct mtd_info *mtd) + { +- int i; ++ int i, res; + struct nand_chip *chip = mtd->priv; + + if (!(chip->options & NAND_OWN_BUFFERS)) +@@ -2655,6 +2858,16 @@ int nand_scan_tail(struct mtd_info *mtd) + case 128: + chip->ecc.layout = &nand_oob_128; + break; ++ case 128: ++ if (chip->planenum > 1) ++ chip->ecc.layout = &nand_oob_64; ++ else ++ chip->ecc.layout = &nand_oob_128; ++ break; ++ case 256: ++ if (chip->planenum > 1) ++ chip->ecc.layout = &nand_oob_128; ++ break; + default: + printk(KERN_WARNING "No oob scheme defined for " + "oobsize %d\n", mtd->oobsize); +@@ -2673,8 +2886,13 @@ int nand_scan_tail(struct mtd_info *mtd) + switch (chip->ecc.mode) { + case NAND_ECC_HW: + /* Use standard hwecc read page function ? */ +- if (!chip->ecc.read_page) ++ if (!chip->ecc.read_page) { ++#ifndef CONFIG_MTD_HW_RS_ECC + chip->ecc.read_page = nand_read_page_hwecc; ++#else ++ chip->ecc.read_page = nand_read_page_hwecc_rs; ++#endif ++ } + if (!chip->ecc.write_page) + chip->ecc.write_page = nand_write_page_hwecc; + if (!chip->ecc.read_page_raw) +@@ -2826,8 +3044,80 @@ int nand_scan_tail(struct mtd_info *mtd) + if (chip->options & NAND_SKIP_BBTSCAN) + return 0; + +- /* Build bad block table */ +- return chip->scan_bbt(mtd); ++ /* Create jz_mtd1 for one plane operation if the NAND support multiple ++ planes operation, because some partitions will only use one plane. */ ++ if ((chip->planenum == 2) && !all_use_planes) { ++ int i, len, numblocks; ++ struct nand_chip *this = (struct nand_chip *) (&jz_mtd1[1]); ++ ++ memcpy(jz_mtd1, mtd, sizeof(*mtd)); ++ jz_mtd1->priv = this; ++ memcpy(this, chip, sizeof(*chip)); ++ ++ this->planenum = 1; ++ jz_mtd1->writesize >>= 1; ++ jz_mtd1->oobsize >>= 1; ++ jz_mtd1->erasesize >>= 1; ++ this->page_shift = chip->page_shift - 1; ++ this->pagemask = (this->chipsize >> this->page_shift) - 1; ++ this->bbt_erase_shift = this->phys_erase_shift = ++ chip->phys_erase_shift - 1; ++ this->ecc.steps >>= 1; ++ this->ecc.total = this->ecc.steps * this->ecc.bytes; ++ this->subpagesize = jz_mtd1->writesize; ++ ++ this->erase_cmd = single_erase_cmd; ++#if defined(CONFIG_MTD_HW_RS_ECC) ++ this->ecc.read_page = nand_read_page_hwecc_rs; ++ this->ecc.write_page = nand_write_page_hwecc; ++#endif ++ this->ecc.read_oob = nand_read_oob_std; ++ this->ecc.write_oob = nand_write_oob_std; ++ this->write_buf = nand_write_buf; ++ this->read_buf = nand_read_buf; ++ ++ /* Firstly, build bad block table as one plane */ ++ res = this->scan_bbt(jz_mtd1); ++ ++ /* Secondly, build bad block table as 2 plane based on bbt of jz_mtd1 */ ++ numblocks = chip->chipsize >> (chip->bbt_erase_shift - 1); /* = (real numblocks * 2) */ ++ len = mtd->size >> (chip->bbt_erase_shift + 2); ++ chip->bbt = kzalloc(len, GFP_KERNEL); ++ ++#define isbad_2plane(block) (((this->bbt[(block) >> 3] >> ((block) & 0x06)) \ ++ | (this->bbt[((block)+2) >> 3] >> (((block)+2) & 0x06))) & 0x03) ++ ++ for (i = 0; i < numblocks; i += 2) { ++ if (isbad_2plane(2*i)) ++ chip->bbt[i >> 3] |= 0x03 << (i & 0x6); ++ } ++ } else { ++ res = chip->scan_bbt(mtd); ++ } ++ ++#if defined(CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY) && !defined(CONFIG_SOC_JZ4730) ++ /* Allocate a block cache for every partitions which works over mtdblock-jz */ ++ { ++ extern int nr_partitions; ++ ++ jz_mtdblock_cache = kmalloc(nr_partitions * sizeof(unsigned char *), GFP_KERNEL); ++ ++ for (i = 0; i < nr_partitions; i++) { ++ if (!(partition_info[i].mtdblock_jz_invalid) && !(partition_info[i].cpu_mode)) { ++ if (partition_info[i].use_planes) { ++ jz_mtdblock_cache[i] = kmalloc(mtd->erasesize, GFP_KERNEL); ++ printk("Allocate 0x%x bytes for jz_mtdblock%d at address:0x%p.\n", mtd->erasesize, i, jz_mtdblock_cache[i]); ++ } else { ++ jz_mtdblock_cache[i] = kmalloc(jz_mtd1->erasesize, GFP_KERNEL); ++ printk("Allocate 0x%x bytes for jz_mtdblock%d at address:0x%p.\n", jz_mtd1->erasesize, i, jz_mtdblock_cache[i]); ++ } ++ if (!jz_mtdblock_cache[i]) ++ printk("Cannot allocate memory for jz_mtdblock%d!\n", i); ++ } ++ } ++ } ++#endif ++ return res; + } + + /* is_module_text_address() isn't exported, and it's mostly a pointless +diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c +index 55c23e5..34c5a29 100644 +--- a/drivers/mtd/nand/nand_bbt.c ++++ b/drivers/mtd/nand/nand_bbt.c +@@ -401,7 +401,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, + * below as it makes shifting and masking less painful */ + numblocks = mtd->size >> (this->bbt_erase_shift - 1); + startblock = 0; +- from = 0; ++ from = (CONFIG_MTD_BADBLOCK_FLAG_PAGE << this->page_shift); //from = 0; + } else { + if (chip >= this->numchips) { + printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", +diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c +index 69ee2c9..8665859 100644 +--- a/drivers/mtd/nand/nand_ids.c ++++ b/drivers/mtd/nand/nand_ids.c +@@ -109,6 +109,9 @@ struct nand_flash_dev nand_flash_ids[] = { + {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16}, + {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, + ++ /* 32 Gigabit */ ++ {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, ++ + /* + * Renesas AND 1 Gigabit. Those chips do not support extended id and + * have a strange page/block layout ! The chosen minimum erasesize is +diff --git a/drivers/mtd/udc_cache.c b/drivers/mtd/udc_cache.c +new file mode 100644 +index 0000000..35b4be0 +--- /dev/null ++++ b/drivers/mtd/udc_cache.c +@@ -0,0 +1,531 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CACHE_MAX_NUM 256 ++#define SECTOR_SIZE 512 ++ ++//#define UDC_CACHE_DEBUG ++ ++#ifdef UDC_CACHE_DEBUG ++#define dprintk(a...) printk(a) ++#else ++#define dprintk(a...) while(0){} ++#endif ++ ++typedef struct { ++ unsigned short CacheState; ++ unsigned short UseCount; ++ unsigned short CacheChange; ++ unsigned short CacheReserve; ++ unsigned int BlockId; ++ unsigned char *aBlockData; ++} SSFDC__LB_CACHE; ++ ++#define FREE_CACHE 0 ++#define PREWRITE_CACHE 2 ++#define OFTEN_USE_CACHE 3 ++#define SECTOR_SHIFT 9 ++ ++#define CACHE_TO_UNCATCH(x) ((unsigned int)x | 0xa0000000) ++static unsigned int __aBlockData[SECTOR_SIZE * CACHE_MAX_NUM / 4] __attribute__ ((aligned (32))); ++static SSFDC__LB_CACHE ssfdc_cache[CACHE_MAX_NUM]; ++static unsigned short Cur_CacheCount = 0; ++int FlushDataState = 0; ++static struct mtdblk_dev *g_udc_mtdblk; ++static struct mtd_info *g_udc_mtd; ++ ++extern int udc_mtdblock_readsect(struct mtdblk_dev *, unsigned long, char *, int); ++extern int udc_mtdblock_writesect(struct mtdblk_dev *, unsigned long, char *); ++extern struct mtdblk_dev *udc_get_mtdblk(void); ++extern struct mtd_info *udc_get_mtd(void); ++extern void udc_flush_cache(struct mtdblk_dev *mtdblk); ++ ++#define _NAND_LB_Write(pCache) udc_mtdblock_writesect(g_udc_mtdblk, pCache->BlockId,pCache->aBlockData) ++#define _NAND_LB_Read(Sector,pBuffer) udc_mtdblock_readsect(g_udc_mtdblk, Sector, pBuffer, SECTOR_SIZE); ++ ++#define DMA_ENABLE 0 ++ ++#if DMA_ENABLE ++#define DMA_CHANNEL 5 ++#define PHYSADDR(x) virt_to_phys((void *)x) ++#else ++#define lb_memcpy memcpy ++#endif ++ ++#if DMA_ENABLE ++static void lb_memcpy(void *target,void* source,unsigned int len) ++{ ++ int ch = DMA_CHANNEL; ++ if(((unsigned int)source < 0xa0000000) && len) ++ dma_cache_wback_inv((unsigned long)source, len); ++ if(((unsigned int)target < 0xa0000000) && len) ++ dma_cache_wback_inv((unsigned long)target, len); ++ ++ REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source); ++ REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); ++ REG_DMAC_DTCR(ch) = len / 32; ++ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; ++ REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32|DMAC_DCMD_DS_32BYTE; ++ REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; ++ while ( REG_DMAC_DTCR(ch) ); ++} ++#endif ++ ++static void _NAND_LB_InitCache(void) ++{ ++ int i; ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++#if DMA_ENABLE ++ unsigned char * ptr = (unsigned char *)CACHE_TO_UNCATCH(__aBlockData); ++#else ++ unsigned char * ptr = (unsigned char *)(__aBlockData); ++#endif ++ for(i = 0;i < CACHE_MAX_NUM;i++) ++ { ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ pCache->CacheChange = 0; ++ pCache->aBlockData = ptr; ++ ptr+=SECTOR_SIZE; ++ pCache++; ++ } ++ Cur_CacheCount = 0; ++} ++ ++static SSFDC__LB_CACHE * _NAND_LB_GetFreeCache(void) ++{ ++ int ret = 0; ++ SSFDC__LB_CACHE *pCacheInfo = &ssfdc_cache[Cur_CacheCount]; ++ while(1) ++ { ++ if(ret >= CACHE_MAX_NUM) ++ return 0; ++ if(pCacheInfo >= &ssfdc_cache[CACHE_MAX_NUM]) ++ { ++ pCacheInfo = ssfdc_cache; ++ Cur_CacheCount = 0; ++ } ++ ++ if(pCacheInfo->CacheState == FREE_CACHE) ++ { ++ return pCacheInfo; ++ } ++ pCacheInfo++; ++ Cur_CacheCount++; ++ ret++; ++ } ++ return 0; ++} ++ ++static void _NAND_LB_CloseCACHES(unsigned int sectorstart,unsigned int sectorend) ++{ ++ unsigned int i; ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++ for( i = 0;i < CACHE_MAX_NUM;i++){ ++ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ ++ pCache->CacheChange = 0; ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ } ++ pCache++; ++ } ++} ++ ++static void _NAND_LB_FLUSHCACHES(unsigned int sectorstart,unsigned int sectorend) ++{ ++ unsigned int i; ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++ for( i = 0;i < CACHE_MAX_NUM;i++){ ++ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ ++ if(pCache->CacheChange) ++ _NAND_LB_Write(pCache); ++ pCache->CacheChange = 0; ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ } ++ pCache++; ++ ++ } ++} ++ ++inline static int Get_NAND_CacheFreeCount(void) ++{ ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; ++ unsigned int count = 0; ++ while(pCache < pEndCache) ++ { ++ if(pCache->CacheState == FREE_CACHE) ++ count++; ++ pCache++; ++ } ++ return count; ++ ++} ++ ++static unsigned int _NAND_LB_PreWiteToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) ++{ ++ SSFDC__LB_CACHE *pWriteCache; ++ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; ++ unsigned int sector = -1; ++ unsigned int flag; ++ while(1) ++ { ++ sector = -1; ++ flag = 0; ++ pWriteCache = ssfdc_cache; ++ while(pWriteCache < pEndCache) ++ { ++ if(pWriteCache->CacheState == update) //PREWRITE_CACHE ++ { ++ if(pWriteCache->BlockId < sector) ++ { ++ sector = pWriteCache->BlockId; ++ pCache = pWriteCache; ++ } ++ }else ++ flag++; ++ pWriteCache++; ++ } ++ ++ if(flag < CACHE_MAX_NUM) ++ { ++ if(pCache->CacheChange) ++ { ++ _NAND_LB_Write(pCache); ++ pCache->CacheChange = 0; ++ } ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ (*count)++; ++ }else ++ break; ++ } ++ return 0; ++} ++ ++static void _NAND_LB_OftenToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) ++{ ++ SSFDC__LB_CACHE *pWriteCache = pCache; ++ SSFDC__LB_CACHE *pOldCache = pCache; ++ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; ++ ++ dprintk("%s!\n",__FUNCTION__); ++ while(pCache) ++ { ++ if(pCache->CacheState == OFTEN_USE_CACHE) ++ { ++ if(pWriteCache->CacheState != OFTEN_USE_CACHE) ++ pWriteCache = pCache; ++ else if(pWriteCache->UseCount > pCache->UseCount) ++ { ++ pWriteCache = pCache; ++ } ++ } ++ pCache++; ++ if(pCache >= pEndCache) ++ break; ++ } ++ if(pWriteCache->CacheState == OFTEN_USE_CACHE) ++ { ++ (*count)++; ++ if(pWriteCache->CacheChange) ++ _NAND_LB_Write(pWriteCache); ++ pWriteCache->CacheState = FREE_CACHE; ++ ++ pWriteCache->UseCount = 0; ++ pWriteCache->CacheChange = 0; ++ if(update != -1) ++ update--; ++ if(update != 0) ++ _NAND_LB_OftenToNand(pOldCache,count,update); ++ } ++} ++ ++static int _NAND_LB_FreeCache(unsigned int update) ++{ ++ unsigned short freecount = 0,totalfree = 0; ++ ++ freecount = 0; ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); ++ ++ totalfree += freecount; ++ dprintk("free count = %d\n",freecount); ++ if(freecount == 0) ++ { ++ freecount = 0; ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); ++ totalfree += freecount; ++ update = 0; ++ } ++ if(update) ++ { ++ if(Get_NAND_CacheFreeCount() < CACHE_MAX_NUM * 1 / 4) // because fat is 4 sector ++ { ++ freecount = 0; ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); ++ totalfree += freecount; ++ } ++ } ++ ++ dprintk("Free = %d\r\n",totalfree); ++ return totalfree; ++} ++ ++static int _NAND_LB_GetFromCache(unsigned int Sector, void *pBuffer) { ++ ++ SSFDC__LB_CACHE *pCache = &ssfdc_cache[Cur_CacheCount]; ++ SSFDC__LB_CACHE *pUseCache = 0; ++ unsigned short i; ++ dprintk("sector = %x pBuffer = %x\n",Sector,pBuffer); ++ if(pCache >= &ssfdc_cache[CACHE_MAX_NUM]) ++ pCache = ssfdc_cache; ++ ++ i = 0; ++ while (1) { ++ if(pCache->CacheState != FREE_CACHE) ++ { ++ if (Sector == pCache->BlockId) { ++ dprintk("Cache is use = %d\r\n",pCache->BlockId); ++ pUseCache = pCache; ++ pCache->UseCount++; ++ if(pCache->UseCount == 0) ++ pCache->UseCount = -1; ++ pCache->CacheState = OFTEN_USE_CACHE; ++ } ++ } ++ pCache--; ++ if(pCache < ssfdc_cache) ++ pCache = &ssfdc_cache[CACHE_MAX_NUM - 1]; ++ ++ i++; ++ if (i >= CACHE_MAX_NUM) { ++ break; /* Sector not in cache */ ++ } ++ } ++ if (pUseCache) { ++ dprintk("From Cache %d\r\n",Sector); ++ lb_memcpy(pBuffer, pUseCache->aBlockData, SECTOR_SIZE); ++ return 0; ++ } ++ return -1; ++} ++ ++static void _NAND_LB_ClearCache(void) { ++ ++ unsigned short freecount = 0; ++ dprintk("Clear Cache\r\n"); ++ ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); ++} ++ ++static void _NAND_LB_CopyToCache(unsigned int Sector, void *pBuffer,unsigned short rw) ++{ ++ SSFDC__LB_CACHE *pCache = _NAND_LB_GetFreeCache(); ++ dprintk("Copy to Cache = 0x%08x 0x%08x\r\n",pCache,ssfdc_cache); ++ ++ if(!pCache) ++ { ++ _NAND_LB_FreeCache(rw); ++ ++ pCache = _NAND_LB_GetFreeCache(); ++ } ++ pCache->BlockId = Sector; ++ pCache->CacheState = PREWRITE_CACHE; ++ pCache->UseCount = 0; ++ pCache->CacheChange = rw; ++ ++ lb_memcpy(pCache->aBlockData,pBuffer,SECTOR_SIZE); ++} ++ ++ ++static int _NAND_LB_UpdateInCache(unsigned int Sector, void *pBuffer) { ++ short i,ret = 0; ++ i = Cur_CacheCount; ++ if(Cur_CacheCount > CACHE_MAX_NUM) ++ i = 0; ++ while(1) ++ { ++ if(ret >= CACHE_MAX_NUM) ++ return -1; ++ if(ssfdc_cache[i].CacheState != FREE_CACHE) ++ { ++ ++ if(ssfdc_cache[i].BlockId == Sector) ++ { ++ dprintk("UpdateInCache = %d\r\n",Sector); ++ ssfdc_cache[i].CacheState = OFTEN_USE_CACHE; ++ ssfdc_cache[i].UseCount++; ++ ssfdc_cache[i].CacheChange = 1; ++ lb_memcpy(ssfdc_cache[i].aBlockData,pBuffer,SECTOR_SIZE); ++ return 0; ++ } ++ } ++ i--; ++ if(i < 0) ++ i = CACHE_MAX_NUM - 1; ++ ret++; ++ } ++ return -1; ++} ++ ++static int NAND_LB_MultiRead(unsigned int Sector, void *pBuffer,unsigned int SectorCount) ++{ ++ int i,ret,end; ++ void *p; ++ ++ dprintk("NAND_LB_MultiRead = %d %d \n",Sector,SectorCount); ++ end = Sector + SectorCount; ++ _NAND_LB_FLUSHCACHES(Sector,end); ++ ++ p = pBuffer; ++ for (i = Sector; i < end; i ++) ++ { ++ ret = udc_mtdblock_readsect(g_udc_mtdblk, i, p, SECTOR_SIZE); ++ p += SECTOR_SIZE; ++ } ++ return ret; ++} ++ ++static int NAND_LB_Read(unsigned int Sector, void *pBuffer) ++{ ++ int x; ++#if DMA_ENABLE ++ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); ++ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); ++#else ++ unsigned char *ptr = (unsigned char *)pBuffer; ++#endif ++ dprintk("LB_Read = %d \n",Sector); ++ if(_NAND_LB_GetFromCache(Sector,ptr)) ++ { ++ x = _NAND_LB_Read(Sector,ptr); ++ _NAND_LB_CopyToCache(Sector,ptr,0); ++ } ++ return 512; ++} ++ ++static int NAND_LB_MultiWrite(unsigned int Sector, void *pBuffer,unsigned int SectorCount) ++{ ++ int i,ret; ++ unsigned char *p; ++ ++ _NAND_LB_CloseCACHES(Sector,Sector + SectorCount); ++ p = (unsigned char *)pBuffer; ++ for (i = Sector; i < Sector + SectorCount; i ++) ++ { ++ ret = udc_mtdblock_writesect(g_udc_mtdblk, i, p); ++ p += 512; ++ } ++ return ret; ++} ++ ++static int NAND_LB_Write(unsigned int Sector, void *pBuffer) ++{ ++#if DMA_ENABLE ++ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); ++ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); ++#else ++ unsigned char *ptr = (unsigned char *)pBuffer; ++#endif ++ dprintk("LB_Write = %x %x\r\n",Sector,pBuffer); ++ if(_NAND_LB_UpdateInCache(Sector,ptr)) ++ { ++ _NAND_LB_CopyToCache(Sector,ptr,1); ++ } ++ return 512; ++} ++/********************************************************************* ++* ++* Global functions ++* ++***********************************************************************/ ++ ++int NAND_LB_Init(void) ++{ ++ dprintk("UDC CACHE Init \n"); ++ _NAND_LB_InitCache(); ++ g_udc_mtdblk = udc_get_mtdblk(); ++ g_udc_mtd = udc_get_mtd(); ++ return 0; ++} ++ ++int NAND_LB_FLASHCACHE(void) ++{ ++ dprintk("Flush lb cache !\n"); ++ _NAND_LB_ClearCache(); ++// dprintk("Flush mtd cache !\n"); ++// udc_flush_cache(g_udc_mtdblk); ++ return 0; ++} ++ ++int NAND_MTD_FLASHCACHE(void) ++{ ++ dprintk("Flush mtd cache !\n"); ++ udc_flush_cache(g_udc_mtdblk); ++ return 0; ++} ++ ++int udc_read(unsigned long long offset, unsigned int len, unsigned char *buf) ++{ ++ unsigned long block,sector,i; ++ ++ block = offset >> SECTOR_SHIFT; ++ sector = len >> SECTOR_SHIFT; ++ dprintk("read dev = ia:%x, s:%d c:%d\r\n",buf,block,sector); ++ ++ if (sector <= 8) ++ { ++ for(i = 0;i < sector; i++) ++ { ++ NAND_LB_Read(block + i,(void *)(buf)); ++ buf += 512; ++ } ++ } ++ else ++ NAND_LB_MultiRead(block, buf, sector); ++ ++ return len; ++} ++ ++int udc_write(unsigned long long offset, unsigned int len, unsigned char *buf) ++{ ++ unsigned long block,sector,i; ++ ++ block = offset >> SECTOR_SHIFT; ++ sector = len >> SECTOR_SHIFT; ++ dprintk("write dev s:%d c:%d\r\n",block,sector); ++ ++ if(sector <= 8) ++ { ++ for(i = 0;i < sector; i++) ++ { ++ NAND_LB_Write(block + i,(void *)(buf)); ++ buf += 512; ++ FlushDataState = 1; ++ } ++ }else ++ NAND_LB_MultiWrite(block,(void *)(buf),sector); ++ ++ return len; ++} ++ ++EXPORT_SYMBOL_GPL(udc_write); ++EXPORT_SYMBOL_GPL(udc_read); ++EXPORT_SYMBOL_GPL(NAND_LB_Init); ++EXPORT_SYMBOL_GPL(NAND_LB_FLASHCACHE); ++EXPORT_SYMBOL_GPL(FlushDataState); ++EXPORT_SYMBOL_GPL(NAND_MTD_FLASHCACHE); +diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig +index 5f6509a..c0acd09 100644 +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -207,6 +207,24 @@ config MII + or internal device. It is safe to say Y or M here even if your + ethernet card lack MII. + ++config JZ_ETH ++ tristate "JZ4730/JZ5730 On-Chip Ethernet support" ++ depends on NET_ETHERNET && (SOC_JZ4730 || SOC_JZ5730 || JZ_FPGA) ++ help ++ Say Y for support of JZ4730/JZ5730 On-Chip Ethernet interface. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called jz_eth. ++ ++config JZCS8900 ++ tristate "JZ CS8900A Ethernet support" ++ depends on NET_ETHERNET && (SOC_JZ4740 || SOC_JZ4750) ++ help ++ Say Y for support of JZ CS8900A Ethernet interface. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called jzcs8900a. ++ + config MACB + tristate "Atmel MACB support" + depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91CAP9 +diff --git a/drivers/net/Makefile b/drivers/net/Makefile +index ead8cab..8d87dfd 100644 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -103,6 +103,8 @@ obj-$(CONFIG_MII) += mii.o + obj-$(CONFIG_MDIO) += mdio.o + obj-$(CONFIG_PHYLIB) += phy/ + ++obj-$(CONFIG_JZ_ETH) += jz_eth.o ++obj-$(CONFIG_JZCS8900) += jzcs8900a.o + obj-$(CONFIG_SUNDANCE) += sundance.o + obj-$(CONFIG_HAMACHI) += hamachi.o + obj-$(CONFIG_NET) += Space.o loopback.o +diff --git a/drivers/net/jz_eth.c b/drivers/net/jz_eth.c +new file mode 100644 +index 0000000..ade9556 +--- /dev/null ++++ b/drivers/net/jz_eth.c +@@ -0,0 +1,1290 @@ ++/* ++ * linux/drivers/net/jz_eth.c ++ * ++ * Jz4730/Jz5730 On-Chip ethernet driver. ++ * ++ * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz_eth.h" ++ ++#define P2ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0xa0000000) ++#define P1ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0x80000000) ++ ++//#define DEBUG ++#ifdef DEBUG ++# define DBPRINTK(fmt,args...) printk(KERN_DEBUG fmt,##args) ++#else ++# define DBPRINTK(fmt,args...) do {} while(0) ++#endif ++ ++#define errprintk(fmt,args...) printk(KERN_ERR fmt,##args); ++#define infoprintk(fmt,args...) printk(KERN_INFO fmt,##args); ++ ++#define DRV_NAME "jz_eth" ++#define DRV_VERSION "1.2" ++#define DRV_AUTHOR "Peter Wei " ++#define DRV_DESC "JzSOC On-chip Ethernet driver" ++ ++MODULE_AUTHOR(DRV_AUTHOR); ++MODULE_DESCRIPTION(DRV_DESC); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Local variables ++ */ ++static struct net_device *netdev; ++static char * hwaddr = NULL; ++static int debug = -1; ++static struct mii_if_info mii_info; ++ ++MODULE_PARM_DESC(debug, "i"); ++MODULE_PARM_DESC(hwaddr,"s"); ++ ++/* ++ * Local routines ++ */ ++static irqreturn_t jz_eth_interrupt(int irq, void *dev_id); ++ ++static int link_check_thread (void *data); ++ ++/* ++ * Get MAC address ++ */ ++ ++#define I2C_DEVICE 0x57 ++#define MAC_OFFSET 64 ++ ++extern void i2c_open(void); ++extern void i2c_close(void); ++extern int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++ ++static inline unsigned char str2hexnum(unsigned char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return 0; /* foo */ ++} ++ ++static inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for (i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= (str2hexnum(*str++)); ++ ea[i] = num; ++ } ++} ++ ++static int ethaddr_cmd = 0; ++static unsigned char ethaddr_hex[6]; ++ ++static int __init ethernet_addr_setup(char *str) ++{ ++ if (!str) { ++ printk("ethaddr not set in command line\n"); ++ return -1; ++ } ++ ethaddr_cmd = 1; ++ str2eaddr(ethaddr_hex, str); ++ ++ return 0; ++} ++ ++__setup("ethaddr=", ethernet_addr_setup); ++ ++static int get_mac_address(struct net_device *dev) ++{ ++ int i; ++ unsigned char flag0=0; ++ unsigned char flag1=0xff; ++ ++ dev->dev_addr[0] = 0xff; ++ if (hwaddr != NULL) { ++ /* insmod jz-ethc.o hwaddr=00:ef:a3:c1:00:10 */ ++ str2eaddr(dev->dev_addr, hwaddr); ++ } else if (ethaddr_cmd) { ++ /* linux command line: ethaddr=00:ef:a3:c1:00:10 */ ++ for (i=0; i<6; i++) ++ dev->dev_addr[i] = ethaddr_hex[i]; ++ } else { ++#if 0 ++ /* mac address in eeprom: byte 0x40-0x45 */ ++ i2c_open(); ++ i2c_read(I2C_DEVICE, dev->dev_addr, MAC_OFFSET, 6); ++ i2c_close(); ++#endif ++ } ++ ++ /* check whether valid MAC address */ ++ for (i=0; i<6; i++) { ++ flag0 |= dev->dev_addr[i]; ++ flag1 &= dev->dev_addr[i]; ++ } ++ if ((dev->dev_addr[0] & 0xC0) || (flag0 == 0) || (flag1 == 0xff)) { ++ printk("WARNING: There is not MAC address, use default ..\n"); ++ dev->dev_addr[0] = 0x00; ++ dev->dev_addr[1] = 0xef; ++ dev->dev_addr[2] = 0xa3; ++ dev->dev_addr[3] = 0xc1; ++ dev->dev_addr[4] = 0x00; ++ dev->dev_addr[5] = 0x10; ++ dev->dev_addr[5] = 0x03; ++ } ++ return 0; ++} ++ ++/*---------------------------------------------------------------------*/ ++ ++static u32 jz_eth_curr_mode(struct net_device *dev); ++ ++/* ++ * Ethernet START/STOP routines ++ */ ++#define START_ETH { \ ++ s32 val; \ ++ val = readl(DMA_OMR); \ ++ val |= OMR_ST | OMR_SR; \ ++ writel(val, DMA_OMR); \ ++} ++ ++#define STOP_ETH { \ ++ s32 val; \ ++ val = readl(DMA_OMR); \ ++ val &= ~(OMR_ST|OMR_SR); \ ++ writel(val, DMA_OMR); \ ++} ++ ++/* ++ * Link check routines ++ */ ++static void start_check(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ ++ np->thread_die = 0; ++ init_waitqueue_head(&np->thr_wait); ++ init_completion (&np->thr_exited); ++ np->thr_pid = kernel_thread (link_check_thread,(void *)dev, ++ CLONE_FS | CLONE_FILES); ++ if (np->thr_pid < 0) ++ errprintk("%s: unable to start kernel thread\n",dev->name); ++} ++ ++static int close_check(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ int ret = 0; ++ ++ if (np->thr_pid >= 0) { ++ np->thread_die = 1; ++ wmb(); ++ ret = kill_proc (np->thr_pid, SIGTERM, 1); ++ if (ret) { ++ errprintk("%s: unable to signal thread\n", dev->name); ++ return 1; ++ } ++ wait_for_completion (&np->thr_exited); ++ } ++ return 0; ++} ++ ++static int link_check_thread(void *data) ++{ ++ struct net_device *dev=(struct net_device *)data; ++ struct jz_eth_private *np = (struct jz_eth_private *)netdev->priv; ++ unsigned char current_link; ++ unsigned long timeout; ++ ++ daemonize("%s", dev->name); ++ spin_lock_irq(¤t->sighand->siglock); ++ sigemptyset(¤t->blocked); ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ strncpy (current->comm, dev->name, sizeof(current->comm) - 1); ++ current->comm[sizeof(current->comm) - 1] = '\0'; ++ ++ while (1) { ++ timeout = 3*HZ; ++ do { ++ timeout = interruptible_sleep_on_timeout (&np->thr_wait, timeout); ++ /* make swsusp happy with our thread */ ++// if (current->flags & PF_FREEZE) ++// refrigerator(PF_FREEZE); ++ } while (!signal_pending (current) && (timeout > 0)); ++ ++ if (signal_pending (current)) { ++ spin_lock_irq(¤t->sighand->siglock); ++ flush_signals(current); ++ spin_unlock_irq(¤t->sighand->siglock); ++ } ++ ++ if (np->thread_die) ++ break; ++ ++ current_link=mii_link_ok(&mii_info); ++ if (np->link_state!=current_link) { ++ if (current_link) { ++ infoprintk("%s: Ethernet Link OK!\n",dev->name); ++ jz_eth_curr_mode(dev); ++ netif_carrier_on(dev); ++ } ++ else { ++ errprintk("%s: Ethernet Link offline!\n",dev->name); ++ netif_carrier_off(dev); ++ } ++ } ++ np->link_state=current_link; ++ ++ } ++ complete_and_exit (&np->thr_exited, 0); ++} ++ ++#ifdef DEBUG ++/* ++ * Display ethernet packet header ++ * This routine is used for test function ++ */ ++static void eth_dbg_rx(struct sk_buff *skb, int len) ++{ ++ ++ int i, j; ++ ++ printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", ++ (u8)skb->data[0], ++ (u8)skb->data[1], ++ (u8)skb->data[2], ++ (u8)skb->data[3], ++ (u8)skb->data[4], ++ (u8)skb->data[5], ++ (u8)skb->data[6], ++ (u8)skb->data[7], ++ (u8)skb->data[8], ++ (u8)skb->data[9], ++ (u8)skb->data[10], ++ (u8)skb->data[11], ++ (u8)skb->data[12], ++ (u8)skb->data[13], ++ len); ++ for (j=0; len>0; j+=16, len-=16) { ++ printk(" %03x: ",j); ++ for (i=0; i<16 && idata[i+j]); ++ } ++ printk("\n"); ++ } ++ return; ++ } ++#endif ++ ++/* ++ * Reset ethernet device ++ */ ++static inline void jz_eth_reset(void) ++{ ++ u32 i; ++ i = readl(DMA_BMR); ++ writel(i | BMR_SWR, DMA_BMR); ++ for(i = 0; i < 1000; i++) { ++ if(!(readl(DMA_BMR) & BMR_SWR)) break; ++ mdelay(1); ++ } ++} ++ ++/* ++ * MII operation routines ++ */ ++static inline void mii_wait(void) ++{ ++ int i; ++ for(i = 0; i < 10000; i++) { ++ if(!(readl(MAC_MIIA) & 0x1)) ++ break; ++ mdelay(1); ++ } ++ if (i >= 10000) ++ printk("MII wait timeout : %d.\n", i); ++} ++ ++static int mdio_read(struct net_device *dev,int phy_id, int location) ++{ ++ u32 mii_cmd = (phy_id << 11) | (location << 6) | 1; ++ int retval = 0; ++ ++ writel(mii_cmd, MAC_MIIA); ++ mii_wait(); ++ retval = readl(MAC_MIID) & 0x0000ffff; ++ ++ return retval; ++ ++} ++ ++static void mdio_write(struct net_device *dev,int phy_id, int location, int data) ++{ ++ u32 mii_cmd = (phy_id << 11) | (location << 6) | 0x2 | 1; ++ ++ writel(mii_cmd, MAC_MIIA); ++ writel(data & 0x0000ffff, MAC_MIID); ++ mii_wait(); ++} ++ ++ ++/* ++ * Search MII phy ++ */ ++static int jz_search_mii_phy(struct net_device *dev) ++{ ++ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ int phy, phy_idx = 0; ++ ++ np->valid_phy = 0xff; ++ for (phy = 0; phy < 32; phy++) { ++ int mii_status = mdio_read(dev,phy, 1); ++ if (mii_status != 0xffff && mii_status != 0x0000) { ++ np->phys[phy_idx] = phy; ++ np->ecmds[phy_idx].speed=SPEED_100; ++ np->ecmds[phy_idx].duplex=DUPLEX_FULL; ++ np->ecmds[phy_idx].port=PORT_MII; ++ np->ecmds[phy_idx].transceiver=XCVR_INTERNAL; ++ np->ecmds[phy_idx].phy_address=np->phys[phy_idx]; ++ np->ecmds[phy_idx].autoneg=AUTONEG_ENABLE; ++ np->ecmds[phy_idx].advertising=(ADVERTISED_10baseT_Half | ++ ADVERTISED_10baseT_Full | ++ ADVERTISED_100baseT_Half | ++ ADVERTISED_100baseT_Full); ++ phy_idx++; ++ } ++ } ++ if (phy_idx == 1) { ++ np->valid_phy = np->phys[0]; ++ np->phy_type = 0; ++ } ++ if (phy_idx != 0) { ++ phy = np->valid_phy; ++ np->advertising = mdio_read(dev,phy, 4); ++ } ++ return phy_idx; ++} ++ ++/* ++ * CRC calc for Destination Address for gets hashtable index ++ */ ++ ++#define POLYNOMIAL 0x04c11db7UL ++static u16 jz_hashtable_index(u8 *addr) ++{ ++#if 1 ++ u32 crc = 0xffffffff, msb; ++ int i, j; ++ u32 byte; ++ for (i = 0; i < 6; i++) { ++ byte = *addr++; ++ for (j = 0; j < 8; j++) { ++ msb = crc >> 31; ++ crc <<= 1; ++ if (msb ^ (byte & 1)) crc ^= POLYNOMIAL; ++ byte >>= 1; ++ } ++ } ++ return ((int)(crc >> 26)); ++#endif ++#if 0 ++ int crc = -1; ++ int length=6; ++ int bit; ++ unsigned char current_octet; ++ while (--length >= 0) { ++ current_octet = *addr++; ++ for (bit = 0; bit < 8; bit++, current_octet >>= 1) ++ crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ++ POLYNOMIAL : 0); ++ } ++ return ((int)(crc >> 26)); ++#endif ++} ++ ++/* ++ * Multicast filter and config multicast hash table ++ */ ++#define MULTICAST_FILTER_LIMIT 64 ++ ++static void jz_set_multicast_list(struct net_device *dev) ++{ ++ int i, hash_index; ++ u32 mcr, hash_h, hash_l, hash_bit; ++ ++ mcr = readl(MAC_MCR); ++ mcr &= ~(MCR_PR | MCR_PM | MCR_HP); ++ ++ if (dev->flags & IFF_PROMISC) { ++ /* Accept any kinds of packets */ ++ mcr |= MCR_PR; ++ hash_h = 0xffffffff; ++ hash_l = 0xffffffff; ++ DBPRINTK("%s: enter promisc mode!\n",dev->name); ++ } ++ else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MULTICAST_FILTER_LIMIT)){ ++ /* Accept all multicast packets */ ++ mcr |= MCR_PM; ++ hash_h = 0xffffffff; ++ hash_l = 0xffffffff; ++ DBPRINTK("%s: enter allmulticast mode! %d \n",dev->name,dev->mc_count); ++ } ++ else if (dev->flags & IFF_MULTICAST) ++ { ++ /* Update multicast hash table */ ++ struct dev_mc_list *mclist; ++ hash_h = readl(MAC_HTH); ++ hash_l = readl(MAC_HTL); ++ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; ++ i++, mclist = mclist->next) ++ { ++ hash_index = jz_hashtable_index(mclist->dmi_addr); ++ hash_bit=0x00000001; ++ hash_bit <<= (hash_index & 0x1f); ++ if (hash_index > 0x1f) ++ hash_h |= hash_bit; ++ else ++ hash_l |= hash_bit; ++ DBPRINTK("----------------------------\n"); ++#ifdef DEBUG ++ int j; ++ for (j=0;jdmi_addrlen;j++) ++ printk("%2.2x:",mclist->dmi_addr[j]); ++ printk("\n"); ++#endif ++ DBPRINTK("dmi.addrlen => %d\n",mclist->dmi_addrlen); ++ DBPRINTK("dmi.users => %d\n",mclist->dmi_users); ++ DBPRINTK("dmi.gusers => %d\n",mclist->dmi_users); ++ } ++ writel(hash_h,MAC_HTH); ++ writel(hash_l,MAC_HTL); ++ mcr |= MCR_HP; ++ DBPRINTK("This is multicast hash table high bits [%4.4x]\n",readl(MAC_HTH)); ++ DBPRINTK("This is multicast hash table low bits [%4.4x]\n",readl(MAC_HTL)); ++ DBPRINTK("%s: enter multicast mode!\n",dev->name); ++ } ++ writel(mcr,MAC_MCR); ++} ++ ++static inline int jz_phy_reset(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ unsigned int mii_reg0; ++ unsigned int count; ++ ++ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR); ++ mii_reg0 |=MII_CR_RST; ++ mdio_write(dev,np->valid_phy,MII_BMCR,mii_reg0); //reset phy ++ for ( count = 0; count < 1000; count++) { ++ mdelay(1); ++ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR); ++ if (!(mii_reg0 & MII_CR_RST)) break; //reset completed ++ } ++ if (count>=100) ++ return 1; //phy error ++ else ++ return 0; ++} ++ ++/* ++ * Show all mii registers - this routine is used for test ++ */ ++#ifdef DEBUG ++static void mii_db_out(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ unsigned int mii_test; ++ ++ mii_test = mdio_read(dev,np->valid_phy,MII_BMCR); ++ DBPRINTK("BMCR ====> 0x%4.4x \n",mii_test); ++ ++ mii_test = mdio_read(dev,np->valid_phy,MII_BMSR); ++ DBPRINTK("BMSR ====> 0x%4.4x \n",mii_test); ++ ++ mii_test = mdio_read(dev,np->valid_phy,MII_ANAR); ++ DBPRINTK("ANAR ====> 0x%4.4x \n",mii_test); ++ ++ mii_test = mdio_read(dev,np->valid_phy,MII_ANLPAR); ++ DBPRINTK("ANLPAR ====> 0x%4.4x \n",mii_test); ++ ++ mii_test = mdio_read(dev,np->valid_phy,16); ++ DBPRINTK("REG16 ====> 0x%4.4x \n",mii_test); ++ ++ mii_test = mdio_read(dev,np->valid_phy,17); ++ DBPRINTK("REG17 ====> 0x%4.4x \n",mii_test); ++} ++#endif ++ ++/* ++ * Start Auto-Negotiation function for PHY ++ */ ++static int jz_autonet_complete(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ int count; ++ u32 mii_reg1, timeout = 3000; ++ ++ for (count = 0; count < timeout; count++) { ++ mdelay(1); ++ mii_reg1 = mdio_read(dev,np->valid_phy,MII_BMSR); ++ if (mii_reg1 & 0x0020) break; ++ } ++ //mii_db_out(dev); //for debug to display all register of MII ++ if (count >= timeout) ++ return 1; //auto negotiation error ++ else ++ return 0; ++} ++ ++/* ++ * Get current mode of eth phy ++ */ ++static u32 jz_eth_curr_mode(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ unsigned int mii_reg17; ++ u32 flag = 0; ++ ++ mii_reg17 = mdio_read(dev,np->valid_phy,MII_DSCSR); ++ np->media = mii_reg17>>12; ++ if (np->media==8) { ++ infoprintk("%s: Current Operation Mode is [100M Full Duplex]",dev->name); ++ flag = 0; ++ np->full_duplex=1; ++ } ++ if (np->media==4) { ++ infoprintk("%s: Current Operation Mode is [100M Half Duplex]",dev->name); ++ flag = 0; ++ np->full_duplex=0; ++ } ++ if (np->media==2) { ++ infoprintk("%s: Current Operation Mode is [10M Full Duplex]",dev->name); ++ flag = OMR_TTM; ++ np->full_duplex=1; ++ } ++ if (np->media==1) { ++ infoprintk("%s: Current Operation Mode is [10M Half Duplex]",dev->name); ++ flag = OMR_TTM; ++ np->full_duplex=0; ++ } ++ printk("\n"); ++ return flag; ++} ++ ++/* ++ * Ethernet device hardware init ++ * This routine initializes the ethernet device hardware and PHY ++ */ ++static int jz_init_hw(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ struct ethtool_cmd ecmd; ++ u32 mcr, omr; ++ u32 sts, flag = 0; ++ int i; ++ ++ jz_eth_reset(); ++ STOP_ETH; ++#if 0 ++ /* mii operation */ ++ if (jz_phy_reset(dev)) { ++ errprintk("PHY device do not reset!\n"); ++ return -EPERM; // return operation not permitted ++ } ++#endif ++ /* Set MAC address */ ++ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[0]), MAC_MAL); ++ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[4]), MAC_MAH); ++ printk("%s: JZ On-Chip ethernet (MAC ", dev->name); ++ for (i = 0; i < 5; i++) { ++ printk("%2.2x:", dev->dev_addr[i]); ++ } ++ printk("%2.2x, IRQ %d)\n", dev->dev_addr[i], dev->irq); ++ ++ np->mii_phy_cnt = jz_search_mii_phy(dev); ++ printk("%s: Found %d PHY on JZ MAC\n", dev->name, np->mii_phy_cnt); ++ ++ mii_info.phy_id = np->valid_phy; ++ mii_info.dev = dev; ++ mii_info.mdio_read = &mdio_read; ++ mii_info.mdio_write = &mdio_write; ++ ++ ecmd.speed = SPEED_100; ++ ecmd.duplex = DUPLEX_FULL; ++ ecmd.port = PORT_MII; ++ ecmd.transceiver = XCVR_INTERNAL; ++ ecmd.phy_address = np->valid_phy; ++ ecmd.autoneg = AUTONEG_ENABLE; ++ ++ mii_ethtool_sset(&mii_info,&ecmd); ++ if (jz_autonet_complete(dev)) ++ errprintk("%s: Ethernet Module AutoNegotiation failed\n",dev->name); ++ mii_ethtool_gset(&mii_info,&ecmd); ++ ++ infoprintk("%s: Provide Modes: ",dev->name); ++ for (i = 0; i < 5;i++) ++ if (ecmd.advertising & (1<full_duplex) ++ mcr |= MCR_FDX; ++ mcr |= MCR_BFD | MCR_TE | MCR_RE | MCR_OWD|MCR_HBD; ++ writel(mcr, MAC_MCR); ++// mcr &= (readl(MAC_MCR) & ~(MCR_PM | MCR_PR | MCR_IF | MCR_HO | MCR_HP)); ++// mcr &= 0xffdf; ++// mcr |= 0x0020; ++// writel(mcr, MAC_MCR); ++ ++ /* Set base address of TX and RX descriptors */ ++ writel(np->dma_rx_ring, DMA_RRBA); ++ writel(np->dma_tx_ring, DMA_TRBA); ++ ++ START_ETH; ++ ++ /* set interrupt mask */ ++ writel(IMR_DEFAULT | IMR_ENABLE, DMA_IMR); ++ ++ /* Reset any pending (stale) interrupts */ ++ sts = readl(DMA_STS); ++ writel(sts, DMA_STS); ++ ++ return 0; ++} ++ ++static int jz_eth_open(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ int retval, i; ++ ++ retval = request_irq(dev->irq, jz_eth_interrupt, 0, dev->name, dev); ++ if (retval) { ++ errprintk("%s: unable to get IRQ %d .\n", dev->name, dev->irq); ++ return -EAGAIN; ++ } ++ ++ for (i = 0; i < NUM_RX_DESCS; i++) { ++ np->rx_ring[i].status = cpu_to_le32(R_OWN); ++ np->rx_ring[i].desc1 = cpu_to_le32(RX_BUF_SIZE | RD_RCH); ++ np->rx_ring[i].buf1_addr = cpu_to_le32(np->dma_rx_buf + i*RX_BUF_SIZE); ++ np->rx_ring[i].next_addr = cpu_to_le32(np->dma_rx_ring + (i+1) * sizeof (jz_desc_t)); ++ } ++ np->rx_ring[NUM_RX_DESCS - 1].next_addr = cpu_to_le32(np->dma_rx_ring); ++ ++ for (i = 0; i < NUM_TX_DESCS; i++) { ++ np->tx_ring[i].status = cpu_to_le32(0); ++ np->tx_ring[i].desc1 = cpu_to_le32(TD_TCH); ++ np->tx_ring[i].buf1_addr = 0; ++ np->tx_ring[i].next_addr = cpu_to_le32(np->dma_tx_ring + (i+1) * sizeof (jz_desc_t)); ++ } ++ np->tx_ring[NUM_TX_DESCS - 1].next_addr = cpu_to_le32(np->dma_tx_ring); ++ ++ np->rx_head = 0; ++ np->tx_head = np->tx_tail = 0; ++ ++ jz_init_hw(dev); ++ ++ dev->trans_start = jiffies; ++ netif_start_queue(dev); ++ start_check(dev); ++ ++ return 0; ++} ++ ++static int jz_eth_close(struct net_device *dev) ++{ ++ netif_stop_queue(dev); ++ close_check(dev); ++ STOP_ETH; ++ free_irq(dev->irq, dev); ++ return 0; ++} ++ ++/* ++ * Get the current statistics. ++ * This may be called with the device open or closed. ++ */ ++static struct net_device_stats * jz_eth_get_stats(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ int tmp; ++ ++ tmp = readl(DMA_MFC); // After read clear to zero ++ np->stats.rx_missed_errors += (tmp & MFC_CNT2) + ((tmp & MFC_CNT1) >> 16); ++ ++ return &np->stats; ++} ++ ++/* ++ * ethtool routines ++ */ ++static int jz_ethtool_ioctl(struct net_device *dev, void *useraddr) ++{ ++ struct jz_eth_private *np = dev->priv; ++ u32 ethcmd; ++ ++ /* dev_ioctl() in ../../net/core/dev.c has already checked ++ capable(CAP_NET_ADMIN), so don't bother with that here. */ ++ ++ if (get_user(ethcmd, (u32 *)useraddr)) ++ return -EFAULT; ++ ++ switch (ethcmd) { ++ ++ case ETHTOOL_GDRVINFO: { ++ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; ++ strcpy (info.driver, DRV_NAME); ++ strcpy (info.version, DRV_VERSION); ++ strcpy (info.bus_info, "OCS"); ++ if (copy_to_user (useraddr, &info, sizeof (info))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ /* get settings */ ++ case ETHTOOL_GSET: { ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ spin_lock_irq(&np->lock); ++ mii_ethtool_gset(&mii_info, &ecmd); ++ spin_unlock_irq(&np->lock); ++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) ++ return -EFAULT; ++ return 0; ++ } ++ /* set settings */ ++ case ETHTOOL_SSET: { ++ int r; ++ struct ethtool_cmd ecmd; ++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) ++ return -EFAULT; ++ spin_lock_irq(&np->lock); ++ r = mii_ethtool_sset(&mii_info, &ecmd); ++ spin_unlock_irq(&np->lock); ++ return r; ++ } ++ /* restart autonegotiation */ ++ case ETHTOOL_NWAY_RST: { ++ return mii_nway_restart(&mii_info); ++ } ++ /* get link status */ ++ case ETHTOOL_GLINK: { ++ struct ethtool_value edata = {ETHTOOL_GLINK}; ++ edata.data = mii_link_ok(&mii_info); ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ /* get message-level */ ++ case ETHTOOL_GMSGLVL: { ++ struct ethtool_value edata = {ETHTOOL_GMSGLVL}; ++ edata.data = debug; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ /* set message-level */ ++ case ETHTOOL_SMSGLVL: { ++ struct ethtool_value edata; ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ debug = edata.data; ++ return 0; ++ } ++ ++ ++ default: ++ break; ++ } ++ ++ return -EOPNOTSUPP; ++ ++} ++ ++/* ++ * Config device ++ */ ++static int jz_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct jz_eth_private *np =(struct jz_eth_private *)dev->priv; ++ struct mii_ioctl_data *data, rdata; ++ ++ switch (cmd) { ++ case SIOCETHTOOL: ++ return jz_ethtool_ioctl(dev, (void *) rq->ifr_data); ++ case SIOCGMIIPHY: ++ case SIOCDEVPRIVATE: ++ data = (struct mii_ioctl_data *)&rq->ifr_data; ++ data->phy_id = np->valid_phy; ++ case SIOCGMIIREG: ++ case SIOCDEVPRIVATE+1: ++ data = (struct mii_ioctl_data *)&rq->ifr_data; ++ data->val_out = mdio_read(dev,np->valid_phy, data->reg_num & 0x1f); ++ return 0; ++ case SIOCSMIIREG: ++ case SIOCDEVPRIVATE+2: ++ data = (struct mii_ioctl_data *)&rq->ifr_data; ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ mdio_write(dev,np->valid_phy, data->reg_num & 0x1f, data->val_in); ++ return 0; ++ case READ_COMMAND: ++ data = (struct mii_ioctl_data *)rq->ifr_data; ++ if (copy_from_user(&rdata,data,sizeof(rdata))) ++ return -EFAULT; ++ rdata.val_out = mdio_read(dev,rdata.phy_id, rdata.reg_num & 0x1f); ++ if (copy_to_user(data,&rdata,sizeof(rdata))) ++ return -EFAULT; ++ return 0; ++ case WRITE_COMMAND: ++ if (np->phy_type==1) { ++ data = (struct mii_ioctl_data *)rq->ifr_data; ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ if (copy_from_user(&rdata,data,sizeof(rdata))) ++ return -EFAULT; ++ mdio_write(dev,rdata.phy_id, rdata.reg_num & 0x1f, rdata.val_in); ++ } ++ return 0; ++ case GETDRIVERINFO: ++ if (np->phy_type==1) { ++ data = (struct mii_ioctl_data *)rq->ifr_data; ++ if (copy_from_user(&rdata,data,sizeof(rdata))) ++ return -EFAULT; ++ rdata.val_in = 0x1; ++ rdata.val_out = 0x00d0; ++ if (copy_to_user(data,&rdata,sizeof(rdata))) ++ return -EFAULT; ++ } ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++/* ++ * Received one packet ++ */ ++static void eth_rxready(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private*)dev->priv; ++ struct sk_buff *skb; ++ unsigned char *pkt_ptr; ++ u32 pkt_len; ++ u32 status; ++ ++ status = le32_to_cpu(np->rx_ring[np->rx_head].status); ++ while (!(status & R_OWN)) { /* owner bit = 0 */ ++ if (status & RD_ES) { /* error summary */ ++ np->stats.rx_errors++; /* Update the error stats. */ ++ if (status & (RD_RF | RD_TL)) ++ np->stats.rx_frame_errors++; ++ if (status & RD_CE) ++ np->stats.rx_crc_errors++; ++ if (status & RD_TL) ++ np->stats.rx_length_errors++; ++ } else { ++ pkt_ptr = bus_to_virt(le32_to_cpu(np->rx_ring[np->rx_head].buf1_addr)); ++ pkt_len = ((status & RD_FL) >> 16) - 4; ++ ++ skb = dev_alloc_skb(pkt_len + 2); ++ if (skb == NULL) { ++ printk("%s: Memory squeeze, dropping.\n", ++ dev->name); ++ np->stats.rx_dropped++; ++ break; ++ } ++ skb->dev = dev; ++ skb_reserve(skb, 2); /* 16 byte align */ ++ ++ //pkt_ptr = P1ADDR(pkt_ptr); ++ //dma_cache_inv(pkt_ptr, pkt_len); ++ memcpy(skb->data, pkt_ptr, pkt_len); ++ skb_put(skb, pkt_len); ++ ++ //eth_dbg_rx(skb, pkt_len); ++ skb->protocol = eth_type_trans(skb,dev); ++ netif_rx(skb); /* pass the packet to upper layers */ ++ dev->last_rx = jiffies; ++ np->stats.rx_packets++; ++ np->stats.rx_bytes += pkt_len; ++ } ++ np->rx_ring[np->rx_head].status = cpu_to_le32(R_OWN); ++ ++ np->rx_head ++; ++ if (np->rx_head >= NUM_RX_DESCS) ++ np->rx_head = 0; ++ status = le32_to_cpu(np->rx_ring[np->rx_head].status); ++ } ++} ++ ++/* ++ * Tx timeout routine ++ */ ++static void jz_eth_tx_timeout(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ ++ jz_init_hw(dev); ++ np->stats.tx_errors ++; ++ netif_wake_queue(dev); ++} ++ ++/* ++ * One packet was transmitted ++ */ ++static void eth_txdone(struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private*)dev->priv; ++ int tx_tail = np->tx_tail; ++ ++ while (tx_tail != np->tx_head) { ++ int entry = tx_tail % NUM_TX_DESCS; ++ s32 status = le32_to_cpu(np->tx_ring[entry].status); ++ if(status < 0) break; ++ if (status & TD_ES ) { /* Error summary */ ++ np->stats.tx_errors++; ++ if (status & TD_NC) np->stats.tx_carrier_errors++; ++ if (status & TD_LC) np->stats.tx_window_errors++; ++ if (status & TD_UF) np->stats.tx_fifo_errors++; ++ if (status & TD_DE) np->stats.tx_aborted_errors++; ++ if (np->tx_head != np->tx_tail) ++ writel(1, DMA_TPD); /* Restart a stalled TX */ ++ } else ++ np->stats.tx_packets++; ++ /* Update the collision counter */ ++ np->stats.collisions += ((status & TD_EC) ? 16 : ((status & TD_CC) >> 3)); ++ /* Free the original skb */ ++ if (np->tx_skb[entry]) { ++ dev_kfree_skb_irq(np->tx_skb[entry]); ++ np->tx_skb[entry] = 0; ++ } ++ tx_tail++; ++ } ++ if (np->tx_full && (tx_tail + NUM_TX_DESCS > np->tx_head + 1)) { ++ /* The ring is no longer full */ ++ np->tx_full = 0; ++ netif_start_queue(dev); ++ } ++ np->tx_tail = tx_tail; ++} ++ ++/* ++ * Update the tx descriptor ++ */ ++static void load_tx_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ int entry = np->tx_head % NUM_TX_DESCS; ++ ++ np->tx_ring[entry].buf1_addr = cpu_to_le32(virt_to_bus(buf)); ++ np->tx_ring[entry].desc1 &= cpu_to_le32((TD_TER | TD_TCH)); ++ np->tx_ring[entry].desc1 |= cpu_to_le32(flags); ++ np->tx_ring[entry].status = cpu_to_le32(T_OWN); ++ np->tx_skb[entry] = skb; ++} ++ ++/* ++ * Transmit one packet ++ */ ++static int jz_eth_send_packet(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; ++ u32 length; ++ ++ if (np->tx_full) { ++ return 0; ++ } ++#ifdef CONFIG_FPGA ++ mdelay(10); ++#else ++ udelay(500); /* FIXME: can we remove this delay ? */ ++#endif ++ length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; ++ dma_cache_wback((unsigned long)skb->data, length); ++ load_tx_packet(dev, (char *)skb->data, TD_IC | TD_LS | TD_FS | length, skb); ++ spin_lock_irq(&np->lock); ++ np->tx_head ++; ++ np->stats.tx_bytes += length; ++ writel(1, DMA_TPD); /* Start the TX */ ++ dev->trans_start = jiffies; /* for timeout */ ++ if (np->tx_tail + NUM_TX_DESCS > np->tx_head + 1) { ++ np->tx_full = 0; ++ } ++ else { ++ np->tx_full = 1; ++ netif_stop_queue(dev); ++ } ++ spin_unlock_irq(&np->lock); ++ ++ return 0; ++} ++ ++/* ++ * Interrupt service routine ++ */ ++static irqreturn_t jz_eth_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = (struct net_device *)dev_id; ++ struct jz_eth_private *np = dev->priv; ++ u32 sts; ++ int i; ++ ++ spin_lock(&np->lock); ++ ++ writel((readl(DMA_IMR) & ~IMR_ENABLE), DMA_IMR); /* Disable interrupt */ ++ ++ for (i = 0; i < 100; i++) { ++ sts = readl(DMA_STS); ++ writel(sts, DMA_STS); /* clear status */ ++ ++ if (!(sts & IMR_DEFAULT)) break; ++ ++ if (sts & (DMA_INT_RI | DMA_INT_RU)) /* Rx IRQ */ ++ eth_rxready(dev); ++ if (sts & (DMA_INT_TI | DMA_INT_TU)) /* Tx IRQ */ ++ eth_txdone(dev); ++ ++ /* check error conditions */ ++ if (sts & DMA_INT_FB){ /* fatal bus error */ ++ STOP_ETH; ++ errprintk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",dev->name, sts); ++ break; ++ } ++ ++ if (sts & DMA_INT_UN) { /* Transmit underrun */ ++ u32 omr; ++ omr = readl(DMA_OMR); ++ if (!(omr & OMR_SF)) { ++ omr &= ~(OMR_ST | OMR_SR); ++ writel(omr, DMA_OMR); ++ while (readl(DMA_STS) & STS_TS); /* wait for stop */ ++ if ((omr & OMR_TR) < OMR_TR) { /* ? */ ++ omr += TR_24; ++ } else { ++ omr |= OMR_SF; ++ } ++ writel(omr | OMR_ST | OMR_SR, DMA_OMR); ++ } ++ } ++ } ++ ++ writel(readl(DMA_IMR) | IMR_ENABLE, DMA_IMR); /* enable interrupt */ ++ ++ spin_unlock(&np->lock); ++ ++ return IRQ_HANDLED; ++} ++ ++#if 0 //def CONFIG_PM ++/* ++ * Suspend the ETH interface. ++ */ ++static int jz_eth_suspend(struct net_device *dev, int state) ++{ ++ struct jz_eth_private *jep = (struct jz_eth_private *)dev->priv; ++ unsigned long flags, tmp; ++ ++ printk("ETH suspend.\n"); ++ ++ if (!netif_running(dev)) { ++ return 0; ++ } ++ ++ netif_device_detach(dev); ++ ++ spin_lock_irqsave(&jep->lock, flags); ++ ++ /* Disable interrupts, stop Tx and Rx. */ ++ REG32(DMA_IMR) = 0; ++ STOP_ETH; ++ ++ /* Update the error counts. */ ++ tmp = REG32(DMA_MFC); ++ jep->stats.rx_missed_errors += (tmp & 0x1ffff); ++ jep->stats.rx_fifo_errors += ((tmp >> 17) & 0x7ff); ++ ++ spin_unlock_irqrestore(&jep->lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * Resume the ETH interface. ++ */ ++static int jz_eth_resume(struct net_device *dev) ++{ ++ printk("ETH resume.\n"); ++ ++ if (!netif_running(dev)) ++ return 0; ++ ++ jz_init_hw(dev); ++ ++ netif_device_attach(dev); ++ jz_eth_tx_timeout(dev); ++ netif_wake_queue(dev); ++ ++ return 0; ++} ++ ++static int jz_eth_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ int ret; ++ ++ if (!dev->data) ++ return -EINVAL; ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ ret = jz_eth_suspend((struct net_device *)dev->data, ++ (int)data); ++ break; ++ ++ case PM_RESUME: ++ ret = jz_eth_resume((struct net_device *)dev->data); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#endif /* CONFIG_PM */ ++ ++static int __init jz_eth_init(void) ++{ ++ struct net_device *dev; ++ struct jz_eth_private *np; ++ int err; ++ ++ dev = alloc_etherdev(sizeof(struct jz_eth_private)); ++ if (!dev) { ++ printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME); ++ return -ENOMEM; ++ } ++ netdev = dev; ++ ++ np = (struct jz_eth_private *)P2ADDR(dev->priv); ++ dev->priv = np; ++ memset(np, 0, sizeof(struct jz_eth_private)); ++ ++ np->vaddr_rx_buf = (u32)dma_alloc_noncoherent(NULL, NUM_RX_DESCS*RX_BUF_SIZE, ++ &np->dma_rx_buf, 0); ++ ++ if (!np->vaddr_rx_buf) { ++ printk(KERN_ERR "%s: Cannot alloc dma buffers\n", DRV_NAME); ++ unregister_netdev(dev); ++ free_netdev(dev); ++ return -ENOMEM; ++ } ++ ++ np->dma_rx_ring = virt_to_bus(np->rx_ring); ++ np->dma_tx_ring = virt_to_bus(np->tx_ring); ++ np->full_duplex = 1; ++ np->link_state = 1; ++ ++ spin_lock_init(&np->lock); ++ ++ ether_setup(dev); ++ dev->irq = IRQ_ETH; ++ dev->open = jz_eth_open; ++ dev->stop = jz_eth_close; ++ dev->hard_start_xmit = jz_eth_send_packet; ++ dev->get_stats = jz_eth_get_stats; ++ dev->set_multicast_list = jz_set_multicast_list; ++ dev->do_ioctl = jz_eth_ioctl; ++ dev->tx_timeout = jz_eth_tx_timeout; ++ dev->watchdog_timeo = ETH_TX_TIMEOUT; ++ ++ /* configure MAC address */ ++ get_mac_address(dev); ++ ++ if ((err = register_netdev(dev)) != 0) { ++ printk(KERN_ERR "%s: Cannot register net device, error %d\n", ++ DRV_NAME, err); ++ free_netdev(dev); ++ return -ENOMEM; ++ } ++ ++//#ifdef 0 //CONFIG_PM ++// np->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, jz_eth_pm_callback); ++// if (np->pmdev) ++// np->pmdev->data = dev; ++//#endif ++ ++ return 0; ++} ++ ++static void __exit jz_eth_exit(void) ++{ ++ struct net_device *dev = netdev; ++ struct jz_eth_private *np = dev->priv; ++ ++ unregister_netdev(dev); ++ dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE, ++ (void *)np->vaddr_rx_buf, np->dma_rx_buf); ++ free_netdev(dev); ++} ++ ++module_init(jz_eth_init); ++module_exit(jz_eth_exit); +diff --git a/drivers/net/jz_eth.h b/drivers/net/jz_eth.h +new file mode 100644 +index 0000000..cb8486e +--- /dev/null ++++ b/drivers/net/jz_eth.h +@@ -0,0 +1,403 @@ ++/* ++ * linux/drivers/net/jz_eth.h ++ * ++ * Jz4730/Jz5730 On-Chip ethernet driver. ++ * ++ * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++#ifndef __JZ_ETH_H__ ++#define __JZ_ETH_H__ ++ ++/* DMA control and status registers */ ++#define DMA_BMR (ETH_BASE + 0x1000) // Bus mode ++#define DMA_TPD (ETH_BASE + 0x1004) // Transmit poll demand register ++#define DMA_RPD (ETH_BASE + 0x1008) // Receieve poll demand register ++#define DMA_RRBA (ETH_BASE + 0x100C) // Receieve descriptor base address ++#define DMA_TRBA (ETH_BASE + 0x1010) // Transmit descriptor base address ++#define DMA_STS (ETH_BASE + 0x1014) // Status register ++#define DMA_OMR (ETH_BASE + 0x1018) // Command register ++#define DMA_IMR (ETH_BASE + 0x101C) ++#define DMA_MFC (ETH_BASE + 0x1020) ++ ++/* DMA CSR8-CSR19 reserved */ ++#define DMA_CTA (ETH_BASE + 0x1050) ++#define DMA_CRA (ETH_BASE + 0x1054) ++ ++/* Mac control and status registers */ ++#define MAC_MCR (ETH_BASE + 0x0000) ++#define MAC_MAH (ETH_BASE + 0x0004) ++#define MAC_MAL (ETH_BASE + 0x0008) ++#define MAC_HTH (ETH_BASE + 0x000C) ++#define MAC_HTL (ETH_BASE + 0x0010) ++#define MAC_MIIA (ETH_BASE + 0x0014) ++#define MAC_MIID (ETH_BASE + 0x0018) ++#define MAC_FCR (ETH_BASE + 0x001C) ++#define MAC_VTR1 (ETH_BASE + 0x0020) ++#define MAC_VTR2 (ETH_BASE + 0x0024) ++ ++/* ++ * Bus Mode Register (DMA_BMR) ++ */ ++#define BMR_PBL 0x00003f00 /* Programmable Burst Length */ ++#define BMR_DSL 0x0000007c /* Descriptor Skip Length */ ++#define BMR_BAR 0x00000002 /* Bus ARbitration */ ++#define BMR_SWR 0x00000001 /* Software Reset */ ++ ++#define PBL_0 0x00000000 /* DMA burst length = amount in RX FIFO */ ++#define PBL_1 0x00000100 /* 1 longword DMA burst length */ ++#define PBL_2 0x00000200 /* 2 longwords DMA burst length */ ++#define PBL_4 0x00000400 /* 4 longwords DMA burst length */ ++#define PBL_8 0x00000800 /* 8 longwords DMA burst length */ ++#define PBL_16 0x00001000 /* 16 longwords DMA burst length */ ++#define PBL_32 0x00002000 /* 32 longwords DMA burst length */ ++ ++#define DSL_0 0x00000000 /* 0 longword / descriptor */ ++#define DSL_1 0x00000004 /* 1 longword / descriptor */ ++#define DSL_2 0x00000008 /* 2 longwords / descriptor */ ++#define DSL_4 0x00000010 /* 4 longwords / descriptor */ ++#define DSL_8 0x00000020 /* 8 longwords / descriptor */ ++#define DSL_16 0x00000040 /* 16 longwords / descriptor */ ++#define DSL_32 0x00000080 /* 32 longwords / descriptor */ ++ ++/* ++ * Status Register (DMA_STS) ++ */ ++#define STS_BE 0x03800000 /* Bus Error Bits */ ++#define STS_TS 0x00700000 /* Transmit Process State */ ++#define STS_RS 0x000e0000 /* Receive Process State */ ++ ++#define TS_STOP 0x00000000 /* Stopped */ ++#define TS_FTD 0x00100000 /* Running Fetch Transmit Descriptor */ ++#define TS_WEOT 0x00200000 /* Running Wait for End Of Transmission */ ++#define TS_QDAT 0x00300000 /* Running Queue skb data into TX FIFO */ ++#define TS_RES 0x00400000 /* Reserved */ ++#define TS_SPKT 0x00500000 /* Reserved */ ++#define TS_SUSP 0x00600000 /* Suspended */ ++#define TS_CLTD 0x00700000 /* Running Close Transmit Descriptor */ ++ ++#define RS_STOP 0x00000000 /* Stopped */ ++#define RS_FRD 0x00020000 /* Running Fetch Receive Descriptor */ ++#define RS_CEOR 0x00040000 /* Running Check for End of Receive Packet */ ++#define RS_WFRP 0x00060000 /* Running Wait for Receive Packet */ ++#define RS_SUSP 0x00080000 /* Suspended */ ++#define RS_CLRD 0x000a0000 /* Running Close Receive Descriptor */ ++#define RS_FLUSH 0x000c0000 /* Running Flush RX FIFO */ ++#define RS_QRFS 0x000e0000 /* Running Queue RX FIFO into RX Skb */ ++ ++/* ++ * Operation Mode Register (DMA_OMR) ++ */ ++#define OMR_TTM 0x00400000 /* Transmit Threshold Mode */ ++#define OMR_SF 0x00200000 /* Store and Forward */ ++#define OMR_TR 0x0000c000 /* Threshold Control Bits */ ++#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */ ++#define OMR_OSF 0x00000004 /* Operate on Second Frame */ ++#define OMR_SR 0x00000002 /* Start/Stop Receive */ ++ ++#define TR_18 0x00000000 /* Threshold set to 18 (32) bytes */ ++#define TR_24 0x00004000 /* Threshold set to 24 (64) bytes */ ++#define TR_32 0x00008000 /* Threshold set to 32 (128) bytes */ ++#define TR_40 0x0000c000 /* Threshold set to 40 (256) bytes */ ++ ++/* ++ * Missed Frames Counters (DMA_MFC) ++ */ ++//#define MFC_CNT1 0xffff0000 /* Missed Frames Counter Bits by application */ ++#define MFC_CNT1 0x0ffe0000 /* Missed Frames Counter Bits by application */ ++#define MFC_CNT2 0x0000ffff /* Missed Frames Counter Bits by controller */ ++ ++/* ++ * Mac control Register (MAC_MCR) ++ */ ++#define MCR_RA 0x80000000 /* Receive All */ ++#define MCR_HBD 0x10000000 /* HeartBeat Disable */ ++#define MCR_PS 0x08000000 /* Port Select */ ++#define MCR_OWD 0x00800000 /* Receive own Disable */ ++#define MCR_OM 0x00600000 /* Operating(loopback) Mode */ ++#define MCR_FDX 0x00100000 /* Full Duplex Mode */ ++#define MCR_PM 0x00080000 /* Pass All Multicast */ ++#define MCR_PR 0x00040000 /* Promiscuous Mode */ ++#define MCR_IF 0x00020000 /* Inverse Filtering */ ++#define MCR_PB 0x00010000 /* Pass Bad Frames */ ++#define MCR_HO 0x00008000 /* Hash Only Filtering Mode */ ++#define MCR_HP 0x00002000 /* Hash/Perfect Receive Filtering Mode */ ++#define MCR_FC 0x00001000 /* Late Collision control */ ++#define MCR_BFD 0x00000800 /* Boardcast frame Disable */ ++#define MCR_RED 0x00000400 /* Retry Disable */ ++#define MCR_APS 0x00000100 /* Automatic pad stripping */ ++#define MCR_BL 0x000000c0 /* Back off Limit */ ++#define MCR_DC 0x00000020 /* Deferral check */ ++#define MCR_TE 0x00000008 /* Transmitter enable */ ++#define MCR_RE 0x00000004 /* Receiver enable */ ++ ++#define MCR_MII_10 ( OMR_TTM | MCR_PS) ++#define MCR_MII_100 ( MCR_HBD | MCR_PS) ++ ++/* Flow control Register (MAC_FCR) */ ++#define FCR_PT 0xffff0000 /* Pause time */ ++#define FCR_PCF 0x00000004 /* Pass control frames */ ++#define FCR_FCE 0x00000002 /* Flow control enable */ ++#define FCR_FCB 0x00000001 /* Flow control busy */ ++ ++ ++/* Constants for the interrupt mask and ++ * interrupt status registers. (DMA_SIS and DMA_IMR) ++ */ ++#define DMA_INT_NI 0x00010000 // Normal interrupt summary ++#define DMA_INT_AI 0x00008000 // Abnormal interrupt summary ++#define DMA_INT_ER 0x00004000 // Early receive interrupt ++#define DMA_INT_FB 0x00002000 // Fatal bus error ++#define DMA_INT_ET 0x00000400 // Early transmit interrupt ++#define DMA_INT_RW 0x00000200 // Receive watchdog timeout ++#define DMA_INT_RS 0x00000100 // Receive stop ++#define DMA_INT_RU 0x00000080 // Receive buffer unavailble ++#define DMA_INT_RI 0x00000040 // Receive interrupt ++#define DMA_INT_UN 0x00000020 // Underflow ++#define DMA_INT_TJ 0x00000008 // Transmit jabber timeout ++#define DMA_INT_TU 0x00000004 // Transmit buffer unavailble ++#define DMA_INT_TS 0x00000002 // Transmit stop ++#define DMA_INT_TI 0x00000001 // Transmit interrupt ++ ++/* ++ * Receive Descriptor Bit Summary ++ */ ++#define R_OWN 0x80000000 /* Own Bit */ ++#define RD_FF 0x40000000 /* Filtering Fail */ ++#define RD_FL 0x3fff0000 /* Frame Length */ ++#define RD_ES 0x00008000 /* Error Summary */ ++#define RD_DE 0x00004000 /* Descriptor Error */ ++#define RD_LE 0x00001000 /* Length Error */ ++#define RD_RF 0x00000800 /* Runt Frame */ ++#define RD_MF 0x00000400 /* Multicast Frame */ ++#define RD_FS 0x00000200 /* First Descriptor */ ++#define RD_LS 0x00000100 /* Last Descriptor */ ++#define RD_TL 0x00000080 /* Frame Too Long */ ++#define RD_CS 0x00000040 /* Collision Seen */ ++#define RD_FT 0x00000020 /* Frame Type */ ++#define RD_RJ 0x00000010 /* Receive Watchdog timeout*/ ++#define RD_RE 0x00000008 /* Report on MII Error */ ++#define RD_DB 0x00000004 /* Dribbling Bit */ ++#define RD_CE 0x00000002 /* CRC Error */ ++ ++#define RD_RER 0x02000000 /* Receive End Of Ring */ ++#define RD_RCH 0x01000000 /* Second Address Chained */ ++#define RD_RBS2 0x003ff800 /* Buffer 2 Size */ ++#define RD_RBS1 0x000007ff /* Buffer 1 Size */ ++ ++/* ++ * Transmit Descriptor Bit Summary ++ */ ++#define T_OWN 0x80000000 /* Own Bit */ ++#define TD_ES 0x00008000 /* Frame Aborted (error summary)*/ ++#define TD_LO 0x00000800 /* Loss Of Carrier */ ++#define TD_NC 0x00000400 /* No Carrier */ ++#define TD_LC 0x00000200 /* Late Collision */ ++#define TD_EC 0x00000100 /* Excessive Collisions */ ++#define TD_HF 0x00000080 /* Heartbeat Fail */ ++#define TD_CC 0x0000003c /* Collision Counter */ ++#define TD_UF 0x00000002 /* Underflow Error */ ++#define TD_DE 0x00000001 /* Deferred */ ++ ++#define TD_IC 0x80000000 /* Interrupt On Completion */ ++#define TD_LS 0x40000000 /* Last Segment */ ++#define TD_FS 0x20000000 /* First Segment */ ++#define TD_FT1 0x10000000 /* Filtering Type */ ++#define TD_SET 0x08000000 /* Setup Packet */ ++#define TD_AC 0x04000000 /* Add CRC Disable */ ++#define TD_TER 0x02000000 /* Transmit End Of Ring */ ++#define TD_TCH 0x01000000 /* Second Address Chained */ ++#define TD_DPD 0x00800000 /* Disabled Padding */ ++#define TD_FT0 0x00400000 /* Filtering Type */ ++#define TD_TBS2 0x003ff800 /* Buffer 2 Size */ ++#define TD_TBS1 0x000007ff /* Buffer 1 Size */ ++ ++#define PERFECT_F 0x00000000 ++#define HASH_F TD_FT0 ++#define INVERSE_F TD_FT1 ++#define HASH_O_F (TD_FT1 | TD_F0) ++ ++/* ++ * Constant setting ++ */ ++ ++#define IMR_DEFAULT ( DMA_INT_TI | DMA_INT_RI | \ ++ DMA_INT_TS | DMA_INT_RS | \ ++ DMA_INT_TU | DMA_INT_RU | \ ++ DMA_INT_FB ) ++ ++#define IMR_ENABLE (DMA_INT_NI | DMA_INT_AI) ++ ++#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ ++#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ ++ ++#define HASH_TABLE_LEN 512 /* Bits */ ++#define HASH_BITS 0x01ff /* 9 LS bits */ ++ ++#define SETUP_FRAME_LEN 192 /* Bytes */ ++#define IMPERF_PA_OFFSET 156 /* Bytes */ ++ ++/* ++ * Address Filtering Modes ++ */ ++#define PERFECT 0 /* 16 perfect physical addresses */ ++#define HASH_PERF 1 /* 1 perfect, 512 multicast addresses */ ++#define PERFECT_REJ 2 /* Reject 16 perfect physical addresses */ ++#define ALL_HASH 3 /* Hashes all physical & multicast addrs */ ++ ++#define ALL 0 /* Clear out all the setup frame */ ++#define PHYS_ADDR_ONLY 1 /* Update the physical address only */ ++ ++/* MII register */ ++#define MII_BMCR 0x00 /* MII Basic Mode Control Register */ ++#define MII_BMSR 0x01 /* MII Basic Mode Status Register */ ++#define MII_ID1 0x02 /* PHY Identifier Register 1 */ ++#define MII_ID2 0x03 /* PHY Identifier Register 2 */ ++#define MII_ANAR 0x04 /* Auto Negotiation Advertisement Register */ ++#define MII_ANLPAR 0x05 /* Auto Negotiation Link Partner Ability */ ++#define MII_ANER 0x06 /* Auto Negotiation Expansion */ ++#define MII_DSCR 0x10 /* Davicom Specified Configration Register */ ++#define MII_DSCSR 0x11 /* Davicom Specified Configration/Status Register */ ++#define MII_10BTCSR 0x12 /* 10base-T Specified Configration/Status Register */ ++ ++ ++#define MII_PREAMBLE 0xffffffff /* MII Management Preamble */ ++#define MII_TEST 0xaaaaaaaa /* MII Test Signal */ ++#define MII_STRD 0x06 /* Start of Frame+Op Code: use low nibble */ ++#define MII_STWR 0x0a /* Start of Frame+Op Code: use low nibble */ ++ ++/* ++ * MII Management Control Register ++ */ ++#define MII_CR_RST 0x8000 /* RESET the PHY chip */ ++#define MII_CR_LPBK 0x4000 /* Loopback enable */ ++#define MII_CR_SPD 0x2000 /* 0: 10Mb/s; 1: 100Mb/s */ ++#define MII_CR_ASSE 0x1000 /* Auto Speed Select Enable */ ++#define MII_CR_PD 0x0800 /* Power Down */ ++#define MII_CR_ISOL 0x0400 /* Isolate Mode */ ++#define MII_CR_RAN 0x0200 /* Restart Auto Negotiation */ ++#define MII_CR_FDM 0x0100 /* Full Duplex Mode */ ++#define MII_CR_CTE 0x0080 /* Collision Test Enable */ ++ ++/* ++ * MII Management Status Register ++ */ ++#define MII_SR_T4C 0x8000 /* 100BASE-T4 capable */ ++#define MII_SR_TXFD 0x4000 /* 100BASE-TX Full Duplex capable */ ++#define MII_SR_TXHD 0x2000 /* 100BASE-TX Half Duplex capable */ ++#define MII_SR_TFD 0x1000 /* 10BASE-T Full Duplex capable */ ++#define MII_SR_THD 0x0800 /* 10BASE-T Half Duplex capable */ ++#define MII_SR_ASSC 0x0020 /* Auto Speed Selection Complete*/ ++#define MII_SR_RFD 0x0010 /* Remote Fault Detected */ ++#define MII_SR_ANC 0x0008 /* Auto Negotiation capable */ ++#define MII_SR_LKS 0x0004 /* Link Status */ ++#define MII_SR_JABD 0x0002 /* Jabber Detect */ ++#define MII_SR_XC 0x0001 /* Extended Capabilities */ ++ ++/* ++ * MII Management Auto Negotiation Advertisement Register ++ */ ++#define MII_ANA_TAF 0x03e0 /* Technology Ability Field */ ++#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */ ++#define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */ ++#define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ ++#define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ ++#define MII_ANA_100M 0x0380 /* 100Mb Technology Ability Mask */ ++#define MII_ANA_10M 0x0060 /* 10Mb Technology Ability Mask */ ++#define MII_ANA_CSMA 0x0001 /* CSMA-CD Capable */ ++ ++/* ++ * MII Management Auto Negotiation Remote End Register ++ */ ++#define MII_ANLPA_NP 0x8000 /* Next Page (Enable) */ ++#define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */ ++#define MII_ANLPA_RF 0x2000 /* Remote Fault */ ++#define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */ ++#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */ ++#define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */ ++#define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ ++#define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ ++#define MII_ANLPA_100M 0x0380 /* 100Mb Technology Ability Mask */ ++#define MII_ANLPA_10M 0x0060 /* 10Mb Technology Ability Mask */ ++#define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */ ++ ++/* ++ * MII Management DAVICOM Specified Configuration And Status Register ++ */ ++#define MII_DSCSR_100FDX 0x8000 /* 100M Full Duplex Operation Mode */ ++#define MII_DSCSR_100HDX 0x4000 /* 100M Half Duplex Operation Mode */ ++#define MII_DSCSR_10FDX 0x2000 /* 10M Full Duplex Operation Mode */ ++#define MII_DSCSR_10HDX 0x1000 /* 10M Half Duplex Operation Mode */ ++#define MII_DSCSR_ANMB 0x000f /* Auto-Negotiation Monitor Bits */ ++ ++ ++/* ++ * Used by IOCTL ++ */ ++#define READ_COMMAND (SIOCDEVPRIVATE+4) ++#define WRITE_COMMAND (SIOCDEVPRIVATE+5) ++#define GETDRIVERINFO (SIOCDEVPRIVATE+6) ++ ++/* ++ * Device data and structure ++ */ ++ ++#define ETH_TX_TIMEOUT (6*HZ) ++ ++#define RX_BUF_SIZE 1536 ++ ++#define NUM_RX_DESCS 32 ++#define NUM_TX_DESCS 16 ++ ++static const char *media_types[] = { ++ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", ++ "100baseTx-FD", "100baseT4", 0 ++}; ++ ++typedef struct { ++ unsigned int status; ++ unsigned int desc1; ++ unsigned int buf1_addr; ++ unsigned int next_addr; ++} jz_desc_t; ++ ++struct jz_eth_private { ++ jz_desc_t tx_ring[NUM_TX_DESCS]; /* transmit descriptors */ ++ jz_desc_t rx_ring[NUM_RX_DESCS]; /* receive descriptors */ ++ dma_addr_t dma_tx_ring; /* bus address of tx ring */ ++ dma_addr_t dma_rx_ring; /* bus address of rx ring */ ++ dma_addr_t dma_rx_buf; /* DMA address of rx buffer */ ++ unsigned int vaddr_rx_buf; /* virtual address of rx buffer */ ++ ++ unsigned int rx_head; /* first rx descriptor */ ++ unsigned int tx_head; /* first tx descriptor */ ++ unsigned int tx_tail; /* last unacked transmit packet */ ++ unsigned int tx_full; /* transmit buffers are full */ ++ struct sk_buff *tx_skb[NUM_TX_DESCS]; /* skbuffs for packets to transmit */ ++ ++ struct net_device_stats stats; ++ spinlock_t lock; ++ ++ int media; /* Media (eg TP), mode (eg 100B)*/ ++ int full_duplex; /* Current duplex setting. */ ++ int link_state; ++ char phys[32]; /* List of attached PHY devices */ ++ char valid_phy; /* Current linked phy-id with MAC */ ++ int mii_phy_cnt; ++ int phy_type; /* 1-RTL8309,0-DVCOM */ ++ struct ethtool_cmd ecmds[32]; ++ u16 advertising; /* NWay media advertisement */ ++ ++ pid_t thr_pid; /* Link cheak thread ID */ ++ int thread_die; ++ struct completion thr_exited; ++ wait_queue_head_t thr_wait; ++ ++ struct pm_dev *pmdev; ++}; ++ ++#endif /* __JZ_ETH_H__ */ +diff --git a/drivers/net/jzcs8900a.c b/drivers/net/jzcs8900a.c +new file mode 100644 +index 0000000..db345d0 +--- /dev/null ++++ b/drivers/net/jzcs8900a.c +@@ -0,0 +1,649 @@ ++ ++/* ++ * linux/drivers/net/jzcs8900a.c ++ * ++ * Author: Lucifer ++ * ++ * A Cirrus Logic CS8900A driver for Linux ++ * based on the cs89x0 driver written by Russell Nelson, ++ * Donald Becker, and others. ++ * ++ * This source code is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++/* ++ * At the moment the driver does not support memory mode operation. ++ * It is trivial to implement this, but not worth the effort. ++ */ ++ ++/* ++ * TODO: ++ * ++ * 1. If !ready in send_start(), queue buffer and send it in interrupt handler ++ * when we receive a BufEvent with Rdy4Tx, send it again. dangerous! ++ * 2. how do we prevent interrupt handler destroying integrity of get_stats()? ++ * 3. Change reset code to check status. ++ * 4. Implement set_mac_address and remove fake mac address ++ * 5. Link status detection stuff ++ * 6. Write utility to write EEPROM, do self testing, etc. ++ * 7. Implement DMA routines (I need a board w/ DMA support for that) ++ * 8. Power management ++ * 9. Add support for multiple ethernet chips ++ * 10. Add support for other cs89xx chips (need hardware for that) ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "jzcs8900a.h" ++ ++#define FULL_DUPLEX ++#define INT_PIN 0 ++#ifdef CONFIG_SOC_JZ4740 ++#define CIRRUS_DEFAULT_IO 0xa8000000 ++#define CIRRUS_DEFAULT_IRQ 107 ++ ++#elif CONFIG_SOC_JZ4750 ++#define CIRRUS_DEFAULT_IO 0xac000000 ++ ++#ifdef CONFIG_JZ4750_FUWA ++#define CIRRUS_DEFAULT_IRQ (32*4+20+48) ++#else ++#define CIRRUS_DEFAULT_IRQ (32*2 +6+48) ++#endif ++ ++ ++#endif ++ ++typedef struct { ++ struct net_device_stats stats; ++ u16 txlen; ++} cirrus_t; ++ ++static int ethaddr_cmd = 0; ++static unsigned char ethaddr_hex[6]; ++static struct net_device *dev; ++ ++/* ++ * I/O routines ++ */ ++static void gpio_init_cs8900(void) ++{ ++#ifdef CONFIG_SOC_JZ4740 ++ __gpio_as_func0(60); //CS4# ++ __gpio_as_func0(61); //RD# ++ __gpio_as_func0(62); //WR# ++ __gpio_as_irq_high_level(59); //irq ++ __gpio_disable_pull(59); //disable pull ++ REG_EMC_SMCR4 |= (1 << 6); //16bit ++#elif CONFIG_SOC_JZ4750 ++ __gpio_as_func0(32*2+23); //CS3# ++ __gpio_as_func0(32*2+25); //RD# ++ __gpio_as_func0(32*2+26); //WR# ++ ++#ifdef CONFIG_JZ4750_FUWA ++ __gpio_as_irq_high_level(32*4+20); //irq ++ __gpio_disable_pull(32*4+20); //disable pull ++#else ++ __gpio_as_irq_high_level(32*2 +6); //irq ++ __gpio_disable_pull(32*2 +6); //disable pull ++#endif ++ ++ REG_EMC_SMCR3 |= (1 << 6); //16bit ++#endif ++ udelay(1); ++} ++ ++static inline u16 cirrus_read (struct net_device *dev,u16 reg) ++{ ++ outw (reg,dev->base_addr + PP_Address); ++ return (inw (dev->base_addr + PP_Data)); ++} ++ ++static inline void cirrus_write (struct net_device *dev,u16 reg,u16 value) ++{ ++ outw (reg,dev->base_addr + PP_Address); ++ outw (value,dev->base_addr + PP_Data); ++} ++ ++static inline void cirrus_set (struct net_device *dev,u16 reg,u16 value) ++{ ++ cirrus_write (dev,reg,cirrus_read (dev,reg) | value); ++} ++ ++static inline void cirrus_clear (struct net_device *dev,u16 reg,u16 value) ++{ ++ cirrus_write (dev,reg,cirrus_read (dev,reg) & ~value); ++} ++ ++static inline void cirrus_frame_read (struct net_device *dev,struct sk_buff *skb,u16 length) ++{ ++ insw (dev->base_addr,skb_put (skb,length),(length + 1) / 2); ++} ++ ++static inline void cirrus_frame_write (struct net_device *dev,struct sk_buff *skb) ++{ ++ outsw (dev->base_addr,skb->data,(skb->len + 1) / 2); ++} ++ ++/* ++ * Debugging functions ++ */ ++ ++#ifdef DEBUG ++static inline int printable (int c) ++{ ++ return ((c >= 32 && c <= 126) || ++ (c >= 174 && c <= 223) || ++ (c >= 242 && c <= 243) || ++ (c >= 252 && c <= 253)); ++} ++ ++static void dump16 (struct net_device *dev,const u8 *s,size_t len) ++{ ++ int i; ++ char str[128]; ++ ++ if (!len) return; ++ ++ *str = '\0'; ++ ++ for (i = 0; i < len; i++) { ++ if (i && !(i % 4)) strcat (str," "); ++ sprintf (str,"%s%.2x ",str,s[i]); ++ } ++ ++ for ( ; i < 16; i++) { ++ if (i && !(i % 4)) strcat (str," "); ++ strcat (str," "); ++ } ++ ++ strcat (str," "); ++ for (i = 0; i < len; i++) sprintf (str,"%s%c",str,printable (s[i]) ? s[i] : '.'); ++ ++ printk (KERN_DEBUG "%s: %s\n",dev->name,str); ++} ++ ++static void hexdump (struct net_device *dev,const void *ptr,size_t size) ++{ ++ const u8 *s = (u8 *) ptr; ++ int i; ++ for (i = 0; i < size / 16; i++, s += 16) dump16 (dev,s,16); ++ dump16 (dev,s,size % 16); ++} ++ ++static void dump_packet (struct net_device *dev,struct sk_buff *skb,const char *type) ++{ ++ printk (KERN_INFO "%s: %s %d byte frame %.2x:%.2x:%.2x:%.2x:%.2x:%.2x to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x type %.4x\n", ++ dev->name, ++ type, ++ skb->len, ++ skb->data[0],skb->data[1],skb->data[2],skb->data[3],skb->data[4],skb->data[5], ++ skb->data[6],skb->data[7],skb->data[8],skb->data[9],skb->data[10],skb->data[11], ++ (skb->data[12] << 8) | skb->data[13]); ++ if (skb->len < 0x100) hexdump (dev,skb->data,skb->len); ++} ++#endif /* #ifdef DEBUG */ ++ ++/* ++ * Driver functions ++ */ ++ ++static void cirrus_receive (struct net_device *dev) ++{ ++ cirrus_t *priv = (cirrus_t *) dev->priv; ++ struct sk_buff *skb; ++ u16 status,length; ++ ++ status = cirrus_read (dev,PP_RxStatus); ++ length = cirrus_read (dev,PP_RxLength); ++ ++ if (!(status & RxOK)) { ++ priv->stats.rx_errors++; ++ if ((status & (Runt | Extradata))) priv->stats.rx_length_errors++; ++ if ((status & CRCerror)) priv->stats.rx_crc_errors++; ++ return; ++ } ++ ++ if ((skb = dev_alloc_skb (length + 4)) == NULL) { ++ priv->stats.rx_dropped++; ++ return; ++ } ++ ++ skb->dev = dev; ++ skb_reserve (skb,2); ++ ++ cirrus_frame_read (dev,skb,length); ++ skb->protocol = eth_type_trans (skb,dev); ++ ++ netif_rx (skb); ++ dev->last_rx = jiffies; ++ ++ priv->stats.rx_packets++; ++ priv->stats.rx_bytes += length; ++} ++ ++static int cirrus_send_start (struct sk_buff *skb,struct net_device *dev) ++{ ++ cirrus_t *priv = (cirrus_t *) dev->priv; ++ u16 status; ++ ++ mdelay(10); ++ netif_stop_queue (dev); ++ ++ cirrus_write (dev,PP_TxCMD,TxStart (After5)); ++ cirrus_write (dev,PP_TxLength,skb->len); ++ ++ status = cirrus_read (dev,PP_BusST); ++ ++ if ((status & TxBidErr)) { ++ printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len); ++ priv->stats.tx_errors++; ++ priv->stats.tx_aborted_errors++; ++ priv->txlen = 0; ++ return (1); ++ } ++ ++ if (!(status & Rdy4TxNOW)) { ++ //printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name); ++ priv->stats.tx_errors++; ++ priv->txlen = 0; ++ /* FIXME: store skb and send it in interrupt handler */ ++ return (1); ++ } ++ ++ cirrus_frame_write (dev,skb); ++ dev->trans_start = jiffies; ++ ++ dev_kfree_skb (skb); ++ ++ priv->txlen = skb->len; ++ ++ return (0); ++} ++ ++static irqreturn_t cirrus_interrupt(int irq, void *id) ++{ ++ struct net_device *dev = (struct net_device *) id; ++ cirrus_t *priv; ++ u16 status; ++ ++ if (dev->priv == NULL) { ++ return IRQ_NONE; ++ } ++ ++ priv = (cirrus_t *) dev->priv; ++ ++ while ((status = cirrus_read (dev,PP_ISQ))) { ++ switch (RegNum (status)) { ++ case RxEvent: ++ cirrus_receive (dev); ++ break; ++ ++ case TxEvent: ++ priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL)); ++ if (!(RegContent (status) & TxOK)) { ++ priv->stats.tx_errors++; ++ if ((RegContent (status) & Out_of_window)) priv->stats.tx_window_errors++; ++ if ((RegContent (status) & Jabber)) priv->stats.tx_aborted_errors++; ++ break; ++ } else if (priv->txlen) { ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += priv->txlen; ++ } ++ priv->txlen = 0; ++ netif_wake_queue (dev); ++ break; ++ ++ case BufEvent: ++ if ((RegContent (status) & RxMiss)) { ++ u16 missed = MissCount (cirrus_read (dev,PP_RxMISS)); ++ priv->stats.rx_errors += missed; ++ priv->stats.rx_missed_errors += missed; ++ } ++ if ((RegContent (status) & TxUnderrun)) { ++ priv->stats.tx_errors++; ++ priv->stats.tx_fifo_errors++; ++ } ++ /* FIXME: if Rdy4Tx, transmit last sent packet (if any) */ ++ priv->txlen = 0; ++ netif_wake_queue (dev); ++ break; ++ ++ case TxCOL: ++ priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL)); ++ break; ++ ++ case RxMISS: ++ status = MissCount (cirrus_read (dev,PP_RxMISS)); ++ priv->stats.rx_errors += status; ++ priv->stats.rx_missed_errors += status; ++ break; ++ default: ++ return IRQ_HANDLED; ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void cirrus_transmit_timeout (struct net_device *dev) ++{ ++ cirrus_t *priv = (cirrus_t *) dev->priv; ++ priv->stats.tx_errors++; ++ priv->stats.tx_heartbeat_errors++; ++ priv->txlen = 0; ++ netif_wake_queue (dev); ++} ++ ++static int cirrus_start (struct net_device *dev) ++{ ++ int result; ++ ++ /* valid ethernet address? */ ++ if (!is_valid_ether_addr(dev->dev_addr)) { ++ printk(KERN_ERR "%s: invalid ethernet MAC address\n",dev->name); ++ return (-EINVAL); ++ } ++ ++ /* install interrupt handler */ ++ if ((result = request_irq (dev->irq, &cirrus_interrupt, IRQF_DISABLED, dev->name, dev)) < 0) { ++ printk (KERN_ERR "%s: could not register interrupt %d\n",dev->name,dev->irq); ++ return (result); ++ } ++ ++ /* enable the ethernet controller */ ++ cirrus_set (dev,PP_RxCFG,RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE); ++ cirrus_set (dev,PP_RxCTL,RxOKA | IndividualA | BroadcastA); ++ cirrus_set (dev,PP_TxCFG,TxOKiE | Out_of_windowiE | JabberiE); ++ cirrus_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE); ++ cirrus_set (dev,PP_LineCTL,SerRxON | SerTxON); ++ cirrus_set (dev,PP_BusCTL,EnableRQ); ++ ++#ifdef FULL_DUPLEX ++ cirrus_set (dev,PP_TestCTL,FDX); ++#endif /* #ifdef FULL_DUPLEX */ ++ ++ /* start the queue */ ++ netif_start_queue (dev); ++ __gpio_unmask_irq(59); ++ ++ //MOD_INC_USE_COUNT; ++ return (0); ++} ++ ++static int cirrus_stop (struct net_device *dev) ++{ ++ /* disable ethernet controller */ ++ cirrus_write (dev,PP_BusCTL,0); ++ cirrus_write (dev,PP_TestCTL,0); ++ cirrus_write (dev,PP_SelfCTL,0); ++ cirrus_write (dev,PP_LineCTL,0); ++ cirrus_write (dev,PP_BufCFG,0); ++ cirrus_write (dev,PP_TxCFG,0); ++ cirrus_write (dev,PP_RxCTL,0); ++ cirrus_write (dev,PP_RxCFG,0); ++ ++ /* uninstall interrupt handler */ ++ free_irq (dev->irq,dev); ++ ++ /* stop the queue */ ++ netif_stop_queue (dev); ++ ++ //MOD_DEC_USE_COUNT; ++ ++ return (0); ++} ++ ++static int cirrus_set_mac_address (struct net_device *dev, void *p) ++{ ++ struct sockaddr *addr = (struct sockaddr *)p; ++ int i; ++ ++ if (netif_running(dev)) ++ return -EBUSY; ++ ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ ++ /* configure MAC address */ ++ for (i = 0; i < ETH_ALEN; i += 2) ++ cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8)); ++ ++ return 0; ++} ++ ++static struct net_device_stats *cirrus_get_stats (struct net_device *dev) ++{ ++ cirrus_t *priv = (cirrus_t *) dev->priv; ++ return (&priv->stats); ++} ++ ++static void cirrus_set_receive_mode (struct net_device *dev) ++{ ++ if ((dev->flags & IFF_PROMISC)) ++ cirrus_set (dev,PP_RxCTL,PromiscuousA); ++ else ++ cirrus_clear (dev,PP_RxCTL,PromiscuousA); ++ ++ if ((dev->flags & IFF_ALLMULTI) && dev->mc_list) ++ cirrus_set (dev,PP_RxCTL,MulticastA); ++ else ++ cirrus_clear (dev,PP_RxCTL,MulticastA); ++} ++ ++/* ++ * Architecture dependant code ++ */ ++ ++/* ++ * Driver initialization routines ++ */ ++ ++int __init cirrus_probe(void) ++{ ++ static cirrus_t priv; ++ int i; ++ u16 value; ++ ++ printk ("Jz CS8900A driver for Linux (V0.02)\n"); ++ ++ /* Init hardware for PAVO board */ ++ gpio_init_cs8900(); ++ ++ /* Allocate ethernet device */ ++ dev = alloc_etherdev(sizeof(struct net_device)); ++ ++ memset (&priv,0,sizeof (cirrus_t)); ++ ++ ether_setup (dev); ++ ++ dev->open = cirrus_start; ++ dev->stop = cirrus_stop; ++ dev->hard_start_xmit = cirrus_send_start; ++ dev->get_stats = cirrus_get_stats; ++ dev->set_multicast_list = cirrus_set_receive_mode; ++ dev->set_mac_address = cirrus_set_mac_address; ++ dev->tx_timeout = cirrus_transmit_timeout; ++ dev->watchdog_timeo = HZ; ++ ++ if (ethaddr_cmd==1) ++ { ++ dev->dev_addr[0] = ethaddr_hex[0]; ++ dev->dev_addr[1] = ethaddr_hex[1]; ++ dev->dev_addr[2] = ethaddr_hex[2]; ++ dev->dev_addr[3] = ethaddr_hex[3]; ++ dev->dev_addr[4] = ethaddr_hex[4]; ++ dev->dev_addr[5] = ethaddr_hex[5]; ++ } ++ else //default mac address 00:2a:cc:2a:af:fe ++ { ++ dev->dev_addr[0] = 0x00; ++ dev->dev_addr[1] = 0x62; ++ dev->dev_addr[2] = 0x9c; ++ dev->dev_addr[3] = 0x61; ++ dev->dev_addr[4] = 0xcf; ++ dev->dev_addr[5] = 0x16; ++ } ++ dev->if_port = IF_PORT_10BASET; ++ dev->priv = (void *) &priv; ++ ++ dev->base_addr = CIRRUS_DEFAULT_IO; ++ dev->irq = CIRRUS_DEFAULT_IRQ; ++ ++ ++ /* module parameters override everything */ ++ if (!dev->base_addr) { ++ printk (KERN_ERR ++ "%s: No default I/O base address defined. Use io=... or\n" ++ "%s: define CIRRUS_DEFAULT_IO for your platform\n", ++ dev->name,dev->name); ++ return (-EINVAL); ++ } ++ ++ if (!dev->irq) { ++ printk (KERN_ERR ++ "%s: No default IRQ number defined. Use irq=... or\n" ++ "%s: define CIRRUS_DEFAULT_IRQ for your platform\n", ++ dev->name,dev->name); ++ return (-EINVAL); ++ } ++#if 0 ++ if ((result = check_region (dev->base_addr,16))) { ++ printk (KERN_ERR "%s: can't get I/O port address 0x%lx\n",dev->name,dev->base_addr); ++ return (result); ++ } ++#endif ++ if (!request_region (dev->base_addr,16,dev->name)) ++ return -EBUSY; ++#if 0 ++ /* verify EISA registration number for Cirrus Logic */ ++ if ((value = cirrus_read (dev,PP_ProductID)) != EISA_REG_CODE) { ++ printk (KERN_ERR "%s: incorrect signature 0x%.4x\n",dev->name,value); ++ return (-ENXIO); ++ } ++#endif ++ ++ /* verify chip version */ ++ value = cirrus_read (dev,PP_ProductID + 2); ++ if (VERSION (value) != CS8900A) { ++ printk (KERN_ERR "%s: unknown chip version 0x%.8x\n",dev->name,VERSION (value)); ++ return (-ENXIO); ++ } ++ printk (KERN_INFO "%s: CS8900A rev %c detected\n",dev->name,'B' + REVISION (value) - REV_B); ++ ++ /* setup interrupt number */ ++ cirrus_write (dev,PP_IntNum,INT_PIN); ++ ++ /* configure MAC address */ ++ for (i = 0; i < ETH_ALEN; i += 2) ++ { ++ //printk(" %x",dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8)); ++ cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8)); ++ } ++ ++ if (register_netdev(dev) != 0) { ++ printk(KERN_ERR " Cannot register net device\n"); ++ free_netdev(dev); ++ return -ENOMEM; ++ } ++ ++ return (0); ++} ++ ++static inline unsigned char str2hexnum(unsigned char c) ++{ ++ if(c >= '0' && c <= '9') ++ return c - '0'; ++ if(c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if(c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ return 0; /* foo */ ++} ++ ++static inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for(i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= (str2hexnum(*str++)); ++ ea[i] = num; ++ } ++} ++ ++static int __init ethernet_addr_setup(char *str) ++{ ++ if (!str) { ++ printk("ethaddr not set in command line\n"); ++ return -1; ++ } ++ ethaddr_cmd = 1; ++ str2eaddr(ethaddr_hex, str); ++ return 0; ++} ++ ++__setup("ethaddr=", ethernet_addr_setup); ++ ++//EXPORT_NO_SYMBOLS; ++ ++MODULE_AUTHOR ("Lucifer "); ++MODULE_DESCRIPTION ("Jz CS8900A driver for Linux (V0.02)"); ++MODULE_LICENSE ("GPL"); ++ ++//#ifdef MODULE ++ ++ ++#if 0 ++static int io = 0; ++static int irq = 0; ++ ++module_param(io, int, 0); ++MODULE_PARM_DESC (io,"I/O Base Address"); ++//MODULE_PARM (io,"i"); ++ ++module_param(irq, int, 0); ++MODULE_PARM_DESC (irq,"IRQ Number"); ++//MODULE_PARM (irq,"i"); ++#endif ++ ++static int __init jzcs8900_init(void) ++{ ++ if (cirrus_probe()) { ++ printk(KERN_WARNING "jzcs8900: No cs8900a found\n"); ++ } ++ ++ return 0; ++} ++ ++static void __exit jzcs8900_exit(void) ++{ ++ release_region(dev->base_addr,16); ++ unregister_netdev(dev); ++ free_netdev(dev); ++} ++ ++module_init(jzcs8900_init); ++module_exit(jzcs8900_exit); +diff --git a/drivers/net/jzcs8900a.h b/drivers/net/jzcs8900a.h +new file mode 100644 +index 0000000..68d76bb +--- /dev/null ++++ b/drivers/net/jzcs8900a.h +@@ -0,0 +1,235 @@ ++#ifndef JZCS8900A_H ++#define JZCS8900A_H ++ ++/* ++ * linux/drivers/net/jzcs8900a.h ++ * ++ * Author: Lucifer ++ * ++ * A Cirrus Logic CS8900A driver for Linux ++ * based on the cs89x0 driver written by Russell Nelson, ++ * Donald Becker, and others. ++ * ++ * This source code is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++/* ++ * Ports ++ */ ++ ++#define PP_Address 0x0a /* PacketPage Pointer Port (Section 4.10.10) */ ++#define PP_Data 0x0c /* PacketPage Data Port (Section 4.10.10) */ ++ ++/* ++ * Registers ++ */ ++ ++#define PP_ProductID 0x0000 /* Section 4.3.1 Product Identification Code */ ++#define PP_MemBase 0x002c /* Section 4.9.2 Memory Base Address Register */ ++#define PP_IntNum 0x0022 /* Section 3.2.3 Interrupt Number */ ++#define PP_EEPROMCommand 0x0040 /* Section 4.3.11 EEPROM Command */ ++#define PP_EEPROMData 0x0042 /* Section 4.3.12 EEPROM Data */ ++#define PP_RxCFG 0x0102 /* Section 4.4.6 Receiver Configuration */ ++#define PP_RxCTL 0x0104 /* Section 4.4.8 Receiver Control */ ++#define PP_TxCFG 0x0106 /* Section 4.4.9 Transmit Configuration */ ++#define PP_BufCFG 0x010a /* Section 4.4.12 Buffer Configuration */ ++#define PP_LineCTL 0x0112 /* Section 4.4.16 Line Control */ ++#define PP_SelfCTL 0x0114 /* Section 4.4.18 Self Control */ ++#define PP_BusCTL 0x0116 /* Section 4.4.20 Bus Control */ ++#define PP_TestCTL 0x0118 /* Section 4.4.22 Test Control */ ++#define PP_ISQ 0x0120 /* Section 4.4.5 Interrupt Status Queue */ ++#define PP_TxEvent 0x0128 /* Section 4.4.10 Transmitter Event */ ++#define PP_BufEvent 0x012c /* Section 4.4.13 Buffer Event */ ++#define PP_RxMISS 0x0130 /* Section 4.4.14 Receiver Miss Counter */ ++#define PP_TxCOL 0x0132 /* Section 4.4.15 Transmit Collision Counter */ ++#define PP_SelfST 0x0136 /* Section 4.4.19 Self Status */ ++#define PP_BusST 0x0138 /* Section 4.4.21 Bus Status */ ++#define PP_TxCMD 0x0144 /* Section 4.4.11 Transmit Command */ ++#define PP_TxLength 0x0146 /* Section 4.5.2 Transmit Length */ ++#define PP_IA 0x0158 /* Section 4.6.2 Individual Address (IEEE Address) */ ++#define PP_RxStatus 0x0400 /* Section 4.7.1 Receive Status */ ++#define PP_RxLength 0x0402 /* Section 4.7.1 Receive Length (in bytes) */ ++#define PP_RxFrame 0x0404 /* Section 4.7.2 Receive Frame Location */ ++#define PP_TxFrame 0x0a00 /* Section 4.7.2 Transmit Frame Location */ ++ ++/* ++ * Values ++ */ ++ ++/* PP_IntNum */ ++#define INTRQ0 0x0000 ++#define INTRQ1 0x0001 ++#define INTRQ2 0x0002 ++#define INTRQ3 0x0003 ++ ++/* PP_ProductID */ ++#define EISA_REG_CODE 0x630e ++#define REVISION(x) (((x) & 0x1f00) >> 8) ++#define VERSION(x) ((x) & ~0x1f00) ++ ++#define CS8900A 0x0000 ++#define REV_B 7 ++#define REV_C 8 ++#define REV_D 9 ++ ++/* PP_RxCFG */ ++#define Skip_1 0x0040 ++#define StreamE 0x0080 ++#define RxOKiE 0x0100 ++#define RxDMAonly 0x0200 ++#define AutoRxDMAE 0x0400 ++#define BufferCRC 0x0800 ++#define CRCerroriE 0x1000 ++#define RuntiE 0x2000 ++#define ExtradataiE 0x4000 ++ ++/* PP_RxCTL */ ++#define IAHashA 0x0040 ++#define PromiscuousA 0x0080 ++#define RxOKA 0x0100 ++#define MulticastA 0x0200 ++#define IndividualA 0x0400 ++#define BroadcastA 0x0800 ++#define CRCerrorA 0x1000 ++#define RuntA 0x2000 ++#define ExtradataA 0x4000 ++ ++/* PP_TxCFG */ ++#define Loss_of_CRSiE 0x0040 ++#define SQErroriE 0x0080 ++#define TxOKiE 0x0100 ++#define Out_of_windowiE 0x0200 ++#define JabberiE 0x0400 ++#define AnycolliE 0x0800 ++#define T16colliE 0x8000 ++ ++/* PP_BufCFG */ ++#define SWint_X 0x0040 ++#define RxDMAiE 0x0080 ++#define Rdy4TxiE 0x0100 ++#define TxUnderruniE 0x0200 ++#define RxMissiE 0x0400 ++#define Rx128iE 0x0800 ++#define TxColOvfiE 0x1000 ++#define MissOvfloiE 0x2000 ++#define RxDestiE 0x8000 ++ ++/* PP_LineCTL */ ++#define SerRxON 0x0040 ++#define SerTxON 0x0080 ++#define AUIonly 0x0100 ++#define AutoAUI_10BT 0x0200 ++#define ModBackoffE 0x0800 ++#define PolarityDis 0x1000 ++#define L2_partDefDis 0x2000 ++#define LoRxSquelch 0x4000 ++ ++/* PP_SelfCTL */ ++#define RESET 0x0040 ++#define SWSuspend 0x0100 ++#define HWSleepE 0x0200 ++#define HWStandbyE 0x0400 ++#define HC0E 0x1000 ++#define HC1E 0x2000 ++#define HCB0 0x4000 ++#define HCB1 0x8000 ++ ++/* PP_BusCTL */ ++#define ResetRxDMA 0x0040 ++#define DMAextend 0x0100 ++#define UseSA 0x0200 ++#define MemoryE 0x0400 ++#define DMABurst 0x0800 ++#define IOCHRDYE 0x1000 ++#define RxDMAsize 0x2000 ++#define EnableRQ 0x8000 ++ ++/* PP_TestCTL */ ++#define DisableLT 0x0080 ++#define ENDECloop 0x0200 ++#define AUIloop 0x0400 ++#define DisableBackoff 0x0800 ++#define FDX 0x4000 ++ ++/* PP_ISQ */ ++#define RegNum(x) ((x) & 0x3f) ++#define RegContent(x) ((x) & ~0x3d) ++ ++#define RxEvent 0x0004 ++#define TxEvent 0x0008 ++#define BufEvent 0x000c ++#define RxMISS 0x0010 ++#define TxCOL 0x0012 ++ ++/* PP_RxStatus */ ++#define IAHash 0x0040 ++#define Dribblebits 0x0080 ++#define RxOK 0x0100 ++#define Hashed 0x0200 ++#define IndividualAdr 0x0400 ++#define Broadcast 0x0800 ++#define CRCerror 0x1000 ++#define Runt 0x2000 ++#define Extradata 0x4000 ++ ++#define HashTableIndex(x) ((x) >> 0xa) ++ ++/* PP_TxCMD */ ++#define After5 0 ++#define After381 1 ++#define After1021 2 ++#define AfterAll 3 ++#define TxStart(x) ((x) << 6) ++ ++#define Force 0x0100 ++#define Onecoll 0x0200 ++#define InhibitCRC 0x1000 ++#define TxPadDis 0x2000 ++ ++/* PP_BusST */ ++#define TxBidErr 0x0080 ++#define Rdy4TxNOW 0x0100 ++ ++/* PP_TxEvent */ ++#define Loss_of_CRS 0x0040 ++#define SQEerror 0x0080 ++#define TxOK 0x0100 ++#define Out_of_window 0x0200 ++#define Jabber 0x0400 ++#define T16coll 0x8000 ++ ++#define TX_collisions(x) (((x) >> 0xb) & ~0x8000) ++ ++/* PP_BufEvent */ ++#define SWint 0x0040 ++#define RxDMAFrame 0x0080 ++#define Rdy4Tx 0x0100 ++#define TxUnderrun 0x0200 ++#define RxMiss 0x0400 ++#define Rx128 0x0800 ++#define RxDest 0x8000 ++ ++/* PP_RxMISS */ ++#define MissCount(x) ((x) >> 6) ++ ++/* PP_TxCOL */ ++#define ColCount(x) ((x) >> 6) ++ ++/* PP_SelfST */ ++#define T3VActive 0x0040 ++#define INITD 0x0080 ++#define SIBUSY 0x0100 ++#define EEPROMpresent 0x0200 ++#define EEPROMOK 0x0400 ++#define ELpresent 0x0800 ++#define EEsize 0x1000 ++ ++/* PP_EEPROMCommand */ ++#define EEWriteRegister 0x0100 ++#define EEReadRegister 0x0200 ++#define EEEraseRegister 0x0300 ++#define ELSEL 0x0400 ++ ++#endif /* #ifndef CIRRUS_H */ +diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig +index 2a37b3f..8a8e831 100644 +--- a/drivers/pnp/Kconfig ++++ b/drivers/pnp/Kconfig +@@ -5,7 +5,7 @@ + menuconfig PNP + bool "Plug and Play support" + depends on HAS_IOMEM +- depends on ISA || ACPI ++# depends on ISA || ACPI + ---help--- + Plug and Play (PnP) is a standard for peripherals which allows those + peripherals to be configured by software, e.g. assign IRQ's or other +diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c +index 5dba909..fd77eb4 100644 +--- a/drivers/pnp/core.c ++++ b/drivers/pnp/core.c +@@ -74,6 +74,8 @@ int pnp_register_protocol(struct pnp_protocol *protocol) + return device_register(&protocol->dev); + } + ++EXPORT_SYMBOL(pnp_register_protocol); ++ + /** + * pnp_protocol_unregister - removes a pnp protocol from the pnp layer + * @protocol: pointer to the corresponding pnp_protocol structure +@@ -86,6 +88,8 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol) + device_unregister(&protocol->dev); + } + ++EXPORT_SYMBOL(pnp_unregister_protocol); ++ + static void pnp_free_ids(struct pnp_dev *dev) + { + struct pnp_id *id; +@@ -196,6 +200,8 @@ int pnp_add_device(struct pnp_dev *dev) + return 0; + } + ++EXPORT_SYMBOL(pnp_add_device); ++ + void __pnp_remove_device(struct pnp_dev *dev) + { + spin_lock(&pnp_lock); +@@ -205,6 +211,21 @@ void __pnp_remove_device(struct pnp_dev *dev) + device_unregister(&dev->dev); + } + ++/** ++ * pnp_remove_device - removes a pnp device from the pnp layer ++ * @dev: pointer to dev to add ++ * ++ * this function will free all mem used by dev ++ */ ++void pnp_remove_device(struct pnp_dev *dev) ++{ ++ if (!dev || dev->card) ++ return; ++ __pnp_remove_device(dev); ++} ++ ++EXPORT_SYMBOL(pnp_remove_device); ++ + static int __init pnp_init(void) + { + return bus_register(&pnp_bus_type); +diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c +index 527ee76..9e1132f 100644 +--- a/drivers/pnp/driver.c ++++ b/drivers/pnp/driver.c +@@ -259,3 +259,4 @@ EXPORT_SYMBOL(pnp_register_driver); + EXPORT_SYMBOL(pnp_unregister_driver); + EXPORT_SYMBOL(pnp_device_attach); + EXPORT_SYMBOL(pnp_device_detach); ++EXPORT_SYMBOL(pnp_add_id); +diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c +index ba97654..525211c 100644 +--- a/drivers/pnp/resource.c ++++ b/drivers/pnp/resource.c +@@ -406,6 +406,10 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res) + + int pnp_check_dma(struct pnp_dev *dev, struct resource *res) + { ++ printk("*********** %s, %s, line[%d]: Fix me, this should update in the future *********\n", ++ __FILE__, __FUNCTION__, __LINE__); ++ return 0; /* should be update in the future. Wolfgang ???*/ ++ + #ifndef CONFIG_IA64 + int i; + struct pnp_dev *tdev; +diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c +index fb867a9..e8d0962 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, + }, +@@ -2213,6 +2213,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 +2309,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 +2319,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 +2354,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 +2437,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 +2475,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 +diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig +index dcd49f1..0eb9723 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/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index 7f8e83a..29ca462 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -374,6 +374,61 @@ config SUPERH_BUILT_IN_M66592 + # Controllers available only in discrete form (and all PCI controllers) + # + ++config USB_GADGET_JZ4740 ++ boolean "JZ4740 UDC" ++ depends on SOC_JZ4740 ++ select USB_GADGET_DUALSPEED ++ help ++ Select this to support the Ingenic JZ4740 processor ++ high speed USB device controller. ++ ++config USB_JZ4740 ++ tristate ++ depends on USB_GADGET_JZ4740 ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ ++config USB_GADGET_JZ4750 ++ boolean "JZ4750 UDC" ++ depends on SOC_JZ4750 ++ select USB_GADGET_DUALSPEED ++ help ++ Select this to support the Ingenic JZ4750 processor ++ high speed USB device controller. ++ ++config USB_JZ4750 ++ tristate ++ depends on USB_GADGET_JZ4750 ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ ++config USB_GADGET_JZ4750D ++ boolean "JZ4750D UDC" ++ depends on SOC_JZ4750D ++ select USB_GADGET_DUALSPEED ++ help ++ Select this to support the Ingenic JZ4750D processor ++ high speed USB device controller. ++ ++config USB_JZ4750D ++ tristate ++ depends on USB_GADGET_JZ4750D ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ ++config USB_GADGET_JZ4730 ++ boolean "JZ4730 UDC" ++ depends on SOC_JZ4730 ++ help ++ Select this to support the Ingenic JZ4730 processor ++ full speed USB device controller. ++ ++config USB_JZ4730 ++ tristate ++ depends on USB_GADGET_JZ4730 ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ + config USB_GADGET_AMD5536UDC + boolean "AMD5536 UDC" + depends on PCI +@@ -702,6 +757,14 @@ config USB_FILE_STORAGE_TEST + behavior of USB Mass Storage hosts. Not needed for + normal operation. + ++config UDC_USE_LB_CACHE ++ bool "enable lb cache" ++ depends on USB_FILE_STORAGE && (SOC_JZ4740 || SOC_JZ4750 || SOC_JZ4750D) ++ default y ++ help ++ say "y" to enable lb cache and UDC work in faster speed. ++ say "n" to disable lb cache and UDC work in normal speed. ++ + config USB_G_SERIAL + tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" + help +diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile +index e6017e6..03e6df3 100644 +--- a/drivers/usb/gadget/Makefile ++++ b/drivers/usb/gadget/Makefile +@@ -27,6 +27,11 @@ obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o + obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o + obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o + obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o ++obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o ++obj-$(CONFIG_USB_JZ4730) += jz4730_udc.o ++obj-$(CONFIG_USB_JZ4750) += jz4740_udc.o ++obj-$(CONFIG_USB_JZ4750D) += jz4740_udc.o ++ + + # + # USB gadget drivers +diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c +index 1e6aa50..ba357c9 100644 +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -297,6 +297,18 @@ MODULE_LICENSE("Dual BSD/GPL"); + + + /*-------------------------------------------------------------------------*/ ++#if defined(CONFIG_UDC_USE_LB_CACHE) ++#define GHOST ++#endif ++ ++#ifdef GHOST ++extern unsigned long udc_read(unsigned long long offset, unsigned int len, unsigned char *); ++extern unsigned long udc_write(unsigned long long offset, unsigned int len, unsigned char *); ++extern int NAND_LB_Init(void); ++extern int NAND_LB_FLASHCACHE(void); ++extern int NAND_MTD_FLASHCACHE(void); ++extern int FlushDataState; ++#endif + + #define LDBG(lun,fmt,args...) \ + dev_dbg(&(lun)->dev , fmt , ## args) +@@ -575,7 +587,9 @@ struct lun { + unsigned int prevent_medium_removal : 1; + unsigned int registered : 1; + unsigned int info_valid : 1; +- ++#ifdef GHOST ++ unsigned int is_nand : 1; ++#endif + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; +@@ -819,6 +833,7 @@ static u32 get_unaligned_be24(u8 *buf) + #define STRING_SERIAL 3 + #define STRING_CONFIG 4 + #define STRING_INTERFACE 5 ++#define STRING_MS_OS 0xee + + /* There is only one configuration. */ + #define CONFIG_VALUE 1 +@@ -1006,6 +1021,7 @@ static struct usb_string strings[] = { + {STRING_SERIAL, serial}, + {STRING_CONFIG, "Self-powered"}, + {STRING_INTERFACE, "Mass Storage"}, ++ {STRING_MS_OS, "Microsoft"}, + {} + }; + +@@ -1627,9 +1643,20 @@ static int do_read(struct fsg_dev *fsg) + + /* Perform the read */ + file_offset_tmp = file_offset; ++#ifdef GHOST ++ if (curlun->is_nand) ++ nread = udc_read(file_offset_tmp, amount, bh->buf); ++ else ++ nread = vfs_read(curlun->filp, ++ (char __user *) bh->buf, ++ amount, &file_offset_tmp); ++ ++#else + nread = vfs_read(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); ++#endif ++ + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nread); +@@ -1813,9 +1840,18 @@ static int do_write(struct fsg_dev *fsg) + + /* Perform the write */ + file_offset_tmp = file_offset; ++#ifdef GHOST ++ if (curlun->is_nand) ++ nwritten = udc_write(file_offset_tmp, amount, bh->buf); ++ else ++ nwritten = vfs_write(curlun->filp, ++ (char __user *) bh->buf, ++ amount, &file_offset_tmp); ++#else + nwritten = vfs_write(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); ++#endif + VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nwritten); +@@ -1974,9 +2010,19 @@ static int do_verify(struct fsg_dev *fsg) + + /* Perform the read */ + file_offset_tmp = file_offset; ++#ifdef GHOST ++ if (curlun->is_nand) ++ nread = udc_read(file_offset_tmp, amount, bh->buf); ++ else ++ nread = vfs_read(curlun->filp, ++ (char __user *) bh->buf, ++ amount, &file_offset_tmp); ++#else + nread = vfs_read(curlun->filp, + (char __user *) bh->buf, + amount, &file_offset_tmp); ++#endif ++ + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nread); +@@ -2992,6 +3038,15 @@ static int do_scsi_command(struct fsg_dev *fsg) + reply = check_command(fsg, 6, DATA_DIR_NONE, + 0, 1, + "TEST UNIT READY"); ++#ifdef GHOST ++ if( FlushDataState >= 1) ++ FlushDataState++; ++ if(FlushDataState > 6) ++ { ++ NAND_LB_FLASHCACHE(); ++ FlushDataState = 0; ++ } ++#endif + break; + + /* Although optional, this command is used by MS-Windows. We +@@ -3544,6 +3599,13 @@ static int fsg_main_thread(void *fsg_) + + /* The main loop */ + while (fsg->state != FSG_STATE_TERMINATED) { ++#ifdef GHOST ++ if ((fsg->atomic_bitflags & SUSPENDED)) ++ { ++ NAND_LB_FLASHCACHE(); ++ NAND_MTD_FLASHCACHE(); ++ } ++#endif + if (exception_in_progress(fsg) || signal_pending(current)) { + handle_exception(fsg); + continue; +@@ -3675,6 +3737,13 @@ static int open_backing_file(struct lun *curlun, const char *filename) + curlun->num_sectors = num_sectors; + LDBG(curlun, "open backing file: %s\n", filename); + rc = 0; ++#ifdef GHOST ++ if (strstr(filename,"mtd")) ++ { ++ curlun->is_nand = 1; ++ NAND_LB_Init(); ++ } ++#endif + + out: + filp_close(filp, current->files); +diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h +index 8e0e9a0..553ff9e 100644 +--- a/drivers/usb/gadget/gadget_chips.h ++++ b/drivers/usb/gadget/gadget_chips.h +@@ -15,6 +15,18 @@ + #ifndef __GADGET_CHIPS_H + #define __GADGET_CHIPS_H + ++#ifdef CONFIG_USB_GADGET_JZ4740 ++#define gadget_is_jz4740(g) !strcmp("jz4740_udc", (g)->name) ++#else ++#define gadget_is_jz4740(g) 0 ++#endif ++ ++#ifdef CONFIG_USB_GADGET_JZ4730 ++#define gadget_is_jz4730(g) !strcmp("jz4730_udc", (g)->name) ++#else ++#define gadget_is_jz4730(g) 0 ++#endif ++ + #ifdef CONFIG_USB_GADGET_NET2280 + #define gadget_is_net2280(g) !strcmp("net2280", (g)->name) + #else +@@ -239,6 +251,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) + return 0x23; + else if (gadget_is_langwell(gadget)) + return 0x24; ++ else if (gadget_is_jz4730(gadget)) ++ return 0x25; ++ else if (gadget_is_jz4740(gadget)) ++ return 0x26; ++ + return -ENOENT; + } + +diff --git a/drivers/usb/gadget/jz4730_udc.c b/drivers/usb/gadget/jz4730_udc.c +new file mode 100644 +index 0000000..fb182a6 +--- /dev/null ++++ b/drivers/usb/gadget/jz4730_udc.c +@@ -0,0 +1,1403 @@ ++/* ++ * JZ4730 USB Device Controller driver ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++/* ++ * This device has ep0 and six bulk/interrupt/iso endpoints. ++ * ++ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep3in-bulk, ++ * ep4in-iso, ep5out-bulk, ep6out-bulk, ep7out-iso. ++ * - Gadget drivers can choose ep maxpacket (8/16/32/64). ++ * - Just PIO mode currently. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "jz4730_udc.h" ++ ++//#define DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args) ++//#define DEBUG_EP0(fmt,args...) printk(KERN_DEBUG fmt , ## args) ++ ++#ifndef DEBUG ++# define DEBUG(fmt,args...) do {} while(0) ++#endif ++#ifndef DEBUG_EP0 ++# define DEBUG_EP0(fmt,args...) do {} while(0) ++#endif ++ ++#define DRIVER_DESC "JZ4730 USB Device Controller" ++#define DRIVER_VERSION "20 Sep 2007" ++ ++static const char driver_name [] = "jz4730_udc"; ++static const char driver_desc [] = DRIVER_DESC; ++ ++static unsigned int udc_debug = 0; /* 0: normal mode, 1: test udc cable type mode */ ++ ++module_param(udc_debug, int, 0); ++MODULE_PARM_DESC(udc_debug, "test udc cable type"); ++ ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++extern int jz_udc_active; /* 0: No actions; 1: Have actions */ ++#endif ++ ++/* ++ * Local declarations. ++ */ ++static void nuke(struct jz4730_ep *, int status); ++static inline void pio_irq_enable(struct jz4730_ep *ep); ++static inline void pio_irq_disable(struct jz4730_ep *ep); ++static void jz4730_udc_release (struct device *dev) {} ++/*-------------------------------------------------------------------------*/ ++ ++static int jz4730_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct jz4730_udc *dev; ++ struct jz4730_ep *ep; ++ unsigned long flags; ++ u32 max; ++ ++ ep = container_of(_ep, struct jz4730_ep, ep); ++ if (!_ep || !desc || ep->desc ++ || desc->bDescriptorType != USB_DT_ENDPOINT) ++ return -EINVAL; ++ dev = ep->dev; ++ if (ep == &dev->ep[0]) ++ return -EINVAL; ++ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ if (ep->index != (desc->bEndpointAddress & 0x0f)) ++ return -EINVAL; ++ ++ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ case USB_ENDPOINT_XFER_INT: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++// max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); ++ max = 64; ++ ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ ep->stopped = 0; ++ ep->desc = desc; ++ ep->ep.maxpacket = max; ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG("enable %s %s maxpacket %u\n", ep->ep.name, ++ ep->is_in ? "IN" : "OUT", max); ++ ++ return 0; ++} ++ ++static int jz4730_ep_disable(struct usb_ep *_ep) ++{ ++ struct jz4730_ep *ep; ++ struct jz4730_udc *dev; ++ unsigned long flags; ++ ++ ep = container_of(_ep, struct jz4730_ep, ep); ++ if (!_ep || !ep->desc) ++ return -ENODEV; ++ dev = ep->dev; ++ if (dev->ep0state == EP0_SUSPEND) ++ return -EBUSY; ++ ++ DEBUG("disable %s\n", _ep->name); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ /* Nuke all pending requests */ ++ nuke(ep, -ESHUTDOWN); ++ ++ /* Disable ep IRQ */ ++ pio_irq_disable(ep); ++ ++ ep->desc = 0; ++ ep->stopped = 1; ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return 0; ++} ++ ++static struct usb_request *jz4730_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) ++{ ++ struct jz4730_request *req; ++ ++ req = kzalloc(sizeof *req, gfp_flags); ++ if (!req) ++ return 0; ++ ++ INIT_LIST_HEAD(&req->queue); ++ return &req->req; ++} ++ ++static void jz4730_free_request(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct jz4730_request *req; ++ ++ req = container_of(_req, struct jz4730_request, req); ++ WARN_ON(!list_empty(&req->queue)); ++ kfree(req); ++} ++ ++static void *jz4730_alloc_buffer(struct usb_ep *_ep, unsigned bytes, ++ dma_addr_t *dma, gfp_t gfp_flags) ++{ ++ void *retval; ++ ++ retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM)); ++ if (retval) ++ *dma = virt_to_phys(retval); ++ return retval; ++} ++ ++static void jz4730_free_buffer(struct usb_ep *_ep, void *buf, ++ dma_addr_t dma, unsigned bytes) ++{ ++ kfree(buf); ++} ++ ++/* ++ * done - retire a request; caller blocked irqs ++ */ ++static void done(struct jz4730_ep *ep, struct jz4730_request *req, int status) ++{ ++ struct jz4730_udc *dev; ++ unsigned stopped = ep->stopped; ++ ++ list_del_init(&req->queue); ++ ++ if (likely(req->req.status == -EINPROGRESS)) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ if (status && status != -ESHUTDOWN) ++ DEBUG("complete %s req %p stat %d len %u/%u\n", ++ ep->ep.name, &req->req, status, ++ req->req.actual, req->req.length); ++ ++ dev = ep->dev; ++ ++ /* don't modify queue heads during completion callback */ ++ ep->stopped = 1; ++ spin_unlock(&dev->lock); ++ req->req.complete(&ep->ep, &req->req); ++ spin_lock(&dev->lock); ++ ep->stopped = stopped; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static __inline__ int write_packet(struct jz4730_ep *ep, ++ struct jz4730_request *req, int max) ++{ ++ u8 *buf; ++ int length, nlong, nbyte; ++ volatile u32 *fifo = (volatile u32 *)ep->fifo; ++ ++ buf = req->req.buf + req->req.actual; ++ prefetch(buf); ++ ++ length = req->req.length - req->req.actual; ++ length = min(length, max); ++ req->req.actual += length; ++ ++ DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); ++ ++ if (!length) { ++ /* Send ZLP */ ++ writel(0, (unsigned int *)UDC_TXZLP); ++ writel(0x12345678, (unsigned int *)fifo); ++ } ++ else { ++ nlong = length >> 2; ++ nbyte = length & 0x3; ++ while (nlong--) { ++ *fifo = *((u32 *)buf); ++ buf += 4; ++ } ++ while (nbyte--) { ++ *((volatile u8 *)fifo) = *buf++; ++ } ++ } ++ ++ writel(0, (unsigned int *)UDC_TXCONFIRM); ++ ++ return length; ++} ++ ++static __inline__ int read_packet(struct jz4730_ep *ep, ++ struct jz4730_request *req, int count) ++{ ++ u8 *buf; ++ int length, nlong, nbyte; ++ volatile u32 *fifo = (volatile u32 *)ep->fifo; ++ ++ buf = req->req.buf + req->req.actual; ++ prefetchw(buf); ++ ++ length = req->req.length - req->req.actual; ++ length = min(length, count); ++ req->req.actual += length; ++ ++ DEBUG("Read %d, fifo %p\n", length, fifo); ++ ++ nlong = length >> 2; ++ nbyte = length & 0x3; ++ while (nlong--) { ++ *((u32 *)buf) = *fifo; ++ buf += 4; ++ } ++ if (nbyte) { ++ u32 data = *fifo; ++ while (nbyte--) { ++ *buf++ = data & 0x0ff; ++ data >>= 8; ++ } ++ } ++ ++ REG32(UDC_RXCONFIRM); ++ ++ return length; ++} ++ ++/** Write request to FIFO (max write == maxp size) ++ * Return: 0 = still running, 1 = completed, negative = errno ++ */ ++static int write_fifo(struct jz4730_ep *ep, struct jz4730_request *req) ++{ ++ u32 max, count; ++ int is_last; ++ ++ max = ep->ep.maxpacket; ++ ++ count = write_packet(ep, req, max); ++ ++ /* last packet often short (sometimes a zlp, especially on ep0) */ ++ if (unlikely(count != max)) { ++ is_last = 1; ++ } else { ++ if (likely(req->req.length != req->req.actual) ++ || req->req.zero) ++ is_last = 0; ++ else ++ is_last = 1; ++ } ++ ++ DEBUG("write %s (%d)(IN) %d bytes%s req %p %d/%d is_last %d\n", ++ ep->ep.name, ep->index, count, ++ (count != ep->ep.maxpacket) ? " (short)" : "", ++ req, req->req.actual, req->req.length, is_last); ++ ++ /* requests complete when all IN data is in the FIFO, ++ * or sometimes later, if a zlp was needed. ++ */ ++ if (is_last) { ++ done(ep, req, 0); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/** Read to request from FIFO (max read == bytes in fifo) ++ * Return: 0 = still running, 1 = completed, negative = errno ++ */ ++static int read_fifo(struct jz4730_ep *ep, struct jz4730_request *req, u32 count) ++{ ++ int is_short; ++ ++ is_short = (count < ep->ep.maxpacket); ++ ++ count = read_packet(ep, req, count); ++ ++ DEBUG("read %s %u bytes%s OUT req %p %u/%u is_short %d\n", ++ ep->ep.name, count, (count < ep->ep.maxpacket) ? "(short)" : "", ++ req, req->req.actual, req->req.length, is_short); ++ ++ /* completion */ ++ if (is_short || req->req.actual == req->req.length) { ++ done(ep, req, 0); ++ return 1; ++ } ++ ++ /* finished that packet. the next one may be waiting... */ ++ return 0; ++} ++ ++static inline void pio_irq_enable(struct jz4730_ep *ep) ++{ ++ switch (ep->index) { ++ case 0: ++ REG_UDC_EPIntMR &= ~0x1; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ REG_UDC_EPIntMR &= ~(1 << ep->index); ++ break; ++ case 5: ++ case 6: ++ case 7: ++ REG_UDC_EPIntMR &= ~(1 << (ep->index + 16)); ++ break; ++ } ++} ++ ++static inline void pio_irq_disable(struct jz4730_ep *ep) ++{ ++ switch (ep->index) { ++ case 0: ++ REG_UDC_EPIntMR |= 0x1; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ REG_UDC_EPIntMR |= (1 << ep->index); ++ break; ++ case 5: ++ case 6: ++ case 7: ++ REG_UDC_EPIntMR |= (1 << (ep->index + 16)); ++ break; ++ } ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int ++jz4730_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) ++{ ++ struct jz4730_request *req; ++ struct jz4730_ep *ep; ++ struct jz4730_udc *dev; ++ unsigned long flags; ++ int status; ++ ++ /* always require a cpu-view buffer so pio works */ ++ req = container_of(_req, struct jz4730_request, req); ++ if (unlikely(!_req || !_req->complete ++ || !_req->buf || !list_empty(&req->queue))) ++ return -EINVAL; ++ ep = container_of(_ep, struct jz4730_ep, ep); ++ if (unlikely(!_ep || (!ep->desc && ep->index != 0))) ++ return -EINVAL; ++ dev = ep->dev; ++ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) ++ return -ESHUTDOWN; ++ ++ DEBUG("%s queue req %p, len %u buf %p\n", ++ _ep->name, _req, _req->length, _req->buf); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ _req->status = -EINPROGRESS; ++ _req->actual = 0; ++ ++ /* for ep0 IN without premature status, zlp is required and ++ * writing EOP starts the status stage (OUT). ++ */ ++ if (unlikely(ep->index == 0 && ep->is_in)) ++ _req->zero = 1; ++ ++ /* kickstart this i/o queue? */ ++ status = 0; ++ if (list_empty(&ep->queue) && likely(!ep->stopped)) { ++ if (unlikely(ep->index == 0)) { ++ pio_irq_enable(ep); ++ if (ep->irq_pending || ++ (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0)) { ++ u32 stats, count; ++ ++ stats = REG_UDC_EP0OutSR; ++ if (stats & UDC_EPSR_OUT_RCVDATA) { ++ ep->irq_pending = 0; ++ REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK; ++ if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0) ++ REG_UDC_EPIntR = UDC_EPIntR_OUTEP0; ++ ++ count = OUT_COUNT(stats); ++ if (read_fifo(ep, req, count) == 1) ++ req = 0; ++ } ++ } ++ ++ } else if (ep->is_in) { ++ /* EP1 ~ EP4 */ ++ if (ep->irq_pending || ++ (REG_UDC_EPIntR & UDC_EPIntR_INEP2)) { ++ if (REG_UDC_EP2InSR & UDC_EPSR_IN) { ++ ep->irq_pending = 0; ++ REG_UDC_EP2InSR &= ~UDC_EPSR_IN; ++ if (REG_UDC_EPIntR & UDC_EPIntR_INEP2) ++ REG_UDC_EPIntR = UDC_EPIntR_INEP2; ++ ++ if (write_fifo(ep, req) == 1) ++ req = 0; ++ } ++ } ++ pio_irq_enable(ep); ++ } else { ++ /* EP5 ~ EP7 */ ++ pio_irq_enable(ep); ++ ++ if (ep->irq_pending || ++ (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)) { ++ u32 stats, count; ++ ++ stats = REG_UDC_EP5OutSR; ++ if (stats & UDC_EPSR_OUT_RCVDATA) { ++ ep->irq_pending = 0; ++ REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK; ++ if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5) ++ REG_UDC_EPIntR = UDC_EPIntR_OUTEP5; ++ ++ count = OUT_COUNT(stats); ++ if (read_fifo(ep, req, count) == 1) ++ req = 0; ++ } ++ } ++ } ++ } ++ ++ /* pio or dma irq handler advances the queue. */ ++ if (likely(req != 0)) { ++ list_add_tail(&req->queue, &ep->queue); ++ } ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return status; ++} ++ ++/* dequeue ALL requests */ ++static void nuke(struct jz4730_ep *ep, int status) ++{ ++ struct jz4730_request *req; ++ ++ if (list_empty(&ep->queue)) ++ return; ++ while (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, struct jz4730_request, queue); ++ done(ep, req, status); ++ } ++} ++ ++/* dequeue JUST ONE request */ ++static int jz4730_dequeue(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct jz4730_request *req; ++ struct jz4730_ep *ep; ++ struct jz4730_udc *dev; ++ unsigned long flags; ++ int stopped; ++ ++ ep = container_of(_ep, struct jz4730_ep, ep); ++ if (!_ep || !_req || (!ep->desc && ep->index != 0)) ++ return -EINVAL; ++ dev = ep->dev; ++ if (!dev->driver) ++ return -ESHUTDOWN; ++ ++ DEBUG("%s %s %p\n", __FUNCTION__, _ep->name,_req); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ stopped = ep->stopped; ++ ep->stopped = 1; ++ ++ /* make sure it's actually queued on this endpoint */ ++ list_for_each_entry (req, &ep->queue, queue) { ++ if (&req->req == _req) ++ break; ++ } ++ if (&req->req != _req) { ++ spin_unlock_irqrestore (&dev->lock, flags); ++ return -EINVAL; ++ } ++ ++ /* queue head may be partially complete. */ ++ if (ep->queue.next == &req->queue) { ++ done (ep, req, -ECONNRESET); ++ req = 0; ++ } ++ ++ if (req) ++ done (ep, req, -ECONNRESET); ++ ep->stopped = stopped; ++ ++ spin_unlock_irqrestore (&ep->dev->lock, flags); ++ return req ? 0 : -EOPNOTSUPP; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz4730_clear_halt(struct jz4730_ep *ep) ++{ ++ if (ep->stopped) { ++ ep->stopped = 0; ++ } ++} ++ ++static int jz4730_set_halt(struct usb_ep *_ep, int value) ++{ ++ struct jz4730_ep *ep; ++ unsigned long flags; ++ int retval = 0; ++ ++ if (!_ep) ++ return -ENODEV; ++ ep = container_of (_ep, struct jz4730_ep, ep); ++ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03) ++ == USB_ENDPOINT_XFER_ISOC) ++ return -EINVAL; ++ ++ if (ep->index == 0) { ++ if (value) { ++ ep->dev->ep0state = EP0_STALL; ++ ep->dev->ep[0].stopped = 1; ++ } else ++ return -EINVAL; ++ ++ /* don't change EPxSTATUS_EP_INVALID to READY */ ++ } else if (!ep->desc) { ++ DEBUG("%s %s inactive?\n", __FUNCTION__, ep->ep.name); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ if (!list_empty(&ep->queue)) ++ retval = -EAGAIN; ++ else if (!value) ++ jz4730_clear_halt(ep); ++ else { ++ ep->stopped = 1; ++ } ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return retval; ++} ++ ++static int jz4730_fifo_status(struct usb_ep *_ep) ++{ ++ struct jz4730_ep *ep; ++ u32 size = 0; ++ ++ if (!_ep) ++ return -ENODEV; ++ ep = container_of(_ep, struct jz4730_ep, ep); ++ ++ /* size is only reported sanely for OUT */ ++ if (ep->is_in) ++ return -EOPNOTSUPP; ++ ++ return size; ++} ++ ++static void jz4730_fifo_flush(struct usb_ep *_ep) ++{ ++ struct jz4730_ep *ep; ++ ++ if (!_ep) ++ return; ++ ep = container_of(_ep, struct jz4730_ep, ep); ++ ++ /* don't change EPxSTATUS_EP_INVALID to READY */ ++ if (!ep->desc && ep->index != 0) { ++ return; ++ } ++} ++ ++static struct usb_ep_ops jz4730_ep_ops = { ++ .enable = jz4730_ep_enable, ++ .disable = jz4730_ep_disable, ++ ++ .alloc_request = jz4730_alloc_request, ++ .free_request = jz4730_free_request, ++#if 0 ++ .alloc_buffer = jz4730_alloc_buffer, ++ .free_buffer = jz4730_free_buffer, ++#endif ++ .queue = jz4730_queue, ++ .dequeue = jz4730_dequeue, ++ ++ .set_halt = jz4730_set_halt, ++ .fifo_status = jz4730_fifo_status, ++ .fifo_flush = jz4730_fifo_flush, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int jz4730_get_frame(struct usb_gadget *_gadget) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static const struct usb_gadget_ops jz4730_ops = { ++ .get_frame = jz4730_get_frame, ++ // no remote wakeup ++ // not selfpowered ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void udc_reinit(struct jz4730_udc *dev) ++{ ++ static char *names [] = { "ep0", "ep1in-int", "ep2in-bulk", "ep3in-bulk", ++ "ep4in-iso", "ep5out-bulk", "ep6out-bulk", ++ "ep7out-iso" }; ++ int i; ++ ++ INIT_LIST_HEAD (&dev->gadget.ep_list); ++ dev->gadget.ep0 = &dev->ep[0].ep; ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ dev->ep0state = EP0_DISCONNECT; ++ ++ for (i = 0; i < MAX_EP_NUM; i++) { ++ struct jz4730_ep *ep = &dev->ep[i]; ++ ++ ep->index = i; ++ ep->ep.name = names[i]; ++ ep->fifo = ep_fifo[i]; ++ ep->ep.maxpacket = 64; ++ ++ ep->ep.ops = &jz4730_ep_ops; ++ list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ++ ep->dev = dev; ++ INIT_LIST_HEAD(&ep->queue); ++ ++ ep->desc = 0; ++ ep->stopped = 1; ++ ep->irq_pending = 0; ++ } ++ ++ dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; ++ list_del_init(&dev->ep[0].ep.ep_list); ++} ++ ++/* Reset udc registers */ ++static void udc_reset(struct jz4730_udc *dev) ++{ ++ REG_UDC_DevIntMR = 0x32; /* Enable RESET and SC interrupts */ ++ REG_UDC_EPIntMR = 0x0; /* Enable all EP interrupts */ ++ REG_UDC_DevCFGR = 0x17; ++ REG_UDC_DevCR = 0x0; ++ ++ REG_UDC_EP0InCR = (0 << 4) | (1 << 1); ++ REG_UDC_EP0InCR = (0 << 4); ++ REG_UDC_EP1InCR = (3 << 4) | (1 << 1); ++ REG_UDC_EP1InCR = (3 << 4); ++ REG_UDC_EP2InCR = (2 << 4) | (1 << 1); ++ REG_UDC_EP2InCR = (2 << 4); ++ REG_UDC_EP3InCR = (2 << 4) | (1 << 1); ++ REG_UDC_EP3InCR = (2 << 4); ++ REG_UDC_EP4InCR = (1 << 4) | (1 << 1); ++ REG_UDC_EP4InCR = (1 << 4); ++ ++ REG_UDC_EP0OutCR = (0 << 4); ++ REG_UDC_EP5OutCR = (2 << 4); ++ REG_UDC_EP6OutCR = (2 << 4); ++ REG_UDC_EP7OutCR = (1 << 4); ++ ++ REG_UDC_EP0InSR = 0; ++ REG_UDC_EP1InSR = 0; ++ REG_UDC_EP2InSR = 0; ++ REG_UDC_EP3InSR = 0; ++ REG_UDC_EP4InSR = 0; ++ REG_UDC_EP5OutSR = 0; ++ REG_UDC_EP6OutSR = 0; ++ REG_UDC_EP7OutSR = 0; ++ ++ REG_UDC_EP0InBSR = MAX_EP0_SIZE/4; ++ REG_UDC_EP1InBSR = MAX_EP1_SIZE/4; ++ REG_UDC_EP2InBSR = MAX_EP2_SIZE/4; ++ REG_UDC_EP3InBSR = MAX_EP3_SIZE/4; ++ REG_UDC_EP4InBSR = MAX_EP4_SIZE/4; ++ ++ REG_UDC_EP0InMPSR = MAX_EP0_SIZE; ++ REG_UDC_EP1InMPSR = MAX_EP1_SIZE; ++ REG_UDC_EP2InMPSR = MAX_EP2_SIZE; ++ REG_UDC_EP3InMPSR = MAX_EP3_SIZE; ++ REG_UDC_EP4InMPSR = MAX_EP4_SIZE; ++ ++ REG_UDC_EP0OutMPSR = MAX_EP0_SIZE; ++ REG_UDC_EP5OutMPSR = MAX_EP5_SIZE; ++ REG_UDC_EP6OutMPSR = MAX_EP6_SIZE; ++ REG_UDC_EP7OutMPSR = MAX_EP7_SIZE; ++ ++ REG_UDC_EP0InfR = (MAX_EP0_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (0 << 5) | (0 << 4) | (0 << 0); ++ REG_UDC_EP1InfR = (MAX_EP1_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (3 << 5) | (1 << 4) | (1 << 0); ++ REG_UDC_EP2InfR = (MAX_EP2_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (2 << 0); ++ REG_UDC_EP3InfR = (MAX_EP3_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (3 << 0); ++ REG_UDC_EP4InfR = (MAX_EP4_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (1 << 4) | (4 << 0); ++ REG_UDC_EP5InfR = (MAX_EP5_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (5 << 0); ++ REG_UDC_EP6InfR = (MAX_EP6_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (6 << 0); ++ REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0); ++ ++ REG_UDC_STCMAR = 0xffff; ++} ++ ++static void ep0_start(struct jz4730_udc *dev) ++{ ++ udc_reset(dev); ++ udc_reinit(dev); ++ ++ /* expect ep0 requests when the host drops reset */ ++ dev->gadget.speed = USB_SPEED_FULL; ++ dev->ep0state = EP0_IDLE; ++} ++ ++static void udc_enable(struct jz4730_udc *dev) ++{ ++ /* Enable udc and enable all interrupts */ ++ __intc_unmask_irq(IRQ_UDC); ++ __harb_usb0_udc(); ++ ++ /* start enumeration now, or after power detect irq */ ++ ep0_start(dev); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* keeping it simple: ++ * - one bus driver, initted first; ++ * - one function driver, initted second ++ */ ++ ++static struct jz4730_udc *the_controller; ++ ++/* when a driver is successfully registered, it will receive ++ * control requests including set_configuration(), which enables ++ * non-control requests. then usb traffic follows until a ++ * disconnect is reported. then a host may connect again, or ++ * the driver might get unbound. ++ */ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ struct jz4730_udc *dev = the_controller; ++ int retval; ++ ++ if (!driver ++// || driver->speed != USB_SPEED_FULL ++ || !driver->bind ++ || !driver->unbind ++ || !driver->disconnect ++ || !driver->setup) ++ { ++ printk("\n -EINVAL"); ++ return -EINVAL; ++ } ++ if (!dev) ++ return -ENODEV; ++ ++ if (dev->driver) ++ return -EBUSY; ++ ++ /* hook up the driver */ ++ dev->driver = driver; ++ retval = driver->bind(&dev->gadget); ++ if (retval) { ++ DEBUG("bind to driver %s --> error %d\n", ++ driver->driver.name, retval); ++ dev->driver = 0; ++ return retval; ++ } ++ /* then enable host detection and ep0; and we're ready ++ * for set_configuration as well as eventual disconnect. ++ */ ++ udc_enable(dev); ++ ++ DEBUG("registered gadget driver '%s'\n", driver->driver.name); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++static void ++stop_activity(struct jz4730_udc *dev, struct usb_gadget_driver *driver) ++{ ++ unsigned i; ++ ++ DEBUG("%s\n", __FUNCTION__); ++ ++ if (dev->gadget.speed == USB_SPEED_UNKNOWN) ++ driver = 0; ++ ++ /* disconnect gadget driver after quiesceing hw and the driver */ ++ udc_reset (dev); ++ for (i = 0; i < MAX_EP_NUM; i++) ++ nuke(&dev->ep [i], -ESHUTDOWN); ++ if (driver) { ++ spin_unlock(&dev->lock); ++ driver->disconnect(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ ++ if (dev->driver) ++ udc_enable(dev); ++} ++ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct jz4730_udc *dev = the_controller; ++ unsigned long flags; ++ ++ /* disable UDC irq */ ++ __intc_mask_irq(IRQ_UDC); ++ __harb_usb0_uhc(); ++ ++ if (!dev) ++ return -ENODEV; ++ if (!driver || driver != dev->driver) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ dev->driver = 0; ++ stop_activity(dev, driver); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ driver->unbind(&dev->gadget); ++ ++ DEBUG("unregistered driver '%s'\n", driver->driver.name); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++static void jz4730_epn_out(struct jz4730_udc *dev, int ep_idx, u32 count) ++{ ++ struct jz4730_request *req; ++ struct jz4730_ep *ep = &dev->ep[ep_idx]; ++ ++ req = list_entry(ep->queue.next, struct jz4730_request, queue); ++ read_fifo(ep, req, count); ++} ++ ++static void jz4730_epn_in(struct jz4730_udc *dev, int ep_idx) ++{ ++ struct jz4730_request *req; ++ struct jz4730_ep *ep = &dev->ep[ep_idx]; ++ ++ req = list_entry(ep->queue.next, struct jz4730_request, queue); ++ write_fifo(ep, req); ++} ++ ++/****************************************************************/ ++/* End Point 0 related functions */ ++/****************************************************************/ ++ ++/* return: 0 = still running, 1 = completed, negative = errno */ ++static int write_fifo_ep0(struct jz4730_ep *ep, struct jz4730_request *req) ++{ ++ u32 max, count; ++ int is_last; ++ ++ max = ep->ep.maxpacket; ++ ++ count = write_packet(ep, req, max); ++ ++ /* last packet is usually short (or a zlp) */ ++ if (unlikely(count != max)) ++ is_last = 1; ++ else { ++ if (likely(req->req.length != req->req.actual) || req->req.zero) ++ is_last = 0; ++ else ++ is_last = 1; ++ } ++ ++ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, ++ ep->ep.name, count, ++ is_last ? "/L" : "", req->req.length - req->req.actual, req); ++ ++ /* requests complete when all IN data is in the FIFO */ ++ if (is_last) { ++ done(ep, req, 0); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Simulate a USB_REQ_SET_CONFIGURATION to the function driver, ++ * this is required to enable the endpoints of the function driver. ++ * UDC should let software have the chance to handle this standard ++ * request, unfortunately UDC can't do that. ++ */ ++static void psudo_set_config(void) ++{ ++ struct jz4730_udc *dev = (struct jz4730_udc *) the_controller; ++ struct usb_ctrlrequest ctrl; ++ int tmp; ++ ++ /* SETUP packet */ ++ ctrl.bRequestType = 0x00; ++ ctrl.bRequest = USB_REQ_SET_CONFIGURATION; ++ ctrl.wValue = 1; ++ ctrl.wIndex = 0; ++ ctrl.wLength = 0; ++ ++ nuke(&dev->ep[0], 0); ++ dev->ep[0].stopped = 0; ++ ++ if (likely(ctrl.bRequestType & USB_DIR_IN)) { ++ dev->ep[0].is_in = 1; ++ dev->ep0state = EP0_IN; ++ } else { ++ dev->ep[0].is_in = 0; ++ dev->ep0state = EP0_OUT; ++ } ++ ++ /* delegate everything to the gadget driver. ++ * it may respond after this irq handler returns. ++ */ ++ spin_unlock (&dev->lock); ++ tmp = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock (&dev->lock); ++ if (unlikely(tmp < 0)) { ++ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n", ++ ctrl.bRequestType, ctrl.bRequest, tmp); ++ dev->ep[0].stopped = 1; ++ dev->ep0state = EP0_STALL; ++ } ++} ++ ++/* ++ * Read 8 bytes setup packet from EP0 RX buffer ++ */ ++static void read_setup_packet(u8 *buf) ++{ ++ u32 *tmp = (u32 *)buf; ++ ++ *tmp++ = readl((unsigned int *)RXFIFO); ++ *tmp++ = readl((unsigned int *)RXFIFO); ++ ++ REG32(UDC_RXCONFIRM); ++} ++ ++static void jz4730_ep0_setup(struct jz4730_udc *dev) ++{ ++ struct jz4730_ep *ep = &dev->ep[0]; ++ struct usb_ctrlrequest ctrl; ++ int tmp; ++ ++ /* read control req from fifo (8 bytes) */ ++ read_setup_packet((unsigned char *) &ctrl); ++ ++ DEBUG_EP0("SETUP %02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bRequestType, ctrl.bRequest, ++ ctrl.wValue, ctrl.wIndex, ctrl.wLength); ++ ++ /* Set direction of EP0 */ ++ if (likely(ctrl.bRequestType & USB_DIR_IN)) { ++ ep->is_in = 1; ++ dev->ep0state = EP0_IN; ++ } else { ++ ep->is_in = 0; ++ dev->ep0state = EP0_OUT; ++ } ++ ++ /* Nuke all previous transfers */ ++ nuke(ep, 0); ++ ep->stopped = 0; ++ ++ /* delegate everything to the gadget driver. ++ * it may respond after this irq handler returns. ++ */ ++ if (likely((u32)dev->driver)) { ++ /* device-2-host (IN) or no data setup command, process immediately */ ++ spin_unlock(&dev->lock); ++ tmp = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock(&dev->lock); ++ ++ if (unlikely(tmp < 0)) { ++ /* setup processing failed, force stall */ ++ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n", ++ ctrl.bRequestType, ctrl.bRequest, tmp); ++ dev->ep0state = EP0_STALL; ++ } ++ } ++} ++ ++static int jz4730_ep0_in(struct jz4730_udc *dev) ++{ ++ struct jz4730_request *req; ++ struct jz4730_ep *ep = &dev->ep[0]; ++ int ret; ++ ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = list_entry(ep->queue.next, struct jz4730_request, queue); ++ ++ if (!req) { ++ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); ++ return 0; ++ } ++ ++ ret = write_fifo_ep0(ep, req); ++ ++ return ret; ++} ++ ++static void jz4730_ep0_out(struct jz4730_udc *dev) ++{ ++ u32 epsr; ++ struct jz4730_ep *ep = &dev->ep[0]; ++ ++ epsr = REG_UDC_EP0OutSR; ++ REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK; ++ ++ if (epsr & UDC_EPSR_OUT_RCVSETUP) { ++ jz4730_ep0_setup(dev); ++ } ++ else if (epsr & UDC_EPSR_OUT_RCVDATA) { ++ u32 count = __udc_ep0out_packet_size(); ++ if (count == 0) { ++ readl((unsigned int *)UDC_RXCONFIRM); // ack zero packet ++ } ++ else { ++ /* EP0 OUT Data */ ++ if (list_empty(&ep->queue)) { ++ ep->irq_pending = 1; ++ pio_irq_disable(ep); ++ } ++ else ++ jz4730_epn_out(dev, 0, count); ++ ++ } ++ } ++} ++ ++static void handle_reset_irq(struct jz4730_udc *dev) ++{ ++ int i; ++ ++ /* clear any status */ ++ REG_UDC_EPIntR = 0xffffffff; ++ REG_UDC_DevIntR = 0xffffffff; ++ ++ /* reset udc */ ++ udc_reset(dev); ++ ++ /* reset driver status */ ++ for (i = 0; i < MAX_EP_NUM; i++) { ++ struct jz4730_ep *ep = &dev->ep[i]; ++ ++ ep->irq_pending = 0; ++// nuke(ep, 0); ++ nuke(ep, -ESHUTDOWN); ++ } ++} ++ ++static irqreturn_t jz4730_udc_irq(int irq, void *_dev) ++{ ++ struct jz4730_udc *dev = _dev; ++ struct jz4730_ep *ep; ++ ++ u32 intr_dev, intr_ep, stats, count; ++ ++ spin_lock(&dev->lock); ++ ++ intr_dev = REG_UDC_DevIntR; ++ intr_ep = REG_UDC_EPIntR; ++ ++ DEBUG("*** udc irq intr_dev=0x%x intr_ep=0x%x\n", intr_dev, intr_ep); ++ ++ if (!intr_dev && !intr_ep) { ++ spin_unlock(&dev->lock); ++ return IRQ_HANDLED; ++ } ++ ++ if (udc_debug) { ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++ jz_udc_active = 1; ++#endif ++ REG_UDC_DevIntR = intr_dev; ++ REG_UDC_EPIntR = intr_ep; ++ __harb_usb0_uhc(); ++ __intc_mask_irq(IRQ_UDC); ++ spin_unlock(&dev->lock); ++ return IRQ_HANDLED; ++ } ++ ++ if (intr_dev) { ++ if (intr_dev & UDC_DevIntR_SC) { ++ psudo_set_config(); ++ udelay(100); ++ } ++ ++ if (intr_dev & UDC_DevIntR_UR) { ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++ jz_udc_active = 1; ++#endif ++ handle_reset_irq(dev); ++ } ++ ++ REG_UDC_DevIntR = intr_dev; ++ } ++ ++ if (intr_ep & UDC_EPIntR_OUTEP0) { ++ REG_UDC_EPIntR = UDC_EPIntR_OUTEP0; ++ jz4730_ep0_out(dev); ++ } ++ ++ if (intr_ep & UDC_EPIntR_INEP0) { ++ ep = &dev->ep[0]; ++ if (list_empty(&ep->queue)) { ++ pio_irq_disable(ep); ++ } ++ else { ++ stats = REG_UDC_EP0InSR; ++ if (stats & UDC_EPSR_IN) { ++ REG_UDC_EPIntR = UDC_EPIntR_INEP0; ++ REG_UDC_EP0InSR &= ~UDC_EPSR_IN; ++ ++ jz4730_ep0_in(dev); ++ } ++ } ++ } ++ ++ if (intr_ep & UDC_EPIntR_OUTEP5) { ++ REG_UDC_EPIntR = UDC_EPIntR_OUTEP5; ++ ep = &dev->ep[5]; ++ if (list_empty(&ep->queue)) { ++ ep->irq_pending = 1; ++ pio_irq_disable(ep); ++ } ++ else { ++ stats = REG_UDC_EP5OutSR; ++ if (stats & UDC_EPSR_OUT_RCVDATA) { ++ REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK; ++ ++ count = OUT_COUNT(stats); ++ jz4730_epn_out(dev, 5, count); ++ } ++ } ++ } ++ ++ if (intr_ep & UDC_EPIntR_INEP2) { ++ ep = &dev->ep[2]; ++ if (list_empty(&ep->queue)) { ++ ep->irq_pending = 1; ++ pio_irq_disable(ep); ++ } ++ else { ++ stats = REG_UDC_EP2InSR; ++ if (stats & UDC_EPSR_IN) { ++ REG_UDC_EP2InSR &= ~UDC_EPSR_IN; ++ jz4730_epn_in(dev, 2); ++ } ++ } ++ ++ REG_UDC_EPIntR = UDC_EPIntR_INEP2; ++ } ++ ++ if (intr_ep & UDC_EPIntR_INEP1) { ++ ep = &dev->ep[1]; ++ if (list_empty(&ep->queue)) { ++ ep->irq_pending = 1; ++ pio_irq_disable(ep); ++ } ++ else { ++ stats = REG_UDC_EP1InSR; ++ if (stats & UDC_EPSR_IN) { ++ REG_UDC_EP1InSR &= ~UDC_EPSR_IN; ++ jz4730_epn_in(dev, 1); ++ } ++ } ++ ++ REG_UDC_EPIntR = UDC_EPIntR_INEP1; ++ } ++ ++ spin_unlock(&dev->lock); ++ return IRQ_HANDLED; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct jz4730_udc udc_dev = { ++ .usb_address = 0, ++ ++ .gadget = { ++ .ops = &jz4730_ops, ++ .ep0 = &udc_dev.ep[0].ep, ++ .name = driver_name, ++ .dev = { ++ .bus_id = "gadget", ++ }, ++ }, ++ /* control endpoint no need to init here!*/ ++ /* control endpoint */ ++}; ++ ++ ++/* tear down the binding between this driver and the pci device */ ++static int jz4730_udc_remove(struct platform_device *pdev) ++{ ++ struct jz4730_udc *dev = platform_get_drvdata(pdev); ++ ++ if (dev->driver) ++ return -EBUSY; ++ ++ /* USB port0 as UHC */ ++ __harb_usb0_uhc(); ++ ++ /* reset udc */ ++ udc_reset(dev); ++ ++ /* clear any status */ ++ REG_UDC_EPIntR = 0xffffffff; ++ REG_UDC_DevIntR = 0xffffffff; ++ ++ /* disable all UDC interrupts */ ++ REG_UDC_DevIntMR = 0xffffffff; ++ REG_UDC_EPIntMR = 0xffffffff; ++ ++ free_irq(IRQ_UDC, dev); ++ platform_set_drvdata(pdev, 0); ++ device_unregister(&dev->gadget.dev); ++ the_controller = 0; ++ ++ return 0; ++} ++ ++static int jz4730_udc_probe(struct platform_device *pdev) ++{ ++ struct jz4730_udc *dev = &udc_dev; ++ int retval,rc; ++ ++ /* if you want to support more than one controller in a system, ++ * usb_gadget_driver_{register,unregister}() must change. ++ */ ++ if (the_controller) { ++ printk("Check the_controller: %s\n", driver_name); ++ return -EBUSY; ++ } ++ ++ spin_lock_init(&dev->lock); ++ device_initialize(&dev->gadget.dev); ++ dev->gadget.dev.parent = &pdev->dev; //if no,can only insmod once!! ++ dev->gadget.dev.release = jz4730_udc_release; ++ rc = device_register (&dev->gadget.dev); ++ if (rc < 0) ++ return rc; ++ platform_set_drvdata(pdev, dev); ++ ++ /* ++ * Note: we just mask INTC irq but allow UDC irq. ++ * This avoid that we miss any UDC irqs. ++ */ ++ ++ /* To avoid any UDC irqs here, we call cli() first */ ++// cli(); ++ ++ /* disable INTC irq */ ++ __intc_mask_irq(IRQ_UDC); ++ ++ /* init to known state, then setup irqs */ ++ udc_reset(dev); ++ udc_reinit(dev); ++ ++ /* request UDC irq */ ++ if (request_irq(IRQ_UDC, jz4730_udc_irq, IRQF_DISABLED, // SA_INTERRUPT, ++ driver_name, dev) != 0) { ++ printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC); ++ retval = -EBUSY; ++ goto done; ++ } ++ ++ /* disable INTC irq again since request_irq has enabled it */ ++ __intc_mask_irq(IRQ_UDC); ++ __intc_ack_irq(IRQ_UDC); ++ ++ /* Re-enable irqs */ ++// sti(); ++ ++ printk(KERN_INFO "%s\n", driver_desc); ++ printk(KERN_INFO "version: " DRIVER_VERSION "\n"); ++ ++ /* done */ ++ the_controller = dev; ++ ++ return 0; ++ ++done: ++ if (dev) ++ jz4730_udc_remove (pdev); ++ return retval; ++} ++ ++static struct platform_driver udc_driver = { ++ .probe = jz4730_udc_probe, ++ .remove = jz4730_udc_remove, ++ .suspend = NULL, ++ .resume = NULL, ++ .driver = { ++ .name = (char *) driver_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++static struct platform_device the_udc_pdev = { ++ .name = (char *) driver_name, ++ .id = -1, ++ .dev = { ++ .release = jz4730_udc_release, ++ }, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int __init udc_init (void) ++{ ++ platform_driver_register(&udc_driver); ++ return platform_device_register (&the_udc_pdev); ++} ++ ++static void __exit udc_exit (void) ++{ ++ platform_driver_unregister(&udc_driver); ++ platform_device_unregister(&the_udc_pdev); ++} ++ ++module_init(udc_init); ++module_exit(udc_exit); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR("Wei Jianli "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/usb/gadget/jz4730_udc.h b/drivers/usb/gadget/jz4730_udc.h +new file mode 100644 +index 0000000..6ea368b +--- /dev/null ++++ b/drivers/usb/gadget/jz4730_udc.h +@@ -0,0 +1,107 @@ ++/* ++ * JZ4730 USB Device Controller driver ++ * ++ * Copyright (C) 2005 by Wei Jianli ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#ifndef __JZ4730_UDC_H__ ++#define __JZ4730_UDC_H__ ++ ++/* DRIVER DATA STRUCTURES and UTILITIES */ ++#define MAX_EP_NUM 8 /* Number of endpoints on this UDC */ ++ ++#define MAX_EP0_SIZE 32 ++#define MAX_EP1_SIZE 64 ++#define MAX_EP2_SIZE 64 ++#define MAX_EP3_SIZE 64 ++#define MAX_EP4_SIZE 64 ++#define MAX_EP5_SIZE 64 ++#define MAX_EP6_SIZE 64 ++#define MAX_EP7_SIZE 64 ++ ++// UDC FIFO ++#define RXFIFO (UDC_RXFIFO) /* EP0 OUT, EP5-7 OUT */ ++#define TXFIFOEP0 (UDC_TXFIFOEP0) /* EP0 IN */ ++#define TXFIFOEP1 (TXFIFOEP0 + MAX_EP0_SIZE) /* EP1 IN */ ++#define TXFIFOEP2 (TXFIFOEP1 + MAX_EP1_SIZE) /* EP2 IN */ ++#define TXFIFOEP3 (TXFIFOEP2 + MAX_EP2_SIZE) /* EP3 IN */ ++#define TXFIFOEP4 (TXFIFOEP3 + MAX_EP3_SIZE) /* EP4 IN */ ++ ++static u32 ep_fifo[MAX_EP_NUM] = {TXFIFOEP0, TXFIFOEP1, TXFIFOEP2, ++ TXFIFOEP3, TXFIFOEP4, RXFIFO, RXFIFO, ++ RXFIFO}; ++ ++#define OUT_COUNT(stats) \ ++ ((stats&UDC_EPSR_RXPKTSIZE_MASK)>>UDC_EPSR_RXPKTSIZE_BIT) ++ ++struct jz4730_ep { ++ struct usb_ep ep; ++ struct jz4730_udc *dev; ++ ++ u8 index; ++ u8 is_in; ++ u8 stopped; ++ u8 irq_pending; ++ u32 fifo; ++ ++ struct list_head queue; ++ const struct usb_endpoint_descriptor *desc; ++}; ++ ++struct jz4730_request { ++ struct usb_request req; ++ struct list_head queue; ++}; ++ ++enum ep0state { ++ EP0_DISCONNECT, /* no host */ ++ EP0_IDLE, /* between STATUS ack and SETUP report */ ++ EP0_IN, EP0_OUT, /* data stage */ ++ EP0_STATUS, /* status stage */ ++ EP0_STALL, /* data or status stages */ ++ EP0_SUSPEND, /* usb suspend */ ++}; ++ ++struct jz4730_udc { ++ struct usb_gadget gadget; ++ struct usb_gadget_driver *driver; ++ spinlock_t lock; ++ ++ struct jz4730_ep ep[MAX_EP_NUM]; ++ enum ep0state ep0state; ++ unsigned char usb_address; ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* 2.5 stuff that's sometimes missing in 2.4 */ ++ ++#ifndef container_of ++#define container_of list_entry ++#endif ++ ++#ifndef likely ++#define likely(x) (x) ++#define unlikely(x) (x) ++#endif ++ ++#ifndef BUG_ON ++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) ++#endif ++ ++#ifndef WARN_ON ++#define WARN_ON(x) do { } while (0) ++#endif ++ ++#ifndef IRQ_NONE ++typedef void irqreturn_t; ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define IRQ_RETVAL(x) ++#endif ++ ++#endif /* __JZ4730_UDC_H__ */ +diff --git a/drivers/usb/gadget/jz4740_udc.c b/drivers/usb/gadget/jz4740_udc.c +new file mode 100644 +index 0000000..a1d5dbb +--- /dev/null ++++ b/drivers/usb/gadget/jz4740_udc.c +@@ -0,0 +1,2251 @@ ++/* ++ * linux/drivers/usb/gadget/jz4740_udc.c ++ * ++ * Ingenic JZ4740 on-chip high speed USB device controller ++ * ++ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++/* ++ * This device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint. ++ * ++ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk. ++ * - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz4740_udc.h" ++ ++//#define DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args) ++//#define DEBUG(fmt,args...) printk(fmt , ## args) ++//#define DEBUG_EP0(fmt,args...) printk(fmt , ## args) ++//#define DEBUG_SETUP(fmt,args...) printk(fmt , ## args) ++ ++#ifndef DEBUG ++# define DEBUG(fmt,args...) do {} while(0) ++#endif ++#ifndef DEBUG_EP0 ++# define NO_STATES ++# define DEBUG_EP0(fmt,args...) do {} while(0) ++#endif ++#ifndef DEBUG_SETUP ++# define DEBUG_SETUP(fmt,args...) do {} while(0) ++#endif ++ ++static unsigned int udc_debug = 0; /* 0: normal mode, 1: test udc cable type mode */ ++ ++module_param(udc_debug, int, 0); ++MODULE_PARM_DESC(udc_debug, "test udc cable or power type"); ++ ++static unsigned int use_dma = 1; /* 1: use DMA, 0: use PIO */ ++ ++module_param(use_dma, int, 0); ++MODULE_PARM_DESC(use_dma, "DMA mode enable flag"); ++ ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++extern int jz_udc_active; /* 0: No actions; 1: Have actions */ ++#endif ++ ++/* ++ * Local definintions. ++ */ ++ ++#define DRIVER_VERSION "13-Mar-2008" ++#define DRIVER_DESC "JZ4740 USB Device Controller" ++ ++static const char gadget_name [] = "jz4740_udc"; ++ ++struct jz4740_udc *the_controller; ++ ++static const char driver_name [] = "jz4740_udc"; ++static const char driver_desc [] = DRIVER_DESC; ++static const char ep0name[] = "ep0"; ++ ++#ifndef NO_STATES ++static char *state_names[] = { ++ "WAIT_FOR_SETUP", ++ "DATA_STATE_XMIT", ++ "DATA_STATE_NEED_ZLP", ++ "WAIT_FOR_OUT_STATUS", ++ "DATA_STATE_RECV" ++}; ++#endif ++ ++/* ++ * Local declarations. ++ */ ++static int jz4740_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc); ++static int jz4740_ep_disable(struct usb_ep *_ep); ++static struct usb_request *jz4740_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags); ++static void jz4740_free_request(struct usb_ep *_ep, struct usb_request *_req); ++ ++static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags); ++static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req); ++static int jz4740_set_halt(struct usb_ep *_ep, int value); ++static int jz4740_fifo_status(struct usb_ep *_ep); ++static void jz4740_fifo_flush(struct usb_ep *_ep); ++ ++static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep); ++static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr); ++ ++static void done(struct jz4740_ep *ep, struct jz4740_request *req, ++ int status); ++static void pio_irq_enable(struct jz4740_ep *ep); ++static void pio_irq_disable(struct jz4740_ep *ep); ++static void stop_activity(struct jz4740_udc *dev, ++ struct usb_gadget_driver *driver); ++static void nuke(struct jz4740_ep *ep, int status); ++static void flush(struct jz4740_ep *ep); ++static void udc_enable(struct jz4740_udc *dev); ++static void udc_set_address(struct jz4740_udc *dev, unsigned char address); ++static void jz4740_udc_release (struct device *dev) {} ++ ++extern void *dma_alloc_noncoherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t flag); ++extern void dma_free_noncoherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle); ++ ++static struct usb_ep_ops jz4740_ep_ops = { ++ .enable = jz4740_ep_enable, ++ .disable = jz4740_ep_disable, ++ ++ .alloc_request = jz4740_alloc_request, ++ .free_request = jz4740_free_request, ++ ++ .queue = jz4740_queue, ++ .dequeue = jz4740_dequeue, ++ ++ .set_halt = jz4740_set_halt, ++ .fifo_status = jz4740_fifo_status, ++ .fifo_flush = jz4740_fifo_flush, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* inline functions of register read/write/set/clear */ ++ ++static __inline__ u8 usb_readb(u32 port) ++{ ++ return *(volatile u8 *)port; ++} ++ ++static __inline__ u16 usb_readw(u32 port) ++{ ++ return *(volatile u16 *)port; ++} ++ ++static __inline__ u32 usb_readl(u32 port) ++{ ++ return *(volatile u32 *)port; ++} ++ ++static __inline__ void usb_writeb(u32 port, u8 val) ++{ ++ *(volatile u8 *)port = val; ++} ++ ++static __inline__ void usb_writew(u32 port, u16 val) ++{ ++ *(volatile u16 *)port = val; ++} ++ ++static __inline__ void usb_writel(u32 port, u32 val) ++{ ++ *(volatile u32 *)port = val; ++} ++ ++static __inline__ void usb_setb(u32 port, u8 val) ++{ ++ volatile u8 *ioport = (volatile u8 *)(port); ++ *ioport = (*ioport) | val; ++} ++ ++static __inline__ void usb_setw(u32 port, u16 val) ++{ ++ volatile u16 *ioport = (volatile u16 *)(port); ++ *ioport = (*ioport) | val; ++} ++ ++static __inline__ void usb_setl(u32 port, u32 val) ++{ ++ volatile u32 *ioport = (volatile u32 *)(port); ++ *ioport = (*ioport) | val; ++} ++ ++static __inline__ void usb_clearb(u32 port, u8 val) ++{ ++ volatile u8 *ioport = (volatile u8 *)(port); ++ *ioport = (*ioport) & ~val; ++} ++ ++static __inline__ void usb_clearw(u32 port, u16 val) ++{ ++ volatile u16 *ioport = (volatile u16 *)(port); ++ *ioport = (*ioport) & ~val; ++} ++ ++static __inline__ void usb_clearl(u32 port, u32 val) ++{ ++ volatile u32 *ioport = (volatile u32 *)(port); ++ *ioport = (*ioport) & ~val; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static __inline__ int write_packet(struct jz4740_ep *ep, ++ struct jz4740_request *req, int max) ++{ ++ u8 *buf; ++ int length, nlong, nbyte; ++ volatile u32 *fifo = (volatile u32 *)ep->fifo; ++ ++ buf = req->req.buf + req->req.actual; ++ prefetch(buf); ++ ++ length = req->req.length - req->req.actual; ++ length = min(length, max); ++ req->req.actual += length; ++ ++ DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); ++ ++ nlong = length >> 2; ++ nbyte = length & 0x3; ++ while (nlong--) { ++ *fifo = *((u32 *)buf); ++ buf += 4; ++ } ++ while (nbyte--) { ++ *((volatile u8 *)fifo) = *buf++; ++ } ++ ++ return length; ++} ++ ++static __inline__ int read_packet(struct jz4740_ep *ep, ++ struct jz4740_request *req, int count) ++{ ++ u8 *buf; ++ int length, nlong, nbyte; ++ volatile u32 *fifo = (volatile u32 *)ep->fifo; ++ ++ buf = req->req.buf + req->req.actual; ++ prefetchw(buf); ++ ++ length = req->req.length - req->req.actual; ++ length = min(length, count); ++ req->req.actual += length; ++ ++ DEBUG("Read %d, fifo %p\n", length, fifo); ++ ++ nlong = length >> 2; ++ nbyte = length & 0x3; ++ while (nlong--) { ++ *((u32 *)buf) = *fifo; ++ buf += 4; ++ } ++ while (nbyte--) { ++ *buf++ = *((volatile u8 *)fifo); ++ } ++ ++ return length; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * udc_disable - disable USB device controller ++ */ ++static void udc_disable(struct jz4740_udc *dev) ++{ ++ DEBUG("%s, %p\n", __FUNCTION__, dev); ++ ++ udc_set_address(dev, 0); ++ ++ /* Disable interrupts */ ++ usb_writew(USB_REG_INTRINE, 0); ++ usb_writew(USB_REG_INTROUTE, 0); ++ usb_writeb(USB_REG_INTRUSBE, 0); ++ ++ /* Disable DMA */ ++ usb_writel(USB_REG_CNTL1, 0); ++ usb_writel(USB_REG_CNTL2, 0); ++ ++ /* Disconnect from usb */ ++ usb_clearb(USB_REG_POWER, USB_POWER_SOFTCONN); ++ ++ /* Disable the USB PHY */ ++#ifdef CONFIG_SOC_JZ4740 ++ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE; ++#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; ++#endif ++ ++ dev->ep0state = WAIT_FOR_SETUP; ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++} ++ ++/* ++ * udc_reinit - initialize software state ++ */ ++static void udc_reinit(struct jz4740_udc *dev) ++{ ++ u32 i; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, dev); ++ ++ /* device/ep0 records init */ ++ INIT_LIST_HEAD(&dev->gadget.ep_list); ++ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); ++ dev->ep0state = WAIT_FOR_SETUP; ++ ++ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { ++ struct jz4740_ep *ep = &dev->ep[i]; ++ ++ if (i != 0) ++ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); ++ ++ INIT_LIST_HEAD(&ep->queue); ++ ep->desc = 0; ++ ep->stopped = 0; ++ ep->pio_irqs = 0; ++ } ++} ++ ++/* until it's enabled, this UDC should be completely invisible ++ * to any USB host. ++ */ ++static void udc_enable(struct jz4740_udc *dev) ++{ ++ int i; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, dev); ++ ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ ++ /* Flush FIFO for each */ ++ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { ++ struct jz4740_ep *ep = &dev->ep[i]; ++ ++ usb_set_index(ep_index(ep)); ++ flush(ep); ++ } ++ ++ /* Set this bit to allow the UDC entering low-power mode when ++ * there are no actions on the USB bus. ++ * UDC still works during this bit was set. ++ */ ++ __cpm_stop_udc(); ++ ++ /* Enable the USB PHY */ ++#ifdef CONFIG_SOC_JZ4740 ++ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; ++#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE; ++#endif ++ ++ /* Disable interrupts */ ++ usb_writew(USB_REG_INTRINE, 0); ++ usb_writew(USB_REG_INTROUTE, 0); ++ usb_writeb(USB_REG_INTRUSBE, 0); ++ ++ /* Enable interrupts */ ++ usb_setw(USB_REG_INTRINE, USB_INTR_EP0); ++ usb_setb(USB_REG_INTRUSBE, USB_INTR_RESET); ++ /* Don't enable rest of the interrupts */ ++ /* usb_setw(USB_REG_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2); ++ usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1); */ ++ ++ /* Enable SUSPEND */ ++ /* usb_setb(USB_REG_POWER, USB_POWER_SUSPENDM); */ ++ ++ /* Enable HS Mode */ ++ usb_setb(USB_REG_POWER, USB_POWER_HSENAB); ++ ++ /* Let host detect UDC: ++ * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this ++ * transistor on and pull the USBDP pin HIGH. ++ */ ++ usb_setb(USB_REG_POWER, USB_POWER_SOFTCONN); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* keeping it simple: ++ * - one bus driver, initted first; ++ * - one function driver, initted second ++ */ ++ ++/* ++ * Register entry point for the peripheral controller driver. ++ */ ++ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ struct jz4740_udc *dev = the_controller; ++ int retval; ++ ++ if (!driver ++ || !driver->bind ++ || !driver->unbind || !driver->disconnect || !driver->setup) ++ { ++ printk("\n-EINVAL"); ++ return -EINVAL; ++ } ++ if (!dev) ++ { ++ printk("\n-ENODEV"); ++ return -ENODEV; ++ } ++ if (dev->driver) ++ { ++ printk("\n-ENODEV"); ++ return -EBUSY; ++ } ++ ++ /* hook up the driver */ ++ dev->driver = driver; ++ retval = driver->bind(&dev->gadget); ++ if (retval) { ++ DEBUG("%s: bind to driver %s --> error %d\n", dev->gadget.name, ++ driver->driver.name, retval); ++ dev->driver = 0; ++ return retval; ++ } ++ ++ /* then enable host detection and ep0; and we're ready ++ * for set_configuration as well as eventual disconnect. ++ */ ++ udc_enable(dev); ++ DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name, ++ driver->driver.name); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++ ++static void stop_activity(struct jz4740_udc *dev, ++ struct usb_gadget_driver *driver) ++{ ++ int i; ++ ++ DEBUG("%s\n", __FUNCTION__); ++ ++ /* don't disconnect drivers more than once */ ++ if (dev->gadget.speed == USB_SPEED_UNKNOWN) ++ driver = 0; ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ ++ /* prevent new request submissions, kill any outstanding requests */ ++ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { ++ struct jz4740_ep *ep = &dev->ep[i]; ++ ++ ep->stopped = 1; ++ ++ usb_set_index(ep_index(ep)); ++ nuke(ep, -ESHUTDOWN); ++ } ++ ++ /* report disconnect; the driver is already quiesced */ ++ if (driver) { ++ spin_unlock(&dev->lock); ++ driver->disconnect(&dev->gadget); ++ spin_lock(&dev->lock); ++ } ++ ++ /* re-init driver-visible data structures */ ++ udc_reinit(dev); ++} ++ ++ ++/* ++ * Unregister entry point for the peripheral controller driver. ++ */ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct jz4740_udc *dev = the_controller; ++ unsigned long flags; ++ ++ if (!dev) ++ return -ENODEV; ++ if (!driver || driver != dev->driver) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ dev->driver = 0; ++ stop_activity(dev, driver); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ driver->unbind(&dev->gadget); ++ ++ udc_disable(dev); ++ ++ DEBUG("unregistered driver '%s'\n", driver->driver.name); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * Starting DMA using mode 1 ++ */ ++static void kick_dma(struct jz4740_ep *ep, struct jz4740_request *req) ++{ ++ u32 count = req->req.length; ++ u32 physaddr = virt_to_phys((void *)req->req.buf); ++ ++ usb_set_index(ep_index(ep)); ++ if (ep_is_in(ep)) { /* Bulk-IN transfer using DMA channel 1 */ ++ ep->reg_addr = USB_REG_ADDR1; ++ ++ dma_cache_wback_inv((unsigned long)req->req.buf, count); ++ ++ pio_irq_enable(ep); ++ ++ usb_writeb(USB_REG_INCSRH, ++ USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE); ++ ++ usb_writel(USB_REG_ADDR1, physaddr); ++ usb_writel(USB_REG_COUNT1, count); ++ usb_writel(USB_REG_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 | ++ USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); ++ } ++ else { /* Bulk-OUT transfer using DMA channel 2 */ ++ ep->reg_addr = USB_REG_ADDR2; ++ ++ dma_cache_wback_inv((unsigned long)req->req.buf, count); ++ ++ pio_irq_enable(ep); ++ ++ usb_setb(USB_REG_OUTCSRH, ++ USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); ++ ++ usb_writel(USB_REG_ADDR2, physaddr); ++ usb_writel(USB_REG_COUNT2, count); ++ usb_writel(USB_REG_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 | ++ USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); ++ } ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/** Write request to FIFO (max write == maxp size) ++ * Return: 0 = still running, 1 = completed, negative = errno ++ * NOTE: INDEX register must be set for EP ++ */ ++static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req) ++{ ++ u32 max, csr; ++ u32 physaddr = virt_to_phys((void *)req->req.buf); ++ ++ max = le16_to_cpu(ep->desc->wMaxPacketSize); ++ ++ if (use_dma) { ++ u32 dma_count; ++ ++ /* DMA interrupt generated due to the last packet loaded into the FIFO */ ++ ++ dma_count = usb_readl(ep->reg_addr) - physaddr; ++ req->req.actual += dma_count; ++ ++ if (dma_count % max) { ++ /* If the last packet is less than MAXP, set INPKTRDY manually */ ++ usb_setb(ep->csr, USB_INCSR_INPKTRDY); ++ } ++ ++ done(ep, req, 0); ++ if (list_empty(&ep->queue)) { ++ pio_irq_disable(ep); ++ return 1; ++ } ++ else { ++ /* advance the request queue */ ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ kick_dma(ep, req); ++ return 0; ++ } ++ } ++ ++ /* ++ * PIO mode handling starts here ... ++ */ ++ ++ csr = usb_readb(ep->csr); ++ ++ if (!(csr & USB_INCSR_FFNOTEMPT)) { ++ unsigned count; ++ int is_last, is_short; ++ ++ count = write_packet(ep, req, max); ++ usb_setb(ep->csr, USB_INCSR_INPKTRDY); ++ ++ /* last packet is usually short (or a zlp) */ ++ if (unlikely(count != max)) ++ is_last = is_short = 1; ++ else { ++ if (likely(req->req.length != req->req.actual) ++ || req->req.zero) ++ is_last = 0; ++ else ++ is_last = 1; ++ /* interrupt/iso maxpacket may not fill the fifo */ ++ is_short = unlikely(max < ep_maxpacket(ep)); ++ } ++ ++ DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, ++ ep->ep.name, count, ++ is_last ? "/L" : "", is_short ? "/S" : "", ++ req->req.length - req->req.actual, req); ++ ++ /* requests complete when all IN data is in the FIFO */ ++ if (is_last) { ++ done(ep, req, 0); ++ if (list_empty(&ep->queue)) { ++ pio_irq_disable(ep); ++ } ++ return 1; ++ } ++ } else { ++ DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); ++ } ++ ++ return 0; ++} ++ ++/** Read to request from FIFO (max read == bytes in fifo) ++ * Return: 0 = still running, 1 = completed, negative = errno ++ * NOTE: INDEX register must be set for EP ++ */ ++static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req) ++{ ++ u32 csr; ++ unsigned count, is_short; ++ u32 physaddr = virt_to_phys((void *)req->req.buf); ++ ++ if (use_dma) { ++ u32 dma_count; ++ ++ /* DMA interrupt generated due to a packet less than MAXP loaded into the FIFO */ ++ ++ dma_count = usb_readl(ep->reg_addr) - physaddr; ++ req->req.actual += dma_count; ++ ++ /* Disable interrupt and DMA */ ++ pio_irq_disable(ep); ++ usb_writel(USB_REG_CNTL2, 0); ++ ++ /* Read all bytes from this packet */ ++ count = usb_readw(USB_REG_OUTCOUNT); ++ count = read_packet(ep, req, count); ++ ++ if (count) { ++ /* If the last packet is greater than zero, clear OUTPKTRDY manually */ ++ usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY); ++ } ++ ++ done(ep, req, 0); ++ ++ if (!list_empty(&ep->queue)) { ++ /* advance the request queue */ ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ kick_dma(ep, req); ++ } ++ ++ return 1; ++ } ++ ++ /* ++ * PIO mode handling starts here ... ++ */ ++ ++ /* make sure there's a packet in the FIFO. */ ++ csr = usb_readb(ep->csr); ++ if (!(csr & USB_OUTCSR_OUTPKTRDY)) { ++ DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* read all bytes from this packet */ ++ count = usb_readw(USB_REG_OUTCOUNT); ++ ++ is_short = (count < ep->ep.maxpacket); ++ ++ count = read_packet(ep, req, count); ++ ++ DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", ++ ep->ep.name, csr, count, ++ is_short ? "/S" : "", req, req->req.actual, req->req.length); ++ ++ /* Clear OutPktRdy */ ++ usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY); ++ ++ /* completion */ ++ if (is_short || req->req.actual == req->req.length) { ++ done(ep, req, 0); ++ ++ if (list_empty(&ep->queue)) ++ pio_irq_disable(ep); ++ return 1; ++ } ++ ++ /* finished that packet. the next one may be waiting... */ ++ return 0; ++} ++ ++/* ++ * done - retire a request; caller blocked irqs ++ * INDEX register is preserved to keep same ++ */ ++static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status) ++{ ++ unsigned int stopped = ep->stopped; ++ u32 index; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, ep); ++ list_del_init(&req->queue); ++ ++ if (likely(req->req.status == -EINPROGRESS)) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ if (status && status != -ESHUTDOWN) ++ DEBUG("complete %s req %p stat %d len %u/%u\n", ++ ep->ep.name, &req->req, status, ++ req->req.actual, req->req.length); ++ ++ /* don't modify queue heads during completion callback */ ++ ep->stopped = 1; ++ /* Read current index (completion may modify it) */ ++ index = usb_readb(USB_REG_INDEX); ++ ++ spin_unlock(&ep->dev->lock); ++ req->req.complete(&ep->ep, &req->req); ++ spin_lock(&ep->dev->lock); ++ ++ /* Restore index */ ++ usb_set_index(index); ++ ep->stopped = stopped; ++} ++ ++/** Enable EP interrupt */ ++static void pio_irq_enable(struct jz4740_ep *ep) ++{ ++ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); ++ ++ if (ep_is_in(ep)) { ++ switch (ep_index(ep)) { ++ case 1: ++ usb_setw(USB_REG_INTRINE, USB_INTR_INEP1); ++ break; ++ case 2: ++ usb_setw(USB_REG_INTRINE, USB_INTR_INEP2); ++ break; ++ default: ++ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); ++ break; ++ } ++ } ++ else { ++ switch (ep_index(ep)) { ++ case 1: ++ usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1); ++ break; ++ default: ++ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); ++ break; ++ } ++ } ++} ++ ++/** Disable EP interrupt */ ++static void pio_irq_disable(struct jz4740_ep *ep) ++{ ++ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); ++ ++ if (ep_is_in(ep)) { ++ switch (ep_index(ep)) { ++ case 1: ++ usb_clearw(USB_REG_INTRINE, USB_INTR_INEP1); ++ break; ++ case 2: ++ usb_clearw(USB_REG_INTRINE, USB_INTR_INEP2); ++ break; ++ default: ++ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); ++ break; ++ } ++ } ++ else { ++ switch (ep_index(ep)) { ++ case 1: ++ usb_clearw(USB_REG_INTROUTE, USB_INTR_OUTEP1); ++ break; ++ default: ++ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); ++ break; ++ } ++ } ++} ++ ++/* ++ * nuke - dequeue ALL requests ++ */ ++static void nuke(struct jz4740_ep *ep, int status) ++{ ++ struct jz4740_request *req; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, ep); ++ ++ /* Flush FIFO */ ++ flush(ep); ++ ++ /* called with irqs blocked */ ++ while (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ done(ep, req, status); ++ } ++ ++ /* Disable IRQ if EP is enabled (has descriptor) */ ++ if (ep->desc) ++ pio_irq_disable(ep); ++} ++ ++/** Flush EP FIFO ++ * NOTE: INDEX register must be set before this call ++ */ ++static void flush(struct jz4740_ep *ep) ++{ ++ DEBUG("%s, %p\n", __FUNCTION__, ep); ++ ++ switch (ep->ep_type) { ++ case ep_control: ++ break; ++ ++ case ep_bulk_in: ++ case ep_interrupt: ++ usb_setb(ep->csr, USB_INCSR_FF); ++ break; ++ ++ case ep_bulk_out: ++ usb_setb(ep->csr, USB_OUTCSR_FF); ++ break; ++ } ++} ++ ++/** ++ * jz4740_in_epn - handle IN interrupt ++ */ ++static void jz4740_in_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr) ++{ ++ u32 csr; ++ struct jz4740_ep *ep = &dev->ep[ep_idx + 1]; ++ struct jz4740_request *req; ++ ++ usb_set_index(ep_index(ep)); ++ ++ csr = usb_readb(ep->csr); ++ DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); ++ ++ if (csr & USB_INCSR_SENTSTALL) { ++ DEBUG("USB_INCSR_SENTSTALL\n"); ++ usb_clearb(ep->csr, USB_INCSR_SENTSTALL); ++ return; ++ } ++ ++ if (!ep->desc) { ++ DEBUG("%s: NO EP DESC\n", __FUNCTION__); ++ return; ++ } ++ ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ ++ DEBUG("req: %p\n", req); ++ ++ if (!req) ++ return; ++ ++ write_fifo(ep, req); ++} ++ ++/* ++ * Bulk OUT (recv) ++ */ ++static void jz4740_out_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr) ++{ ++ struct jz4740_ep *ep = &dev->ep[ep_idx]; ++ struct jz4740_request *req; ++ ++ DEBUG("%s: %d\n", __FUNCTION__, ep_idx); ++ ++ usb_set_index(ep_index(ep)); ++ if (ep->desc) { ++ u32 csr; ++ ++ if (use_dma) { ++ /* DMA starts here ... */ ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ ++ if (req) ++ read_fifo(ep, req); ++ return; ++ } ++ ++ /* ++ * PIO mode starts here ... ++ */ ++ ++ while ((csr = usb_readb(ep->csr)) & ++ (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { ++ DEBUG("%s: %x\n", __FUNCTION__, csr); ++ ++ if (csr & USB_OUTCSR_SENTSTALL) { ++ DEBUG("%s: stall sent, flush fifo\n", ++ __FUNCTION__); ++ /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ ++ flush(ep); ++ } else if (csr & USB_OUTCSR_OUTPKTRDY) { ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = ++ list_entry(ep->queue.next, ++ struct jz4740_request, ++ queue); ++ ++ if (!req) { ++ DEBUG("%s: NULL REQ %d\n", ++ __FUNCTION__, ep_idx); ++ break; ++ } else { ++ read_fifo(ep, req); ++ } ++ } ++ } ++ } else { ++ /* Throw packet away.. */ ++ printk("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx); ++ flush(ep); ++ } ++} ++ ++static int jz4740_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct jz4740_ep *ep; ++ struct jz4740_udc *dev; ++ unsigned long flags; ++ u32 max, csrh = 0; ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (!_ep || !desc || ep->desc || _ep->name == ep0name ++ || desc->bDescriptorType != USB_DT_ENDPOINT ++ || ep->bEndpointAddress != desc->bEndpointAddress) { ++ DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* xfer types must match, except that interrupt ~= bulk */ ++ if (ep->bmAttributes != desc->bmAttributes ++ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK ++ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { ++ DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); ++ return -EINVAL; ++ } ++ ++ dev = ep->dev; ++ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { ++ DEBUG("%s, bogus device state\n", __FUNCTION__); ++ return -ESHUTDOWN; ++ } ++ ++ max = le16_to_cpu(desc->wMaxPacketSize); ++ ++ /* Configure the endpoint */ ++ usb_set_index(desc->bEndpointAddress & 0x0F); ++ if (ep_is_in(ep)) { ++ usb_writew(USB_REG_INMAXP, max); ++ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ case USB_ENDPOINT_XFER_INT: ++ csrh &= ~USB_INCSRH_ISO; ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ csrh |= USB_INCSRH_ISO; ++ break; ++ } ++ usb_writeb(USB_REG_INCSRH, csrh); ++ } ++ else { ++ usb_writew(USB_REG_OUTMAXP, max); ++ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ csrh &= ~USB_OUTCSRH_ISO; ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ csrh &= ~USB_OUTCSRH_ISO; ++ csrh |= USB_OUTCSRH_DNYT; ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ csrh |= USB_OUTCSRH_ISO; ++ break; ++ } ++ usb_writeb(USB_REG_OUTCSRH, csrh); ++ } ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ ep->stopped = 0; ++ ep->desc = desc; ++ ep->pio_irqs = 0; ++ ep->ep.maxpacket = max; ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ /* Reset halt state (does flush) */ ++ jz4740_set_halt(_ep, 0); ++ ++ DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); ++ ++ return 0; ++} ++ ++/** Disable EP ++ * NOTE: Sets INDEX register ++ */ ++static int jz4740_ep_disable(struct usb_ep *_ep) ++{ ++ struct jz4740_ep *ep; ++ unsigned long flags; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, _ep); ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (!_ep || !ep->desc) { ++ DEBUG("%s, %s not enabled\n", __FUNCTION__, ++ _ep ? ep->ep.name : NULL); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ usb_set_index(ep_index(ep)); ++ ++ /* Nuke all pending requests (does flush) */ ++ nuke(ep, -ESHUTDOWN); ++ ++ /* Disable ep IRQ */ ++ pio_irq_disable(ep); ++ ++ ep->desc = 0; ++ ep->stopped = 1; ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); ++ return 0; ++} ++ ++static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) ++{ ++ struct jz4740_request *req; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, ep); ++ ++ req = kzalloc(sizeof(*req), gfp_flags); ++ if (!req) ++ return 0; ++ ++ INIT_LIST_HEAD(&req->queue); ++ ++ return &req->req; ++} ++ ++static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req) ++{ ++ struct jz4740_request *req; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, ep); ++ ++ req = container_of(_req, struct jz4740_request, req); ++ WARN_ON(!list_empty(&req->queue)); ++ kfree(req); ++} ++ ++/*--------------------------------------------------------------------*/ ++ ++/** Queue one request ++ * Kickstart transfer if needed ++ * NOTE: Sets INDEX register ++ */ ++static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, ++ gfp_t gfp_flags) ++{ ++ struct jz4740_request *req; ++ struct jz4740_ep *ep; ++ struct jz4740_udc *dev; ++ unsigned long flags; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, _ep); ++ ++ req = container_of(_req, struct jz4740_request, req); ++ if (unlikely ++ (!_req || !_req->complete || !_req->buf ++ || !list_empty(&req->queue))) { ++ DEBUG("%s, bad params\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { ++ DEBUG("%s, bad ep\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ dev = ep->dev; ++ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { ++ DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); ++ return -ESHUTDOWN; ++ } ++ ++ DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, ++ _req->buf); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ ++ _req->status = -EINPROGRESS; ++ _req->actual = 0; ++ ++ /* kickstart this i/o queue? */ ++ DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), ++ ep->stopped); ++ if (list_empty(&ep->queue) && likely(!ep->stopped)) { ++ u32 csr; ++ ++ if (unlikely(ep_index(ep) == 0)) { ++ /* EP0 */ ++ list_add_tail(&req->queue, &ep->queue); ++ jz4740_ep0_kick(dev, ep); ++ req = 0; ++ } else if (use_dma) { ++ /* DMA */ ++ kick_dma(ep, req); ++ } ++ /* PIO */ ++ else if (ep_is_in(ep)) { ++ /* EP1 & EP2 */ ++ usb_set_index(ep_index(ep)); ++ csr = usb_readb(ep->csr); ++ pio_irq_enable(ep); ++ if (!(csr & USB_INCSR_FFNOTEMPT)) { ++ if (write_fifo(ep, req) == 1) ++ req = 0; ++ } ++ } else { ++ /* EP1 */ ++ usb_set_index(ep_index(ep)); ++ csr = usb_readb(ep->csr); ++ pio_irq_enable(ep); ++ if (csr & USB_OUTCSR_OUTPKTRDY) { ++ if (read_fifo(ep, req) == 1) ++ req = 0; ++ } ++ } ++ } ++ ++ /* pio or dma irq handler advances the queue. */ ++ if (likely(req != 0)) ++ list_add_tail(&req->queue, &ep->queue); ++ ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ return 0; ++} ++ ++/* dequeue JUST ONE request */ ++static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct jz4740_ep *ep; ++ struct jz4740_request *req; ++ unsigned long flags; ++ ++ DEBUG("%s, %p\n", __FUNCTION__, _ep); ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (!_ep || ep->ep.name == ep0name) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ /* make sure it's actually queued on this endpoint */ ++ list_for_each_entry(req, &ep->queue, queue) { ++ if (&req->req == _req) ++ break; ++ } ++ if (&req->req != _req) { ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return -EINVAL; ++ } ++ ++ done(ep, req, -ECONNRESET); ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return 0; ++} ++ ++/** Halt specific EP ++ * Return 0 if success ++ * NOTE: Sets INDEX register to EP ! ++ */ ++static int jz4740_set_halt(struct usb_ep *_ep, int value) ++{ ++ struct jz4740_ep *ep; ++ unsigned long flags; ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { ++ DEBUG("%s, bad ep\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ usb_set_index(ep_index(ep)); ++ ++ DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); ++ ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ ++ if (ep_index(ep) == 0) { ++ /* EP0 */ ++ usb_setb(USB_REG_CSR0, USB_CSR0_SENDSTALL); ++ } else if (ep_is_in(ep)) { ++ u32 csr = usb_readb(ep->csr); ++ if (value && ((csr & USB_INCSR_FFNOTEMPT) ++ || !list_empty(&ep->queue))) { ++ /* ++ * Attempts to halt IN endpoints will fail (returning -EAGAIN) ++ * if any transfer requests are still queued, or if the controller ++ * FIFO still holds bytes that the host hasnÂ’t collected. ++ */ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ DEBUG ++ ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", ++ (csr & USB_INCSR_FFNOTEMPT), ++ !list_empty(&ep->queue)); ++ return -EAGAIN; ++ } ++ flush(ep); ++ if (value) { ++ usb_setb(ep->csr, USB_INCSR_SENDSTALL); ++ } ++ else { ++ usb_clearb(ep->csr, USB_INCSR_SENDSTALL); ++ usb_setb(ep->csr, USB_INCSR_CDT); ++ } ++ } else { ++ ++ flush(ep); ++ if (value) { ++ usb_setb(ep->csr, USB_OUTCSR_SENDSTALL); ++ } ++ else { ++ usb_clearb(ep->csr, USB_OUTCSR_SENDSTALL); ++ usb_setb(ep->csr, USB_OUTCSR_CDT); ++ } ++ } ++ ++ if (value) { ++ ep->stopped = 1; ++ } else { ++ ep->stopped = 0; ++ } ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ ++ DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); ++ ++ return 0; ++} ++ ++/** Return bytes in EP FIFO ++ * NOTE: Sets INDEX register to EP ++ */ ++static int jz4740_fifo_status(struct usb_ep *_ep) ++{ ++ u32 csr; ++ int count = 0; ++ struct jz4740_ep *ep; ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (!_ep) { ++ DEBUG("%s, bad ep\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); ++ ++ /* LPD can't report unclaimed bytes from IN fifos */ ++ if (ep_is_in(ep)) ++ return -EOPNOTSUPP; ++ ++ usb_set_index(ep_index(ep)); ++ ++ csr = usb_readb(ep->csr); ++ if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || ++ csr & 0x1) { ++ count = usb_readw(USB_REG_OUTCOUNT); ++ } ++ ++ return count; ++} ++ ++/** Flush EP FIFO ++ * NOTE: Sets INDEX register to EP ++ */ ++static void jz4740_fifo_flush(struct usb_ep *_ep) ++{ ++ struct jz4740_ep *ep; ++ ++ ep = container_of(_ep, struct jz4740_ep, ep); ++ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { ++ DEBUG("%s, bad ep\n", __FUNCTION__); ++ return; ++ } ++ ++ usb_set_index(ep_index(ep)); ++ flush(ep); ++} ++ ++/****************************************************************/ ++/* End Point 0 related functions */ ++/****************************************************************/ ++ ++/* return: 0 = still running, 1 = completed, negative = errno */ ++static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) ++{ ++ u32 max; ++ unsigned count; ++ int is_last; ++ ++ max = ep_maxpacket(ep); ++ ++ count = write_packet(ep, req, max); ++ ++ /* last packet is usually short (or a zlp) */ ++ if (unlikely(count != max)) ++ is_last = 1; ++ else { ++ if (likely(req->req.length != req->req.actual) || req->req.zero) ++ is_last = 0; ++ else ++ is_last = 1; ++ } ++ ++ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, ++ ep->ep.name, count, ++ is_last ? "/L" : "", req->req.length - req->req.actual, req); ++ ++ /* requests complete when all IN data is in the FIFO */ ++ if (is_last) { ++ done(ep, req, 0); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static __inline__ int jz4740_fifo_read(struct jz4740_ep *ep, ++ unsigned char *cp, int max) ++{ ++ int bytes; ++ int count = usb_readw(USB_REG_OUTCOUNT); ++ volatile u8 *fifo = (volatile u8 *)ep->fifo; ++ ++ if (count > max) ++ count = max; ++ bytes = count; ++ while (count--) ++ *cp++ = *fifo; ++ return bytes; ++} ++ ++static __inline__ void jz4740_fifo_write(struct jz4740_ep *ep, ++ unsigned char *cp, int count) ++{ ++ volatile u8 *fifo = (volatile u8 *)ep->fifo; ++ DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count); ++ while (count--) ++ *fifo = *cp++; ++} ++ ++static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) ++{ ++ u32 csr; ++ u8 *buf; ++ unsigned bufferspace, count, is_short; ++ volatile u8 *fifo = (volatile u8 *)ep->fifo; ++ ++ DEBUG_EP0("%s\n", __FUNCTION__); ++ ++ csr = usb_readb(USB_REG_CSR0); ++ if (!(csr & USB_CSR0_OUTPKTRDY)) ++ return 0; ++ ++ buf = req->req.buf + req->req.actual; ++ prefetchw(buf); ++ bufferspace = req->req.length - req->req.actual; ++ ++ /* read all bytes from this packet */ ++ if (likely(csr & USB_CSR0_OUTPKTRDY)) { ++ count = usb_readw(USB_REG_OUTCOUNT); ++ req->req.actual += min(count, bufferspace); ++ } else /* zlp */ ++ count = 0; ++ ++ is_short = (count < ep->ep.maxpacket); ++ DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", ++ ep->ep.name, csr, count, ++ is_short ? "/S" : "", req, req->req.actual, req->req.length); ++ ++ while (likely(count-- != 0)) { ++ u8 byte = (u8) (*fifo & 0xff); ++ ++ if (unlikely(bufferspace == 0)) { ++ /* this happens when the driver's buffer ++ * is smaller than what the host sent. ++ * discard the extra data. ++ */ ++ if (req->req.status != -EOVERFLOW) ++ DEBUG_EP0("%s overflow %d\n", ep->ep.name, ++ count); ++ req->req.status = -EOVERFLOW; ++ } else { ++ *buf++ = byte; ++ bufferspace--; ++ } ++ } ++ ++ /* completion */ ++ if (is_short || req->req.actual == req->req.length) { ++ done(ep, req, 0); ++ return 1; ++ } ++ ++ /* finished that packet. the next one may be waiting... */ ++ return 0; ++} ++ ++/** ++ * udc_set_address - set the USB address for this device ++ * @address: ++ * ++ * Called from control endpoint function after it decodes a set address setup packet. ++ */ ++static void udc_set_address(struct jz4740_udc *dev, unsigned char address) ++{ ++ DEBUG_EP0("%s: %d\n", __FUNCTION__, address); ++ ++ dev->usb_address = address; ++ usb_writeb(USB_REG_FADDR, address); ++} ++ ++/* ++ * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY) ++ * - if error ++ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits ++ * - else ++ * set USB_CSR0_SVDOUTPKTRDY bit ++ if last set USB_CSR0_DATAEND bit ++ */ ++static void jz4740_ep0_out(struct jz4740_udc *dev, u32 csr) ++{ ++ struct jz4740_request *req; ++ struct jz4740_ep *ep = &dev->ep[0]; ++ int ret; ++ ++ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); ++ ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ ++ if (req) { ++ if (req->req.length == 0) { ++ DEBUG_EP0("ZERO LENGTH OUT!\n"); ++/* usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); */ ++ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY)); ++ dev->ep0state = WAIT_FOR_SETUP; ++ return; ++ } ++ ret = read_fifo_ep0(ep, req); ++ if (ret) { ++ /* Done! */ ++ DEBUG_EP0("%s: finished, waiting for status\n", ++ __FUNCTION__); ++ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); ++ dev->ep0state = WAIT_FOR_SETUP; ++ } else { ++ /* Not done yet.. */ ++ DEBUG_EP0("%s: not finished\n", __FUNCTION__); ++ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); ++ } ++ } else { ++ DEBUG_EP0("NO REQ??!\n"); ++ } ++} ++ ++/* ++ * DATA_STATE_XMIT ++ */ ++static int jz4740_ep0_in(struct jz4740_udc *dev, u32 csr) ++{ ++ struct jz4740_request *req; ++ struct jz4740_ep *ep = &dev->ep[0]; ++ int ret, need_zlp = 0; ++ ++ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); ++ ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = list_entry(ep->queue.next, struct jz4740_request, queue); ++ ++ if (!req) { ++ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); ++ return 0; ++ } ++ ++ if (req->req.length == 0) { ++ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); ++ dev->ep0state = WAIT_FOR_SETUP; ++ return 1; ++ } ++ ++ if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) { ++ /* Next write will end with the packet size, */ ++ /* so we need zero-length-packet */ ++ need_zlp = 1; ++ } ++ ++ ret = write_fifo_ep0(ep, req); ++ ++ if (ret == 1 && !need_zlp) { ++ /* Last packet */ ++ DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); ++ ++ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); ++ dev->ep0state = WAIT_FOR_SETUP; ++ } else { ++ DEBUG_EP0("%s: not finished\n", __FUNCTION__); ++ usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); ++ } ++ ++ if (need_zlp) { ++ DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); ++ usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); ++ dev->ep0state = DATA_STATE_NEED_ZLP; ++ } ++ ++ return 1; ++} ++ ++#if 0 ++static int jz4740_handle_get_status(struct jz4740_udc *dev, ++ struct usb_ctrlrequest *ctrl) ++{ ++ struct jz4740_ep *ep0 = &dev->ep[0]; ++ struct jz4740_ep *qep; ++ int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); ++ u16 val = 0; ++ ++ if (reqtype == USB_RECIP_INTERFACE) { ++ /* This is not supported. ++ * And according to the USB spec, this one does nothing.. ++ * Just return 0 ++ */ ++ DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); ++ } else if (reqtype == USB_RECIP_DEVICE) { ++ DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); ++ val |= (1 << 0); /* Self powered */ ++ /*val |= (1<<1); *//* Remote wakeup */ ++ } else if (reqtype == USB_RECIP_ENDPOINT) { ++ int ep_num = (ctrl->wIndex & ~USB_DIR_IN); ++ ++ DEBUG_SETUP ++ ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", ++ ep_num, ctrl->wLength); ++ ++ if (ctrl->wLength > 2 || ep_num > 3) ++ return -EOPNOTSUPP; ++ ++ qep = &dev->ep[ep_num]; ++ if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) ++ && ep_index(qep) != 0) { ++ return -EOPNOTSUPP; ++ } ++ ++ usb_set_index(ep_index(qep)); ++ ++ /* Return status on next IN token */ ++ switch (qep->ep_type) { ++ case ep_control: ++ val = ++ (usb_readb(qep->csr) & USB_CSR0_SENDSTALL) == ++ USB_CSR0_SENDSTALL; ++ break; ++ case ep_bulk_in: ++ case ep_interrupt: ++ val = ++ (usb_readb(qep->csr) & USB_INCSR_SENDSTALL) == ++ USB_INCSR_SENDSTALL; ++ break; ++ case ep_bulk_out: ++ val = ++ (usb_readb(qep->csr) & USB_OUTCSR_SENDSTALL) == ++ USB_OUTCSR_SENDSTALL; ++ break; ++ } ++ ++ /* Back to EP0 index */ ++ usb_set_index(0); ++ ++ DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, ++ ctrl->wIndex, val); ++ } else { ++ DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); ++ return -EOPNOTSUPP; ++ } ++ ++ /* Clear "out packet ready" */ ++ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); ++ /* Put status to FIFO */ ++ jz4740_fifo_write(ep0, (u8 *) & val, sizeof(val)); ++ /* Issue "In packet ready" */ ++ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); ++ ++ return 0; ++} ++#endif ++ ++/* ++ * WAIT_FOR_SETUP (OUTPKTRDY) ++ * - read data packet from EP0 FIFO ++ * - decode command ++ * - if error ++ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits ++ * - else ++ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits ++ */ ++static void jz4740_ep0_setup(struct jz4740_udc *dev, u32 csr) ++{ ++ struct jz4740_ep *ep = &dev->ep[0]; ++ struct usb_ctrlrequest ctrl; ++ int i; ++ ++ DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); ++ ++ /* Nuke all previous transfers */ ++ nuke(ep, -EPROTO); ++ ++ /* read control req from fifo (8 bytes) */ ++ jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8); ++ ++ DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bRequestType, ctrl.bRequest, ++ ctrl.wValue, ctrl.wIndex, ctrl.wLength); ++ ++ /* Set direction of EP0 */ ++ if (likely(ctrl.bRequestType & USB_DIR_IN)) { ++ ep->bEndpointAddress |= USB_DIR_IN; ++ } else { ++ ep->bEndpointAddress &= ~USB_DIR_IN; ++ } ++ ++ /* Handle some SETUP packets ourselves */ ++ switch (ctrl.bRequest) { ++ case USB_REQ_SET_ADDRESS: ++ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) ++ break; ++ ++ DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); ++ udc_set_address(dev, ctrl.wValue); ++ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); ++ return; ++ ++ case USB_REQ_SET_CONFIGURATION: ++ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) ++ break; ++ ++ DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue); ++ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); ++ ++ /* Enable RESUME and SUSPEND interrupts */ ++ usb_setb(USB_REG_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND)); ++ break; ++ ++ case USB_REQ_SET_INTERFACE: ++ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) ++ break; ++ ++ DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue); ++ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); ++ break; ++ ++// case USB_REQ_GET_STATUS: ++// if (jz4740_handle_get_status(dev, &ctrl) == 0) ++// return; ++ ++ case USB_REQ_CLEAR_FEATURE: ++ case USB_REQ_SET_FEATURE: ++ if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { ++ struct jz4740_ep *qep; ++ int ep_num = (ctrl.wIndex & 0x0f); ++ ++ /* Support only HALT feature */ ++ if (ctrl.wValue != 0 || ctrl.wLength != 0 ++ || ep_num > 3 || ep_num < 1) ++ break; ++ ++ qep = &dev->ep[ep_num]; ++ spin_unlock(&dev->lock); ++ if (ctrl.bRequest == USB_REQ_SET_FEATURE) { ++ DEBUG_SETUP("SET_FEATURE (%d)\n", ++ ep_num); ++ jz4740_set_halt(&qep->ep, 1); ++ } else { ++ DEBUG_SETUP("CLR_FEATURE (%d)\n", ++ ep_num); ++ jz4740_set_halt(&qep->ep, 0); ++ } ++ spin_lock(&dev->lock); ++ ++ usb_set_index(0); ++ ++ /* Reply with a ZLP on next IN token */ ++ usb_setb(USB_REG_CSR0, ++ (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); ++ return; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* gadget drivers see class/vendor specific requests, ++ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, ++ * and more. ++ */ ++ if (likely((u32)dev->driver)) { ++ /* device-2-host (IN) or no data setup command, process immediately */ ++ spin_unlock(&dev->lock); ++ ++ i = dev->driver->setup(&dev->gadget, &ctrl); ++ spin_lock(&dev->lock); ++ ++ if (unlikely(i < 0)) { ++ /* setup processing failed, force stall */ ++ DEBUG_SETUP ++ (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", ++ i); ++ usb_set_index(0); ++ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL)); ++ ++ /* ep->stopped = 1; */ ++ dev->ep0state = WAIT_FOR_SETUP; ++ } ++ else { ++ DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength); ++ if (!ctrl.wLength) { ++ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); ++ } ++ } ++ } ++} ++ ++/* ++ * DATA_STATE_NEED_ZLP ++ */ ++static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, u32 csr) ++{ ++ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); ++ ++ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); ++ dev->ep0state = WAIT_FOR_SETUP; ++} ++ ++/* ++ * handle ep0 interrupt ++ */ ++static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr) ++{ ++ struct jz4740_ep *ep = &dev->ep[0]; ++ u32 csr; ++ ++ /* Set index 0 */ ++ usb_set_index(0); ++ csr = usb_readb(USB_REG_CSR0); ++ ++ DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]); ++ ++ /* ++ * if SENT_STALL is set ++ * - clear the SENT_STALL bit ++ */ ++ if (csr & USB_CSR0_SENTSTALL) { ++ DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr); ++ usb_clearb(USB_REG_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL); ++ nuke(ep, -ECONNABORTED); ++ dev->ep0state = WAIT_FOR_SETUP; ++ return; ++ } ++ ++ /* ++ * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear ++ * - fill EP0 FIFO ++ * - if last packet ++ * - set IN_PKT_RDY | DATA_END ++ * - else ++ * set IN_PKT_RDY ++ */ ++ if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) { ++ DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n", ++ __FUNCTION__); ++ ++ switch (dev->ep0state) { ++ case DATA_STATE_XMIT: ++ DEBUG_EP0("continue with DATA_STATE_XMIT\n"); ++ jz4740_ep0_in(dev, csr); ++ return; ++ case DATA_STATE_NEED_ZLP: ++ DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); ++ jz4740_ep0_in_zlp(dev, csr); ++ return; ++ default: ++ /* Stall? */ ++// DEBUG_EP0("Odd state!! state = %s\n", ++// state_names[dev->ep0state]); ++ dev->ep0state = WAIT_FOR_SETUP; ++ /* nuke(ep, 0); */ ++ /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */ ++// break; ++ return; ++ } ++ } ++ ++ /* ++ * if SETUPEND is set ++ * - abort the last transfer ++ * - set SERVICED_SETUP_END_BIT ++ */ ++ if (csr & USB_CSR0_SETUPEND) { ++ DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr); ++ ++ usb_setb(USB_REG_CSR0, USB_CSR0_SVDSETUPEND); ++ nuke(ep, 0); ++ dev->ep0state = WAIT_FOR_SETUP; ++ } ++ ++ /* ++ * if USB_CSR0_OUTPKTRDY is set ++ * - read data packet from EP0 FIFO ++ * - decode command ++ * - if error ++ * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits ++ * - else ++ * set SVDOUTPKTRDY | DATAEND bits ++ */ ++ if (csr & USB_CSR0_OUTPKTRDY) { ++ ++ DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, ++ csr); ++ ++ switch (dev->ep0state) { ++ case WAIT_FOR_SETUP: ++ DEBUG_EP0("WAIT_FOR_SETUP\n"); ++ jz4740_ep0_setup(dev, csr); ++ break; ++ ++ case DATA_STATE_RECV: ++ DEBUG_EP0("DATA_STATE_RECV\n"); ++ jz4740_ep0_out(dev, csr); ++ break; ++ ++ default: ++ /* send stall? */ ++ DEBUG_EP0("strange state!! 2. send stall? state = %d\n", ++ dev->ep0state); ++ break; ++ } ++ } ++} ++ ++static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep) ++{ ++ u32 csr; ++ ++ usb_set_index(0); ++ csr = usb_readb(USB_REG_CSR0); ++ ++ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); ++ ++ /* Clear "out packet ready" */ ++ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); ++ ++ if (ep_is_in(ep)) { ++ dev->ep0state = DATA_STATE_XMIT; ++ jz4740_ep0_in(dev, csr); ++ } else { ++ dev->ep0state = DATA_STATE_RECV; ++ jz4740_ep0_out(dev, csr); ++ } ++} ++ ++/** Handle USB RESET interrupt ++ */ ++static void jz4740_reset_irq(struct jz4740_udc *dev) ++{ ++ dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ? ++ USB_SPEED_HIGH : USB_SPEED_FULL; ++ ++ DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address, ++ (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" ); ++} ++ ++/* ++ * jz4740 usb device interrupt handler. ++ */ ++static irqreturn_t jz4740_udc_irq(int irq, void *_dev) ++{ ++ struct jz4740_udc *dev = _dev; ++ ++ u32 intr_usb = usb_readb(USB_REG_INTRUSB) & 0x7; /* mask SOF */ ++ u32 intr_in = usb_readw(USB_REG_INTRIN); ++ u32 intr_out = usb_readw(USB_REG_INTROUT); ++ u32 intr_dma = usb_readb(USB_REG_INTR); ++ ++ if (!intr_usb && !intr_in && !intr_out && !intr_dma) ++ return IRQ_HANDLED; ++ ++ DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n", ++ intr_out, intr_in, intr_usb); ++ ++ spin_lock(&dev->lock); ++ ++ /* Check for resume from suspend mode */ ++ if ((intr_usb & USB_INTR_RESUME) && ++ (usb_readb(USB_REG_INTRUSBE) & USB_INTR_RESUME)) { ++ DEBUG("USB resume\n"); ++ } ++ ++ /* Check for system interrupts */ ++ if (intr_usb & USB_INTR_RESET) { ++ DEBUG("USB reset\n"); ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++ jz_udc_active = 1; ++#endif ++ if (udc_debug) { ++ /* We have tested the cable type, disable module and ++ * disconnect from host right now. ++ */ ++ udc_disable(dev); ++ spin_unlock(&dev->lock); ++ return IRQ_HANDLED; ++ } ++ jz4740_reset_irq(dev); ++ } ++ ++ /* Check for endpoint 0 interrupt */ ++ if (intr_in & USB_INTR_EP0) { ++ DEBUG("USB_INTR_EP0 (control)\n"); ++ jz4740_handle_ep0(dev, intr_in); ++ } ++ ++ /* Check for Bulk-IN DMA interrupt */ ++ if (intr_dma & 0x1) { ++ int ep_num; ++ ep_num = (usb_readl(USB_REG_CNTL1) >> 4) & 0xf; ++ jz4740_in_epn(dev, ep_num, intr_in); ++ } ++ ++ /* Check for Bulk-OUT DMA interrupt */ ++ if (intr_dma & 0x2) { ++ int ep_num; ++ ep_num = (usb_readl(USB_REG_CNTL2) >> 4) & 0xf; ++ jz4740_out_epn(dev, ep_num, intr_out); ++ } ++ ++ /* Check for each configured endpoint interrupt */ ++ if (intr_in & USB_INTR_INEP1) { ++ DEBUG("USB_INTR_INEP1\n"); ++ jz4740_in_epn(dev, 1, intr_in); ++ } ++ ++ if (intr_in & USB_INTR_INEP2) { ++ DEBUG("USB_INTR_INEP2\n"); ++ jz4740_in_epn(dev, 2, intr_in); ++ } ++ ++ if (intr_out & USB_INTR_OUTEP1) { ++ DEBUG("USB_INTR_OUTEP1\n"); ++ jz4740_out_epn(dev, 1, intr_out); ++ } ++ ++ /* Check for suspend mode */ ++ if ((intr_usb & USB_INTR_SUSPEND) && ++ (usb_readb(USB_REG_INTRUSBE) & USB_INTR_SUSPEND)) { ++ DEBUG("USB suspend\n"); ++ dev->driver->suspend(&dev->gadget); ++ /* Host unloaded from us, can do something, such as flushing ++ the NAND block cache etc. */ ++ } ++ ++#ifdef CONFIG_JZ_UDC_HOTPLUG ++ jz_udc_active = 1; ++#endif ++ ++ spin_unlock(&dev->lock); ++ return IRQ_HANDLED; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int jz4740_udc_get_frame(struct usb_gadget *_gadget) ++{ ++ DEBUG("%s, %p\n", __FUNCTION__, _gadget); ++ return usb_readw(USB_REG_FRAME); ++} ++ ++static int jz4740_udc_wakeup(struct usb_gadget *_gadget) ++{ ++ /* host may not have enabled remote wakeup */ ++ /*if ((UDCCS0 & UDCCS0_DRWF) == 0) ++ return -EHOSTUNREACH; ++ udc_set_mask_UDCCR(UDCCR_RSM); */ ++ return -ENOTSUPP; ++} ++ ++static const struct usb_gadget_ops jz4740_udc_ops = { ++ .get_frame = jz4740_udc_get_frame, ++ .wakeup = jz4740_udc_wakeup, ++ /* current versions must always be self-powered */ ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct jz4740_udc udc_dev = { ++ .usb_address = 0, ++ ++ .gadget = { ++ .ops = &jz4740_udc_ops, ++ .ep0 = &udc_dev.ep[0].ep, ++ .name = driver_name, ++ .dev = { ++ .bus_id = "gadget", ++ }, ++ }, ++ ++ /* control endpoint */ ++ .ep[0] = { ++ .ep = { ++ .name = ep0name, ++ .ops = &jz4740_ep_ops, ++ .maxpacket = EP0_MAXPACKETSIZE, ++ }, ++ .dev = &udc_dev, ++ ++ .bEndpointAddress = 0, ++ .bmAttributes = 0, ++ ++ .ep_type = ep_control, ++ .fifo = USB_FIFO_EP0, ++ .csr = USB_REG_CSR0, ++ }, ++ ++ /* bulk out endpoint */ ++ .ep[1] = { ++ .ep = { ++ .name = "ep1out-bulk", ++ .ops = &jz4740_ep_ops, ++ .maxpacket = EPBULK_MAXPACKETSIZE, ++ }, ++ .dev = &udc_dev, ++ ++ .bEndpointAddress = 1, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ ++ .ep_type = ep_bulk_out, ++ .fifo = USB_FIFO_EP1, ++ .csr = USB_REG_OUTCSR, ++ }, ++ ++ /* bulk in endpoint */ ++ .ep[2] = { ++ .ep = { ++ .name = "ep1in-bulk", ++ .ops = &jz4740_ep_ops, ++ .maxpacket = EPBULK_MAXPACKETSIZE, ++ }, ++ .dev = &udc_dev, ++ ++ .bEndpointAddress = USB_DIR_IN | 1, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ ++ .ep_type = ep_bulk_in, ++ .fifo = USB_FIFO_EP1, ++ .csr = USB_REG_INCSR, ++ }, ++ ++ /* interrupt in endpoint */ ++ .ep[3] = { ++ .ep = { ++ .name = "ep2in-int", ++ .ops = &jz4740_ep_ops, ++ .maxpacket = EPINTR_MAXPACKETSIZE, ++ }, ++ .dev = &udc_dev, ++ ++ .bEndpointAddress = USB_DIR_IN | 2, ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ ++ .ep_type = ep_interrupt, ++ .fifo = USB_FIFO_EP2, ++ .csr = USB_REG_INCSR, ++ }, ++}; ++ ++static int jz4740_udc_probe(struct platform_device *pdev) ++{ ++ struct jz4740_udc *dev = &udc_dev; ++ int rc; ++ ++ DEBUG("%s\n", __FUNCTION__); ++ ++ spin_lock_init(&dev->lock); ++ the_controller = dev; ++ ++ dev->dev = &pdev->dev; ++ device_initialize(&dev->gadget.dev); ++ dev->gadget.dev.parent = &pdev->dev; ++ ++// strcpy (dum->gadget.dev.bus_id, "gadget"); ++ dev->gadget.dev.release = jz4740_udc_release; ++ if ((rc = device_register (&dev->gadget.dev)) < 0) ++ return rc; ++ platform_set_drvdata(pdev, dev); ++ ++ udc_disable(dev); ++ udc_reinit(dev); ++ ++ /* irq setup */ ++ if (request_irq(IRQ_UDC, jz4740_udc_irq, IRQF_DISABLED,//SA_SHIRQ/*|SA_SAMPLE_RANDOM*/, ++ driver_name, dev) != 0) { ++ printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC); ++ return -EBUSY; ++ } ++ ++ printk(KERN_INFO "%s\n", driver_desc); ++ printk(KERN_INFO "version: " DRIVER_VERSION "\n"); ++ ++ return 0; ++} ++ ++static int jz4740_udc_remove(struct platform_device *pdev) ++{ ++ struct jz4740_udc *dev = platform_get_drvdata(pdev); ++ DEBUG("%s: %p\n", __FUNCTION__, dev); ++ ++ if (dev->driver) ++ return -EBUSY; ++ ++ udc_disable(dev); ++#ifdef UDC_PROC_FILE ++ remove_proc_entry(proc_node_name, NULL); ++#endif ++ ++ free_irq(IRQ_UDC, dev); ++ platform_set_drvdata(pdev, 0); ++ device_unregister(&dev->gadget.dev); ++ the_controller = 0; ++ ++ return 0; ++} ++ ++static struct platform_driver udc_driver = { ++ .probe = jz4740_udc_probe, ++ .remove = jz4740_udc_remove, ++ .suspend = NULL, ++ .resume = NULL, ++ .driver = { ++ .name = (char *) driver_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++ ++ ++static struct platform_device the_udc_pdev = { ++ .name = (char *) gadget_name, ++ .id = -1, ++ .dev = { ++ .release = jz4740_udc_release, ++ }, ++}; ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int __init udc_init (void) ++{ ++ platform_driver_register(&udc_driver); ++ return platform_device_register (&the_udc_pdev); ++} ++ ++static void __exit udc_exit (void) ++{ ++ platform_driver_unregister(&udc_driver); ++ platform_device_unregister(&the_udc_pdev); ++} ++ ++module_init(udc_init); ++module_exit(udc_exit); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR("Wei Jianli "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/usb/gadget/jz4740_udc.h b/drivers/usb/gadget/jz4740_udc.h +new file mode 100644 +index 0000000..ee642b4 +--- /dev/null ++++ b/drivers/usb/gadget/jz4740_udc.h +@@ -0,0 +1,112 @@ ++/* ++ * linux/drivers/usb/gadget/jz4740_udc.h ++ * ++ * Ingenic JZ4740 on-chip high speed USB device controller ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef __USB_GADGET_JZ4740_H__ ++#define __USB_GADGET_JZ4740_H__ ++ ++/*-------------------------------------------------------------------------*/ ++ ++// Max packet size ++#define EP0_MAXPACKETSIZE 64 ++#define EPBULK_MAXPACKETSIZE 512 ++#define EPINTR_MAXPACKETSIZE 64 ++ ++#define UDC_MAX_ENDPOINTS 4 ++ ++/*-------------------------------------------------------------------------*/ ++ ++typedef enum ep_type { ++ ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt ++} ep_type_t; ++ ++struct jz4740_ep { ++ struct usb_ep ep; ++ struct jz4740_udc *dev; ++ ++ const struct usb_endpoint_descriptor *desc; ++ struct list_head queue; ++ unsigned long pio_irqs; ++ ++ u8 stopped; ++ u8 bEndpointAddress; ++ u8 bmAttributes; ++ ++ ep_type_t ep_type; ++ u32 fifo; ++ u32 csr; ++ ++ u32 reg_addr; ++}; ++ ++struct jz4740_request { ++ struct usb_request req; ++ struct list_head queue; ++}; ++ ++enum ep0state { ++ WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */ ++ DATA_STATE_XMIT, /* data tx stage */ ++ DATA_STATE_NEED_ZLP, /* data tx zlp stage */ ++ WAIT_FOR_OUT_STATUS, /* status stages */ ++ DATA_STATE_RECV, /* data rx stage */ ++}; ++ ++struct jz4740_udc { ++ struct usb_gadget gadget; ++ struct usb_gadget_driver *driver; ++ struct device *dev; ++ spinlock_t lock; ++ ++ enum ep0state ep0state; ++ struct jz4740_ep ep[UDC_MAX_ENDPOINTS]; ++ ++ unsigned char usb_address; ++}; ++ ++extern struct jz4740_udc *the_controller; ++ ++#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN) ++#define ep_maxpacket(EP) ((EP)->ep.maxpacket) ++#define ep_index(EP) ((EP)->bEndpointAddress&0xF) ++#define usb_set_index(i) (REG8(USB_REG_INDEX) = (i)) ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* 2.5 stuff that's sometimes missing in 2.4 */ ++ ++#ifndef container_of ++#define container_of list_entry ++#endif ++ ++#ifndef likely ++#define likely(x) (x) ++#define unlikely(x) (x) ++#endif ++ ++#ifndef BUG_ON ++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) ++#endif ++ ++#ifndef WARN_ON ++#define WARN_ON(x) do { } while (0) ++#endif ++ ++#ifndef IRQ_NONE ++typedef void irqreturn_t; ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define IRQ_RETVAL(x) ++#endif ++ ++#endif /* __USB_GADGET_JZ4740_H__ */ +diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c +index 5815168..148ef67 100644 +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -992,6 +992,11 @@ MODULE_LICENSE ("GPL"); + #define PCI_DRIVER ohci_pci_driver + #endif + ++#ifdef CONFIG_JZSOC ++#include "ohci-jz.c" ++#define PLATFORM_DRIVER ohci_hcd_jz_driver ++#endif ++ + #if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111) + #include "ohci-sa1111.c" + #define SA1111_DRIVER ohci_hcd_sa1111_driver +diff --git a/drivers/usb/host/ohci-jz.c b/drivers/usb/host/ohci-jz.c +new file mode 100644 +index 0000000..9604728 +--- /dev/null ++++ b/drivers/usb/host/ohci-jz.c +@@ -0,0 +1,260 @@ ++/* ++ * OHCI HCD (Host Controller Driver) for USB. ++ * ++ * (C) Copyright 1999 Roman Weissgaerber ++ * (C) Copyright 2000-2002 David Brownell ++ * (C) Copyright 2002 Hewlett-Packard Company ++ * ++ * Bus Glue for Ingenic Jz47xx. ++ * ++ * Written by Christopher Hoover ++ * Based on fragments of previous driver by Rusell King et al. ++ * ++ * Modified for LH7A404 from ohci-sa1111.c ++ * by Durgesh Pattamatta ++ * Modified for AMD Alchemy Au1xxx ++ * by Matt Porter ++ * Modified for Jz47xx from ohci-au1xxx.c ++ * by Peter ++ * ++ * This file is licenced under the GPL. ++ */ ++ ++#include ++#include ++ ++#include ++ ++extern int usb_disabled(void); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz_start_ohc(struct platform_device *dev) ++{ ++ printk(KERN_DEBUG __FILE__ ++ ": starting JZ OHCI USB Controller\n"); ++ ++ /* enable host controller */ ++ __cpm_start_uhc(); ++ ++#ifdef CONFIG_SOC_JZ4750 ++ __cpm_enable_uhcphy(); ++#endif ++ ++ printk(KERN_DEBUG __FILE__ ++ ": Clock to USB host has been enabled \n"); ++} ++ ++static void jz_stop_ohc(struct platform_device *dev) ++{ ++ printk(KERN_DEBUG __FILE__ ++ ": stopping JZ OHCI USB Controller\n"); ++ ++#ifdef CONFIG_SOC_JZ4750 ++ __cpm_suspend_uhcphy(); ++#endif ++ ++ __cpm_stop_uhc(); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* configure so an HC device and id are always provided */ ++/* always called with process context; sleeping is OK */ ++ ++ ++/** ++ * usb_ohci_jz_probe - initialize Jz-based HCDs ++ * Context: !in_interrupt() ++ * ++ * Allocates basic resources for this USB host controller, and ++ * then invokes the start() method for the HCD associated with it ++ * through the hotplug entry's driver_data. ++ * ++ */ ++static int usb_ohci_jz_probe(const struct hc_driver *driver, ++ struct platform_device *dev) ++{ ++ int retval; ++ struct usb_hcd *hcd; ++ ++ if (dev->resource[1].flags != IORESOURCE_IRQ) { ++ pr_debug("resource[1] is not IORESOURCE_IRQ\n"); ++ return -ENOMEM; ++ } ++ ++ hcd = usb_create_hcd(driver, &dev->dev, "jz"); ++ if (!hcd) ++ return -ENOMEM; ++ hcd->rsrc_start = dev->resource[0].start; ++ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; ++ ++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { ++ pr_debug("request_mem_region failed\n"); ++ retval = -EBUSY; ++ goto err1; ++ } ++ ++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); ++ if (!hcd->regs) { ++ pr_debug("ioremap failed\n"); ++ retval = -ENOMEM; ++ goto err2; ++ } ++ ++ jz_start_ohc(dev); ++ ohci_hcd_init(hcd_to_ohci(hcd)); ++ ++ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED); ++ if (retval == 0) ++ return retval; ++ ++ jz_stop_ohc(dev); ++ iounmap(hcd->regs); ++ err2: ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++ err1: ++ usb_put_hcd(hcd); ++ return retval; ++} ++ ++ ++/* may be called without controller electrically present */ ++/* may be called with controller, bus, and devices active */ ++ ++/** ++ * usb_hcd_jz_remove - shutdown processing for Jz-based HCDs ++ * @dev: USB Host Controller being removed ++ * Context: !in_interrupt() ++ * ++ * Reverses the effect of usb_hcd_jz_probe(), first invoking ++ * the HCD's stop() method. It is always called from a thread ++ * context, normally "rmmod", "apmd", or something similar. ++ * ++ */ ++static void usb_ohci_jz_remove(struct usb_hcd *hcd, struct platform_device *dev) ++{ ++ usb_remove_hcd(hcd); ++ jz_stop_ohc(dev); ++ iounmap(hcd->regs); ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++ usb_put_hcd(hcd); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int __devinit ++ohci_jz_start (struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci (hcd); ++ int ret; ++ ++ ohci_dbg (ohci, "ohci_jz_start, ohci:%p", ohci); ++ ++ if ((ret = ohci_init (ohci)) < 0) ++ return ret; ++ ++ if ((ret = ohci_run (ohci)) < 0) { ++ err ("can't start %s", hcd->self.bus_name); ++ ohci_stop (hcd); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static const struct hc_driver ohci_jz_hc_driver = { ++ .description = hcd_name, ++ .product_desc = "JZ OHCI", ++ .hcd_priv_size = sizeof(struct ohci_hcd), ++ ++ /* ++ * generic hardware linkage ++ */ ++ .irq = ohci_irq, ++ .flags = HCD_USB11 | HCD_MEMORY, ++ ++ /* ++ * basic lifecycle operations ++ */ ++ .start = ohci_jz_start, ++ .stop = ohci_stop, ++ .shutdown = ohci_shutdown, ++ ++ /* ++ * managing i/o requests and associated device resources ++ */ ++ .urb_enqueue = ohci_urb_enqueue, ++ .urb_dequeue = ohci_urb_dequeue, ++ .endpoint_disable = ohci_endpoint_disable, ++ ++ /* ++ * scheduling support ++ */ ++ .get_frame_number = ohci_get_frame, ++ ++ /* ++ * root hub support ++ */ ++ .hub_status_data = ohci_hub_status_data, ++ .hub_control = ohci_hub_control, ++ .hub_irq_enable = ohci_rhsc_enable, ++#ifdef CONFIG_PM ++ .bus_suspend = ohci_bus_suspend, ++ .bus_resume = ohci_bus_resume, ++#endif ++ .start_port_reset = ohci_start_port_reset, ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int ohci_hcd_jz_drv_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ pr_debug ("In ohci_hcd_jz_drv_probe"); ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ ret = usb_ohci_jz_probe(&ohci_jz_hc_driver, pdev); ++ return ret; ++} ++ ++static int ohci_hcd_jz_drv_remove(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ ++ usb_ohci_jz_remove(hcd, pdev); ++ return 0; ++} ++ /*TBD*/ ++/*static int ohci_hcd_jz_drv_suspend(struct platform_device *dev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(dev); ++ ++ return 0; ++} ++static int ohci_hcd_jz_drv_resume(struct platform_device *dev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(dev); ++ ++ return 0; ++} ++*/ ++ ++static struct platform_driver ohci_hcd_jz_driver = { ++ .probe = ohci_hcd_jz_drv_probe, ++ .remove = ohci_hcd_jz_drv_remove, ++ .shutdown = usb_hcd_platform_shutdown, ++ /*.suspend = ohci_hcd_jz_drv_suspend, */ ++ /*.resume = ohci_hcd_jz_drv_resume, */ ++ .driver = { ++ .name = "jz-ohci", ++ .owner = THIS_MODULE, ++ }, ++}; ++ +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 3b54b39..45df749 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -237,6 +237,226 @@ 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 to . ++ ++choice ++ depends on FB_JZ4740_SLCD ++ prompt "SLCD Panel" ++ default JZ_SLCD_LGDP4551_8BUS ++ ++config JZ_SLCD_LGDP4551 ++ bool "LG LGDP4551 Smart LCD panel" ++ ---help--- ++ Driver for Smart LCD LGDP4551, 8-bit sytem interface, 16BPP. ++ ++config JZ_SLCD_SPFD5420A ++ bool "SPFD5420A Smart LCD panel" ++ ---help--- ++ Driver for Smart LCD SPFD5420A 18-bit sytem interface, 18BPP. ++ ++config JZ_SLCD_TRULY ++ bool "TRULY Smart LCD panel (MAX Pixels 400x240)" ++ ---help--- ++ ++endchoice ++ ++config FB_JZLCD_4730_4740 ++ tristate "JZ4730 JZ4740 LCD controller support" ++ depends on FB_JZSOC && (SOC_JZ4730 || SOC_JZ4740) ++ help ++ This is the frame buffer device driver for the JZ4730 and JZ4740 LCD controller. ++config JZLCD_FRAMEBUFFER_MAX ++ int "Default FrameBuffer num" ++ depends on FB_JZLCD_4730_4740 ++ default "1" ++ ---help--- ++ JZ LCD driver support multi-framebuffers for video applications. ++config JZLCD_FRAMEBUFFER_ROTATE_SUPPORT ++ bool "JZLCD FrameBuffer Rotate Support(For TEST)" ++ depends on FB_JZLCD_4730_4740 ++ default n ++ ---help--- ++ JZ LCD driver framebuffer rotate support. Rotate angle can be 0,90,180,270. ++ Note, this fearture is implemented by software, and will cost a lot of cpu capcity. ++ That is to say, if you select this function, you system will become slowly. ++ Rotate cost cpu about: ++ ratate angle 0'C: 0% cpu ++ ratate angle 90'C: 40% cpu ++ ratate angle 180'C: 20% cpu ++ ratate angle 270'C: 40% cpu ++ ++config JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE ++ int "FrameBuffer default rotate angle" ++ depends on JZLCD_FRAMEBUFFER_ROTATE_SUPPORT ++ default 0 ++ ---help--- ++ JZ LCD driver framebuffer angle value can be: ++ 0: 0'C ++ 1: 90'C ++ 2: 180'C ++ 3: 270'C ++config JZLCD_FRAMEBUFFER_BPP ++ int "FrameBuffer bit per pixel" ++ depends on JZLCD_FRAMEBUFFER_ROTATE_SUPPORT ++ default 32 ++ ---help--- ++ JZ LCD driver framebuffer support 8bpp, 16bpp, 32bpp ++choice ++ depends on FB_JZLCD_4730_4740 ++ prompt "LCD Panel" ++ default JZLCD_SAMSUNG_LTP400WQF01 ++ ++config JZLCD_SHARP_LQ035Q7 ++ bool "SHARP LQ035Q7 TFT panel (240x320)" ++ ++config JZLCD_SAMSUNG_LTS350Q1 ++ bool "SAMSUNG LTS350Q1 TFT panel (240x320)" ++ ++config JZLCD_SAMSUNG_LTV350QVF04 ++ bool "SAMSUNG LTV350QV_F04 TFT panel (320x240)" ++ ++config JZLCD_SAMSUNG_LTP400WQF01 ++ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)" ++ ++config JZLCD_SAMSUNG_LTP400WQF02 ++ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)" ++ ++config JZLCD_AUO_A030FL01_V1 ++ bool "AUO A030FL01_V1 TFT panel (480x272)" ++ ++config JZLCD_TRULY_TFTG320240DTSW ++ bool "TRULY TFTG320240DTSW TFT panel (320x240)" ++ ++config JZLCD_TRULY_TFTG320240DTSW_SERIAL ++ bool "TRULY TFTG320240DTSW TFT panel (320x240)(8bit-serial mode)" ++ ++config JZLCD_TRULY_TFTG240320UTSW_63W_E ++ bool "TRULY TFTG240320UTSW-63W-E TFT panel (240x320,2.5in)" ++ ++config JZLCD_FOXCONN_PT035TN01 ++ bool "FOXCONN PT035TN01 TFT panel (320x240)" ++ ++config JZLCD_INNOLUX_PT035TN01_SERIAL ++ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)" ++ ++config JZLCD_TOSHIBA_LTM084P363 ++ bool "Toshiba LTM084P363 TFT panel (800x600)" ++ ++config JZLCD_HYNIX_HT10X21 ++ bool "Hynix HT10X21_300 TFT panel (1024x768)" ++ ++config JZLCD_INNOLUX_AT080TN42 ++ bool "INNOLUX AT080TN42 TFT panel (800x600)" ++ ++config JZLCD_CSTN_800x600 ++ bool "800x600 colorDSTN panel" ++ ++config JZLCD_CSTN_320x240 ++ bool "320x240 colorSTN panel" ++ ++config JZLCD_MSTN_480x320 ++ bool "480x320 monoSTN panel" ++ ++config JZLCD_MSTN_320x240 ++ bool "320x240 monoSTN panel" ++ ++config JZLCD_MSTN_240x128 ++ bool "240x128 monoSTN panel" ++ ++config JZLCD_MSTN_INVERSE ++ bool "Use an inverse color display." ++ depends on (JZLCD_MSTN_480x320 || JZLCD_MSTN_240x128) ++ ++endchoice ++ ++config FB_JZ4750_LCD ++ tristate "JZ4750 LCD Controller support" ++ depends on FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D) ++ ---help--- ++ JZ4750 LCD Controller driver. ++ JZ4750 LCD Controller support OSD function(refer jz4750_lcdc_spec.pdf).JZ4750 LCD OSD implement 2 framebuffer layers: foreground0 and foreground1. JZ4750 LCD driver support only foreground0 default. ++ ++config FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER ++ bool "JZ4750 LCD driver 2 layers framebuffer support." ++ depends on FB_JZ4750_LCD ++ ---help--- ++ JZ4750 LCD driver support only foreground0 by default. ++ If you need both foreground0 and foreground1, please select this. ++ ++config FB_JZ4750_TVE ++ tristate "Jz4750 TV Encode support" ++ depends on FB_JZSOC && FB_JZ4750_LCD ++ default n ++ ++config IPU_JZ4750 ++ tristate "Jz4750 ipu support (Only for debug)" ++ depends on FB_JZSOC && FB_JZ4750_LCD ++ default n ++ ---help--- ++ Test JZ4750 IPU, if not sure, please set it to n. ++ ++config FB_JZ4750_SLCD ++ bool ++ depends on FB_JZ4750_LCD ++ default n ++choice ++ depends on FB_JZ4750_LCD ++ prompt "JZ4750 LCD Panels Support" ++ default JZ4750_LCD_SAMSUNG_LTP400WQF02 ++ ---help--- ++ Please select the lcd panel in you board ++ ++config JZ4750_LCD_SAMSUNG_LTP400WQF01 ++ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)" ++ ++config JZ4750_LCD_SAMSUNG_LTP400WQF02 ++ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)" ++ ++config JZ4750_LCD_AUO_A043FL01V2 ++ bool "AUO A043FL01V2 TFT panel (480x272)(24bits)" ++ ++config JZ4750_LCD_FOXCONN_PT035TN01 ++ bool "FOXCONN PT035TN01 TFT panel (320x240,3.5in)(18bit-parallel mode)" ++ ++config JZ4750_LCD_INNOLUX_PT035TN01_SERIAL ++ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)" ++ ++config JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA ++ bool "TOPPOLY_TD025THEA7 TFT panel(320x240)(serial RGB delta mode)" ++ ++config JZ4750_LCD_TOPPOLY_TD043MGEB1 ++ bool "TOPPOLY_TD043MGEB1 TFT panel(800x480)(24bit mode)" ++ ++config JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT ++ bool "TRULY_TFTG320240DTSW TFT panel (320x240) (Parallel 18bit mode)" ++ ++config JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W ++ bool "TRULY_TFT_GG1P0319LTSW_W (240x320) (Smart LCD 16bit)" ++ ++config JZ4750_SLCD_KGM701A3_TFT_SPFD5420A ++ bool "KGM701A3_TFT_SPFD5420A (400x240) (Smart LCD 18bit)" ++ select FB_JZ4750_SLCD ++ ++config JZ4750D_VGA_DISPLAY ++ depends on SOC_JZ4750D ++ bool "Jz4750D VGA Display" ++endchoice ++ + config FB_CIRRUS + tristate "Cirrus Logic support" + depends on FB && (ZORRO || PCI) +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 01a819f..5a3c60d 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -28,6 +28,10 @@ obj-$(CONFIG_FB_DDC) += fb_ddc.o + obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o + + # Hardware specific drivers go first ++obj-$(CONFIG_FB_JZLCD_4730_4740) += jzlcd.o ++obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd.o ++obj-$(CONFIG_FB_JZ4750_LCD) += jz4750_lcd.o ++obj-$(CONFIG_FB_JZ4750_TVE) += jz4750_tve.o + obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o + obj-$(CONFIG_FB_ARC) += arcfb.o + obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o +diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig +index 2f50a80..92bd3ce 100644 +--- a/drivers/video/console/Kconfig ++++ b/drivers/video/console/Kconfig +@@ -118,6 +118,14 @@ config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY + + If unsure, select n. + ++config FRAMEBUFFER_CONSOLE_CURSOR_FLASH ++ bool "Framebuffer Console Cursor flash" ++ depends on FRAMEBUFFER_CONSOLE ++ help ++ Enable cursor flush for the framebuffer console. This is done ++ in software and may be significantly slower than a normally oriented ++ display. ++ + config FRAMEBUFFER_CONSOLE_ROTATION + bool "Framebuffer Console Rotation" + depends on FRAMEBUFFER_CONSOLE +diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c +index 3a44695..212b25a 100644 +--- a/drivers/video/console/fbcon.c ++++ b/drivers/video/console/fbcon.c +@@ -366,6 +366,7 @@ static void fbcon_update_softback(struct vc_data *vc) + + static void fb_flashcursor(struct work_struct *work) + { ++#ifdef CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH + struct fb_info *info = container_of(work, struct fb_info, queue); + struct fbcon_ops *ops = info->fbcon_par; + struct display *p; +@@ -391,6 +392,7 @@ static void fb_flashcursor(struct work_struct *work) + ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1), + get_color(vc, info, c, 0)); + release_console_sem(); ++#endif + } + + static void cursor_timer_handler(unsigned long dev_addr) +diff --git a/drivers/video/jz4740_slcd.c b/drivers/video/jz4740_slcd.c +new file mode 100644 +index 0000000..41f0928 +--- /dev/null ++++ b/drivers/video/jz4740_slcd.c +@@ -0,0 +1,1334 @@ ++/* ++ * linux/drivers/video/jzslcd.c -- Ingenic On-Chip Smart LCD frame buffer device ++ * ++ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "console/fbcon.h" ++ ++#include "jz4740_slcd.h" ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++ ++#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) ++#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) ++#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) ++#ifdef DEBUG ++#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg) ++#else ++#define print_dbg(f, arg...) do {} while (0) ++#endif ++ ++static jz_dma_desc slcd_palette_desc __attribute__ ((aligned (16))); ++static jz_dma_desc slcd_frame_desc __attribute__ ((aligned (16))); ++ ++static int dma_chan; ++static dma_addr_t slcd_frame_desc_phys_addr, slcd_palette_desc_phys_addr; ++ ++static unsigned char non_link_desp = 0; ++static unsigned char is_set_reg = 0; ++struct lcd_cfb_info { ++ struct fb_info fb; ++ struct display_switch *dispsw; ++ signed int currcon; ++ int func_use_count; ++ ++ struct { ++ u16 red, green, blue; ++ } palette[NR_PALETTE]; ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++struct slcd_reg_info { ++ unsigned int cmd; ++ unsigned int data; ++}; ++static struct slcd_reg_info reg_buf; ++static struct lcd_cfb_info *jzslcd_info; ++ ++struct jzfb_info { ++ unsigned int cfg; /* panel mode and pin usage etc. */ ++ unsigned int w; ++ unsigned int h; ++ unsigned int bpp; /* bit per pixel */ ++ unsigned int bus; ++ unsigned int pclk; /* pixel clk */ ++ ++}; ++ ++static struct jzfb_info jzfb = { ++#ifdef CONFIG_JZ_SLCD_LGDP4551 ++ SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_TYPE_PARALLEL, ++ 400, 240, 16, 8, 16000000 /*16 bpp, 8 bus*/ ++// 240, 400, 18, 8, 16000000 /*18 bpp, 8 bus*/ ++// 400, 240, 18, 8, 16000000 /*18 bpp, 8 bus*/ ++#endif ++ ++#ifdef CONFIG_JZ_SLCD_SPFD5420A ++ SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_TYPE_PARALLEL, ++ 400, 240, 18, 18, 16000000 /*18 bpp, 18 bus*/ ++#endif ++}; ++ ++ ++static volatile unsigned char *slcd_palette; ++static volatile unsigned char *slcd_frame; ++ ++//extern struct display fb_display[MAX_NR_CONSOLES]; ++static irqreturn_t slcd_dma_irq(int irq, void *dev_id); ++ ++ ++static void Mcupanel_RegSet(UINT32 cmd, UINT32 data) ++{ ++ switch (jzfb.bus) { ++ case 8: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); ++ break; ++ case 9: ++ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); ++ data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; ++ break; ++ case 16: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); ++ break; ++ case 18: ++ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); ++ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc); ++ break; ++ default: ++ printk("Don't support %d bit Bus\n", jzfb.bus ); ++ break; ++ } ++} ++ ++/* Sent a command withou data */ ++static void Mcupanel_Command(UINT32 cmd) { ++ switch (jzfb.bus) { ++ case 8: ++ case 9: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); ++ break; ++ case 16: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); ++ break; ++ case 18: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1); ++ break; ++ default: ++ printk("Don't support %d bit Bus\n", jzfb.bus ); ++ break; ++ } ++} ++ ++/* Set the start address of screen, for example (0, 0) */ ++#ifdef CONFIG_JZ_SLCD_LGDP4551 ++static void Mcupanel_SetAddr(UINT16 x, UINT16 y) ++{ ++ Mcupanel_RegSet(0x20,x) ; ++ udelay(1); ++ Mcupanel_RegSet(0x21,y) ; ++ udelay(1); ++ Mcupanel_Command(0x22); ++ ++} ++#endif ++#ifdef CONFIG_JZ_SLCD_SPFD5420A ++void Mcupanel_SetAddr(u32 x, u32 y) //u32 ++{ ++ Mcupanel_RegSet(0x200,x) ; ++ udelay(1); ++ Mcupanel_RegSet(0x201,y) ; ++ udelay(1); ++ Mcupanel_Command(0x202); ++ ++} ++ ++#endif ++ ++static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ unsigned short *ptr, ctmp; ++ ++ print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp); ++ if (regno >= NR_PALETTE) ++ return 1; ++ ++ cfb->palette[regno].red = red ; ++ cfb->palette[regno].green = green; ++ cfb->palette[regno].blue = blue; ++ if (cfb->fb.var.bits_per_pixel <= 16) { ++ red >>= 8; ++ green >>= 8; ++ blue >>= 8; ++ ++ red &= 0xff; ++ green &= 0xff; ++ blue &= 0xff; ++ } ++ switch (cfb->fb.var.bits_per_pixel) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ /* RGB 565 */ ++ if (((red >> 3) == 0) && ((red >> 2) != 0)) ++ red = 1 << 3; ++ if (((blue >> 3) == 0) && ((blue >> 2) != 0)) ++ blue = 1 << 3; ++ ctmp = ((red >> 3) << 11) ++ | ((green >> 2) << 5) | (blue >> 3); ++ ++ ptr = (unsigned short *)slcd_palette; ++ ptr = (unsigned short *)(((u32)ptr)|0xa0000000); ++ ptr[regno] = ctmp; ++ ++ break; ++ ++ case 15: ++ if (regno < 16) ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ ((red >> 3) << 10) | ++ ((green >> 3) << 5) | ++ (blue >> 3); ++ break; ++ case 16: ++ if (regno < 16) { ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ ((red >> 3) << 11) | ++ ((green >> 2) << 5) | ++ (blue >> 3); ++ } ++ break; ++ case 18: ++ case 24: ++ case 32: ++ if (regno < 16) ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ (red << 16) | ++ (green << 8) | ++ (blue << 0); ++ ++/* if (regno < 16) { ++ unsigned val; ++ val = chan_to_field(red, &cfb->fb.var.red); ++ val |= chan_to_field(green, &cfb->fb.var.green); ++ val |= chan_to_field(blue, &cfb->fb.var.blue); ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = val; ++ } ++*/ ++ ++ break; ++ } ++ return 0; ++} ++ ++static int jzfb_ioctl (struct fb_info *info, unsigned int cmd, unsigned long arg ) ++{ ++ int ret = 0; ++ void __user *argp = (void __user *)arg; ++ ++ switch (cmd) { ++ case FBIOSETBACKLIGHT: ++ __slcd_set_backlight_level(arg); /* We support 8 levels here. */ ++ break; ++ case FBIODISPON: ++ __slcd_display_on(); ++ break; ++ case FBIODISPOFF: ++ __slcd_display_off(); ++ break; ++ case FBIO_REFRESH_ALWAYS: ++ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd); ++ if (slcd_frame_desc.dcmd & DMAC_DCMD_LINK) ++ printk("The Smart LCD refreshes automatically. Option is omitted!\n"); ++ else { ++ dprintk("OPEN DMAC_DCMD_LINK \n"); ++ slcd_frame_desc.dcmd &= ~DMAC_DCMD_TIE; ++ slcd_frame_desc.dcmd |= DMAC_DCMD_LINK; ++ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16); ++ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_TIE; ++ __dmac_channel_set_doorbell(dma_chan); ++ } ++ break; ++ case FBIO_REFRESH_EVENTS: ++ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd); ++ if (!(slcd_frame_desc.dcmd & DMAC_DCMD_LINK)) ++ printk("The Smart LCD is refreshed by envents. Option is omitted!\n"); ++ else { ++ non_link_desp = 1; ++ REG_DMAC_DCMD(dma_chan) |= DMAC_DCMD_TIE; ++ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; ++ } ++ break; ++ case FBIO_DO_REFRESH: ++ ++ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd); ++ if (slcd_frame_desc.dcmd & DMAC_DCMD_LINK) ++ printk("The Smart LCD can refresh automatically. Option is omitted!\n"); ++ else { ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ __dmac_channel_set_doorbell(dma_chan); ++ } ++ break; ++ case FBIO_SET_REG: ++ if (copy_from_user(®_buf, argp, sizeof(reg_buf))) ++ return -EFAULT; ++ is_set_reg = 1; ++ REG_DMAC_DCMD(dma_chan) |= DMAC_DCMD_TIE; ++ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ ++static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); ++ ++ /* frame buffer memory */ ++ start = cfb->fb.fix.smem_start; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ ++ ++#if 1 ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Through */ ++#endif ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++/* checks var and eventually tweaks it to something supported, ++ * DO NOT MODIFY PAR */ ++static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ print_dbg("jzfb_check_var"); ++ return 0; ++} ++ ++ ++/* ++ * set the video mode according to info->var ++ */ ++static int jzfb_set_par(struct fb_info *info) ++{ ++// print_dbg("jzfb_set_par"); ++ printk("jzfb_set_par"); ++ return 0; ++} ++ ++ ++/* ++ * (Un)Blank the display. ++ * Fix me: should we use VESA value? ++ */ ++static int jzfb_blank(int blank_mode, struct fb_info *info) ++{ ++ ++ dprintk("fb_blank %d %p", blank_mode, info); ++ ++ switch (blank_mode) { ++ ++ case FB_BLANK_UNBLANK: ++ /* Turn on panel */ ++ break; ++ ++ case FB_BLANK_NORMAL: ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ case FB_BLANK_POWERDOWN: ++ /* Turn off panel */ ++ break; ++ default: ++ break; ++ ++ } ++ return 0; ++} ++ ++/* ++ * pan display ++ */ ++static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ int dy; ++ ++ if (!var || !cfb) { ++ return -EINVAL; ++ } ++ ++ if (var->xoffset - cfb->fb.var.xoffset) { ++ /* No support for X panning for now! */ ++ return -EINVAL; ++ } ++ ++ dy = var->yoffset - cfb->fb.var.yoffset; ++ print_dbg("var.yoffset: %d", dy); ++ if (dy) { ++ ++ print_dbg("Panning screen of %d lines", dy); ++// slcd_frame_desc->databuf += (cfb->fb.fix.line_length * dy); ++// slcd_frame_desc->dsadr += (cfb->fb.fix.line_length * dy); ++ /* TODO: Wait for current frame to finished */ ++ } ++ ++ return 0; ++} ++ ++ ++/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ ++static struct fb_ops jzfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_setcolreg = jzfb_setcolreg, ++ .fb_check_var = jzfb_check_var, ++ .fb_set_par = jzfb_set_par, ++ .fb_blank = jzfb_blank, ++ .fb_pan_display = jzfb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_mmap = jzfb_mmap, ++ .fb_ioctl = jzfb_ioctl, ++}; ++ ++static int jzfb_set_var(struct fb_var_screeninfo *var, int con, ++ struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ //struct display *display; ++ int chgvar = 0; ++ ++ var->height = jzfb.h ; ++ var->width = jzfb.w ; ++ var->bits_per_pixel = jzfb.bpp; ++ ++ var->vmode = FB_VMODE_NONINTERLACED; ++ var->activate = cfb->fb.var.activate; ++ var->xres = var->width; ++ var->yres = var->height; ++ var->xres_virtual = var->width; ++ var->yres_virtual = var->height; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->pixclock = 0; ++ var->left_margin = 0; ++ var->right_margin = 0; ++ var->upper_margin = 0; ++ var->lower_margin = 0; ++ var->hsync_len = 0; ++ var->vsync_len = 0; ++ var->sync = 0; ++ var->activate &= ~FB_ACTIVATE_TEST; ++ ++ /* ++ * CONUPDATE and SMOOTH_XPAN are equal. However, ++ * SMOOTH_XPAN is only used internally by fbcon. ++ */ ++ if (var->vmode & FB_VMODE_CONUPDATE) { ++ var->vmode |= FB_VMODE_YWRAP; ++ var->xoffset = cfb->fb.var.xoffset; ++ var->yoffset = cfb->fb.var.yoffset; ++ } ++ ++ if (var->activate & FB_ACTIVATE_TEST) ++ return 0; ++ ++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) ++ return -EINVAL; ++ ++ if (cfb->fb.var.xres != var->xres) ++ chgvar = 1; ++ if (cfb->fb.var.yres != var->yres) ++ chgvar = 1; ++ if (cfb->fb.var.xres_virtual != var->xres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.yres_virtual != var->yres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) ++ chgvar = 1; ++ ++ //display = fb_display + con; ++ ++ var->red.msb_right = 0; ++ var->green.msb_right = 0; ++ var->blue.msb_right = 0; ++ ++ switch(var->bits_per_pixel){ ++ case 1: /* Mono */ ++ cfb->fb.fix.visual = FB_VISUAL_MONO01; ++ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; ++ break; ++ case 2: /* Mono */ ++ var->red.offset = 0; ++ var->red.length = 2; ++ var->green.offset = 0; ++ var->green.length = 2; ++ var->blue.offset = 0; ++ var->blue.length = 2; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; ++ break; ++ case 4: /* PSEUDOCOLOUR*/ ++ var->red.offset = 0; ++ var->red.length = 4; ++ var->green.offset = 0; ++ var->green.length = 4; ++ var->blue.offset = 0; ++ var->blue.length = 4; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = var->xres / 2; ++ break; ++ case 8: /* PSEUDOCOLOUR, 256 */ ++ var->red.offset = 0; ++ var->red.length = 8; ++ var->green.offset = 0; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = var->xres ; ++ break; ++ case 15: /* DIRECTCOLOUR, 32k */ ++ var->bits_per_pixel = 15; ++ var->red.offset = 10; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 5; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ ++ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 2; ++ break; ++ case 16: /* DIRECTCOLOUR, 64k */ ++ var->bits_per_pixel = 16; ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 2; ++ break; ++ case 18: ++ case 24: ++ case 32: ++ /* DIRECTCOLOUR, 256 */ ++ var->bits_per_pixel = 32; ++ ++ var->red.offset = 16; ++ var->red.length = 8; ++ var->green.offset = 8; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; ++ var->transp.offset = 24; ++ var->transp.length = 8; ++ ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 4; ++ break; ++ ++ default: /* in theory this should never happen */ ++ printk(KERN_WARNING "%s: don't support for %dbpp\n", ++ cfb->fb.fix.id, var->bits_per_pixel); ++ break; ++ } ++ ++ cfb->fb.var = *var; ++ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; ++ ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); ++ dprintk("jzfb_set_var: after fb_set_cmap...\n"); ++ ++ return 0; ++} ++ ++static struct lcd_cfb_info * jzfb_alloc_fb_info(void) ++{ ++ struct lcd_cfb_info *cfb; ++ ++ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); ++ ++ if (!cfb) ++ return NULL; ++ ++ jzslcd_info = cfb; ++ ++ memset(cfb, 0, sizeof(struct lcd_cfb_info) ); ++ ++ cfb->currcon = -1; ++ ++ ++ strcpy(cfb->fb.fix.id, "jz-slcd"); ++ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ cfb->fb.fix.type_aux = 0; ++ cfb->fb.fix.xpanstep = 1; ++ cfb->fb.fix.ypanstep = 1; ++ cfb->fb.fix.ywrapstep = 0; ++ cfb->fb.fix.accel = FB_ACCEL_NONE; ++ ++ cfb->fb.var.nonstd = 0; ++ cfb->fb.var.activate = FB_ACTIVATE_NOW; ++ cfb->fb.var.height = -1; ++ cfb->fb.var.width = -1; ++ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; ++ ++ cfb->fb.fbops = &jzfb_ops; ++ cfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ ++ cfb->fb.pseudo_palette = (void *)(cfb + 1); ++ ++ switch (jzfb.bpp) { ++ case 1: ++ fb_alloc_cmap(&cfb->fb.cmap, 4, 0); ++ break; ++ case 2: ++ fb_alloc_cmap(&cfb->fb.cmap, 8, 0); ++ break; ++ case 4: ++ fb_alloc_cmap(&cfb->fb.cmap, 32, 0); ++ break; ++ case 8: ++ ++ default: ++ fb_alloc_cmap(&cfb->fb.cmap, 256, 0); ++ break; ++ } ++ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); ++ ++ return cfb; ++} ++ ++/* ++ * Map screen memory ++ */ ++static int jzfb_map_smem(struct lcd_cfb_info *cfb) ++{ ++ struct page * map = NULL; ++ unsigned char *tmp; ++ unsigned int page_shift, needroom, t; ++ ++ t = jzfb.bpp; ++ if (jzfb.bpp == 15) ++ t = 16; ++ if (jzfb.bpp == 18 || jzfb.bpp == 24) ++ t = 32; ++ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; ++ ++ for (page_shift = 0; page_shift < 12; page_shift++) ++ if ((PAGE_SIZE << page_shift) >= needroom) ++ break; ++ ++ slcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); ++ slcd_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ if ((!slcd_palette) || (!slcd_frame)) ++ return -ENOMEM; ++ ++ memset((void *)slcd_palette, 0, PAGE_SIZE); ++ memset((void *)slcd_frame, 0, PAGE_SIZE << page_shift); ++ ++ map = virt_to_page(slcd_palette); ++ set_bit(PG_reserved, &map->flags); ++ ++ for (tmp=(unsigned char *)slcd_frame; ++ tmp < slcd_frame + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ set_bit(PG_reserved, &map->flags); ++ } ++ ++ cfb->fb.fix.smem_start = virt_to_phys((void *)slcd_frame); ++ ++ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); ++ ++ cfb->fb.screen_base = ++ (unsigned char *)(((unsigned int)slcd_frame & 0x1fffffff) | 0xa0000000); ++ ++ if (!cfb->fb.screen_base) { ++ printk("%s: unable to map screen memory\n", cfb->fb.fix.id); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void jzfb_free_fb_info(struct lcd_cfb_info *cfb) ++{ ++ if (cfb) { ++ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); ++ kfree(cfb); ++ } ++} ++ ++static void jzfb_unmap_smem(struct lcd_cfb_info *cfb) ++{ ++ struct page * map = NULL; ++ unsigned char *tmp; ++ unsigned int page_shift, needroom, t; ++ ++ t = jzfb.bpp; ++ if (jzfb.bpp == 18 || jzfb.bpp == 24) ++ t = 32; ++ if (jzfb.bpp == 15) ++ t = 16; ++ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; ++ for (page_shift = 0; page_shift < 12; page_shift++) ++ if ((PAGE_SIZE << page_shift) >= needroom) ++ break; ++ ++ if (cfb && cfb->fb.screen_base) { ++ iounmap(cfb->fb.screen_base); ++ cfb->fb.screen_base = NULL; ++ release_mem_region(cfb->fb.fix.smem_start, ++ cfb->fb.fix.smem_len); ++ } ++ ++ if (slcd_palette) { ++ map = virt_to_page(slcd_palette); ++ clear_bit(PG_reserved, &map->flags); ++ free_pages((int)slcd_palette, 0); ++ } ++ ++ if (slcd_frame) { ++ ++ for (tmp=(unsigned char *)slcd_frame; ++ tmp < slcd_frame + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ clear_bit(PG_reserved, &map->flags); ++ } ++ ++ free_pages((int)slcd_frame, page_shift); ++ } ++} ++ ++static void slcd_descriptor_init(void) ++{ ++ int i; ++ int frm_size, pal_size; ++ unsigned int next; ++ unsigned int slcd_frame_src_phys_addr, slcd_palette_src_phys_addr, slcd_dma_dst_phys_addr; ++ ++ i = jzfb.bpp; ++ if (i == 18 || i == 24) ++ i = 32; ++ if (i == 15) ++ i = 16; ++ ++ switch (jzfb.bpp) { ++ case 1: ++ pal_size = 4; ++ break; ++ case 2: ++ pal_size = 8; ++ break; ++ case 4: ++ pal_size = 32; ++ break; ++ case 8: ++ default: ++ pal_size = 512; ++ } ++ ++ frm_size = jzfb.w * jzfb.h * jzfb.bpp / 8; ++ ++ /*Offset of next descriptor*/ ++ slcd_frame_desc_phys_addr = (dma_addr_t)CPHYSADDR((unsigned long)(&slcd_frame_desc)); ++ slcd_palette_desc_phys_addr = (dma_addr_t)CPHYSADDR((unsigned long)(&slcd_palette_desc)); ++ ++ /*Soure address and Target address*/ ++ slcd_palette_src_phys_addr = (unsigned int)virt_to_phys(slcd_palette); ++ slcd_frame_src_phys_addr = (unsigned int)virt_to_phys(slcd_frame); ++ slcd_dma_dst_phys_addr = (unsigned int)CPHYSADDR(SLCD_FIFO); ++ next = slcd_frame_desc_phys_addr >> 4; ++ ++ /* Prepare Palette Descriptor */ ++ slcd_palette_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 ++ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V ++ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; ++ switch (slcd_palette_desc.dcmd & DMAC_DCMD_DS_MASK) { ++ case DMAC_DCMD_DS_32BYTE: ++ pal_size /= 32; ++ break; ++ case DMAC_DCMD_DS_16BYTE: ++ pal_size /= 16; ++ break; ++ case DMAC_DCMD_DS_32BIT: ++ pal_size /= 4; ++ break; ++ case DMAC_DCMD_DS_16BIT: ++ pal_size /= 2; ++ break; ++ case DMAC_DCMD_DS_8BIT: ++ default: ++ break; ++ } ++ ++ slcd_palette_desc.dsadr = (unsigned int)virt_to_phys(slcd_palette); /* DMA source address */ ++ slcd_palette_desc.dtadr = (unsigned int)CPHYSADDR(SLCD_FIFO); /* DMA target address */ ++ slcd_palette_desc.ddadr = (volatile unsigned int)((next << 24) | (pal_size & 0xffffff)); /* offset and size*/ ++ dma_cache_wback((unsigned long)(&slcd_palette_desc), 16); ++ ++ /*Prepare Frame Descriptor in memory*/ ++ switch (jzfb.bpp) { ++ case 8 ... 16: ++ slcd_frame_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 ++ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V ++ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; ++ break; ++ ++ case 17 ... 32: ++ slcd_frame_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 ++ | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V ++ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; ++ break; ++ } ++ switch (slcd_frame_desc.dcmd & DMAC_DCMD_DS_MASK) { ++ case DMAC_DCMD_DS_32BYTE: ++ frm_size /= 32; ++ break; ++ case DMAC_DCMD_DS_16BYTE: ++ frm_size /= 16; ++ break; ++ case DMAC_DCMD_DS_32BIT: ++ frm_size /= 4; ++ break; ++ case DMAC_DCMD_DS_16BIT: ++ frm_size /= 2; ++ break; ++ case DMAC_DCMD_DS_8BIT: ++ default: ++ break; ++ } ++ ++ slcd_frame_desc.dsadr = slcd_frame_src_phys_addr; /* DMA source address */ ++ slcd_frame_desc.dtadr = slcd_dma_dst_phys_addr; /* DMA target address */ ++ slcd_frame_desc.ddadr = (volatile unsigned int)((next << 24) | (frm_size & 0xffffff)); /* offset and size*/ ++ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16); ++} ++ ++void slcd_hw_init(void) ++{ ++ unsigned int val, pclk; ++ int pll_div; ++ ++ REG_LCD_CFG &= ~LCD_CFG_LCDPIN_MASK; ++ REG_LCD_CFG |= LCD_CFG_LCDPIN_SLCD; ++ ++ if ((jzfb.bpp == 18) | (jzfb.bpp == 24)) ++ jzfb.bpp = 32; ++ ++ /* Configure SLCD module for initialize smart lcd registers*/ ++ switch (jzfb.bus) { ++ case 8: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 ++ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_8bit(); ++ break; ++ case 9: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 ++ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_9bit(); ++ break; ++ case 16: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_16 ++ | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_16bit(); ++ break; ++ case 18: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18 ++ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_18bit(); ++ break; ++ default: ++ printk("Error: Don't support BUS %d!\n", jzfb.bus); ++ break; ++ } ++ ++ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; ++ __cpm_stop_lcd(); ++ pclk = jzfb.pclk; ++ pll_div = ( REG_CPM_CPCCR & CPM_CPCCR_PCS ); /* clock source,0:pllout/2 1: pllout */ ++ pll_div = pll_div ? 1 : 2 ; ++ val = ( __cpm_get_pllout()/pll_div ) / pclk; ++ val--; ++ if ( val > 0x1ff ) { ++ printk("CPM_LPCDR too large, set it to 0x1ff\n"); ++ val = 0x1ff; ++ } ++ __cpm_set_pixdiv(val); ++ ++ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ ++ ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ printk("SLCDC: PixClock:%d LcdClock:%d\n", ++ jz_clocks.pixclk, jz_clocks.lcdclk); ++ ++ __cpm_start_lcd(); ++ udelay(1000); ++ __slcd_display_pin_init(); ++ __slcd_special_on(); ++ ++ /* Configure SLCD module for transfer data to smart lcd GRAM*/ ++ switch (jzfb.bus) { ++ case 8: ++ switch (jzfb.bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15: ++ case 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ case 9: ++ switch (jzfb.bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15 ... 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_9_x2; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ case 16: ++ switch (jzfb.bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15 ... 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ case 18: ++ switch (jzfb.bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15: ++ case 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_18; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ default: ++ printk("Error: The BUS %d is not supported\n", jzfb.bus); ++ break; ++ } ++ dprintk("SLCD_CFG=0x%x\n", REG_SLCD_CFG); ++} ++ ++static irqreturn_t slcd_dma_irq(int irq, void *dev_id) ++{ ++ ++ if (__dmac_channel_transmit_halt_detected(dma_chan)) { ++ dprintk("DMA HALT\n"); ++ __dmac_channel_clear_transmit_halt(dma_chan); ++ } ++ ++ if (__dmac_channel_address_error_detected(dma_chan)) { ++ dprintk("DMA ADDR ERROR\n"); ++ __dmac_channel_clear_address_error(dma_chan); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { ++ dprintk("DMA DESC INVALID\n"); ++ __dmac_channel_clear_descriptor_invalid(dma_chan); ++ } ++ ++ if (__dmac_channel_count_terminated_detected(dma_chan)) { ++ dprintk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(dma_chan); ++ if(is_set_reg){ ++ printk("Close DMAC_DCMD_LINK \n"); ++ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; ++ } ++ if (non_link_desp) { ++ printk("Close DMAC_DCMD_LINK \n"); ++ /*Set to Non-Link Descriptor*/ ++ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; ++ } ++ } ++ ++ if (__dmac_channel_transmit_end_detected(dma_chan)) { ++ printk("DMA TT\n"); ++ __dmac_channel_clear_transmit_end(dma_chan); ++ if (non_link_desp) { ++ slcd_frame_desc.dcmd |= DMAC_DCMD_TIE; ++ slcd_frame_desc.dcmd &= ~DMAC_DCMD_LINK; ++ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16); ++ non_link_desp = 0; ++ } ++ if (is_set_reg) { ++ is_set_reg = 0; ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE; /* disable DMA */ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ REG_SLCD_CTRL = 0; ++ ++ /* ++ *add operation here ++ */ ++ Mcupanel_RegSet(reg_buf.cmd, reg_buf.data); ++ Mcupanel_Command(0x0022);/*Write Data to GRAM */ ++ mdelay(100); ++ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; ++ __dmac_channel_set_doorbell(dma_chan); ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++static int slcd_dma_init(void) ++{ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", slcd_dma_irq, 0, NULL); ++ if (dma_chan < 0) { ++ printk("Request DMA Failed\n"); ++ return -1; ++ } ++ printk("DMA channel %d is requested by SLCD!\n", dma_chan); ++ ++ /*Init the SLCD DMA and Enable*/ ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_SLCD; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /*Descriptor Transfer*/ ++ ++ if (jzfb.bpp <= 8) ++ REG_DMAC_DDA(dma_chan) = slcd_palette_desc_phys_addr; ++ else ++ REG_DMAC_DDA(dma_chan) = slcd_frame_desc_phys_addr; ++ ++ /* DMA doorbell set -- start DMA now ... */ ++ __dmac_channel_set_doorbell(dma_chan); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++/* ++ * Suspend the LCDC. ++ */ ++static int jzfb_suspend(void) ++{ ++ ++ __slcd_close_backlight(); ++ __dmac_disable_channel(dma_chan); ++ __slcd_dma_disable(); /* Quick Disable */ ++ __slcd_special_off(); ++ __cpm_stop_lcd(); ++ return 0; ++} ++ ++/* ++ * Resume the LCDC. ++ */ ++ ++static int jzfb_resume(void) ++{ ++ __cpm_start_lcd(); ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ switch (jzfb.bpp) { ++ case 8: ++ /* DATA 8-bit once*/ ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15: ++ case 16: ++ case 18: ++ case 24: ++ case 32: ++ /* DATA 8-bit twice*/ ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; ++ break; ++ default: ++ REG_SLCD_CFG = SLCD_CFG_DWIDTH_8_x2; ++ break; ++ } ++ __slcd_display_pin_init(); ++ __slcd_special_on(); ++ ++ if (jzfb.bpp == 32) { ++ /* DATA 8-bit three time*/ ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; ++ } ++ __slcd_dma_enable(); ++ udelay(100); ++ __dmac_enable_channel(dma_chan); ++ __dmac_channel_set_doorbell(dma_chan); ++ mdelay(200); ++ __slcd_set_backlight_level(80); ++ return 0; ++} ++ ++/* ++ * Power management hook. Note that we won't be called from IRQ context, ++ * unlike the blank functions above, so we may sleep. ++ */ ++static int jzslcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct lcd_cfb_info *cfb = pm_dev->data; ++ ++ if (!cfb) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jzfb_suspend(); ++ break; ++ ++ case PM_RESUME: ++ ret = jzfb_resume(); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#else ++#define jzfb_suspend NULL ++#define jzfb_resume NULL ++#endif /* CONFIG_PM */ ++static int __init jzslcd_fb_init(void) ++{ ++ ++ struct lcd_cfb_info *cfb; ++ int err = 0; ++ ++ /*the parameters of slcd*/ ++ cfb = jzfb_alloc_fb_info(); ++ if (!cfb) ++ goto failed; ++ ++ err = jzfb_map_smem(cfb); ++ if (err) ++ goto failed; ++ jzfb_set_var(&cfb->fb.var, -1, &cfb->fb); ++ ++ slcd_hw_init(); ++ ++ err = register_framebuffer(&cfb->fb); ++ if (err < 0) { ++ printk("jzslcd_fb_init(): slcd register framebuffer err.\n"); ++ goto failed; ++ } ++ ++ printk("fb%d: %s frame buffer device, using %dK of video memory\n", ++ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10); ++ ++ slcd_descriptor_init(); ++ err = slcd_dma_init(); ++ if (err != 0) { ++ printk("SLCD Init DMA Fail!\n"); ++ return err; ++ } ++ mdelay(100); ++ __slcd_set_backlight_level(80); ++ ++#ifdef CONFIG_PM ++ /* ++ * Note that the console registers this as well, but we want to ++ * power down the display prior to sleeping. ++ */ ++//struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback); ++ ++ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzslcd_pm_callback); ++ if (cfb->pm) ++ cfb->pm->data = cfb; ++ ++#endif ++ return 0; ++ ++failed: ++ jzfb_unmap_smem(cfb); ++ jzfb_free_fb_info(cfb); ++ ++ return err; ++} ++ ++#if 0 ++static int jzfb_remove(struct device *dev) ++{ ++ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); ++ jzfb_unmap_smem(cfb); ++ jzfb_free_fb_info(cfb); ++ return 0; ++} ++#endif ++ ++#if 0 ++static struct device_driver jzfb_driver = { ++ .name = "jz-slcd", ++ .bus = &platform_bus_type, ++ .probe = jzfb_probe, ++ .remove = jzfb_remove, ++ .suspend = jzfb_suspend, ++ .resume = jzfb_resume, ++}; ++#endif ++ ++static void __exit jzslcd_fb_cleanup(void) ++{ ++ //driver_unregister(&jzfb_driver); ++ //jzfb_remove(); ++} ++ ++module_init(jzslcd_fb_init); ++module_exit(jzslcd_fb_cleanup); ++ ++MODULE_DESCRIPTION("JzSOC SLCD Controller driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/jz4740_slcd.h b/drivers/video/jz4740_slcd.h +new file mode 100644 +index 0000000..84754f6 +--- /dev/null ++++ b/drivers/video/jz4740_slcd.h +@@ -0,0 +1,376 @@ ++/* ++ * linux/drivers/video/jzslcd.h -- Ingenic On-Chip SLCD frame buffer device ++ * ++ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef __JZSLCD_H__ ++#define __JZSLCD_H__ ++ ++#define UINT16 unsigned short ++#define UINT32 unsigned int ++ ++#define NR_PALETTE 256 ++/* Jz LCDFB supported I/O controls. */ ++#define FBIOSETBACKLIGHT 0x4688 ++#define FBIODISPON 0x4689 ++#define FBIODISPOFF 0x468a ++#define FBIORESET 0x468b ++#define FBIOPRINT_REG 0x468c ++#define FBIO_REFRESH_ALWAYS 0x468d ++#define FBIO_REFRESH_EVENTS 0x468e ++#define FBIO_DO_REFRESH 0x468f ++#define FBIO_SET_REG 0x4690 ++ ++#ifdef CONFIG_JZ_SLCD_LGDP4551 ++#define PIN_CS_N (32*2+18) /* Chip select :SLCD_WR: GPC18 */ ++#define PIN_RESET_N (32*2+21) /* LCD reset :SLCD_RST: GPC21*/ ++#define PIN_RS_N (32*2+19) ++ ++#define __slcd_special_pin_init() \ ++do { \ ++ __gpio_as_output(PIN_CS_N); \ ++ __gpio_as_output(PIN_RESET_N); \ ++ __gpio_clear_pin(PIN_CS_N); /* Clear CS */\ ++ mdelay(100); \ ++} while(0) ++ ++#define __slcd_special_on() \ ++do { /* RESET# */ \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_clear_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(100); \ ++ Mcupanel_RegSet(0x0015,0x0050); \ ++ Mcupanel_RegSet(0x0011,0x0000); \ ++ Mcupanel_RegSet(0x0010,0x3628); \ ++ Mcupanel_RegSet(0x0012,0x0002); \ ++ Mcupanel_RegSet(0x0013,0x0E47); \ ++ udelay(100); \ ++ Mcupanel_RegSet(0x0012,0x0012); \ ++ udelay(100); \ ++ Mcupanel_RegSet(0x0010,0x3620); \ ++ Mcupanel_RegSet(0x0013,0x2E47); \ ++ udelay(50); \ ++ Mcupanel_RegSet(0x0030,0x0000); \ ++ Mcupanel_RegSet(0x0031,0x0502); \ ++ Mcupanel_RegSet(0x0032,0x0307); \ ++ Mcupanel_RegSet(0x0033,0x0304); \ ++ Mcupanel_RegSet(0x0034,0x0004); \ ++ Mcupanel_RegSet(0x0035,0x0401); \ ++ Mcupanel_RegSet(0x0036,0x0707); \ ++ Mcupanel_RegSet(0x0037,0x0303); \ ++ Mcupanel_RegSet(0x0038,0x1E02); \ ++ Mcupanel_RegSet(0x0039,0x1E02); \ ++ Mcupanel_RegSet(0x0001,0x0000); \ ++ Mcupanel_RegSet(0x0002,0x0300); \ ++ if (jzfb.bpp == 16) \ ++ Mcupanel_RegSet(0x0003,0x10B8); /*8-bit system interface two transfers ++ up:0x10B8 down:0x1088 left:0x1090 right:0x10a0*/ \ ++ else \ ++ if (jzfb.bpp == 32)\ ++ Mcupanel_RegSet(0x0003,0xD0B8);/*8-bit system interface three transfers,666 ++ up:0xD0B8 down:0xD088 left:0xD090 right:0xD0A0*/ \ ++ Mcupanel_RegSet(0x0008,0x0204);\ ++ Mcupanel_RegSet(0x000A,0x0008);\ ++ Mcupanel_RegSet(0x0060,0x3100);\ ++ Mcupanel_RegSet(0x0061,0x0001);\ ++ Mcupanel_RegSet(0x0090,0x0052);\ ++ Mcupanel_RegSet(0x0092,0x000F);\ ++ Mcupanel_RegSet(0x0093,0x0001);\ ++ Mcupanel_RegSet(0x009A,0x0008);\ ++ Mcupanel_RegSet(0x00A3,0x0010);\ ++ Mcupanel_RegSet(0x0050,0x0000);\ ++ Mcupanel_RegSet(0x0051,0x00EF);\ ++ Mcupanel_RegSet(0x0052,0x0000);\ ++ Mcupanel_RegSet(0x0053,0x018F);\ ++ /*===Display_On_Function=== */ \ ++ Mcupanel_RegSet(0x0007,0x0001);\ ++ Mcupanel_RegSet(0x0007,0x0021);\ ++ Mcupanel_RegSet(0x0007,0x0023);\ ++ Mcupanel_RegSet(0x0007,0x0033);\ ++ Mcupanel_RegSet(0x0007,0x0133);\ ++ Mcupanel_Command(0x0022);/*Write Data to GRAM */ \ ++ udelay(1); \ ++ Mcupanel_SetAddr(0,0); \ ++ mdelay(100); \ ++} while (0) ++ ++#define __slcd_special_off() \ ++do { \ ++} while(0) ++#endif /*CONFIG_JZ_SLCD_LGDP4551_xxBUS*/ ++ ++#ifdef CONFIG_JZ_SLCD_SPFD5420A ++ ++ //#define PIN_CS_N (32*2+18) // Chip select //GPC18; ++#define PIN_CS_N (32*2+22) // Chip select //GPC18; ++#define PIN_RESET_N (32*1+18) // LCD reset //GPB18; ++#define PIN_RS_N (32*2+19) // LCD RS //GPC19; ++#define PIN_POWER_N (32*3+0) //Power off //GPD0; ++#define PIN_FMARK_N (32*3+1) //fmark //GPD1; ++ ++#define GAMMA() \ ++do { \ ++ Mcupanel_RegSet(0x0300,0x0101); \ ++ Mcupanel_RegSet(0x0301,0x0b27); \ ++ Mcupanel_RegSet(0x0302,0x132a); \ ++ Mcupanel_RegSet(0x0303,0x2a13); \ ++ Mcupanel_RegSet(0x0304,0x270b); \ ++ Mcupanel_RegSet(0x0305,0x0101); \ ++ Mcupanel_RegSet(0x0306,0x1205); \ ++ Mcupanel_RegSet(0x0307,0x0512); \ ++ Mcupanel_RegSet(0x0308,0x0005); \ ++ Mcupanel_RegSet(0x0309,0x0003); \ ++ Mcupanel_RegSet(0x030a,0x0f04); \ ++ Mcupanel_RegSet(0x030b,0x0f00); \ ++ Mcupanel_RegSet(0x030c,0x000f); \ ++ Mcupanel_RegSet(0x030d,0x040f); \ ++ Mcupanel_RegSet(0x030e,0x0300); \ ++ Mcupanel_RegSet(0x030f,0x0500); \ ++ /*** secorrect gamma2 ***/ \ ++ Mcupanel_RegSet(0x0400,0x3500); \ ++ Mcupanel_RegSet(0x0401,0x0001); \ ++ Mcupanel_RegSet(0x0404,0x0000); \ ++ Mcupanel_RegSet(0x0500,0x0000); \ ++ Mcupanel_RegSet(0x0501,0x0000); \ ++ Mcupanel_RegSet(0x0502,0x0000); \ ++ Mcupanel_RegSet(0x0503,0x0000); \ ++ Mcupanel_RegSet(0x0504,0x0000); \ ++ Mcupanel_RegSet(0x0505,0x0000); \ ++ Mcupanel_RegSet(0x0600,0x0000); \ ++ Mcupanel_RegSet(0x0606,0x0000); \ ++ Mcupanel_RegSet(0x06f0,0x0000); \ ++ Mcupanel_RegSet(0x07f0,0x5420); \ ++ Mcupanel_RegSet(0x07f3,0x288a); \ ++ Mcupanel_RegSet(0x07f4,0x0022); \ ++ Mcupanel_RegSet(0x07f5,0x0001); \ ++ Mcupanel_RegSet(0x07f0,0x0000); \ ++} while(0) ++ ++#define __slcd_special_on() \ ++do { \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_clear_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(100); \ ++ if (jzfb.bus == 18) {\ ++ Mcupanel_RegSet(0x0606,0x0000); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0007,0x0001); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0110,0x0001); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0100,0x17b0); \ ++ Mcupanel_RegSet(0x0101,0x0147); \ ++ Mcupanel_RegSet(0x0102,0x019d); \ ++ Mcupanel_RegSet(0x0103,0x8600); \ ++ Mcupanel_RegSet(0x0281,0x0010); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0102,0x01bd); \ ++ udelay(10); \ ++ /************initial************/\ ++ Mcupanel_RegSet(0x0000,0x0000); \ ++ Mcupanel_RegSet(0x0001,0x0000); \ ++ Mcupanel_RegSet(0x0002,0x0400); \ ++ Mcupanel_RegSet(0x0003,0x1288); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ \ ++ Mcupanel_RegSet(0x0006,0x0000); \ ++ Mcupanel_RegSet(0x0008,0x0503); \ ++ Mcupanel_RegSet(0x0009,0x0001); \ ++ Mcupanel_RegSet(0x000b,0x0010); \ ++ Mcupanel_RegSet(0x000c,0x0000); \ ++ Mcupanel_RegSet(0x000f,0x0000); \ ++ Mcupanel_RegSet(0x0007,0x0001); \ ++ Mcupanel_RegSet(0x0010,0x0010); \ ++ Mcupanel_RegSet(0x0011,0x0202); \ ++ Mcupanel_RegSet(0x0012,0x0300); \ ++ Mcupanel_RegSet(0x0020,0x021e); \ ++ Mcupanel_RegSet(0x0021,0x0202); \ ++ Mcupanel_RegSet(0x0022,0x0100); \ ++ Mcupanel_RegSet(0x0090,0x0000); \ ++ Mcupanel_RegSet(0x0092,0x0000); \ ++ Mcupanel_RegSet(0x0100,0x16b0); \ ++ Mcupanel_RegSet(0x0101,0x0147); \ ++ Mcupanel_RegSet(0x0102,0x01bd); \ ++ Mcupanel_RegSet(0x0103,0x2c00); \ ++ Mcupanel_RegSet(0x0107,0x0000); \ ++ Mcupanel_RegSet(0x0110,0x0001); \ ++ Mcupanel_RegSet(0x0210,0x0000); \ ++ Mcupanel_RegSet(0x0211,0x00ef); \ ++ Mcupanel_RegSet(0x0212,0x0000); \ ++ Mcupanel_RegSet(0x0213,0x018f); \ ++ Mcupanel_RegSet(0x0280,0x0000); \ ++ Mcupanel_RegSet(0x0281,0x0001); \ ++ Mcupanel_RegSet(0x0282,0x0000); \ ++ GAMMA(); \ ++ Mcupanel_RegSet(0x0007,0x0173); \ ++ } else { \ ++ Mcupanel_RegSet(0x0600, 0x0001); /*soft reset*/ \ ++ mdelay(10); \ ++ Mcupanel_RegSet(0x0600, 0x0000); /*soft reset*/ \ ++ mdelay(10); \ ++ Mcupanel_RegSet(0x0606, 0x0000); /*i80-i/F Endian Control*/ \ ++ /*===User setting=== */ \ ++ Mcupanel_RegSet(0x0001, 0x0000);/* Driver Output Control-----0x0100 SM(bit10) | 0x400*/ \ ++ Mcupanel_RegSet(0x0002, 0x0100); /*LCD Driving Wave Control 0x0100 */ \ ++ if (jzfb.bpp == 16) \ ++ Mcupanel_RegSet(0x0003, 0x50A8);/*Entry Mode 0x1030*/ \ ++ else /*bpp = 18*/ \ ++ Mcupanel_RegSet(0x0003, 0x1010 | 0xC8); /*Entry Mode 0x1030*/ \ ++ /*#endif */ \ ++ Mcupanel_RegSet(0x0006, 0x0000); /*Outline Sharpening Control*/\ ++ Mcupanel_RegSet(0x0008, 0x0808); /*Sets the number of lines for front/back porch period*/\ ++ Mcupanel_RegSet(0x0009, 0x0001); /*Display Control 3 */\ ++ Mcupanel_RegSet(0x000B, 0x0010); /*Low Power Control*/\ ++ Mcupanel_RegSet(0x000C, 0x0000); /*External Display Interface Control 1 /*0x0001*/\ ++ Mcupanel_RegSet(0x000F, 0x0000); /*External Display Interface Control 2 */\ ++ Mcupanel_RegSet(0x0400, 0xB104);/*Base Image Number of Line---GS(bit15) | 0x8000*/ \ ++ Mcupanel_RegSet(0x0401, 0x0001); /*Base Image Display 0x0001*/\ ++ Mcupanel_RegSet(0x0404, 0x0000); /*Base Image Vertical Scroll Control 0x0000*/\ ++ Mcupanel_RegSet(0x0500, 0x0000); /*Partial Image 1: Display Position*/\ ++ Mcupanel_RegSet(0x0501, 0x0000); /*RAM Address (Start Line Address) */\ ++ Mcupanel_RegSet(0x0502, 0x018f); /*RAM Address (End Line Address) */ \ ++ Mcupanel_RegSet(0x0503, 0x0000); /*Partial Image 2: Display Position RAM Address*/\ ++ Mcupanel_RegSet(0x0504, 0x0000); /*RAM Address (Start Line Address) */\ ++ Mcupanel_RegSet(0x0505, 0x0000); /*RAM Address (End Line Address)*/\ ++ /*Panel interface control===*/\ ++ Mcupanel_RegSet(0x0010, 0x0011); /*Division Ratio,Clocks per Line 14 */\ ++ mdelay(10); \ ++ Mcupanel_RegSet(0x0011, 0x0202); /*Division Ratio,Clocks per Line*/\ ++ Mcupanel_RegSet(0x0012, 0x0300); /*Sets low power VCOM drive period. */\ ++ mdelay(10); \ ++ Mcupanel_RegSet(0x0020, 0x021e); /*Panel Interface Control 4 */\ ++ Mcupanel_RegSet(0x0021, 0x0202); /*Panel Interface Control 5 */\ ++ Mcupanel_RegSet(0x0022, 0x0100); /*Panel Interface Control 6*/\ ++ Mcupanel_RegSet(0x0090, 0x0000); /*Frame Marker Control */\ ++ Mcupanel_RegSet(0x0092, 0x0000); /*MDDI Sub-display Control */\ ++ /*===Gamma setting=== */\ ++ Mcupanel_RegSet(0x0300, 0x0101); /*γ Control*/\ ++ Mcupanel_RegSet(0x0301, 0x0000); /*γ Control*/\ ++ Mcupanel_RegSet(0x0302, 0x0016); /*γ Control*/\ ++ Mcupanel_RegSet(0x0303, 0x2913); /*γ Control*/\ ++ Mcupanel_RegSet(0x0304, 0x260B); /*γ Control*/\ ++ Mcupanel_RegSet(0x0305, 0x0101); /*γ Control*/\ ++ Mcupanel_RegSet(0x0306, 0x1204); /*γ Control*/\ ++ Mcupanel_RegSet(0x0307, 0x0415); /*γ Control*/\ ++ Mcupanel_RegSet(0x0308, 0x0205); /*γ Control*/\ ++ Mcupanel_RegSet(0x0309, 0x0303); /*γ Control*/\ ++ Mcupanel_RegSet(0x030a, 0x0E05); /*γ Control*/\ ++ Mcupanel_RegSet(0x030b, 0x0D01); /*γ Control*/\ ++ Mcupanel_RegSet(0x030c, 0x010D); /*γ Control*/\ ++ Mcupanel_RegSet(0x030d, 0x050E); /*γ Control*/\ ++ Mcupanel_RegSet(0x030e, 0x0303); /*γ Control*/\ ++ Mcupanel_RegSet(0x030f, 0x0502); /*γ Control*/\ ++ /*===Power on sequence===*/\ ++ Mcupanel_RegSet(0x0007, 0x0001); /*Display Control 1*/\ ++ Mcupanel_RegSet(0x0110, 0x0001); /*Power supply startup enable bit*/\ ++ Mcupanel_RegSet(0x0112, 0x0060); /*Power Control 7*/\ ++ Mcupanel_RegSet(0x0100, 0x16B0); /*Power Control 1 */\ ++ Mcupanel_RegSet(0x0101, 0x0115); /*Power Control 2*/\ ++ Mcupanel_RegSet(0x0102, 0x0119); /*Starts VLOUT3,Sets the VREG1OUT.*/\ ++ mdelay(50); \ ++ Mcupanel_RegSet(0x0103, 0x2E00); /*set the amplitude of VCOM*/\ ++ mdelay(50);\ ++ Mcupanel_RegSet(0x0282, 0x0093);/*0x008E);/*0x0093); /*VCOMH voltage*/\ ++ Mcupanel_RegSet(0x0281, 0x000A); /*Selects the factor of VREG1OUT to generate VCOMH. */\ ++ Mcupanel_RegSet(0x0102, 0x01BE); /*Starts VLOUT3,Sets the VREG1OUT.*/\ ++ mdelay(10);\ ++ /*Address */\ ++ Mcupanel_RegSet(0x0210, 0x0000); /*Window Horizontal RAM Address Start*/\ ++ Mcupanel_RegSet(0x0211, 0x00ef); /*Window Horizontal RAM Address End*/\ ++ Mcupanel_RegSet(0x0212, 0x0000); /*Window Vertical RAM Address Start*/\ ++ Mcupanel_RegSet(0x0213, 0x018f); /*Window Vertical RAM Address End */\ ++ Mcupanel_RegSet(0x0200, 0x0000); /*RAM Address Set (Horizontal Address)*/\ ++ Mcupanel_RegSet(0x0201, 0x018f); /*RAM Address Set (Vertical Address)*/ \ ++ /*===Display_On_Function===*/\ ++ Mcupanel_RegSet(0x0007, 0x0021); /*Display Control 1 */\ ++ mdelay(50); /*40*/\ ++ Mcupanel_RegSet(0x0007, 0x0061); /*Display Control 1 */\ ++ mdelay(50); /*100*/\ ++ Mcupanel_RegSet(0x0007, 0x0173); /*Display Control 1 */\ ++ mdelay(50); /*300*/\ ++ }\ ++ Mcupanel_Command(0x0202); /*Write Data to GRAM */ \ ++ udelay(10);\ ++ Mcupanel_SetAddr(0,0);\ ++ udelay(100);\ ++} while(0) ++ ++#define __slcd_special_pin_init() \ ++do { \ ++ __gpio_as_output(PIN_CS_N); \ ++ __gpio_as_output(PIN_RESET_N); \ ++ __gpio_clear_pin(PIN_CS_N); /* Clear CS */ \ ++ __gpio_as_output(PIN_POWER_N); \ ++ mdelay(100); \ ++} while(0) ++ ++#endif /*CONFIG_JZ_SLCD_SPFD5420A*/ ++ ++#ifndef __slcd_special_pin_init ++#define __slcd_special_pin_init() ++#endif ++#ifndef __slcd_special_on ++#define __slcd_special_on() ++#endif ++#ifndef __slcd_special_off ++#define __slcd_special_off() ++#endif ++ ++/* ++ * Platform specific definition ++ */ ++#if defined(CONFIG_SOC_JZ4740) ++#if defined(CONFIG_JZ4740_PAVO) ++#define GPIO_PWM 123 /* GP_D27 */ ++#define PWM_CHN 4 /* pwm channel */ ++#define PWM_FULL 101 ++/* 100 level: 0,1,...,100 */ ++#define __slcd_set_backlight_level(n)\ ++do { \ ++ __gpio_as_output(32*3+27); \ ++ __gpio_set_pin(32*3+27); \ ++} while (0) ++ ++#define __slcd_close_backlight() \ ++do { \ ++ __gpio_as_output(GPIO_PWM); \ ++ __gpio_clear_pin(GPIO_PWM); \ ++} while (0) ++ ++#else ++ ++#define __slcd_set_backlight_level(n) ++#define __slcd_close_backlight() ++ ++#endif /* #if defined(CONFIG_MIPS_JZ4740_PAVO) */ ++ ++#define __slcd_display_pin_init() \ ++do { \ ++ __slcd_special_pin_init(); \ ++} while (0) ++ ++#define __slcd_display_on() \ ++do { \ ++ __slcd_special_on(); \ ++ __slcd_set_backlight_level(80); \ ++} while (0) ++ ++#define __slcd_display_off() \ ++do { \ ++ __slcd_special_off(); \ ++ __slcd_close_backlight(); \ ++} while (0) ++ ++#endif /* CONFIG_SOC_JZ4740 */ ++#endif /*__JZSLCD_H__*/ ++ +diff --git a/drivers/video/jz4750_lcd.c b/drivers/video/jz4750_lcd.c +new file mode 100644 +index 0000000..05a7799 +--- /dev/null ++++ b/drivers/video/jz4750_lcd.c +@@ -0,0 +1,2229 @@ ++/* ++ * linux/drivers/video/jz4750_lcd.c -- Ingenic Jz4750 LCD frame buffer device ++ * ++ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++/* ++ * -------------------------------- ++ * NOTE: ++ * This LCD driver support TFT16 TFT32 LCD, not support STN and Special TFT LCD ++ * now. ++ * It seems not necessory to support STN and Special TFT. ++ * If it's necessary, update this driver in the future. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "console/fbcon.h" ++ ++#include "jz4750_lcd.h" ++#include "jz4750_tve.h" ++ ++#ifdef CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A ++#include "jz_kgm_spfd5420a.h" ++#endif ++ ++MODULE_DESCRIPTION("Jz4750 LCD Controller driver"); ++MODULE_AUTHOR("Wolfgang Wang, "); ++MODULE_LICENSE("GPL"); ++ ++ ++//#define DEBUG ++#undef DEBUG ++ ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg) ++#else ++#define dprintk(x...) ++#define print_dbg(f, arg...) do {} while (0) ++#endif ++ ++#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) ++#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) ++#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) ++ ++struct lcd_cfb_info { ++ struct fb_info fb; ++ struct display_switch *dispsw; ++ signed int currcon; ++ int func_use_count; ++ ++ struct { ++ u16 red, green, blue; ++ } palette[NR_PALETTE]; ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++static struct lcd_cfb_info *jz4750fb_info; ++static struct jz4750_lcd_dma_desc *dma_desc_base; ++static struct jz4750_lcd_dma_desc *dma0_desc_palette, *dma0_desc0, *dma0_desc1, *dma1_desc0, *dma1_desc1; ++#define DMA_DESC_NUM 6 ++ ++static unsigned char *lcd_palette; ++static unsigned char *lcd_frame0; ++static unsigned char *lcd_frame1; ++ ++static struct jz4750_lcd_dma_desc *dma0_desc_cmd0, *dma0_desc_cmd; ++static unsigned char *lcd_cmdbuf ; ++ ++static void jz4750fb_set_mode( struct jz4750lcd_info * lcd_info ); ++static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ); ++ ++ ++ ++struct jz4750lcd_info jz4750_lcd_panel = { ++#if defined(CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ ++ LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ ++ LCD_CFG_HSP | /* Hsync polarity: active low */ ++ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */ ++ .slcd_cfg = 0, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 480, 272, 60, 41, 10, 2, 2, 2, 2, ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */ ++ }, ++#elif defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ ++ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */ ++ LCD_CFG_HSP | /* Hsync polarity: active low */ ++ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */ ++ .slcd_cfg = 0, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 480, 272, 60, 41, 10, 8, 4, 4, 2, ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++// LCD_OSDC_F1EN | /* enable Foreground1 */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {16, 0, 0, 480, 272}, /* bpp, x, y, w, h */ ++ .fg1 = {16, 0, 0, 480, 272}, /* bpp, x, y, w, h */ ++ }, ++#elif defined(CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ ++ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */ ++ LCD_CFG_HSP | /* Hsync polarity: active low */ ++ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */ ++ .slcd_cfg = 0, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 800, 480, 60, 1, 1, 40, 215, 10, 34, ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++// LCD_OSDC_F1EN | /* enable Foreground1 */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0xff, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32, 0, 0, 800, 480}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 800, 480}, /* bpp, x, y, w, h */ ++ }, ++#elif defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */ ++ .slcd_cfg = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 240, 320, 60, 0, 0, 0, 0, 0, 0, ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++// LCD_OSDC_F1EN | /* enable Foreground0 */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32, 0, 0, 240, 320}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 240, 320}, /* bpp, x, y, w, h */ ++ }, ++ ++#elif defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ ++// LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ ++ LCD_CFG_MODE_TFT_24BIT | /* output 24bpp */ ++ LCD_CFG_HSP | /* Hsync polarity: active low */ ++ LCD_CFG_VSP | /* Vsync polarity: leading edge is falling edge */ ++ LCD_CFG_PCP, /* Pix-CLK polarity: data translations at falling edge */ ++ .slcd_cfg = 0, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 320, 240, 80, 1, 1, 10, 50, 10, 13 ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++// LCD_OSDC_F1EN | /* enable Foreground1 */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ ++ }, ++#elif defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_SERIAL_TFT | /* Serial TFT panel */ ++ LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ ++ LCD_CFG_HSP | /* Hsync polarity: active low */ ++ LCD_CFG_VSP | /* Vsync polarity: leading edge is falling edge */ ++ LCD_CFG_PCP, /* Pix-CLK polarity: data translations at falling edge */ ++ .slcd_cfg = 0, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 320, 240, 60, 1, 1, 10, 50, 10, 13 ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ ++ }, ++#elif defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A) ++ .panel = { ++// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ ++ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ ++// LCD_CFG_DITHER | /* dither */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */ ++ .slcd_cfg = SLCD_CFG_DWIDTH_18BIT | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++ 400, 240, 60, 0, 0, 0, 0, 0, 0, ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++// LCD_OSDC_ALPHAMD | /* alpha blending mode */ ++// LCD_OSDC_F1EN | /* enable Foreground1 */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++// .fg0 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */ ++ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */ ++ }, ++#elif defined(CONFIG_JZ4750D_VGA_DISPLAY) ++ .panel = { ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER |/* Underrun recover */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ ++ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */ ++ LCD_CFG_HSP | /* Hsync polarity: active low */ ++ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */ ++ .slcd_cfg = 0, ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ ++// 800, 600, 60, 128, 4, 40, 88, 0, 23 ++ 640, 480, 54, 96, 2, 16, 48, 10, 33 ++// 1280, 720, 50, 152, 15, 22, 200, 14, 1 ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++// LCD_OSDC_F1EN | /* enable Foreground1 */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = 0, ++ .bgcolor = 0x000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80001000, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32, 0, 0, 640, 480}, /* bpp, x, y, w, h */ ++ .fg1 = {32, 0, 0, 640, 480}, /* bpp, x, y, w, h */ ++ }, ++#else ++#error "Select LCD panel first!!!" ++#endif ++}; ++ ++struct jz4750lcd_info jz4750_info_tve = { ++ .panel = { ++ .cfg = LCD_CFG_TVEN | /* output to tve */ ++ LCD_CFG_NEWDES | /* 8words descriptor */ ++ LCD_CFG_RECOVER | /* underrun protect */ ++ LCD_CFG_MODE_INTER_CCIR656, /* Interlace CCIR656 mode */ ++ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst */ ++ TVE_WIDTH_PAL, TVE_HEIGHT_PAL, TVE_FREQ_PAL, 0, 0, 0, 0, 0, 0, ++ }, ++ .osd = { ++ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ ++// LCD_OSDC_ALPHAEN | /* enable alpha */ ++ LCD_OSDC_F0EN, /* enable Foreground0 */ ++ .osd_ctrl = 0, /* disable ipu, */ ++ .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */ ++ .bgcolor = 0x00000000, /* set background color Black */ ++ .colorkey0 = 0, /* disable colorkey */ ++ .colorkey1 = 0, /* disable colorkey */ ++ .alpha = 0xA0, /* alpha value */ ++ .ipu_restart = 0x80000100, /* ipu restart */ ++ .fg_change = FG_CHANGE_ALL, /* change all initially */ ++ .fg0 = {32,}, /* */ ++ .fg0 = {32,}, ++ }, ++}; ++ ++ ++struct jz4750lcd_info *jz4750_lcd_info = &jz4750_lcd_panel; /* default output to lcd panel */ ++ ++#ifdef DEBUG ++static void print_lcdc_registers(void) /* debug */ ++{ ++ /* LCD Controller Resgisters */ ++ printk("REG_LCD_CFG:\t0x%08x\n", REG_LCD_CFG); ++ printk("REG_LCD_CTRL:\t0x%08x\n", REG_LCD_CTRL); ++ printk("REG_LCD_STATE:\t0x%08x\n", REG_LCD_STATE); ++ printk("REG_LCD_OSDC:\t0x%08x\n", REG_LCD_OSDC); ++ printk("REG_LCD_OSDCTRL:\t0x%08x\n", REG_LCD_OSDCTRL); ++ printk("REG_LCD_OSDS:\t0x%08x\n", REG_LCD_OSDS); ++ printk("REG_LCD_BGC:\t0x%08x\n", REG_LCD_BGC); ++ printk("REG_LCD_KEK0:\t0x%08x\n", REG_LCD_KEY0); ++ printk("REG_LCD_KEY1:\t0x%08x\n", REG_LCD_KEY1); ++ printk("REG_LCD_ALPHA:\t0x%08x\n", REG_LCD_ALPHA); ++ printk("REG_LCD_IPUR:\t0x%08x\n", REG_LCD_IPUR); ++ printk("REG_LCD_VAT:\t0x%08x\n", REG_LCD_VAT); ++ printk("REG_LCD_DAH:\t0x%08x\n", REG_LCD_DAH); ++ printk("REG_LCD_DAV:\t0x%08x\n", REG_LCD_DAV); ++ printk("REG_LCD_XYP0:\t0x%08x\n", REG_LCD_XYP0); ++ printk("REG_LCD_XYP1:\t0x%08x\n", REG_LCD_XYP1); ++ printk("REG_LCD_SIZE0:\t0x%08x\n", REG_LCD_SIZE0); ++ printk("REG_LCD_SIZE1:\t0x%08x\n", REG_LCD_SIZE1); ++ printk("REG_LCD_RGBC\t0x%08x\n", REG_LCD_RGBC); ++ printk("REG_LCD_VSYNC:\t0x%08x\n", REG_LCD_VSYNC); ++ printk("REG_LCD_HSYNC:\t0x%08x\n", REG_LCD_HSYNC); ++ printk("REG_LCD_PS:\t0x%08x\n", REG_LCD_PS); ++ printk("REG_LCD_CLS:\t0x%08x\n", REG_LCD_CLS); ++ printk("REG_LCD_SPL:\t0x%08x\n", REG_LCD_SPL); ++ printk("REG_LCD_REV:\t0x%08x\n", REG_LCD_REV); ++ printk("REG_LCD_IID:\t0x%08x\n", REG_LCD_IID); ++ printk("REG_LCD_DA0:\t0x%08x\n", REG_LCD_DA0); ++ printk("REG_LCD_SA0:\t0x%08x\n", REG_LCD_SA0); ++ printk("REG_LCD_FID0:\t0x%08x\n", REG_LCD_FID0); ++ printk("REG_LCD_CMD0:\t0x%08x\n", REG_LCD_CMD0); ++ printk("REG_LCD_OFFS0:\t0x%08x\n", REG_LCD_OFFS0); ++ printk("REG_LCD_PW0:\t0x%08x\n", REG_LCD_PW0); ++ printk("REG_LCD_CNUM0:\t0x%08x\n", REG_LCD_CNUM0); ++ printk("REG_LCD_DESSIZE0:\t0x%08x\n", REG_LCD_DESSIZE0); ++ printk("REG_LCD_DA1:\t0x%08x\n", REG_LCD_DA1); ++ printk("REG_LCD_SA1:\t0x%08x\n", REG_LCD_SA1); ++ printk("REG_LCD_FID1:\t0x%08x\n", REG_LCD_FID1); ++ printk("REG_LCD_CMD1:\t0x%08x\n", REG_LCD_CMD1); ++ printk("REG_LCD_OFFS1:\t0x%08x\n", REG_LCD_OFFS1); ++ printk("REG_LCD_PW1:\t0x%08x\n", REG_LCD_PW1); ++ printk("REG_LCD_CNUM1:\t0x%08x\n", REG_LCD_CNUM1); ++ printk("REG_LCD_DESSIZE1:\t0x%08x\n", REG_LCD_DESSIZE1); ++ printk("==================================\n"); ++ printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff); ++ printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff); ++ printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff); ++ printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff); ++ printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff); ++ printk("==================================\n"); ++ ++ /* Smart LCD Controller Resgisters */ ++ printk("REG_SLCD_CFG:\t0x%08x\n", REG_SLCD_CFG); ++ printk("REG_SLCD_CTRL:\t0x%08x\n", REG_SLCD_CTRL); ++ printk("REG_SLCD_STATE:\t0x%08x\n", REG_SLCD_STATE); ++ printk("==================================\n"); ++ ++ /* TVE Controller Resgisters */ ++ printk("REG_TVE_CTRL:\t0x%08x\n", REG_TVE_CTRL); ++ printk("REG_TVE_FRCFG:\t0x%08x\n", REG_TVE_FRCFG); ++ printk("REG_TVE_SLCFG1:\t0x%08x\n", REG_TVE_SLCFG1); ++ printk("REG_TVE_SLCFG2:\t0x%08x\n", REG_TVE_SLCFG2); ++ printk("REG_TVE_SLCFG3:\t0x%08x\n", REG_TVE_SLCFG3); ++ printk("REG_TVE_LTCFG1:\t0x%08x\n", REG_TVE_LTCFG1); ++ printk("REG_TVE_LTCFG2:\t0x%08x\n", REG_TVE_LTCFG2); ++ printk("REG_TVE_CFREQ:\t0x%08x\n", REG_TVE_CFREQ); ++ printk("REG_TVE_CPHASE:\t0x%08x\n", REG_TVE_CPHASE); ++ printk("REG_TVE_CBCRCFG:\t0x%08x\n", REG_TVE_CBCRCFG); ++ printk("REG_TVE_WSSCR:\t0x%08x\n", REG_TVE_WSSCR); ++ printk("REG_TVE_WSSCFG1:\t0x%08x\n", REG_TVE_WSSCFG1); ++ printk("REG_TVE_WSSCFG2:\t0x%08x\n", REG_TVE_WSSCFG2); ++ printk("REG_TVE_WSSCFG3:\t0x%08x\n", REG_TVE_WSSCFG3); ++ ++ printk("==================================\n"); ++ ++ if ( 1 ) { ++ unsigned int * pii = (unsigned int *)dma_desc_base; ++ int i, j; ++ for (j=0;j< DMA_DESC_NUM ; j++) { ++ printk("dma_desc%d(0x%08x):\n", j, (unsigned int)pii); ++ for (i =0; i<8; i++ ) { ++ printk("\t\t0x%08x\n", *pii++); ++ } ++ } ++ } ++} ++#else ++#define print_lcdc_registers() ++#endif ++ ++static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int jz4750fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ unsigned short *ptr, ctmp; ++ ++// print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp); ++ if (regno >= NR_PALETTE) ++ return 1; ++ ++ cfb->palette[regno].red = red ; ++ cfb->palette[regno].green = green; ++ cfb->palette[regno].blue = blue; ++ if (cfb->fb.var.bits_per_pixel <= 16) { ++ red >>= 8; ++ green >>= 8; ++ blue >>= 8; ++ ++ red &= 0xff; ++ green &= 0xff; ++ blue &= 0xff; ++ } ++ switch (cfb->fb.var.bits_per_pixel) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ if (((jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_SINGLE_MSTN ) || ++ ((jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_DUAL_MSTN )) { ++ ctmp = (77L * red + 150L * green + 29L * blue) >> 8; ++ ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) | ++ (ctmp >> 3); ++ } else { ++ /* RGB 565 */ ++ if (((red >> 3) == 0) && ((red >> 2) != 0)) ++ red = 1 << 3; ++ if (((blue >> 3) == 0) && ((blue >> 2) != 0)) ++ blue = 1 << 3; ++ ctmp = ((red >> 3) << 11) ++ | ((green >> 2) << 5) | (blue >> 3); ++ } ++ ++ ptr = (unsigned short *)lcd_palette; ++ ptr = (unsigned short *)(((u32)ptr)|0xa0000000); ++ ptr[regno] = ctmp; ++ ++ break; ++ ++ case 15: ++ if (regno < 16) ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ ((red >> 3) << 10) | ++ ((green >> 3) << 5) | ++ (blue >> 3); ++ break; ++ case 16: ++ if (regno < 16) { ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ ((red >> 3) << 11) | ++ ((green >> 2) << 5) | ++ (blue >> 3); ++ } ++ break; ++ case 17 ... 32: ++ if (regno < 16) ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ (red << 16) | ++ (green << 8) | ++ (blue << 0); ++ ++/* if (regno < 16) { ++ unsigned val; ++ val = chan_to_field(red, &cfb->fb.var.red); ++ val |= chan_to_field(green, &cfb->fb.var.green); ++ val |= chan_to_field(blue, &cfb->fb.var.blue); ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = val; ++ } ++*/ ++ ++ break; ++ } ++ return 0; ++} ++ ++ ++/* ++ * switch to tve mode from lcd mode ++ * mode: ++ * PANEL_MODE_TVE_PAL: switch to TVE_PAL mode ++ * PANEL_MODE_TVE_NTSC: switch to TVE_NTSC mode ++ */ ++static void jz4750lcd_info_switch_to_TVE(int mode) ++{ ++ struct jz4750lcd_info *info; ++ struct jz4750lcd_osd_t *osd_lcd; ++ int x, y, w, h; ++ ++ info = jz4750_lcd_info = &jz4750_info_tve; ++ osd_lcd = &jz4750_lcd_panel.osd; ++ ++ switch ( mode ) { ++ case PANEL_MODE_TVE_PAL: ++ info->panel.cfg |= LCD_CFG_TVEPEH; /* TVE PAL enable extra halfline signal */ ++ info->panel.w = TVE_WIDTH_PAL; ++ info->panel.h = TVE_HEIGHT_PAL; ++ info->panel.fclk = TVE_FREQ_PAL; ++ w = ( osd_lcd->fg0.w < TVE_WIDTH_PAL )? osd_lcd->fg0.w:TVE_WIDTH_PAL; ++ h = ( osd_lcd->fg0.h < TVE_HEIGHT_PAL )?osd_lcd->fg0.h:TVE_HEIGHT_PAL; ++ x = ((TVE_WIDTH_PAL - w) >> 2) << 1; ++ y = ((TVE_HEIGHT_PAL - h) >> 2) << 1; ++// x = 0; ++// y = 0; ++ info->osd.fg0.bpp = osd_lcd->fg0.bpp; ++ info->osd.fg0.x = x; ++ info->osd.fg0.y = y; ++ info->osd.fg0.w = w; ++ info->osd.fg0.h = h; ++ w = ( osd_lcd->fg1.w < TVE_WIDTH_PAL )? osd_lcd->fg1.w:TVE_WIDTH_PAL; ++ h = ( osd_lcd->fg1.h < TVE_HEIGHT_PAL )?osd_lcd->fg1.h:TVE_HEIGHT_PAL; ++ x = ((TVE_WIDTH_PAL-w) >> 2) << 1; ++ y = ((TVE_HEIGHT_PAL-h) >> 2) << 1; ++ info->osd.fg1.bpp = 32; /* use RGB888 in TVE mode*/ ++ info->osd.fg1.x = x; ++ info->osd.fg1.y = y; ++ info->osd.fg1.w = w; ++ info->osd.fg1.h = h; ++ break; ++ case PANEL_MODE_TVE_NTSC: ++ info->panel.cfg &= ~LCD_CFG_TVEPEH; /* TVE NTSC disable extra halfline signal */ ++ info->panel.w = TVE_WIDTH_NTSC; ++ info->panel.h = TVE_HEIGHT_NTSC; ++ info->panel.fclk = TVE_FREQ_NTSC; ++ w = ( osd_lcd->fg0.w < TVE_WIDTH_NTSC )? osd_lcd->fg0.w:TVE_WIDTH_NTSC; ++ h = ( osd_lcd->fg0.h < TVE_HEIGHT_NTSC)?osd_lcd->fg0.h:TVE_HEIGHT_NTSC; ++ x = ((TVE_WIDTH_NTSC - w) >> 2) << 1; ++ y = ((TVE_HEIGHT_NTSC - h) >> 2) << 1; ++// x = 0; ++// y = 0; ++ info->osd.fg0.bpp = osd_lcd->fg0.bpp; ++ info->osd.fg0.x = x; ++ info->osd.fg0.y = y; ++ info->osd.fg0.w = w; ++ info->osd.fg0.h = h; ++ w = ( osd_lcd->fg1.w < TVE_WIDTH_NTSC )? osd_lcd->fg1.w:TVE_WIDTH_NTSC; ++ h = ( osd_lcd->fg1.h < TVE_HEIGHT_NTSC)?osd_lcd->fg1.h:TVE_HEIGHT_NTSC; ++ x = ((TVE_WIDTH_NTSC - w) >> 2) << 1; ++ y = ((TVE_HEIGHT_NTSC - h) >> 2) << 1; ++ info->osd.fg1.bpp = 32; /* use RGB888 int TVE mode */ ++ info->osd.fg1.x = x; ++ info->osd.fg1.y = y; ++ info->osd.fg1.w = w; ++ info->osd.fg1.h = h; ++ break; ++ default: ++ printk("%s, %s: Unknown tve mode\n", __FILE__, __FUNCTION__); ++ } ++} ++ ++static int jz4750fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ ++ void __user *argp = (void __user *)arg; ++ ++// struct jz4750lcd_info *lcd_info = jz4750_lcd_info; ++ ++ ++ switch (cmd) { ++ case FBIOSETBACKLIGHT: ++ __lcd_set_backlight_level(arg); /* We support 8 levels here. */ ++ break; ++ case FBIODISPON: ++ REG_LCD_STATE = 0; /* clear lcdc status */ ++ __lcd_slcd_special_on(); ++ __lcd_clr_dis(); ++ __lcd_set_ena(); /* enable lcdc */ ++ __lcd_display_on(); ++ break; ++ case FBIODISPOFF: ++ __lcd_display_off(); ++ if ( jz4750_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || ++ jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ ++ __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ ++ else ++ __lcd_set_dis(); /* regular disable */ ++ break; ++ case FBIOPRINT_REG: ++ print_lcdc_registers(); ++ break; ++ case FBIO_GET_MODE: ++ print_dbg("fbio get mode\n"); ++ if (copy_to_user(argp, jz4750_lcd_info, sizeof(struct jz4750lcd_info))) ++ return -EFAULT; ++ break; ++ case FBIO_SET_MODE: ++ print_dbg("fbio set mode\n"); ++ if (copy_from_user(jz4750_lcd_info, argp, sizeof(struct jz4750lcd_info))) ++ return -EFAULT; ++ /* set mode */ ++ jz4750fb_set_mode(jz4750_lcd_info); ++ break; ++ case FBIO_DEEP_SET_MODE: ++ print_dbg("fbio deep set mode\n"); ++ if (copy_from_user(jz4750_lcd_info, argp, sizeof(struct jz4750lcd_info))) ++ return -EFAULT; ++ jz4750fb_deep_set_mode(jz4750_lcd_info); ++ break; ++#ifdef CONFIG_FB_JZ4750_TVE ++ case FBIO_MODE_SWITCH: ++ print_dbg("lcd mode switch between tve and lcd, arg=%lu\n", arg); ++ switch ( arg ) { ++ case PANEL_MODE_TVE_PAL: /* switch to TVE_PAL mode */ ++ case PANEL_MODE_TVE_NTSC: /* switch to TVE_NTSC mode */ ++ jz4750lcd_info_switch_to_TVE(arg); ++ jz4750tve_init(arg); /* tve controller init */ ++ udelay(100); ++ jz4750tve_enable_tve(); ++ /* turn off lcd backlight */ ++ __lcd_display_off(); ++ break; ++ case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */ ++ default : ++ /* turn off TVE, turn off DACn... */ ++ jz4750tve_disable_tve(); ++ jz4750_lcd_info = &jz4750_lcd_panel; ++ /* turn on lcd backlight */ ++ __lcd_display_on(); ++ break; ++ } ++ jz4750fb_deep_set_mode(jz4750_lcd_info); ++ break; ++ case FBIO_GET_TVE_MODE: ++ print_dbg("fbio get TVE mode\n"); ++ if (copy_to_user(argp, jz4750_tve_info, sizeof(struct jz4750tve_info))) ++ return -EFAULT; ++ break; ++ case FBIO_SET_TVE_MODE: ++ print_dbg("fbio set TVE mode\n"); ++ if (copy_from_user(jz4750_tve_info, argp, sizeof(struct jz4750tve_info))) ++ return -EFAULT; ++ /* set tve mode */ ++ jz4750tve_set_tve_mode(jz4750_tve_info); ++ break; ++#endif ++ default: ++ printk("%s, unknown command(0x%x)", __FILE__, cmd); ++ break; ++ } ++ ++ return ret; ++} ++ ++/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ ++static int jz4750fb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); ++ ++ /* frame buffer memory */ ++ start = cfb->fb.fix.smem_start; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ ++ ++#if 1 ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ ++// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Back */ ++#endif ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++/* checks var and eventually tweaks it to something supported, ++ * DO NOT MODIFY PAR */ ++static int jz4750fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ printk("jz4750fb_check_var, not implement\n"); ++ return 0; ++} ++ ++ ++/* ++ * set the video mode according to info->var ++ */ ++static int jz4750fb_set_par(struct fb_info *info) ++{ ++ printk("jz4750fb_set_par, not implemented\n"); ++ return 0; ++} ++ ++ ++/* ++ * (Un)Blank the display. ++ * Fix me: should we use VESA value? ++ */ ++static int jz4750fb_blank(int blank_mode, struct fb_info *info) ++{ ++ dprintk("jz4750 fb_blank %d %p", blank_mode, info); ++ switch (blank_mode) { ++ case FB_BLANK_UNBLANK: ++ //case FB_BLANK_NORMAL: ++ /* Turn on panel */ ++ __lcd_set_ena(); ++ __lcd_display_on(); ++ break; ++ ++ case FB_BLANK_NORMAL: ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ case FB_BLANK_POWERDOWN: ++#if 0 ++ /* Turn off panel */ ++ __lcd_display_off(); ++ __lcd_set_dis(); ++#endif ++ break; ++ default: ++ break; ++ ++ } ++ return 0; ++} ++ ++/* ++ * pan display ++ */ ++static int jz4750fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ int dy; ++ ++ if (!var || !cfb) { ++ return -EINVAL; ++ } ++ ++ if (var->xoffset - cfb->fb.var.xoffset) { ++ /* No support for X panning for now! */ ++ return -EINVAL; ++ } ++ ++ dy = var->yoffset; ++ print_dbg("var.yoffset: %d", dy); ++ if (dy) { ++ dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0 + (cfb->fb.fix.line_length * dy)); ++ dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4750_lcd_dma_desc)); ++ ++ } ++ else { ++ dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0); ++ dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4750_lcd_dma_desc)); ++ } ++ ++ return 0; ++} ++ ++ ++/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ ++static struct fb_ops jz4750fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_setcolreg = jz4750fb_setcolreg, ++ .fb_check_var = jz4750fb_check_var, ++ .fb_set_par = jz4750fb_set_par, ++ .fb_blank = jz4750fb_blank, ++ .fb_pan_display = jz4750fb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_mmap = jz4750fb_mmap, ++ .fb_ioctl = jz4750fb_ioctl, ++}; ++ ++static int jz4750fb_set_var(struct fb_var_screeninfo *var, int con, ++ struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ struct jz4750lcd_info *lcd_info = jz4750_lcd_info; ++ int chgvar = 0; ++ ++ var->height = lcd_info->osd.fg0.h; /* tve mode */ ++ var->width = lcd_info->osd.fg0.w; ++ var->bits_per_pixel = lcd_info->osd.fg0.bpp; ++ ++ var->vmode = FB_VMODE_NONINTERLACED; ++ var->activate = cfb->fb.var.activate; ++ var->xres = var->width; ++ var->yres = var->height; ++ var->xres_virtual = var->width; ++ var->yres_virtual = var->height; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->pixclock = 0; ++ var->left_margin = 0; ++ var->right_margin = 0; ++ var->upper_margin = 0; ++ var->lower_margin = 0; ++ var->hsync_len = 0; ++ var->vsync_len = 0; ++ var->sync = 0; ++ var->activate &= ~FB_ACTIVATE_TEST; ++ ++ /* ++ * CONUPDATE and SMOOTH_XPAN are equal. However, ++ * SMOOTH_XPAN is only used internally by fbcon. ++ */ ++ if (var->vmode & FB_VMODE_CONUPDATE) { ++ var->vmode |= FB_VMODE_YWRAP; ++ var->xoffset = cfb->fb.var.xoffset; ++ var->yoffset = cfb->fb.var.yoffset; ++ } ++ ++ if (var->activate & FB_ACTIVATE_TEST) ++ return 0; ++ ++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) ++ return -EINVAL; ++ ++ if (cfb->fb.var.xres != var->xres) ++ chgvar = 1; ++ if (cfb->fb.var.yres != var->yres) ++ chgvar = 1; ++ if (cfb->fb.var.xres_virtual != var->xres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.yres_virtual != var->yres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) ++ chgvar = 1; ++ ++ //display = fb_display + con; ++ ++ var->red.msb_right = 0; ++ var->green.msb_right = 0; ++ var->blue.msb_right = 0; ++ ++ switch(var->bits_per_pixel){ ++ case 1: /* Mono */ ++ cfb->fb.fix.visual = FB_VISUAL_MONO01; ++ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; ++ break; ++ case 2: /* Mono */ ++ var->red.offset = 0; ++ var->red.length = 2; ++ var->green.offset = 0; ++ var->green.length = 2; ++ var->blue.offset = 0; ++ var->blue.length = 2; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; ++ break; ++ case 4: /* PSEUDOCOLOUR*/ ++ var->red.offset = 0; ++ var->red.length = 4; ++ var->green.offset = 0; ++ var->green.length = 4; ++ var->blue.offset = 0; ++ var->blue.length = 4; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = var->xres / 2; ++ break; ++ case 8: /* PSEUDOCOLOUR, 256 */ ++ var->red.offset = 0; ++ var->red.length = 8; ++ var->green.offset = 0; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = var->xres ; ++ break; ++ case 15: /* DIRECTCOLOUR, 32k */ ++ var->bits_per_pixel = 15; ++ var->red.offset = 10; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 5; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ ++ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 2; ++ break; ++ case 16: /* DIRECTCOLOUR, 64k */ ++ var->bits_per_pixel = 16; ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 2; ++ break; ++ case 17 ... 32: ++ /* DIRECTCOLOUR, 256 */ ++ var->bits_per_pixel = 32; ++ ++ var->red.offset = 16; ++ var->red.length = 8; ++ var->green.offset = 8; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; ++ var->transp.offset = 24; ++ var->transp.length = 8; ++ ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 4; ++ break; ++ ++ default: /* in theory this should never happen */ ++ printk(KERN_WARNING "%s: don't support for %dbpp\n", ++ cfb->fb.fix.id, var->bits_per_pixel); ++ break; ++ } ++ ++ cfb->fb.var = *var; ++ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; ++ ++ /* ++ * Update the old var. The fbcon drivers still use this. ++ * Once they are using cfb->fb.var, this can be dropped. ++ * --rmk ++ */ ++ //display->var = cfb->fb.var; ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); ++ dprintk("jz4750fb_set_var: after fb_set_cmap...\n"); ++ ++ return 0; ++} ++ ++static struct lcd_cfb_info * jz4750fb_alloc_fb_info(void) ++{ ++ struct lcd_cfb_info *cfb; ++ ++ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); ++ ++ if (!cfb) ++ return NULL; ++ ++ jz4750fb_info = cfb; ++ ++ memset(cfb, 0, sizeof(struct lcd_cfb_info) ); ++ ++ cfb->currcon = -1; ++ ++ ++ strcpy(cfb->fb.fix.id, "jz-lcd"); ++ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ cfb->fb.fix.type_aux = 0; ++ cfb->fb.fix.xpanstep = 1; ++ cfb->fb.fix.ypanstep = 1; ++ cfb->fb.fix.ywrapstep = 0; ++ cfb->fb.fix.accel = FB_ACCEL_NONE; ++ ++ cfb->fb.var.nonstd = 0; ++ cfb->fb.var.activate = FB_ACTIVATE_NOW; ++ cfb->fb.var.height = -1; ++ cfb->fb.var.width = -1; ++ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; ++ ++ cfb->fb.fbops = &jz4750fb_ops; ++ cfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ ++ cfb->fb.pseudo_palette = (void *)(cfb + 1); ++ ++ switch (jz4750_lcd_info->osd.fg0.bpp) { ++ case 1: ++ fb_alloc_cmap(&cfb->fb.cmap, 4, 0); ++ break; ++ case 2: ++ fb_alloc_cmap(&cfb->fb.cmap, 8, 0); ++ break; ++ case 4: ++ fb_alloc_cmap(&cfb->fb.cmap, 32, 0); ++ break; ++ case 8: ++ ++ default: ++ fb_alloc_cmap(&cfb->fb.cmap, 256, 0); ++ break; ++ } ++ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); ++ ++ return cfb; ++} ++ ++/* ++ * Map screen memory ++ */ ++static int jz4750fb_map_smem(struct lcd_cfb_info *cfb) ++{ ++ unsigned long page; ++ unsigned int page_shift, needroom, needroom1, bpp, w, h; ++ ++ bpp = jz4750_lcd_info->osd.fg0.bpp; ++ if ( bpp == 18 || bpp == 24) ++ bpp = 32; ++ if ( bpp == 15 ) ++ bpp = 16; ++#ifndef CONFIG_FB_JZ4750_TVE ++ w = jz4750_lcd_info->osd.fg0.w; ++ h = jz4750_lcd_info->osd.fg0.h; ++#else ++ w = ( jz4750_lcd_info->osd.fg0.w > TVE_WIDTH_PAL )?jz4750_lcd_info->osd.fg0.w:TVE_WIDTH_PAL; ++ h = ( jz4750_lcd_info->osd.fg0.h > TVE_HEIGHT_PAL )?jz4750_lcd_info->osd.fg0.h:TVE_HEIGHT_PAL; ++#endif ++ needroom1 = needroom = ((w * bpp + 7) >> 3) * h; ++#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER) ++ bpp = jz4750_lcd_info->osd.fg1.bpp; ++ if ( bpp == 18 || bpp == 24) ++ bpp = 32; ++ if ( bpp == 15 ) ++ bpp = 16; ++ ++#ifndef CONFIG_FB_JZ4750_TVE ++ w = jz4750_lcd_info->osd.fg1.w; ++ h = jz4750_lcd_info->osd.fg1.h; ++#else ++ w = ( jz4750_lcd_info->osd.fg1.w > TVE_WIDTH_PAL )?jz4750_lcd_info->osd.fg1.w:TVE_WIDTH_PAL; ++ h = ( jz4750_lcd_info->osd.fg1.h > TVE_HEIGHT_PAL )?jz4750_lcd_info->osd.fg1.h:TVE_HEIGHT_PAL; ++#endif ++ needroom += ((w * bpp + 7) >> 3) * h; ++#endif // two layer ++ ++ ++ for (page_shift = 0; page_shift < 12; page_shift++) ++ if ((PAGE_SIZE << page_shift) >= needroom) ++ break; ++ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); ++ lcd_frame0 = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ ++ if ((!lcd_palette) || (!lcd_frame0)) ++ return -ENOMEM; ++ memset((void *)lcd_palette, 0, PAGE_SIZE); ++ memset((void *)lcd_frame0, 0, PAGE_SIZE << page_shift); ++ ++ dma_desc_base = (struct jz4750_lcd_dma_desc *)((void*)lcd_palette + ((PALETTE_SIZE+3)/4)*4); ++ ++#if defined(CONFIG_FB_JZ4750_SLCD) ++ ++ lcd_cmdbuf = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); ++ memset((void *)lcd_cmdbuf, 0, PAGE_SIZE); ++ ++ { int data, i, *ptr; ++ ptr = (unsigned int *)lcd_cmdbuf; ++ data = WR_GRAM_CMD; ++ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); ++ for(i = 0; i < 3; i++){ ++ ptr[i] = data; ++ } ++ } ++#endif ++ ++#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER) ++ lcd_frame1 = lcd_frame0 + needroom1; ++#endif ++ ++ /* ++ * Set page reserved so that mmap will work. This is necessary ++ * since we'll be remapping normal memory. ++ */ ++ page = (unsigned long)lcd_palette; ++ SetPageReserved(virt_to_page((void*)page)); ++ ++ for (page = (unsigned long)lcd_frame0; ++ page < PAGE_ALIGN((unsigned long)lcd_frame0 + (PAGE_SIZE<fb.fix.smem_start = virt_to_phys((void *)lcd_frame0); ++ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); /* page_shift/2 ??? */ ++ cfb->fb.screen_base = ++ (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000); ++ ++ if (!cfb->fb.screen_base) { ++ printk("jz4750fb, %s: unable to map screen memory\n", cfb->fb.fix.id); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void jz4750fb_free_fb_info(struct lcd_cfb_info *cfb) ++{ ++ if (cfb) { ++ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); ++ kfree(cfb); ++ } ++} ++ ++static void jz4750fb_unmap_smem(struct lcd_cfb_info *cfb) ++{ ++ struct page * map = NULL; ++ unsigned char *tmp; ++ unsigned int page_shift, needroom, bpp, w, h; ++ ++ bpp = jz4750_lcd_info->osd.fg0.bpp; ++ if ( bpp == 18 || bpp == 24) ++ bpp = 32; ++ if ( bpp == 15 ) ++ bpp = 16; ++ w = jz4750_lcd_info->osd.fg0.w; ++ h = jz4750_lcd_info->osd.fg0.h; ++ needroom = ((w * bpp + 7) >> 3) * h; ++#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER) ++ bpp = jz4750_lcd_info->osd.fg1.bpp; ++ if ( bpp == 18 || bpp == 24) ++ bpp = 32; ++ if ( bpp == 15 ) ++ bpp = 16; ++ w = jz4750_lcd_info->osd.fg1.w; ++ h = jz4750_lcd_info->osd.fg1.h; ++ needroom += ((w * bpp + 7) >> 3) * h; ++#endif ++ ++ for (page_shift = 0; page_shift < 12; page_shift++) ++ if ((PAGE_SIZE << page_shift) >= needroom) ++ break; ++ ++ if (cfb && cfb->fb.screen_base) { ++ iounmap(cfb->fb.screen_base); ++ cfb->fb.screen_base = NULL; ++ release_mem_region(cfb->fb.fix.smem_start, ++ cfb->fb.fix.smem_len); ++ } ++ ++ if (lcd_palette) { ++ map = virt_to_page(lcd_palette); ++ clear_bit(PG_reserved, &map->flags); ++ free_pages((int)lcd_palette, 0); ++ } ++ ++ if (lcd_frame0) { ++ for (tmp=(unsigned char *)lcd_frame0; ++ tmp < lcd_frame0 + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ clear_bit(PG_reserved, &map->flags); ++ } ++ free_pages((int)lcd_frame0, page_shift); ++ } ++} ++ ++/* initial dma descriptors */ ++static void jz4750fb_descriptor_init( struct jz4750lcd_info * lcd_info ) ++{ ++ unsigned int pal_size; ++ ++ switch ( lcd_info->osd.fg0.bpp ) { ++ case 1: ++ pal_size = 4; ++ break; ++ case 2: ++ pal_size = 8; ++ break; ++ case 4: ++ pal_size = 32; ++ break; ++ case 8: ++ default: ++ pal_size = 512; ++ } ++ ++ pal_size /= 4; ++ ++ dma0_desc_palette = dma_desc_base + 0; ++ dma0_desc0 = dma_desc_base + 1; ++ dma0_desc1 = dma_desc_base + 2; ++ dma0_desc_cmd0 = dma_desc_base + 3; /* use only once */ ++ dma0_desc_cmd = dma_desc_base + 4; ++ dma1_desc0 = dma_desc_base + 5; ++ dma1_desc1 = dma_desc_base + 6; ++ ++ /* ++ * Normal TFT panel's DMA Chan0: ++ * TO LCD Panel: ++ * no palette: dma0_desc0 <<==>> dma0_desc0 ++ * palette : dma0_desc_palette <<==>> dma0_desc0 ++ * TO TV Encoder: ++ * no palette: dma0_desc0 <<==>> dma0_desc1 ++ * palette: dma0_desc_palette --> dma0_desc0 ++ * --> dma0_desc1 --> dma0_desc_palette --> ... ++ * ++ * SMART LCD TFT panel(dma0_desc_cmd)'s DMA Chan0: ++ * TO LCD Panel: ++ * no palette: dma0_desc_cmd <<==>> dma0_desc0 ++ * palette : dma0_desc_palette --> dma0_desc_cmd ++ * --> dma0_desc0 --> dma0_desc_palette --> ... ++ * TO TV Encoder: ++ * no palette: dma0_desc_cmd --> dma0_desc0 ++ * --> dma0_desc1 --> dma0_desc_cmd --> ... ++ * palette: dma0_desc_palette --> dma0_desc_cmd ++ * --> dma0_desc0 --> dma0_desc1 ++ * --> dma0_desc_palette --> ... ++ * DMA Chan1: ++ * TO LCD Panel: ++ * dma1_desc0 <<==>> dma1_desc0 ++ * TO TV Encoder: ++ * dma1_desc0 <<==>> dma1_desc1 ++ */ ++ ++#if defined(CONFIG_FB_JZ4750_SLCD) ++ /* First CMD descriptors, use only once, cmd_num isn't 0 */ ++ dma0_desc_cmd0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ dma0_desc_cmd0->databuf = (unsigned int)virt_to_phys((void *)lcd_cmdbuf); ++ dma0_desc_cmd0->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */ ++ dma0_desc_cmd0->cmd = LCD_CMD_CMD | 3; /* command */ ++ dma0_desc_cmd0->offsize = 0; ++ dma0_desc_cmd0->page_width = 0; ++ dma0_desc_cmd0->cmd_num = 3; ++ ++ /* Dummy Command Descriptor, cmd_num is 0 */ ++ dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ dma0_desc_cmd->databuf = 0; ++ dma0_desc_cmd->frame_id = (unsigned int)0x0da000cd; /* dma0's cmd0 */ ++ dma0_desc_cmd->cmd = LCD_CMD_CMD | 0; /* dummy command */ ++ dma0_desc_cmd->cmd_num = 0; ++ dma0_desc_cmd->offsize = 0; ++ dma0_desc_cmd->page_width = 0; ++ ++ /* Palette Descriptor */ ++ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd0); ++#else ++ /* Palette Descriptor */ ++ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++#endif ++ dma0_desc_palette->databuf = (unsigned int)virt_to_phys((void *)lcd_palette); ++ dma0_desc_palette->frame_id = (unsigned int)0xaaaaaaaa; ++ dma0_desc_palette->cmd = LCD_CMD_PAL | pal_size; /* Palette Descriptor */ ++ ++ /* DMA0 Descriptor0 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); ++ else{ /* Normal TFT LCD */ ++#if defined(CONFIG_FB_JZ4750_SLCD) ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); ++#else ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++#endif ++ } ++ ++ dma0_desc0->databuf = virt_to_phys((void *)lcd_frame0); ++ dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ ++ ++ /* DMA0 Descriptor1 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ ++ ++ ++ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup */ ++ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); ++ else ++#if defined(CONFIG_FB_JZ4750_SLCD) /* for smatlcd */ ++ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); ++#else ++ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++#endif ++ dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */ ++ } ++ ++ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup */ ++ REG_LCD_DA0 = virt_to_phys(dma0_desc_palette); ++ else { ++#if defined(CONFIG_FB_JZ4750_SLCD) /* for smartlcd */ ++ REG_LCD_DA0 = virt_to_phys(dma0_desc_cmd0); //smart lcd ++#else ++ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft ++#endif ++ } ++ ++ /* DMA1 Descriptor0 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ ++ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); ++ else /* Normal TFT LCD */ ++ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); ++ ++ dma1_desc0->databuf = virt_to_phys((void *)lcd_frame1); ++ dma1_desc0->frame_id = (unsigned int)0x0000da10; /* DMA1'0 */ ++ ++ /* DMA1 Descriptor1 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ ++ dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); ++ dma1_desc1->frame_id = (unsigned int)0x0000da11; /* DMA1'1 */ ++ } ++ ++ REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ ++ dma_cache_wback_inv((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); ++ ++#if 0 ++ /* Palette Descriptor */ ++ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) ++// dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); ++ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1); ++ else ++ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ dma0_desc_palette->databuf = (unsigned int)virt_to_phys((void *)lcd_palette); ++ dma0_desc_palette->frame_id = (unsigned int)0xaaaaaaaa; ++ dma0_desc_palette->cmd = LCD_CMD_PAL | pal_size; /* Palette Descriptor */ ++ ++ /* Dummy Command Descriptor, cmd_num is 0 */ ++ dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ dma0_desc_cmd->databuf = (unsigned int)virt_to_phys((void *)lcd_cmdbuf); ++ dma0_desc_cmd->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */ ++ dma0_desc_cmd->cmd = LCD_CMD_CMD | 3; /* dummy command */ ++ dma0_desc_cmd->offsize = 0; /* dummy command */ ++ dma0_desc_cmd->page_width = 0; /* dummy command */ ++ dma0_desc_cmd->cmd_num = 3; ++ ++//--------------------------------- ++ dma0_desc_cmd1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ dma0_desc_cmd1->databuf = 0; ++ dma0_desc_cmd1->frame_id = (unsigned int)0x0da0cad1; /* dma0's cmd0 */ ++ dma0_desc_cmd1->cmd = LCD_CMD_CMD | 0; /* dummy command */ ++ dma0_desc_cmd1->cmd_num = 0; ++ dma0_desc_cmd1->offsize = 0; /* dummy command */ ++ dma0_desc_cmd1->page_width = 0; /* dummy command */ ++//----------------------------------- ++ /* DMA0 Descriptor0 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); ++ else{ /* Normal TFT LCD */ ++ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ ++// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); //tft ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); // smart lcd ++ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1); ++// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); ++ else ++ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ } ++ ++ dma0_desc0->databuf = virt_to_phys((void *)lcd_frame0); ++ dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ ++ ++ /* DMA0 Descriptor1 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ ++ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ ++ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); ++ ++ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) ++ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); ++ else ++ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); ++ dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */ ++ } ++ ++ /* DMA1 Descriptor0 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ ++ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); ++ else /* Normal TFT LCD */ ++ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); ++ ++ dma1_desc0->databuf = virt_to_phys((void *)lcd_frame1); ++ dma1_desc0->frame_id = (unsigned int)0x0000da10; /* DMA1'0 */ ++ ++ /* DMA1 Descriptor1 */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ ++ dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); ++ dma1_desc1->frame_id = (unsigned int)0x0000da11; /* DMA1'1 */ ++ } ++ ++ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ ++ REG_LCD_DA0 = virt_to_phys(dma0_desc_palette); ++ else ++// REG_LCD_DA0 = virt_to_phys(dma0_desc_cmd); //smart lcd ++ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft ++ REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ ++ dma_cache_wback_inv((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); ++#endif ++} ++ ++static void jz4750fb_set_panel_mode( struct jz4750lcd_info * lcd_info ) ++{ ++ struct jz4750lcd_panel_t *panel = &lcd_info->panel; ++#ifdef CONFIG_JZ4750D_VGA_DISPLAY ++ REG_TVE_CTRL |= TVE_CTRL_DAPD; ++ REG_TVE_CTRL &= ~( TVE_CTRL_DAPD1 | TVE_CTRL_DAPD2 | TVE_CTRL_DAPD3); ++#endif ++ /* set bpp */ ++ lcd_info->panel.ctrl &= ~LCD_CTRL_BPP_MASK; ++ if ( lcd_info->osd.fg0.bpp == 1 ) ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_1; ++ else if ( lcd_info->osd.fg0.bpp == 2 ) ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_2; ++ else if ( lcd_info->osd.fg0.bpp == 4 ) ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_4; ++ else if ( lcd_info->osd.fg0.bpp == 8 ) ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_8; ++ else if ( lcd_info->osd.fg0.bpp == 15 ) ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_16 | LCD_CTRL_RGB555; ++ else if ( lcd_info->osd.fg0.bpp == 16 ) ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_16 | LCD_CTRL_RGB565; ++ else if ( lcd_info->osd.fg0.bpp > 16 && lcd_info->osd.fg0.bpp < 32+1 ) { ++ lcd_info->osd.fg0.bpp = 32; ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_18_24; ++ } ++ else { ++ printk("The BPP %d is not supported\n", lcd_info->osd.fg0.bpp); ++ lcd_info->osd.fg0.bpp = 32; ++ lcd_info->panel.ctrl |= LCD_CTRL_BPP_18_24; ++ } ++ ++ lcd_info->panel.cfg |= LCD_CFG_NEWDES; /* use 8words descriptor always */ ++ ++ REG_LCD_CTRL = lcd_info->panel.ctrl; /* LCDC Controll Register */ ++ REG_LCD_CFG = lcd_info->panel.cfg; /* LCDC Configure Register */ ++ REG_SLCD_CFG = lcd_info->panel.slcd_cfg; /* Smart LCD Configure Register */ ++ ++ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) /* enable Smart LCD DMA */ ++ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; ++ ++ switch ( lcd_info->panel.cfg & LCD_CFG_MODE_MASK ) { ++ case LCD_CFG_MODE_GENERIC_TFT: ++ case LCD_CFG_MODE_INTER_CCIR656: ++ case LCD_CFG_MODE_NONINTER_CCIR656: ++ case LCD_CFG_MODE_SLCD: ++ default: /* only support TFT16 TFT32, not support STN and Special TFT by now(10-06-2008)*/ ++ REG_LCD_VAT = (((panel->blw + panel->w + panel->elw + panel->hsw)) << 16) | (panel->vsw + panel->bfw + panel->h + panel->efw); ++ REG_LCD_DAH = ((panel->hsw + panel->blw) << 16) | (panel->hsw + panel->blw + panel->w); ++ REG_LCD_DAV = ((panel->vsw + panel->bfw) << 16) | (panel->vsw + panel->bfw + panel->h); ++ REG_LCD_HSYNC = (0 << 16) | panel->hsw; ++ REG_LCD_VSYNC = (0 << 16) | panel->vsw; ++ break; ++ } ++} ++ ++ ++static void jz4750fb_set_osd_mode( struct jz4750lcd_info * lcd_info ) ++{ ++ dprintk("%s, %d\n", __FILE__, __LINE__ ); ++ lcd_info->osd.osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK); ++ if ( lcd_info->osd.fg1.bpp == 15 ) ++ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555; ++ else if ( lcd_info->osd.fg1.bpp == 16 ) ++ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565; ++ else { ++ lcd_info->osd.fg1.bpp = 32; ++ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24; ++ } ++ ++ REG_LCD_OSDC = lcd_info->osd.osd_cfg; /* F0, F1, alpha, */ ++ ++ REG_LCD_OSDCTRL = lcd_info->osd.osd_ctrl; /* IPUEN, bpp */ ++ REG_LCD_RGBC = lcd_info->osd.rgb_ctrl; ++ REG_LCD_BGC = lcd_info->osd.bgcolor; ++ REG_LCD_KEY0 = lcd_info->osd.colorkey0; ++ REG_LCD_KEY1 = lcd_info->osd.colorkey1; ++ REG_LCD_ALPHA = lcd_info->osd.alpha; ++ REG_LCD_IPUR = lcd_info->osd.ipu_restart; ++} ++ ++static void jz4750fb_foreground_resize( struct jz4750lcd_info * lcd_info ) ++{ ++ int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; ++ /* ++ * NOTE: ++ * Foreground change sequence: ++ * 1. Change Position Registers -> LCD_OSDCTL.Change; ++ * 2. LCD_OSDCTRL.Change -> descripter->Size ++ * Foreground, only one of the following can be change at one time: ++ * 1. F0 size; ++ * 2. F0 position ++ * 3. F1 size ++ * 4. F1 position ++ */ ++ ++ /* ++ * The rules of f0, f1's position: ++ * f0.x + f0.w <= panel.w; ++ * f0.y + f0.h <= panel.h; ++ * ++ * When output is LCD panel, fg.y and fg.h can be odd number or even number. ++ * When output is TVE, as the TVE has odd frame and even frame, ++ * to simplified operation, fg.y and fg.h should be even number always. ++ * ++ */ ++ ++ /* Foreground 0 */ ++ if ( lcd_info->osd.fg0.x >= lcd_info->panel.w ) ++ lcd_info->osd.fg0.x = lcd_info->panel.w; ++ if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) ++ lcd_info->osd.fg0.y = lcd_info->panel.h; ++ if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) ++ lcd_info->osd.fg0.w = lcd_info->panel.w - lcd_info->osd.fg0.x; ++ if ( lcd_info->osd.fg0.y + lcd_info->osd.fg0.h > lcd_info->panel.h ) ++ lcd_info->osd.fg0.h = lcd_info->panel.h - lcd_info->osd.fg0.y; ++ /* Foreground 1 */ ++ /* Case TVE ??? TVE 720x573 or 720x480*/ ++ if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) ++ lcd_info->osd.fg1.x = lcd_info->panel.w; ++ if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) ++ lcd_info->osd.fg1.y = lcd_info->panel.h; ++ if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) ++ lcd_info->osd.fg1.w = lcd_info->panel.w - lcd_info->osd.fg1.x; ++ if ( lcd_info->osd.fg1.y + lcd_info->osd.fg1.h > lcd_info->panel.h ) ++ lcd_info->osd.fg1.h = lcd_info->panel.h - lcd_info->osd.fg1.y; ++ ++// fg0_line_size = lcd_info->osd.fg0.w*((lcd_info->osd.fg0.bpp+7)/8); ++ fg0_line_size = (lcd_info->osd.fg0.w*(lcd_info->osd.fg0.bpp)/8); ++ fg0_line_size = ((fg0_line_size+3)>>2)<<2; /* word aligned */ ++ fg0_frm_size = fg0_line_size * lcd_info->osd.fg0.h; ++ ++ fg1_line_size = lcd_info->osd.fg1.w*((lcd_info->osd.fg1.bpp+7)/8); ++ fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */ ++ fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h; ++ ++ if ( lcd_info->osd.fg_change ) { ++ if ( lcd_info->osd.fg_change & FG0_CHANGE_POSITION ) { /* F1 change position */ ++ REG_LCD_XYP0 = lcd_info->osd.fg0.y << 16 | lcd_info->osd.fg0.x; ++ } ++ if ( lcd_info->osd.fg_change & FG1_CHANGE_POSITION ) { /* F1 change position */ ++ REG_LCD_XYP1 = lcd_info->osd.fg1.y << 16 | lcd_info->osd.fg1.x; ++ } ++ ++ /* set change */ ++ if ( !(lcd_info->osd.osd_ctrl & LCD_OSDCTRL_IPU) && ++ (lcd_info->osd.fg_change != FG_CHANGE_ALL) ) ++ REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; ++ ++ /* wait change ready??? */ ++// while ( REG_LCD_OSDS & LCD_OSDS_READY ) /* fix in the future, Wolfgang, 06-20-2008 */ ++ print_dbg("wait LCD_OSDS_READY\n"); ++ ++ if ( lcd_info->osd.fg_change & FG0_CHANGE_SIZE ) { /* change FG0 size */ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ ++ dma0_desc0->cmd = dma0_desc1->cmd = (fg0_frm_size/4)/2; ++ dma0_desc0->offsize = dma0_desc1->offsize ++ = fg0_line_size/4; ++ dma0_desc0->page_width = dma0_desc1->page_width ++ = fg0_line_size/4; ++ dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); ++ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft ++ } ++ else { ++ dma0_desc0->cmd = dma0_desc1->cmd = fg0_frm_size/4; ++ dma0_desc0->offsize = dma0_desc1->offsize =0; ++ dma0_desc0->page_width = dma0_desc1->page_width = 0; ++ } ++ ++ dma0_desc0->desc_size = dma0_desc1->desc_size ++ = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; ++ REG_LCD_SIZE0 = (lcd_info->osd.fg0.h<<16)|lcd_info->osd.fg0.w; ++ ++ } ++ ++ if ( lcd_info->osd.fg_change & FG1_CHANGE_SIZE ) { /* change FG1 size*/ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ ++ dma1_desc0->cmd = dma1_desc1->cmd = (fg1_frm_size/4)/2; ++ dma1_desc0->offsize = dma1_desc1->offsize = fg1_line_size/4; ++ dma1_desc0->page_width = dma1_desc1->page_width = fg1_line_size/4; ++ dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame1 + fg1_line_size)); ++ REG_LCD_DA1 = virt_to_phys(dma0_desc1); //tft ++ ++ } ++ else { ++ dma1_desc0->cmd = dma1_desc1->cmd = fg1_frm_size/4; ++ dma1_desc0->offsize = dma1_desc1->offsize = 0; ++ dma1_desc0->page_width = dma1_desc1->page_width = 0; ++ } ++ ++ dma1_desc0->desc_size = dma1_desc1->desc_size ++ = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; ++ REG_LCD_SIZE1 = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w; ++ } ++ ++ dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); ++ lcd_info->osd.fg_change = FG_NOCHANGE; /* clear change flag */ ++ } ++} ++ ++static void jz4750fb_change_clock( struct jz4750lcd_info * lcd_info ) ++{ ++ ++#if defined(CONFIG_FPGA) ++ REG_LCD_REV = 0x00000004; ++ printk("Fuwa test, pixclk divide REG_LCD_REV=0x%08x\n", REG_LCD_REV); ++ printk("Fuwa test, pixclk %d\n", JZ_EXTAL/(((REG_LCD_REV&0xFF)+1)*2)); ++#else ++ unsigned int val = 0; ++ unsigned int pclk; ++ /* Timing setting */ ++ __cpm_stop_lcd(); ++ ++ val = lcd_info->panel.fclk; /* frame clk */ ++ ++ if ( (lcd_info->panel.cfg & LCD_CFG_MODE_MASK) != LCD_CFG_MODE_SERIAL_TFT) { ++ pclk = val * (lcd_info->panel.w + lcd_info->panel.hsw + lcd_info->panel.elw + lcd_info->panel.blw) * (lcd_info->panel.h + lcd_info->panel.vsw + lcd_info->panel.efw + lcd_info->panel.bfw); /* Pixclk */ ++ } ++ else { ++ /* serial mode: Hsync period = 3*Width_Pixel */ ++ pclk = val * (lcd_info->panel.w*3 + lcd_info->panel.hsw + lcd_info->panel.elw + lcd_info->panel.blw) * (lcd_info->panel.h + lcd_info->panel.vsw + lcd_info->panel.efw + lcd_info->panel.bfw); /* Pixclk */ ++ } ++ ++ /********* In TVE mode PCLK = 27MHz ***********/ ++ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* LCDC output to TVE */ ++ REG_CPM_LPCDR |= CPM_LPCDR_LTCS; ++ pclk = 27000000; ++ val = __cpm_get_pllout2() / pclk; /* pclk */ ++ val--; ++ __cpm_set_pixdiv(val); ++ ++ dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR); ++#if defined(CONFIG_SOC_JZ4750) /* Jz4750D don't use LCLK */ ++ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ ++ ++ val =(__cpm_get_pllout()) / val; ++ if ( val > 0x1f ) { ++ printk("lcd clock divide is too large, set it to 0x1f\n"); ++ val = 0x1f; ++ } ++ __cpm_set_ldiv( val ); ++#endif ++ __cpm_select_pixclk_tve(); ++ ++ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ ++ } ++ else { /* LCDC output to LCD panel */ ++ val = __cpm_get_pllout2() / pclk; /* pclk */ ++ val--; ++ dprintk("ratio: val = %d\n", val); ++ if ( val > 0x7ff ) { ++ printk("pixel clock divid is too large, set it to 0x7ff\n"); ++ val = 0x7ff; ++ } ++ ++ __cpm_set_pixdiv(val); ++ ++ dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR); ++#if defined(CONFIG_SOC_JZ4750) /* Jz4750D don't use LCLK */ ++ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ ++ val =__cpm_get_pllout2() / val; ++ if ( val > 0x1f ) { ++ printk("lcd clock divide is too large, set it to 0x1f\n"); ++ val = 0x1f; ++ } ++ __cpm_set_ldiv( val ); ++#endif ++ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ ++ ++ } ++ ++ dprintk("REG_CPM_LPCDR=0x%08x\n", REG_CPM_LPCDR); ++ dprintk("REG_CPM_CPCCR=0x%08x\n", REG_CPM_CPCCR); ++ ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ printk("LCDC: PixClock:%d\n", jz_clocks.pixclk); ++ ++#if defined(CONFIG_SOC_JZ4750) /* Jz4750D don't use LCLK */ ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ printk("LCDC: LcdClock:%d\n", jz_clocks.lcdclk); ++#endif ++ __cpm_start_lcd(); ++ udelay(1000); ++ /* ++ * set lcd device clock and lcd pixel clock. ++ * what about TVE mode??? ++ * ++ */ ++#endif ++ ++} ++ ++/* ++ * jz4750fb_set_mode(), set osd configure, resize foreground ++ * ++ */ ++static void jz4750fb_set_mode( struct jz4750lcd_info * lcd_info ) ++{ ++ struct lcd_cfb_info *cfb = jz4750fb_info; ++ ++ jz4750fb_set_osd_mode(lcd_info); ++ jz4750fb_foreground_resize(lcd_info); ++ jz4750fb_set_var(&cfb->fb.var, -1, &cfb->fb); ++} ++ ++/* ++ * jz4750fb_deep_set_mode, ++ * ++ */ ++static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ) ++{ ++ /* configurate sequence: ++ * 1. disable lcdc. ++ * 2. init frame descriptor. ++ * 3. set panel mode ++ * 4. set osd mode ++ * 5. start lcd clock in CPM ++ * 6. enable lcdc. ++ */ ++ ++ __lcd_clr_ena(); /* Quick Disable */ ++ lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */ ++ jz4750fb_descriptor_init(lcd_info); ++ jz4750fb_set_panel_mode(lcd_info); ++ jz4750fb_set_mode(lcd_info); ++ jz4750fb_change_clock(lcd_info); ++ __lcd_set_ena(); /* enable lcdc */ ++} ++ ++ ++static irqreturn_t jz4750fb_interrupt_handler(int irq, void *dev_id) ++{ ++ unsigned int state; ++ static int irqcnt=0; ++ ++ state = REG_LCD_STATE; ++ dprintk("In the lcd interrupt handler, state=0x%x\n", state); ++ ++ if (state & LCD_STATE_EOF) /* End of frame */ ++ REG_LCD_STATE = state & ~LCD_STATE_EOF; ++ ++ if (state & LCD_STATE_IFU0) { ++ printk("%s, InFiFo0 underrun\n", __FUNCTION__); ++ REG_LCD_STATE = state & ~LCD_STATE_IFU0; ++ } ++ ++ if (state & LCD_STATE_IFU1) { ++ printk("%s, InFiFo1 underrun\n", __FUNCTION__); ++ REG_LCD_STATE = state & ~LCD_STATE_IFU1; ++ } ++ ++ if (state & LCD_STATE_OFU) { /* Out fifo underrun */ ++ REG_LCD_STATE = state & ~LCD_STATE_OFU; ++ if ( irqcnt++ > 100 ) { ++ __lcd_disable_ofu_intr(); ++ printk("disable Out FiFo underrun irq.\n"); ++ } ++ printk("%s, Out FiFo underrun.\n", __FUNCTION__); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_PM ++ ++/* ++ * Suspend the LCDC. ++ */ ++static int jzfb_suspend(void) ++{ ++ __lcd_clr_ena(); /* Quick Disable */ ++ __lcd_display_off(); ++ __cpm_stop_lcd(); ++ ++ return 0; ++} ++ ++/* ++ * Resume the LCDC. ++ */ ++static int jzfb_resume(void) ++{ ++ __cpm_start_lcd(); ++ __gpio_set_pin(GPIO_DISP_OFF_N); ++ __lcd_special_on(); ++ __lcd_set_ena(); ++ mdelay(200); ++ __lcd_set_backlight_level(80); ++ ++ return 0; ++} ++ ++/* ++ * Power management hook. Note that we won't be called from IRQ context, ++ * unlike the blank functions above, so we may sleep. ++ */ ++static int jzlcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct lcd_cfb_info *cfb = pm_dev->data; ++ ++ if (!cfb) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jzfb_suspend(); ++ break; ++ ++ case PM_RESUME: ++ ret = jzfb_resume(); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#else ++#define jzfb_suspend NULL ++#define jzfb_resume NULL ++#endif /* CONFIG_PM */ ++ ++/* The following routine is only for test */ ++ ++#ifdef DEBUG ++static void test_gpio(int gpio_num, int delay) { ++ __gpio_as_output(gpio_num); ++ while(1) { ++ __gpio_set_pin(gpio_num); ++ udelay(delay); ++ __gpio_clear_pin(gpio_num); ++ udelay(delay); ++ } ++} ++static void display_v_color_bar(int w, int h, int bpp) { ++ int i, j, wpl, data = 0; ++ int *ptr; ++ ptr = (int *)lcd_frame0; ++// ptr = (int *)lcd_frame1; ++ wpl = w*bpp/32; ++ if (!(bpp > 8)) ++ switch(bpp){ ++ case 1: ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i++) { ++ *ptr++ = 0x00ff00ff; ++ } ++ break; ++ case 2: ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i++) { ++ data = (i%4)*0x55555555; ++ *ptr++ = data; ++ } ++ break; ++ case 4: ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i++) { ++ data = (i%16)*0x11111111; ++ *ptr++ = data; ++ } ++ break; ++ case 8: ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i+=2) { ++ data = (i%(256))*0x01010101; ++ *ptr++ = data; ++ *ptr++ = data; ++ } ++ break; ++ } ++ else { ++ switch(bpp) { ++ case 16: ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i++) { ++ if((i/4)%8==0) ++ *ptr++ = 0xffffffff; ++ else if ((i/4)%8==1) ++ *ptr++ = 0xf800f800; ++ else if ((i/4)%8==2) ++ *ptr++ = 0xffe0ffe0; ++ else if ((i/4)%8==3) ++ *ptr++ = 0x07e007e0; ++ else if ((i/4)%8==4) ++ *ptr++ = 0x07ff07ff; ++ else if ((i/4)%8==5) ++ *ptr++ = 0x001f001f; ++ else if ((i/4)%8==6) ++ *ptr++ = 0xf81ff81f; ++ else if ((i/4)%8==7) ++ *ptr++ = 0x00000000; ++ } ++ break; ++ case 18: ++ case 24: ++ case 32: ++ default: ++#if 1 ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i++) { ++ if((i/8)%8==7) ++ *ptr++ = 0xffffff; ++ else if ((i/8)%8==1) ++ *ptr++ = 0xff0000; ++ else if ((i/8)%8==2) ++ *ptr++ = 0xffff00; ++ else if ((i/8)%8==3) ++ *ptr++ = 0x00ff00; ++ else if ((i/8)%8==4) ++ *ptr++ = 0x00ffff; ++ else if ((i/8)%8==5) ++ *ptr++ = 0x0000ff; ++ else if ((i/8)%8==6) ++ *ptr++ = 0xff00ff; ++ else if ((i/8)%8==0) ++ *ptr++ = 0x000000; ++ } ++#else ++ for (j = 0;j < h; j++) ++ for (i = 0;i < wpl; i++) { ++ if((i/8)%8==7) ++ *ptr++ = 0x00ff0000; ++ else if ((i/8)%8==1) ++ *ptr++ = 0xffff0000; ++ else if ((i/8)%8==2) ++ *ptr++ = 0x20ff0000; ++ else if ((i/8)%8==3) ++ *ptr++ = 0x40ff0000; ++ else if ((i/8)%8==4) ++ *ptr++ = 0x60ff0000; ++ else if ((i/8)%8==5) ++ *ptr++ = 0x80ff0000; ++ else if ((i/8)%8==6) ++ *ptr++ = 0xa0ff0000; ++ else if ((i/8)%8==0) ++ *ptr++ = 0xc0ff0000; ++ } ++#endif ++ break; ++ } ++ } ++} ++static void display_h_color_bar(int w, int h, int bpp) { ++ int i, data = 0; ++ int *ptr; ++ int wpl; //word_per_line ++ ptr = (int *)lcd_frame0; ++// ptr = (int *)lcd_frame1; ++ wpl = w*bpp/32; ++ if (!(bpp > 8)) ++ for (i = 0;i < wpl*h;i++) { ++ switch(bpp){ ++ case 1: ++ if(i%(wpl*8)==0) ++ data = ((i/(wpl*8))%2)*0xffffffff; ++ *ptr++ = data; ++ break; ++ case 2: ++ if(i%(wpl*8)==0) ++ data = ((i/(wpl*8))%4)*0x55555555; ++ *ptr++ = data; ++ break; ++ case 4: ++ if(i%(wpl*8)==0) ++ data = ((i/(wpl*8))%16)*0x11111111; ++ *ptr++ = data; ++ break; ++ case 8: ++ if(i%(wpl*8)==0) ++ data = ((i/(wpl*8))%256)*0x01010101; ++ *ptr++ = data; ++ break; ++ } ++ } ++ else { ++ ++ switch(bpp) { ++ case 15: ++ case 16: ++ for (i = 0;i < wpl*h;i++) { ++ if (((i/(wpl*8)) % 8) == 0) ++ *ptr++ = 0xffffffff; ++ else if (((i/(wpl*8)) % 8) == 1) ++ *ptr++ = 0xf800f800; ++ else if (((i/(wpl*8)) % 8) == 2) ++ *ptr++ = 0xffe0ffe0; ++ else if (((i/(wpl*8)) % 8) == 3) ++ *ptr++ = 0x07e007e0; ++ else if (((i/(wpl*8)) % 8) == 4) ++ *ptr++ = 0x07ff07ff; ++ else if (((i/(wpl*8)) % 8) == 5) ++ *ptr++ = 0x001f001f; ++ else if (((i/(wpl*8)) % 8) == 6) ++ *ptr++ = 0xf81ff81f; ++ else if (((i/(wpl*8)) % 8) == 7) ++ *ptr++ = 0x00000000; ++ } ++ break; ++ case 18: ++ case 24: ++ case 32: ++ default: ++ for (i = 0;i < wpl*h;i++) { ++ if (((i/(wpl*8)) % 8) == 7) ++ *ptr++ = 0xffffff; ++ else if (((i/(wpl*8)) % 8) == 2) ++ *ptr++ = 0xff0000; ++ else if (((i/(wpl*8)) % 8) == 4) ++ *ptr++ = 0xffff00; ++ else if (((i/(wpl*8)) % 8) == 6) ++ *ptr++ = 0x00ff00; ++ else if (((i/(wpl*8)) % 8) == 1) ++ *ptr++ = 0x00ffff; ++ else if (((i/(wpl*8)) % 8) == 3) ++ *ptr++ = 0x0000ff; ++ else if (((i/(wpl*8)) % 8) == 5) ++ *ptr++ = 0x000000; ++ else if (((i/(wpl*8)) % 8) == 0) ++ *ptr++ = 0xff00ff; ++ } ++ break; ++ } ++ ++ } ++ ++} ++#endif ++ ++static int __init jz4750fb_init(void) ++{ ++ struct lcd_cfb_info *cfb; ++ int err = 0; ++ ++ /* gpio init __gpio_as_lcd */ ++ if (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_16BIT) ++ __gpio_as_lcd_16bit(); ++ else if (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_24BIT) ++ __gpio_as_lcd_24bit(); ++ else ++ __gpio_as_lcd_18bit(); ++ /* In special mode, we only need init special pin, ++ * as general lcd pin has init in uboot */ ++#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++ switch (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) { ++ case LCD_CFG_MODE_SPECIAL_TFT_1: ++ case LCD_CFG_MODE_SPECIAL_TFT_2: ++ case LCD_CFG_MODE_SPECIAL_TFT_3: ++ __gpio_as_lcd_special(); ++ break; ++ default: ++ ; ++ } ++#endif ++ if ( jz4750_lcd_info->osd.fg0.bpp > 16 && ++ jz4750_lcd_info->osd.fg0.bpp < 32 ) { ++ jz4750_lcd_info->osd.fg0.bpp = 32; ++ } ++ ++ switch ( jz4750_lcd_info->osd.fg1.bpp ) { ++ case 15: ++ case 16: ++ break; ++ case 17 ... 32: ++ jz4750_lcd_info->osd.fg1.bpp = 32; ++ break; ++ default: ++ printk("jz4750fb fg1 not support bpp(%d), force to 32bpp\n", ++ jz4750_lcd_info->osd.fg1.bpp); ++ jz4750_lcd_info->osd.fg1.bpp = 32; ++ } ++ __lcd_clr_dis(); ++ __lcd_clr_ena(); ++ ++ /* Configure SLCD module for setting smart lcd control registers */ ++#if defined(CONFIG_FB_JZ4750_SLCD) ++ __lcd_as_smart_lcd(); ++ __slcd_disable_dma(); ++ __init_slcd_bus(); /* Note: modify this depend on you lcd */ ++ ++#endif ++ /* init clk */ ++ jz4750fb_change_clock(jz4750_lcd_info); ++ __lcd_display_pin_init(); ++ __lcd_slcd_special_on(); ++ ++ cfb = jz4750fb_alloc_fb_info(); ++ if (!cfb) ++ goto failed; ++ ++ err = jz4750fb_map_smem(cfb); ++ if (err) ++ goto failed; ++ ++ jz4750fb_deep_set_mode( jz4750_lcd_info ); ++ ++ err = register_framebuffer(&cfb->fb); ++ if (err < 0) { ++ dprintk("jzfb_init(): register framebuffer err.\n"); ++ goto failed; ++ } ++ printk("fb%d: %s frame buffer device, using %dK of video memory\n", ++ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10); ++ ++ if (request_irq(IRQ_LCD, jz4750fb_interrupt_handler, IRQF_DISABLED, ++ "lcd", 0)) { ++ err = -EBUSY; ++ goto failed; ++ } ++ ++#ifdef CONFIG_PM ++ /* ++ * Note that the console registers this as well, but we want to ++ * power down the display prior to sleeping. ++ */ ++ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback); ++ if (cfb->pm) ++ cfb->pm->data = cfb; ++#endif ++ ++ __lcd_set_ena(); /* enalbe LCD Controller */ ++ __lcd_display_on(); ++ ++#ifdef DEBUG ++ display_h_color_bar(jz4750_lcd_info->osd.fg0.w, jz4750_lcd_info->osd.fg0.h, jz4750_lcd_info->osd.fg0.bpp); ++#endif ++ print_lcdc_registers(); ++ return 0; ++ ++failed: ++ print_dbg(); ++ jz4750fb_unmap_smem(cfb); ++ jz4750fb_free_fb_info(cfb); ++ ++ return err; ++} ++ ++#if 0 ++static int jzfb_remove(struct device *dev) ++{ ++ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); ++ jzfb_unmap_smem(cfb); ++ jzfb_free_fb_info(cfb); ++ return 0; ++} ++#endif ++ ++#if 0 ++static struct device_driver jzfb_driver = { ++ .name = "jz-lcd", ++ .bus = &platform_bus_type, ++ .probe = jzfb_probe, ++ .remove = jzfb_remove, ++ .suspend = jzfb_suspend, ++ .resume = jzfb_resume, ++}; ++#endif ++ ++static void __exit jz4750fb_cleanup(void) ++{ ++ //driver_unregister(&jzfb_driver); ++ //jzfb_remove(); ++} ++ ++module_init(jz4750fb_init); ++module_exit(jz4750fb_cleanup); +diff --git a/drivers/video/jz4750_lcd.h b/drivers/video/jz4750_lcd.h +new file mode 100644 +index 0000000..2d07c43 +--- /dev/null ++++ b/drivers/video/jz4750_lcd.h +@@ -0,0 +1,785 @@ ++/* ++ * linux/drivers/video/jz4750_lcd.h -- Ingenic Jz4750 On-Chip LCD frame buffer device ++ * ++ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef __JZ4750_LCD_H__ ++#define __JZ4750_LCD_H__ ++ ++//#include ++ ++ ++#define NR_PALETTE 256 ++#define PALETTE_SIZE (NR_PALETTE*2) ++ ++/* use new descriptor(8 words) */ ++struct jz4750_lcd_dma_desc { ++ unsigned int next_desc; /* LCDDAx */ ++ unsigned int databuf; /* LCDSAx */ ++ unsigned int frame_id; /* LCDFIDx */ ++ unsigned int cmd; /* LCDCMDx */ ++ unsigned int offsize; /* Stride Offsize(in word) */ ++ unsigned int page_width; /* Stride Pagewidth(in word) */ ++ unsigned int cmd_num; /* Command Number(for SLCD) */ ++ unsigned int desc_size; /* Foreground Size */ ++}; ++ ++struct jz4750lcd_panel_t { ++ unsigned int cfg; /* panel mode and pin usage etc. */ ++ unsigned int slcd_cfg; /* Smart lcd configurations */ ++ unsigned int ctrl; /* lcd controll register */ ++ unsigned int w; /* Panel Width(in pixel) */ ++ unsigned int h; /* Panel Height(in line) */ ++ unsigned int fclk; /* frame clk */ ++ unsigned int hsw; /* hsync width, in pclk */ ++ unsigned int vsw; /* vsync width, in line count */ ++ unsigned int elw; /* end of line, in pclk */ ++ unsigned int blw; /* begin of line, in pclk */ ++ unsigned int efw; /* end of frame, in line count */ ++ unsigned int bfw; /* begin of frame, in line count */ ++}; ++ ++ ++struct jz4750lcd_fg_t { ++ int bpp; /* foreground bpp */ ++ int x; /* foreground start position x */ ++ int y; /* foreground start position y */ ++ int w; /* foreground width */ ++ int h; /* foreground height */ ++}; ++ ++struct jz4750lcd_osd_t { ++ unsigned int osd_cfg; /* OSDEN, ALHPAEN, F0EN, F1EN, etc */ ++ unsigned int osd_ctrl; /* IPUEN, OSDBPP, etc */ ++ unsigned int rgb_ctrl; /* RGB Dummy, RGB sequence, RGB to YUV */ ++ unsigned int bgcolor; /* background color(RGB888) */ ++ unsigned int colorkey0; /* foreground0's Colorkey enable, Colorkey value */ ++ unsigned int colorkey1; /* foreground1's Colorkey enable, Colorkey value */ ++ unsigned int alpha; /* ALPHAEN, alpha value */ ++ unsigned int ipu_restart; /* IPU Restart enable, ipu restart interval time */ ++ ++#define FG_NOCHANGE 0x0000 ++#define FG0_CHANGE_SIZE 0x0001 ++#define FG0_CHANGE_POSITION 0x0002 ++#define FG1_CHANGE_SIZE 0x0010 ++#define FG1_CHANGE_POSITION 0x0020 ++#define FG_CHANGE_ALL ( FG0_CHANGE_SIZE | FG0_CHANGE_POSITION | \ ++ FG1_CHANGE_SIZE | FG1_CHANGE_POSITION ) ++ int fg_change; ++ struct jz4750lcd_fg_t fg0; /* foreground 0 */ ++ struct jz4750lcd_fg_t fg1; /* foreground 1 */ ++}; ++ ++struct jz4750lcd_info { ++ struct jz4750lcd_panel_t panel; ++ struct jz4750lcd_osd_t osd; ++}; ++ ++ ++/* Jz LCDFB supported I/O controls. */ ++#define FBIOSETBACKLIGHT 0x4688 /* set back light level */ ++#define FBIODISPON 0x4689 /* display on */ ++#define FBIODISPOFF 0x468a /* display off */ ++#define FBIORESET 0x468b /* lcd reset */ ++#define FBIOPRINT_REG 0x468c /* print lcd registers(debug) */ ++#define FBIOROTATE 0x46a0 /* rotated fb */ ++#define FBIOGETBUFADDRS 0x46a1 /* get buffers addresses */ ++#define FBIO_GET_MODE 0x46a2 /* get lcd info */ ++#define FBIO_SET_MODE 0x46a3 /* set osd mode */ ++#define FBIO_DEEP_SET_MODE 0x46a4 /* set panel and osd mode */ ++#define FBIO_MODE_SWITCH 0x46a5 /* switch mode between LCD and TVE */ ++#define FBIO_GET_TVE_MODE 0x46a6 /* get tve info */ ++#define FBIO_SET_TVE_MODE 0x46a7 /* set tve mode */ ++ ++/* ++ * LCD panel specific definition ++ */ ++/* AUO */ ++#if defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2) ++#if defined(CONFIG_JZ4750_APUS) /* board pavo */ ++ #define SPEN (32*3+29) /*LCD_CS*/ ++ #define SPCK (32*3+26) /*LCD_SCL*/ ++ #define SPDA (32*3+27) /*LCD_SDA*/ ++ #define LCD_RET (32*4+25) /*LCD_DISP_N use for lcd reset*/ ++#elif defined(CONFIG_JZ4750_FUWA) /* board pavo */ ++ #define SPEN (32*3+29) /*LCD_CS*/ ++ #define SPCK (32*3+26) /*LCD_SCL*/ ++ #define SPDA (32*3+27) /*LCD_SDA*/ ++ #define LCD_RET (32*5+2) /*LCD_DISP_N use for lcd reset*/ ++#elif defined(CONFIG_JZ4750D_CETUS) /* board pavo */ ++ #define SPEN (32*5+13) /*LCD_CS*/ ++ #define SPCK (32*5+10) /*LCD_SCL*/ ++ #define SPDA (32*5+11) /*LCD_SDA*/ ++ #define LCD_RET (32*4+18) /*LCD_DISP_N use for lcd reset*/ ++#else ++#error "driver/video/Jzlcd.h, please define SPI pins on your board." ++#endif ++ ++#define __spi_write_reg(reg, val) \ ++ do { \ ++ unsigned char no; \ ++ unsigned short value; \ ++ unsigned char a=0; \ ++ unsigned char b=0; \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ a=reg; \ ++ b=val; \ ++ __gpio_set_pin(SPEN); \ ++ __gpio_clear_pin(SPCK); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPDA); \ ++ __gpio_clear_pin(SPEN); \ ++ udelay(50); \ ++ value=((a<<8)|(b&0xFF)); \ ++ for(no=0;no<16;no++) \ ++ { \ ++ if((value&0x8000)==0x8000){ \ ++ __gpio_set_pin(SPDA);} \ ++ else{ \ ++ __gpio_clear_pin(SPDA); } \ ++ udelay(50); \ ++ __gpio_set_pin(SPCK); \ ++ value=(value<<1); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPCK); \ ++ } \ ++ __gpio_set_pin(SPEN); \ ++ udelay(400); \ ++ } while (0) ++#define __spi_read_reg(reg,val) \ ++ do{ \ ++ unsigned char no; \ ++ unsigned short value; \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ value = ((reg << 0) | (1 << 7)); \ ++ val = 0; \ ++ __gpio_as_output(SPDA); \ ++ __gpio_set_pin(SPEN); \ ++ __gpio_clear_pin(SPCK); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPDA); \ ++ __gpio_clear_pin(SPEN); \ ++ udelay(50); \ ++ for (no = 0; no < 16; no++ ) { \ ++ udelay(50); \ ++ if(no < 8) \ ++ { \ ++ if (value & 0x80) /* send data */ \ ++ __gpio_set_pin(SPDA); \ ++ else \ ++ __gpio_clear_pin(SPDA); \ ++ udelay(50); \ ++ __gpio_set_pin(SPCK); \ ++ value = (value << 1); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPCK); \ ++ if(no == 7) \ ++ __gpio_as_input(SPDA); \ ++ } \ ++ else \ ++ { \ ++ udelay(100); \ ++ __gpio_set_pin(SPCK); \ ++ udelay(50); \ ++ val = (val << 1); \ ++ val |= __gpio_get_pin(SPDA); \ ++ __gpio_clear_pin(SPCK); \ ++ } \ ++ } \ ++ __gpio_as_output(SPDA); \ ++ __gpio_set_pin(SPEN); \ ++ udelay(400); \ ++ } while(0) ++ ++#define __lcd_special_pin_init() \ ++ do { \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ __gpio_as_output(LCD_RET); \ ++ udelay(50); \ ++ __gpio_clear_pin(LCD_RET); \ ++ udelay(100); \ ++ __gpio_set_pin(LCD_RET); \ ++ } while (0) ++#define __lcd_special_on() \ ++ do { \ ++ udelay(50); \ ++ __gpio_clear_pin(LCD_RET); \ ++ udelay(100); \ ++ __gpio_set_pin(LCD_RET); \ ++} while (0) ++ ++ #define __lcd_special_off() \ ++ do { \ ++ __gpio_clear_pin(LCD_RET); \ ++ } while (0) ++ ++#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */ ++ ++/* TRULY_TFTG320240DTSW */ ++#if defined(CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_16BIT) || defined(CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT) ++ ++#if defined(CONFIG_JZ4750_FUWA) ++#define LCD_RESET_PIN (32*3+25)// LCD_REV, GPD25 ++#else ++#error "Define LCD_RESET_PIN on your board" ++#endif ++ ++#define __lcd_special_on() \ ++do { \ ++ __gpio_as_output(32*3+30);\ ++ __gpio_clear_pin(32*3+30);\ ++ __gpio_as_output(LCD_RESET_PIN); \ ++ __gpio_set_pin(LCD_RESET_PIN); \ ++ udelay(100); \ ++ __gpio_clear_pin(LCD_RESET_PIN); \ ++ udelay(100); \ ++ __gpio_set_pin(LCD_RESET_PIN); \ ++} while (0) ++ ++#endif /* CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW */ ++ ++// Wolfgang 2008.02.23 ++#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA) || defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DUMMY) ++ ++#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA) ++#define PANEL_MODE 0x02 /* RGB Delta */ ++#elif defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DUMMY) ++#define PANEL_MODE 0x00 /* RGB Dummy */ ++#endif ++ ++#if defined(CONFIG_JZ4750_FUWA) /* board FuWa */ ++ #define SPEN (32*3+16) //LCD_D16 - GPD16 ++ #define SPCK (32*3+17) //LCD_D17 - GPD17 ++ #define SPDA (32*3+21) //LCD_DE - GPD21 ++ #define LCD_RET (32*3+25) //LCD_REV - GPD25 //use for lcd reset ++#else ++#error "please define SPI pins on your board." ++#endif ++ ++ #define __spi_write_reg1(reg, val) \ ++ do { \ ++ unsigned char no;\ ++ unsigned short value;\ ++ unsigned char a=0;\ ++ unsigned char b=0;\ ++ a=reg;\ ++ b=val;\ ++ __gpio_set_pin(SPEN);\ ++ udelay(100);\ ++ __gpio_clear_pin(SPCK);\ ++ __gpio_clear_pin(SPDA);\ ++ __gpio_clear_pin(SPEN);\ ++ udelay(25);\ ++ value=((a<<8)|(b&0xFF));\ ++ for(no=0;no<16;no++)\ ++ {\ ++ __gpio_clear_pin(SPCK);\ ++ if((value&0x8000)==0x8000)\ ++ __gpio_set_pin(SPDA);\ ++ else\ ++ __gpio_clear_pin(SPDA);\ ++ udelay(25);\ ++ __gpio_set_pin(SPCK);\ ++ value=(value<<1); \ ++ udelay(25);\ ++ }\ ++ __gpio_clear_pin(SPCK);\ ++ __gpio_set_pin(SPEN);\ ++ udelay(100);\ ++ } while (0) ++ ++ #define __spi_write_reg(reg, val) \ ++ do {\ ++ __spi_write_reg1((reg<<2), val); \ ++ udelay(100); \ ++ }while(0) ++ ++ #define __lcd_special_pin_init() \ ++ do { \ ++ __gpio_as_output(SPEN); /* use SPDA */\ ++ __gpio_as_output(SPCK); /* use SPCK */\ ++ __gpio_as_output(SPDA); /* use SPDA */\ ++ __gpio_as_output(SPDA); /* use reset */\ ++ __gpio_as_output(LCD_RET); /* use reset */\ ++ __gpio_set_pin(LCD_RET);\ ++ mdelay(15);\ ++ __gpio_clear_pin(LCD_RET);\ ++ mdelay(15);\ ++ __gpio_set_pin(LCD_RET);\ ++ } while (0) ++ ++ #define __lcd_special_on() \ ++ do { \ ++ mdelay(10); \ ++ __spi_write_reg(0x00, 0x10); \ ++ __spi_write_reg(0x01, 0xB1); \ ++ __spi_write_reg(0x00, 0x10); \ ++ __spi_write_reg(0x01, 0xB1); \ ++ __spi_write_reg(0x02, PANEL_MODE); /* RGBD MODE */ \ ++ __spi_write_reg(0x03, 0x01); /* Noninterlace*/ \ ++ mdelay(10); \ ++ } while (0) ++ ++ #define __lcd_special_off() \ ++ do { \ ++ } while (0) ++ ++#endif /* CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA */ ++ ++ ++#if defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) || defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) ++ ++#if defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) /* board FUWA */ ++#define MODE 0xcd /* 24bit parellel RGB */ ++#endif ++#if defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) ++#define MODE 0xc9 /* 8bit serial RGB */ ++#endif ++ ++#if defined(CONFIG_JZ4750_FUWA) /* board FuWa */ ++#if 0 ++ #define SPEN (32*5+7) //LCD_SPL GPF7 ++ #define SPCK (32*5+6) //LCD_CLS GPF6 ++ #define SPDA (32*5+5) //LCD_PS GPF5 ++ #define LCD_RET (32*5+4) //LCD_REV GPF4 //use for lcd reset ++#endif ++ #define SPEN (32*3+29) /*LCD_CS*/ ++ #define SPCK (32*3+26) /*LCD_SCL*/ ++ #define SPDA (32*3+27) /*LCD_SDA*/ ++ #define LCD_RET (32*4+25) /*LCD_DISP_N use for lcd reset*/ ++#elif defined(CONFIG_JZ4750D_FUWA1)/* board FuWa */ ++ #define SPEN (32*4+0) /*LCD_CS*/ ++ #define SPCK (32*4+9) /*LCD_SCL*/ ++ #define SPDA (32*4+1) /*LCD_SDA*/ ++ #define LCD_RET (32*4+3) /*LCD_DISP_N use for lcd reset*/ ++#else ++#error "driver/video/Jzlcd.h, please define SPI pins on your board." ++#endif ++ ++ #define __spi_write_reg1(reg, val) \ ++ do { \ ++ unsigned char no;\ ++ unsigned short value;\ ++ unsigned char a=0;\ ++ unsigned char b=0;\ ++ a=reg;\ ++ b=val;\ ++ __gpio_set_pin(SPEN);\ ++ __gpio_set_pin(SPCK);\ ++ __gpio_clear_pin(SPDA);\ ++ __gpio_clear_pin(SPEN);\ ++ udelay(25);\ ++ value=((a<<8)|(b&0xFF));\ ++ for(no=0;no<16;no++)\ ++ {\ ++ __gpio_clear_pin(SPCK);\ ++ if((value&0x8000)==0x8000)\ ++ __gpio_set_pin(SPDA);\ ++ else\ ++ __gpio_clear_pin(SPDA);\ ++ udelay(25);\ ++ __gpio_set_pin(SPCK);\ ++ value=(value<<1); \ ++ udelay(25);\ ++ }\ ++ __gpio_set_pin(SPEN);\ ++ udelay(100);\ ++ } while (0) ++ ++ #define __spi_write_reg(reg, val) \ ++ do {\ ++ __spi_write_reg1((reg<<2|2), val); \ ++ udelay(100); \ ++ }while(0) ++ ++ #define __lcd_special_pin_init() \ ++ do { \ ++ __gpio_as_output(SPEN); /* use SPDA */\ ++ __gpio_as_output(SPCK); /* use SPCK */\ ++ __gpio_as_output(SPDA); /* use SPDA */\ ++ __gpio_as_output(LCD_RET);\ ++ udelay(50);\ ++ __gpio_clear_pin(LCD_RET);\ ++ mdelay(150);\ ++ __gpio_set_pin(LCD_RET);\ ++ } while (0) ++ ++ #define __lcd_special_on() \ ++ do { \ ++ udelay(50);\ ++ __gpio_clear_pin(LCD_RET);\ ++ mdelay(150);\ ++ __gpio_set_pin(LCD_RET);\ ++ mdelay(10);\ ++ __spi_write_reg(0x00, 0x03); \ ++ __spi_write_reg(0x01, 0x40); \ ++ __spi_write_reg(0x02, 0x11); \ ++ __spi_write_reg(0x03, MODE); /* mode */ \ ++ __spi_write_reg(0x04, 0x32); \ ++ __spi_write_reg(0x05, 0x0e); \ ++ __spi_write_reg(0x07, 0x03); \ ++ __spi_write_reg(0x08, 0x08); \ ++ __spi_write_reg(0x09, 0x32); \ ++ __spi_write_reg(0x0A, 0x88); \ ++ __spi_write_reg(0x0B, 0xc6); \ ++ __spi_write_reg(0x0C, 0x20); \ ++ __spi_write_reg(0x0D, 0x20); \ ++ } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level ++ ++/* __spi_write_reg(0x02, 0x03); \ ++ __spi_write_reg(0x06, 0x40); \ ++ __spi_write_reg(0x0a, 0x11); \ ++ __spi_write_reg(0x0e, 0xcd); \ ++ __spi_write_reg(0x12, 0x32); \ ++ __spi_write_reg(0x16, 0x0e); \ ++ __spi_write_reg(0x1e, 0x03); \ ++ __spi_write_reg(0x22, 0x08); \ ++ __spi_write_reg(0x26, 0x40); \ ++ __spi_write_reg(0x2a, 0x88); \ ++ __spi_write_reg(0x2e, 0x88); \ ++ __spi_write_reg(0x32, 0x20); \ ++ __spi_write_reg(0x36, 0x20); \ ++*/ ++// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level ++ ++ #define __lcd_special_off() \ ++ do { \ ++ __spi_write_reg(0x00, 0x03); \ ++ } while (0) ++ ++#endif /* CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 or CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL */ ++ ++#if defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W) ++static inline void CmdWrite(unsigned int cmd) ++{ ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */ ++ udelay(30); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; ++} ++ ++static inline void DataWrite(unsigned int data) ++{ ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */ ++// udelay(30); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; ++} ++ ++ ++static inline void delay(long delay_time) ++{ ++ long cnt; ++ ++// delay_time *= (384/8); ++ delay_time *= (43/8); ++ ++ for (cnt=0;cnt SETP 3 ++ CmdWrite(0x0000); ++ CmdWrite(0x01A0); ++ CmdWrite(0x3B01); ++ ++ CmdWrite(0x2809); ++ delay(1000); ++ CmdWrite(0x1900); ++ delay(1000); ++ CmdWrite(0x2110); ++ delay(1000); ++ CmdWrite(0x1805); ++ delay(1000); ++ CmdWrite(0x1E01); ++ delay(1000); ++ CmdWrite(0x1847); ++ delay(1000); ++ CmdWrite(0x1867); ++ delay(1000); ++ CmdWrite(0x18F7); ++ delay(1000); ++ CmdWrite(0x2100); ++ delay(1000); ++ CmdWrite(0x2809); ++ delay(1000); ++ CmdWrite(0x1A05); ++ delay(1000); ++ CmdWrite(0x19E8); ++ delay(1000); ++ CmdWrite(0x1F64); ++ delay(1000); ++ CmdWrite(0x2045); ++ delay(1000); ++ CmdWrite(0x1E81); ++ delay(1000); ++ CmdWrite(0x1B09); ++ delay(1000); ++ CmdWrite(0x0020); ++ delay(1000); ++ CmdWrite(0x0120); ++ delay(1000); ++ ++ CmdWrite(0x3B01); ++ delay(1000); ++ ++ /* Set Window(239,319), Set Cursor(239,319) */ ++ CmdWrite(0x0510); ++ CmdWrite(0x01C0); ++ CmdWrite(0x4500); ++ CmdWrite(0x46EF); ++ CmdWrite(0x4800); ++ CmdWrite(0x4700); ++ CmdWrite(0x4A3F); ++ CmdWrite(0x4901); ++ CmdWrite(0x42EF); ++ CmdWrite(0x443F); ++ CmdWrite(0x4301); ++ ++} ++ ++#if defined(CONFIG_JZ4750_FUWA) ++//#define PIN_CS_N (32*2+xx) /* a low voltage */ ++#define PIN_RD_N (32*3+21) /* LCD_DE: GP D21, a high voltage */ ++#define PIN_RESET_N (32*3+25) /* LCD_REV GP D25 */ ++#else ++#error "Define special lcd pins for your platform." ++#endif ++ ++#define __lcd_slcd_pin_init() \ ++ do { \ ++ __gpio_as_output(PIN_RD_N); /* RD#: LCD_REV */ \ ++ __gpio_as_output(PIN_RESET_N); /* RESET#: LCD_SPL */ \ ++ __gpio_set_pin(PIN_RD_N); /*set read signal high */ \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(100); \ ++ __gpio_clear_pin(PIN_RESET_N); \ ++ mdelay(100); \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ /* Configure SLCD module */ \ ++ REG_LCD_CTRL &= ~(LCD_CTRL_ENA|LCD_CTRL_DIS); /* disable lcdc */ \ ++ REG_LCD_CFG = LCD_CFG_LCDPIN_SLCD | 0x0D; /* LCM */ \ ++ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; /* disable slcd dma */ \ ++ REG_SLCD_CFG = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL; \ ++ REG_LCD_REV = 0x04; /* lcd clock??? */ \ ++ printk("Fuwa test, pixclk divide REG_LCD_REV=0x%08x\n", REG_LCD_REV); \ ++}while (0) ++ ++#define __lcd_slcd_special_on() \ ++ do { \ ++ __lcd_slcd_pin_init(); \ ++ SlcdInit(); \ ++ REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN; /* slcdc dma enable */ \ ++ } while (0) ++ ++#endif /* #if CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W */ ++ ++#ifndef __lcd_special_pin_init ++#define __lcd_special_pin_init() ++#endif ++#ifndef __lcd_special_on ++#define __lcd_special_on() ++#endif ++#ifndef __lcd_special_off ++#define __lcd_special_off() ++#endif ++ ++ ++/* ++ * Platform specific definition ++ */ ++#if defined(CONFIG_JZ4750D_VGA_DISPLAY) ++#define __lcd_display_pin_init() ++#define __lcd_display_on() ++#define __lcd_display_off() ++#elif defined(CONFIG_JZ4750_APUS)/* board apus */ ++#define __lcd_display_pin_init() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_VCC_EN_N); \ ++ __lcd_special_pin_init(); \ ++} while (0) ++#define __lcd_display_on() \ ++do { \ ++ __gpio_clear_pin(GPIO_LCD_VCC_EN_N); \ ++ __lcd_special_on(); \ ++ __lcd_set_backlight_level(80); \ ++} while (0) ++ ++#define __lcd_display_off() \ ++do { \ ++ __lcd_close_backlight(); \ ++ __lcd_special_off(); \ ++} while (0) ++#elif defined(CONFIG_JZ4750D_CETUS)/* board apus */ ++#define __lcd_display_pin_init() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_VCC_EN_N); \ ++ __lcd_special_pin_init(); \ ++} while (0) ++#define __lcd_display_on() \ ++do { \ ++ __gpio_set_pin(GPIO_LCD_VCC_EN_N); \ ++ __lcd_special_on(); \ ++ __lcd_set_backlight_level(80); \ ++} while (0) ++ ++#define __lcd_display_off() \ ++do { \ ++ __lcd_close_backlight(); \ ++ __lcd_special_off(); \ ++} while (0) ++ ++#else /* other boards */ ++ ++#define __lcd_display_pin_init() \ ++do { \ ++ __lcd_special_pin_init(); \ ++} while (0) ++#define __lcd_display_on() \ ++do { \ ++ __lcd_special_on(); \ ++ __lcd_set_backlight_level(80); \ ++} while (0) ++ ++#define __lcd_display_off() \ ++do { \ ++ __lcd_close_backlight(); \ ++ __lcd_special_off(); \ ++} while (0) ++#endif /* APUS */ ++ ++ ++/***************************************************************************** ++ * LCD display pin dummy macros ++ *****************************************************************************/ ++ ++#ifndef __lcd_display_pin_init ++#define __lcd_display_pin_init() ++#endif ++#ifndef __lcd_slcd_special_on ++#define __lcd_slcd_special_on() ++#endif ++#ifndef __lcd_display_on ++#define __lcd_display_on() ++#endif ++#ifndef __lcd_display_off ++#define __lcd_display_off() ++#endif ++#ifndef __lcd_set_backlight_level ++#define __lcd_set_backlight_level(n) ++#endif ++ ++#endif /* __JZ4750_LCD_H__ */ +diff --git a/drivers/video/jz4750_tve.c b/drivers/video/jz4750_tve.c +new file mode 100644 +index 0000000..3a4ea61 +--- /dev/null ++++ b/drivers/video/jz4750_tve.c +@@ -0,0 +1,104 @@ ++ ++/* ++ * linux/drivers/video/jz4750_tve.c -- Ingenic Jz4750 TVE Controller operation ++ * interface. ++ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. ++ * Author: Wolfgang Wang, ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++ ++#include ++#include "jz4750_tve.h" ++ ++struct jz4750tve_info jz4750_tve_info_PAL = { ++ .ctrl = (4 << TVE_CTRL_YCDLY_BIT) | TVE_CTRL_SYNCT | TVE_CTRL_PAL | TVE_CTRL_SWRST, /* PAL, SVIDEO */ ++ .frcfg = (23 << TVE_FRCFG_L1ST_BIT) | (625 << TVE_FRCFG_NLINE_BIT), ++ .slcfg1 = (800<ctrl = (jz4750_tve_info->ctrl | TVE_CTRL_DAPD) & ( ~( TVE_CTRL_DAPD1 | TVE_CTRL_DAPD2)); ++ jz4750_tve_info->ctrl &= ~TVE_CTRL_SWRST; ++ REG_TVE_CTRL = jz4750_tve_info->ctrl; ++} ++ ++/* turn off TVE, turn off DACn... */ ++void jz4750tve_disable_tve(void) ++{ ++ jz4750_tve_info->ctrl &= ~TVE_CTRL_DAPD;/* DACn disabled??? */ ++ jz4750_tve_info->ctrl |= TVE_CTRL_SWRST;/* DACn disabled??? */ ++ REG_TVE_CTRL = jz4750_tve_info->ctrl; ++} ++ ++void jz4750tve_set_tve_mode( struct jz4750tve_info *tve ) ++{ ++ REG_TVE_CTRL = tve->ctrl; ++ REG_TVE_FRCFG = tve->frcfg; ++ REG_TVE_SLCFG1 = tve->slcfg1; ++ REG_TVE_SLCFG2 = tve->slcfg2; ++ REG_TVE_SLCFG3 = tve->slcfg3; ++ REG_TVE_LTCFG1 = tve->ltcfg1; ++ REG_TVE_LTCFG2 = tve->ltcfg2; ++ REG_TVE_CFREQ = tve->cfreq; ++ REG_TVE_CPHASE = tve->cphase; ++ REG_TVE_CBCRCFG = tve->cbcrcfg; ++ REG_TVE_WSSCR = tve->wsscr; ++ REG_TVE_WSSCFG1 = tve->wsscfg1; ++ REG_TVE_WSSCFG2 = tve->wsscfg2; ++ REG_TVE_WSSCFG3 = tve->wsscfg3; ++} ++ ++void jz4750tve_init( int tve_mode ) ++{ ++ switch ( tve_mode ) { ++ case PANEL_MODE_TVE_PAL: ++ jz4750_tve_info = &jz4750_tve_info_PAL; ++ break; ++ case PANEL_MODE_TVE_NTSC: ++ jz4750_tve_info = &jz4750_tve_info_NTSC; ++ break; ++ } ++ ++ jz4750tve_set_tve_mode( jz4750_tve_info ); ++// jz4750tve_enable_tve(); ++} +diff --git a/drivers/video/jz4750_tve.h b/drivers/video/jz4750_tve.h +new file mode 100644 +index 0000000..00eefe9 +--- /dev/null ++++ b/drivers/video/jz4750_tve.h +@@ -0,0 +1,45 @@ ++#ifndef __JZ4750_TVE_H__ ++#define __JZ4750_TVE_H__ ++ ++ ++#define PANEL_MODE_LCD_PANEL 0 ++#define PANEL_MODE_TVE_PAL 1 ++#define PANEL_MODE_TVE_NTSC 2 ++ ++/* TV parameter */ ++#define TVE_WIDTH_PAL 720 ++#define TVE_HEIGHT_PAL 573 ++#define TVE_FREQ_PAL 50 ++#define TVE_WIDTH_NTSC 720 ++#define TVE_HEIGHT_NTSC 482 ++#define TVE_FREQ_NTSC 60 ++ ++ ++/* Structure for TVE */ ++struct jz4750tve_info { ++ unsigned int ctrl; ++ unsigned int frcfg; ++ unsigned int slcfg1; ++ unsigned int slcfg2; ++ unsigned int slcfg3; ++ unsigned int ltcfg1; ++ unsigned int ltcfg2; ++ unsigned int cfreq; ++ unsigned int cphase; ++ unsigned int cbcrcfg; ++ unsigned int wsscr; ++ unsigned int wsscfg1; ++ unsigned int wsscfg2; ++ unsigned int wsscfg3; ++}; ++ ++extern struct jz4750tve_info *jz4750_tve_info; ++ ++extern void jz4750tve_enable_tve(void); ++extern void jz4750tve_disable_tve(void); ++ ++extern void jz4750tve_set_tve_mode( struct jz4750tve_info *tve ); ++extern void jz4750tve_init( int tve_mode ); ++ ++ ++#endif /* __JZ4750_TVE_H__ */ +diff --git a/drivers/video/jz_kgm_spfd5420a.h b/drivers/video/jz_kgm_spfd5420a.h +new file mode 100644 +index 0000000..33d8bd5 +--- /dev/null ++++ b/drivers/video/jz_kgm_spfd5420a.h +@@ -0,0 +1,385 @@ ++/* Set registers of smart lcd acording to the following routines ++ * Note: BUS width and CMD width and register value width ++ * This example: BUS is 8, 9, 16 or 18-bit; CMD and DATA is 16-bit ++ * Configure SLCD module to initialize smart lcd registers ++ ++ switch (bus) { ++ case 8: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 ++ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_8bit(); ++ break; ++ case 9: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 ++ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_9bit(); ++ break; ++ case 16: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_16 ++ | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_16bit(); ++ break; ++ case 18: ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18 ++ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_TYPE_PARALLEL; ++ __gpio_as_slcd_18bit(); ++ break; ++ } ++ ++ static void Mcupanel_RegSet(unsigned int cmd, unsigned int data) ++ { ++ switch (bus) { ++ case 8: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); ++ break; ++ case 9: ++ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); ++ data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; ++ break; ++ case 16: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); ++ break; ++ case 18: ++ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); ++ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc); ++ break; ++ default: ++ printk("Don't support %d bit Bus\n", jzfb.bus ); ++ break; ++ } ++ } ++ ++ static void Mcupanel_Command(unsigned int cmd) { ++ switch (bus) { ++ case 8: ++ case 9: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); ++ break; ++ case 16: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); ++ break; ++ case 18: ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1); ++ break; ++ default: ++ printk("Don't support %d bit Bus\n", jzfb.bus ); ++ break; ++ } ++ } ++ ++ *Display---------------------------------------- ++ Note: BUS and BPP, send data to gram data register to display ++ BUS: 8, 9, 16 or 18-bit; BPP: 8, 16, 18-bit ++ switch (bus) { ++ case 8: ++ switch (bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15: ++ case 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ case 9: ++ switch (bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15 ... 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_9_x2; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ case 16: ++ switch (bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15 ... 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ case 18: ++ switch (bpp) { ++ case 8: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; ++ break; ++ case 15: ++ case 16: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; ++ break; ++ case 17 ... 32: ++ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; ++ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_18; ++ break; ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ break; ++ } ++ break; ++ default: ++ printk("Error: The BUS %d is not supported\n", jzfb.bus); ++ break; ++ } ++ dprintk("SLCD_CFG=0x%x\n", REG_SLCD_CFG); ++} ++ ************************************************************************************************/ ++ ++#ifndef __JZ_KGM_SPF5420A_H__ ++#define __JZ_KGM_SPF5420A_H__ ++ ++#include ++ ++#if defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A) ++#define WR_GRAM_CMD 0x0202 ++ ++#if defined(CONFIG_JZ4750_FUWA) ++#define PIN_CS_N (32*3+24) // Chip select //GPD24; ++#define PIN_RESET_N (32*5+6) /* LCD_REV GPF6 */ ++#elif defined(CONFIG_JZ4750D_FUWA1) ++#define PIN_CS_N (32*3+24) // Chip select //GPD24; ++#define PIN_RESET_N (32*4+3) /* LCD_REV GPF6 */ ++#else ++#error "Define special lcd pins for your platform." ++#endif ++ ++/* Sent a command with data (18-bit bus, 16-bit index, 16-bit register value) */ ++static void Mcupanel_RegSet(unsigned int cmd, unsigned int data) ++{ ++ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); ++ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); ++ data = ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc); ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; ++} ++ ++/* Sent a command without data (18-bit bus, 16-bit index) */ ++static void Mcupanel_Command(unsigned int cmd) { ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); ++ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1); ++} ++ ++/* Set the start address of screen, for example (0, 0) */ ++void Mcupanel_SetAddr(u32 x, u32 y) //u32 ++{ ++ Mcupanel_RegSet(0x200,x) ; ++ udelay(1); ++ Mcupanel_RegSet(0x201,y) ; ++ udelay(1); ++ Mcupanel_Command(0x202); ++ ++} ++ ++#undef __lcd_special_pin_init ++#define __lcd_special_pin_init() \ ++do { \ ++ __gpio_as_output(PIN_CS_N); \ ++ __gpio_as_output(PIN_RESET_N); \ ++ __gpio_clear_pin(PIN_CS_N); /* Clear CS */ \ ++ mdelay(100); \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_clear_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(100); \ ++} while(0) ++ ++ ++#define GAMMA() \ ++do { \ ++ Mcupanel_RegSet(0x0300,0x0101); \ ++ Mcupanel_RegSet(0x0301,0x0b27); \ ++ Mcupanel_RegSet(0x0302,0x132a); \ ++ Mcupanel_RegSet(0x0303,0x2a13); \ ++ Mcupanel_RegSet(0x0304,0x270b); \ ++ Mcupanel_RegSet(0x0305,0x0101); \ ++ Mcupanel_RegSet(0x0306,0x1205); \ ++ Mcupanel_RegSet(0x0307,0x0512); \ ++ Mcupanel_RegSet(0x0308,0x0005); \ ++ Mcupanel_RegSet(0x0309,0x0003); \ ++ Mcupanel_RegSet(0x030a,0x0f04); \ ++ Mcupanel_RegSet(0x030b,0x0f00); \ ++ Mcupanel_RegSet(0x030c,0x000f); \ ++ Mcupanel_RegSet(0x030d,0x040f); \ ++ Mcupanel_RegSet(0x030e,0x0300); \ ++ Mcupanel_RegSet(0x030f,0x0500); \ ++ /*** secorrect gamma2 ***/ \ ++ Mcupanel_RegSet(0x0400,0x3500); \ ++ Mcupanel_RegSet(0x0401,0x0001); \ ++ Mcupanel_RegSet(0x0404,0x0000); \ ++ Mcupanel_RegSet(0x0500,0x0000); \ ++ Mcupanel_RegSet(0x0501,0x0000); \ ++ Mcupanel_RegSet(0x0502,0x0000); \ ++ Mcupanel_RegSet(0x0503,0x0000); \ ++ Mcupanel_RegSet(0x0504,0x0000); \ ++ Mcupanel_RegSet(0x0505,0x0000); \ ++ Mcupanel_RegSet(0x0600,0x0000); \ ++ Mcupanel_RegSet(0x0606,0x0000); \ ++ Mcupanel_RegSet(0x06f0,0x0000); \ ++ Mcupanel_RegSet(0x07f0,0x5420); \ ++ Mcupanel_RegSet(0x07f3,0x288a); \ ++ Mcupanel_RegSet(0x07f4,0x0022); \ ++ Mcupanel_RegSet(0x07f5,0x0001); \ ++ Mcupanel_RegSet(0x07f0,0x0000); \ ++} while(0) ++ ++#define SlcdInit() \ ++do { \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_clear_pin(PIN_RESET_N); \ ++ mdelay(10); \ ++ __gpio_set_pin(PIN_RESET_N); \ ++ mdelay(100); \ ++ Mcupanel_RegSet(0x0600, 0x0001); /*soft reset*/ \ ++ mdelay(10); \ ++ Mcupanel_RegSet(0x0600, 0x0000); /*soft reset*/ \ ++ mdelay(10); \ ++ Mcupanel_RegSet(0x0606,0x0000); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0007,0x0001); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0110,0x0001); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0100,0x17b0); \ ++ Mcupanel_RegSet(0x0101,0x0147); \ ++ Mcupanel_RegSet(0x0102,0x019d); \ ++ Mcupanel_RegSet(0x0103,0x8600); \ ++ Mcupanel_RegSet(0x0281,0x0010); \ ++ udelay(10); \ ++ Mcupanel_RegSet(0x0102,0x01bd); \ ++ udelay(10); \ ++ /************initial************/\ ++ Mcupanel_RegSet(0x0000,0x0000); \ ++ Mcupanel_RegSet(0x0001,0x0000); \ ++ Mcupanel_RegSet(0x0002,0x0400); \ ++ Mcupanel_RegSet(0x0003,0x12b8); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ \ ++ Mcupanel_RegSet(0x0006,0x0000); \ ++ Mcupanel_RegSet(0x0008,0x0503); \ ++ Mcupanel_RegSet(0x0009,0x0001); \ ++ Mcupanel_RegSet(0x000b,0x0010); \ ++ Mcupanel_RegSet(0x000c,0x0000); \ ++ Mcupanel_RegSet(0x000f,0x0000); \ ++ Mcupanel_RegSet(0x0007,0x0001); \ ++ Mcupanel_RegSet(0x0010,0x0010); \ ++ Mcupanel_RegSet(0x0011,0x0202); \ ++ Mcupanel_RegSet(0x0012,0x0300); \ ++ Mcupanel_RegSet(0x0020,0x021e); \ ++ Mcupanel_RegSet(0x0021,0x0202); \ ++ Mcupanel_RegSet(0x0022,0x0100); \ ++ Mcupanel_RegSet(0x0090,0x0000); \ ++ Mcupanel_RegSet(0x0092,0x0000); \ ++ Mcupanel_RegSet(0x0100,0x16b0); \ ++ Mcupanel_RegSet(0x0101,0x0147); \ ++ Mcupanel_RegSet(0x0102,0x01bd); \ ++ Mcupanel_RegSet(0x0103,0x2c00); \ ++ Mcupanel_RegSet(0x0107,0x0000); \ ++ Mcupanel_RegSet(0x0110,0x0001); \ ++ Mcupanel_RegSet(0x0210,0x0000); \ ++ Mcupanel_RegSet(0x0211,0x00ef); \ ++ Mcupanel_RegSet(0x0212,0x0000); \ ++ Mcupanel_RegSet(0x0213,0x018f); \ ++ Mcupanel_RegSet(0x0280,0x0000); \ ++ Mcupanel_RegSet(0x0281,0x0001); \ ++ Mcupanel_RegSet(0x0282,0x0000); \ ++ GAMMA(); \ ++ Mcupanel_RegSet(0x0007,0x0173); \ ++ Mcupanel_Command(0x0202); /*Write Data to GRAM */ \ ++ udelay(10);\ ++ Mcupanel_SetAddr(0,0);\ ++ udelay(100);\ ++} while(0) ++ ++/*---- LCD Initial ----*/ ++#undef __lcd_slcd_pin_init ++#define __lcd_slcd_pin_init() \ ++ do { \ ++ __lcd_special_pin_init(); \ ++}while (0) ++ ++#undef __lcd_slcd_special_on ++#define __lcd_slcd_special_on() \ ++ do { \ ++ __lcd_slcd_pin_init(); \ ++ SlcdInit(); \ ++ REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN; /* slcdc dma enable */ \ ++ } while (0) ++ ++#define __init_slcd_bus()\ ++do{\ ++ __slcd_set_data_18bit();\ ++ __slcd_set_cmd_18bit();\ ++ __slcd_set_cs_low();\ ++ __slcd_set_rs_low();\ ++ __slcd_set_clk_falling();\ ++ __slcd_set_parallel_type();\ ++}while(0) ++#endif /* #if CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A */ ++ ++#endif /* __JZ_KGM_SPF5420A_H__ */ +diff --git a/drivers/video/jz_toppoly_td043mgeb1.h b/drivers/video/jz_toppoly_td043mgeb1.h +new file mode 100644 +index 0000000..c66494e +--- /dev/null ++++ b/drivers/video/jz_toppoly_td043mgeb1.h +@@ -0,0 +1,264 @@ ++ ++#ifndef __JZ_KGM_TOPPOLY_TD043MGEB1_H__ ++#define __JZ_KGM_TOPPOLY_TD043MGEB1_H__ ++ ++#include ++ ++#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1) ++#if defined(CONFIG_JZ4750_APUS) /* board FuWa */ ++ #define SPEN (32*3+29) /*LCD_CS*/ ++ #define SPCK (32*3+26) /*LCD_SCL*/ ++ #define SPDA (32*3+27) /*LCD_SDA*/ ++ #define LCD_RET (32*4+23) /*LCD_DISP_N use for lcd reset*/ ++ #define LCD_STBY (32*4+25) /*LCD_STBY, use for lcd standby*/ ++#else ++#error "driver/video/Jzlcd.h, please define SPI pins on your board." ++#endif ++ ++#define __spi_write_reg(reg, val) \ ++ do { \ ++ unsigned char no; \ ++ unsigned short value; \ ++ unsigned char a=0; \ ++ unsigned char b=0; \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ a=reg; \ ++ b=val; \ ++ __gpio_set_pin(SPEN); \ ++ __gpio_clear_pin(SPCK); \ ++ udelay(500); \ ++ __gpio_clear_pin(SPDA); \ ++ __gpio_clear_pin(SPEN); \ ++ udelay(500); \ ++ value=((a<<8)|(b&0xFF)); \ ++ for(no=0;no<16;no++) \ ++ { \ ++ if((value&0x8000)==0x8000){ \ ++ __gpio_set_pin(SPDA);} \ ++ else{ \ ++ __gpio_clear_pin(SPDA); } \ ++ udelay(500); \ ++ __gpio_set_pin(SPCK); \ ++ value=(value<<1); \ ++ udelay(500); \ ++ __gpio_clear_pin(SPCK); \ ++ } \ ++ __gpio_set_pin(SPEN); \ ++ udelay(4000); \ ++ } while (0) ++#define __spi_read_reg(reg,val) \ ++ do{ \ ++ unsigned char no; \ ++ unsigned short value; \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ value = ((reg << 0) | (1 << 7)); \ ++ val = 0; \ ++ __gpio_as_output(SPDA); \ ++ __gpio_set_pin(SPEN); \ ++ __gpio_clear_pin(SPCK); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPDA); \ ++ __gpio_clear_pin(SPEN); \ ++ udelay(50); \ ++ for (no = 0; no < 16; no++ ) { \ ++ udelay(50); \ ++ if(no < 8) \ ++ { \ ++ if (value & 0x80) /* send data */ \ ++ __gpio_set_pin(SPDA); \ ++ else \ ++ __gpio_clear_pin(SPDA); \ ++ udelay(50); \ ++ __gpio_set_pin(SPCK); \ ++ value = (value << 1); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPCK); \ ++ if(no == 7) \ ++ __gpio_as_input(SPDA); \ ++ } \ ++ else \ ++ { \ ++ udelay(100); \ ++ __gpio_set_pin(SPCK); \ ++ udelay(50); \ ++ val = (val << 1); \ ++ val |= __gpio_get_pin(SPDA); \ ++ __gpio_clear_pin(SPCK); \ ++ } \ ++ } \ ++ __gpio_as_output(SPDA); \ ++ __gpio_set_pin(SPEN); \ ++ udelay(400); \ ++ } while(0) ++ ++#define __lcd_special_pin_init() \ ++ do { \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ __gpio_as_output(LCD_STBY); \ ++ __gpio_as_output(LCD_RET); \ ++ udelay(500); \ ++ __gpio_clear_pin(LCD_RET); \ ++ udelay(1000); \ ++ __gpio_set_pin(LCD_RET); \ ++ udelay(1000); \ ++ __gpio_set_pin(LCD_STBY); \ ++ udelay(1000); \ ++ } while (0) ++#define __lcd_special_on() \ ++ do { \ ++} while (0) ++ ++ #define __lcd_special_off() \ ++ do { \ ++ __gpio_clear_pin(LCD_RET); \ ++ } while (0) ++ ++#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */ ++ ++#endif /* __JZ_KGM_TOPPOLY_TD043MGEB1_H__ */ ++/* 2.2 ++ __spi_write_reg(0x02, 0x07 ); \ ++ __spi_write_reg(0x03, 0x5f); \ ++ __spi_write_reg(0x04, 0x17); \ ++ __spi_write_reg(0x05, 0x20); \ ++ __spi_write_reg(0x06, 0x08); \ ++ __spi_write_reg(0x07, 0x26); \ ++ __spi_write_reg(0x08, 0x13); \ ++ __spi_write_reg(0x09, 0x33); \ ++ __spi_write_reg(0x0a, 0x20); \ ++ __spi_write_reg(0x0b, 0x20); \ ++ __spi_write_reg(0x0c, 0x20); \ ++ __spi_write_reg(0x0d, 0x20); \ ++ __spi_write_reg(0x0e, 0x10); \ ++ __spi_write_reg(0x0f, 0x10); \ ++ __spi_write_reg(0x10, 0x10); \ ++ __spi_write_reg(0x11, 0x15); \ ++ __spi_write_reg(0x12, 0xaa); \ ++ __spi_write_reg(0x13, 0xff); \ ++ __spi_write_reg(0x14, 0x86); \ ++ __spi_write_reg(0x15, 0x8e); \ ++ __spi_write_reg(0x16, 0xd6); \ ++ __spi_write_reg(0x17, 0xfe); \ ++ __spi_write_reg(0x18, 0x28); \ ++ __spi_write_reg(0x19, 0x52); \ ++ __spi_write_reg(0x1a, 0x7c); \ ++ __spi_write_reg(0x1b, 0xe9); \ ++ __spi_write_reg(0x1c, 0x42); \ ++ __spi_write_reg(0x1d, 0x88); \ ++ __spi_write_reg(0x1e, 0xb8); \ ++ __spi_write_reg(0x1f, 0xff); \ ++ __spi_write_reg(0x20, 0xf0); \ ++ __spi_write_reg(0x21, 0xf0); \ ++ __spi_write_reg(0x22, 0x07); \ ++*/ ++/* 3.1 ++ __spi_write_reg(0x02, 0x07); \ ++ __spi_write_reg(0x03, 0x5f); \ ++ __spi_write_reg(0x04, 0x17); \ ++ __spi_write_reg(0x05, 0x20); \ ++ __spi_write_reg(0x06, 0x08); \ ++ __spi_write_reg(0x07, 0x20); \ ++ __spi_write_reg(0x08, 0x20); \ ++ __spi_write_reg(0x09, 0x20); \ ++ __spi_write_reg(0x0a, 0x20); \ ++ __spi_write_reg(0x0b, 0x20); \ ++ __spi_write_reg(0x0c, 0x20); \ ++ __spi_write_reg(0x0d, 0x22); \ ++ __spi_write_reg(0x0e, 0x10); \ ++ __spi_write_reg(0x0f, 0x10); \ ++ __spi_write_reg(0x10, 0x10); \ ++ __spi_write_reg(0x11, 0x15); \ ++ __spi_write_reg(0x12, 0x6a); \ ++ __spi_write_reg(0x13, 0xff); \ ++ __spi_write_reg(0x14, 0x86); \ ++ __spi_write_reg(0x15, 0x7c); \ ++ __spi_write_reg(0x16, 0xc2); \ ++ __spi_write_reg(0x17, 0xd1); \ ++ __spi_write_reg(0x18, 0xf5); \ ++ __spi_write_reg(0x19, 0x25); \ ++ __spi_write_reg(0x1a, 0x4a); \ ++ __spi_write_reg(0x1b, 0xbf); \ ++ __spi_write_reg(0x1c, 0x15); \ ++ __spi_write_reg(0x1d, 0x6a); \ ++ __spi_write_reg(0x1e, 0xa4); \ ++ __spi_write_reg(0x1f, 0xff); \ ++ __spi_write_reg(0x20, 0xf0); \ ++ __spi_write_reg(0x21, 0xf0); \ ++ __spi_write_reg(0x22, 0x08); \ ++ */ ++ /* 2.5 ++ __spi_write_reg(0x02, 0x07); \ ++ __spi_write_reg(0x03, 0x5f); \ ++ __spi_write_reg(0x04, 0x17); \ ++ __spi_write_reg(0x05, 0x20); \ ++ __spi_write_reg(0x06, 0x08); \ ++ __spi_write_reg(0x07, 0x20); \ ++ __spi_write_reg(0x08, 0x20); \ ++ __spi_write_reg(0x09, 0x20); \ ++ __spi_write_reg(0x0a, 0x20); \ ++ __spi_write_reg(0x0b, 0x20); \ ++ __spi_write_reg(0x0c, 0x20); \ ++ __spi_write_reg(0x0d, 0x22); \ ++ __spi_write_reg(0x0e, 0x10); \ ++ __spi_write_reg(0x0f, 0x10); \ ++ __spi_write_reg(0x10, 0x10); \ ++ __spi_write_reg(0x11, 0x15); \ ++ __spi_write_reg(0x12, 0xaa); \ ++ __spi_write_reg(0x13, 0xff); \ ++ __spi_write_reg(0x14, 0x86); \ ++ __spi_write_reg(0x15, 0x89); \ ++ __spi_write_reg(0x16, 0xc6); \ ++ __spi_write_reg(0x17, 0xea); \ ++ __spi_write_reg(0x18, 0x0c); \ ++ __spi_write_reg(0x19, 0x33); \ ++ __spi_write_reg(0x1a, 0x5e); \ ++ __spi_write_reg(0x1b, 0xd0); \ ++ __spi_write_reg(0x1c, 0x33); \ ++ __spi_write_reg(0x1d, 0x7e); \ ++ __spi_write_reg(0x1e, 0xb3); \ ++ __spi_write_reg(0x1f, 0xff); \ ++ __spi_write_reg(0x20, 0xf0); \ ++ __spi_write_reg(0x21, 0xf0); \ ++ __spi_write_reg(0x22, 0x08); \ ++*/ ++/* ++ __spi_write_reg(0x02, 0x07); \ ++ __spi_write_reg(0x03, 0x5f); \ ++ __spi_write_reg(0x04, 0x17); \ ++ __spi_write_reg(0x05, 0x20); \ ++ __spi_write_reg(0x06, 0x08); \ ++ __spi_write_reg(0x07, 0x20); \ ++ __spi_write_reg(0x08, 0x20); \ ++ __spi_write_reg(0x09, 0x20); \ ++ __spi_write_reg(0x0a, 0x20); \ ++ __spi_write_reg(0x0b, 0x20); \ ++ __spi_write_reg(0x0c, 0x20); \ ++ __spi_write_reg(0x0d, 0x22); \ ++ __spi_write_reg(0x0e, 0x10); \ ++ __spi_write_reg(0x0f, 0x10); \ ++ __spi_write_reg(0x10, 0x10); \ ++ __spi_write_reg(0x11, 0x15); \ ++ __spi_write_reg(0x12, 0xaa); \ ++ __spi_write_reg(0x13, 0xff); \ ++ __spi_write_reg(0x14, 0x86); \ ++ __spi_write_reg(0x15, 0x84); \ ++ __spi_write_reg(0x16, 0xc3); \ ++ __spi_write_reg(0x17, 0xd8); \ ++ __spi_write_reg(0x18, 0x01); \ ++ __spi_write_reg(0x19, 0x28); \ ++ __spi_write_reg(0x1a, 0x53); \ ++ __spi_write_reg(0x1b, 0xc5); \ ++ __spi_write_reg(0x1c, 0x26); \ ++ __spi_write_reg(0x1d, 0x74); \ ++ __spi_write_reg(0x1e, 0xae); \ ++ __spi_write_reg(0x1f, 0xff); \ ++ __spi_write_reg(0x20, 0xf0); \ ++ __spi_write_reg(0x21, 0xf0); \ ++ __spi_write_reg(0x22, 0x08); \ ++ */ +diff --git a/drivers/video/jzlcd.c b/drivers/video/jzlcd.c +new file mode 100644 +index 0000000..357004a +--- /dev/null ++++ b/drivers/video/jzlcd.c +@@ -0,0 +1,1574 @@ ++/* ++ * linux/drivers/video/jzlcd.c -- Ingenic On-Chip LCD frame buffer device ++ * ++ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "console/fbcon.h" ++ ++#include "jzlcd.h" ++ ++#undef DEBUG ++//#define DEBUG ++#ifdef DEBUG ++#define dprintk(x...) printk(x) ++#else ++#define dprintk(x...) ++#endif ++ ++#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) ++#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) ++#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) ++#ifdef DEBUG ++#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg) ++#else ++#define print_dbg(f, arg...) do {} while (0) ++#endif ++ ++struct lcd_cfb_info { ++ struct fb_info fb; ++ struct display_switch *dispsw; ++ signed int currcon; ++ int func_use_count; ++ ++ struct { ++ u16 red, green, blue; ++ } palette[NR_PALETTE]; ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ struct task_struct *rotate_daemon_thread; ++#endif ++}; ++ ++static struct lcd_cfb_info *jzlcd_info; ++ ++struct jzfb_info { ++ unsigned int cfg; /* panel mode and pin usage etc. */ ++ unsigned int w; ++ unsigned int h; ++ unsigned int bpp; /* bit per pixel */ ++ unsigned int fclk; /* frame clk */ ++ unsigned int hsw; /* hsync width, in pclk */ ++ unsigned int vsw; /* vsync width, in line count */ ++ unsigned int elw; /* end of line, in pclk */ ++ unsigned int blw; /* begin of line, in pclk */ ++ unsigned int efw; /* end of frame, in line count */ ++ unsigned int bfw; /* begin of frame, in line count */ ++}; ++ ++static struct jzfb_info jzfb = { ++#if defined(CONFIG_JZLCD_SHARP_LQ035Q7) ++ MODE_TFT_SHARP | PCLK_N | VSYNC_N, ++ 240, 320, 16, 60, 1, 2, 1, 2, 0, 6 ++#endif ++#if defined(CONFIG_JZLCD_SAMSUNG_LTS350Q1) ++ MODE_TFT_SAMSUNG | PCLK_N, ++ 240, 320, 16, 60, 1, 2, (254-240), 0, 7, 0 ++#endif ++#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04) ++ MODE_TFT_GEN | HSYNC_N | VSYNC_N, ++ 320, 240, 16, 70, 19, 4, 20, 14, 18, 6 ++#endif ++#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF01) ++ MODE_TFT_GEN | HSYNC_N | VSYNC_N, ++ 480, 272, 16, 60, 41, 10, 2, 2, 2, 2 ++#endif ++ ++#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF02) ++ /* MODE_TFT_18BIT: JZ4740@ version */ ++ MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N, ++ 480, 272, 32, 60, 41, 10, 2, 2, 2, 2 ++#endif ++#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW) ++ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N, ++ 320, 240, 16, 85, 30, 3, 38, 20, 11, 8 ++#endif ++#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL) ++ MODE_8BIT_SERIAL_TFT | HSYNC_N | VSYNC_N | PCLK_N, ++ /* serial mode 280 lines, parallel mode 240 lines */ ++ 320, 280, 32, 60, (30*3), 3, (20*3), (38*3), 46, 23 ++#endif ++#if defined(CONFIG_JZLCD_AUO_A030FL01_V1) ++ MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N, ++ 480, 272, 32, 60, 39, 10, 8, 4, 4, 2 ++#endif ++#if defined(CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E) ++ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N | DE_N, ++ 320, 240, 16, 60, 3, 3, 3, 3, 3, 85 /* 320x240 */ ++#endif ++#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) ++ #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 ++#endif ++#if defined(CONFIG_JZLCD_HYNIX_HT10X21) ++ MODE_TFT_GEN | PCLK_N, ++ 1024, 768, 16, 45, 1, 1, 75, 0, 3, 0 ++#endif ++#if defined(CONFIG_JZLCD_TOSHIBA_LTM084P363) ++ MODE_TFT_GEN | PCLK_N, ++ 800, 600, 16, 50, 1, 2, 199, 0, 2, 0 ++#endif ++#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42) ++ MODE_TFT_SHARP | PCLK_N, ++ 800, 600, 16, 40, 1, 1, 255, 0, 34, 0 ++#endif ++#if defined(CONFIG_JZLCD_CSTN_800x600) ++ MODE_STN_COLOR_DUAL | STN_DAT_PIN8, ++ 800, 600, 16, 30, 8, 1, 0, 0, 0, 0 ++#endif ++#if defined(CONFIG_JZLCD_CSTN_320x240) ++ MODE_STN_COLOR_SINGLE | STN_DAT_PIN8, ++ 320, 240, 16, 120, 8, 1, 8, 0, 0, 0 ++#endif ++#if defined(CONFIG_JZLCD_MSTN_640x480) ++ MODE_STN_MONO_DUAL | STN_DAT_PIN4, ++ 640, 480, 8, 110, 4, 1, 4, 0, 0, 0 ++#endif ++#if defined(CONFIG_JZLCD_MSTN_320x240) ++ MODE_STN_MONO_SINGLE | STN_DAT_PIN4, ++ 320, 240, 8, 110, 4, 1, 4, 0, 0, 0 ++#endif ++#if defined(CONFIG_JZLCD_MSTN_480x320) ++ MODE_STN_MONO_SINGLE | STN_DAT_PIN8 ++#if defined(CONFIG_JZLCD_MSTN_INVERSE) ++ | DATA_INVERSE ++#endif ++ , 480, 320, 8, 65, 8, 1, 8, 0, 0, 0 ++#endif ++ ++#if defined(CONFIG_JZLCD_MSTN_240x128) ++ MODE_STN_MONO_SINGLE | STN_DAT_PIN1 ++#if defined(CONFIG_JZLCD_MSTN_INVERSE) ++ | DATA_INVERSE ++#endif ++ , 240, 128, 8, 100, 1, 1, 1, 0, 0, 0 ++#endif ++}; ++ ++static struct lcd_desc *lcd_desc_base; ++static struct lcd_desc *lcd_palette_desc; ++static struct lcd_desc *lcd_frame_desc0; ++static struct lcd_desc *lcd_frame_desc1; ++ ++static unsigned char *lcd_palette; ++static unsigned char *lcd_frame[CONFIG_JZLCD_FRAMEBUFFER_MAX]; ++struct jz_lcd_buffer_addrs_t jz_lcd_buffer_addrs; ++//extern struct display fb_display[MAX_NR_CONSOLES]; ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++static unsigned char *lcd_frame_user_fb; ++/* default rotate angle */ ++static volatile int rotate_angle = CONFIG_JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE; ++#endif ++ ++#ifdef DEBUG ++static void print_regs(void) /* debug */ ++{ ++ printk("REG_LCD_CFG:\t0x%8.8x\n", REG_LCD_CFG); ++ printk("REG_LCD_VSYNC:\t0x%8.8x\n", REG_LCD_VSYNC); ++ printk("REG_LCD_HSYNC:\t0x%8.8x\n", REG_LCD_HSYNC); ++ printk("REG_LCD_VAT:\t0x%8.8x\n", REG_LCD_VAT); ++ printk("REG_LCD_DAH:\t0x%8.8x\n", REG_LCD_DAH); ++ printk("REG_LCD_DAV:\t0x%8.8x\n", REG_LCD_DAV); ++ printk("REG_LCD_PS:\t0x%8.8x\n", REG_LCD_PS); ++ printk("REG_LCD_CLS:\t0x%8.8x\n", REG_LCD_CLS); ++ printk("REG_LCD_SPL:\t0x%8.8x\n", REG_LCD_SPL); ++ printk("REG_LCD_REV:\t0x%8.8x\n", REG_LCD_REV); ++ printk("REG_LCD_CTRL:\t0x%8.8x\n", REG_LCD_CTRL); ++ printk("REG_LCD_STATE:\t0x%8.8x\n", REG_LCD_STATE); ++ printk("REG_LCD_IID:\t0x%8.8x\n", REG_LCD_IID); ++ printk("REG_LCD_DA0:\t0x%8.8x\n", REG_LCD_DA0); ++ printk("REG_LCD_SA0:\t0x%8.8x\n", REG_LCD_SA0); ++ printk("REG_LCD_FID0:\t0x%8.8x\n", REG_LCD_FID0); ++ printk("REG_LCD_CMD0:\t0x%8.8x\n", REG_LCD_CMD0); ++ ++ printk("==================================\n"); ++ printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff); ++ printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff); ++ printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff); ++ printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff); ++ printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff); ++ printk("==================================\n"); ++ ++} ++#else ++#define print_regs() ++#endif ++ ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++static int jzfb_rotate_daemon_thread(void *info) ++{ ++ int i,j; ++ struct fb_info *fb = &jzlcd_info->fb; ++ ++ while (!kthread_should_stop()) { ++#if (CONFIG_JZLCD_FRAMEBUFFER_BPP == 8) ++ unsigned char *plcd_frame = (unsigned char *)lcd_frame[0]; ++ unsigned char *pfb = (unsigned char *) (fb->screen_base); ++#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 16) ++ unsigned short *plcd_frame = (unsigned short *)lcd_frame[0]; ++ unsigned short *pfb = (unsigned short *) (fb->screen_base); ++#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 32) ++ unsigned int *plcd_frame = (unsigned int *)lcd_frame[0]; ++ unsigned int *pfb = (unsigned int *) (fb->screen_base); ++#else ++#error "ERROR, rotate not support this bpp." ++#endif ++ switch ( rotate_angle ) { ++ case FB_ROTATE_UR: ++ printk("%s, Warning, this shouldn't reache\n", __FUNCTION__); ++ ssleep(1); ++ break; ++ case FB_ROTATE_UD: /* cost about 30ms, can be accelrated by dma in the future */ ++ plcd_frame += jzfb.w*jzfb.h -1; ++ for (i=0;ivar.height+1; i++) { ++ for (j=1; j < fb->var.width+1; j++) ++ plcd_frame[j*fb->var.height-i] = *pfb++; ++ } ++ msleep(100); /* sleep 100ms */ ++ break; ++ case FB_ROTATE_CCW: /* cost about 80ms */ ++ for (i=0;ivar.height;i++) { ++ for ( j=fb->var.width-1;j>=0;j--) ++ plcd_frame[j*fb->var.height+i] = *pfb++; ++ } ++ msleep(100); /* sleep 100ms */ ++ break; ++ default: /* FB_ROTATE_UR */ ++ dprintk("Unknown rotate(%d) type\n", rotate_angle); ++ ssleep(1); ++ } ++ ++ dma_cache_wback_inv((unsigned int)(lcd_frame_user_fb), fb->fix.smem_len); ++ } ++ return 0; ++} ++/* ++ * rotate param angle: ++ * 0: FB_ROTATE_UR, 0'C ++ * 1: FB_ROTATE_CW, 90'C ++ * 2: FB_ROTATE_UD, 180'C ++ * 3: FB_ROTATE_CCW, 270'C ++ */ ++static int jzfb_rotate_change( int angle ) ++{ ++ struct fb_info *fb = &jzlcd_info->fb; ++ ++ /* clear frame buffer */ ++ memset((void*)lcd_frame_user_fb, 0x00, fb->fix.smem_len); ++ switch ( angle ) { ++ case FB_ROTATE_UR: ++ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.w; ++ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.h; ++ /* change lcd controller's data buffer to lcd_frame_user_fb*/ ++ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame_user_fb); ++ if ( rotate_angle != FB_ROTATE_UR ) ++ kthread_stop(jzlcd_info->rotate_daemon_thread); ++ rotate_angle = angle; ++ break; ++ case FB_ROTATE_UD: ++ case FB_ROTATE_CW: ++ case FB_ROTATE_CCW: ++ if ( angle == FB_ROTATE_UD ) { ++ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.w; ++ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.h; ++ } ++ else { /* CW, CCW */ ++ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.h; ++ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.w; ++ } ++ /* change lcd controller's data buffer to lcd_frame[0]*/ ++ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]); ++ if ( rotate_angle == FB_ROTATE_UR || \ ++ jzlcd_info->rotate_daemon_thread == NULL) ++ jzlcd_info->rotate_daemon_thread = kthread_run( jzfb_rotate_daemon_thread, jzlcd_info, "%s", "jzlcd-rotate-daemon"); /* start rotate daemon */ ++ rotate_angle = angle; ++ break; ++ default: ++ printk("Invalid angle(%d)\n", (unsigned int)angle); ++ } ++ fb->fix.line_length = fb->var.xres * CONFIG_JZLCD_FRAMEBUFFER_BPP/8; ++ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0), sizeof(struct lcd_desc)); ++ return 0; ++} ++ ++void jzfb_fb_rotate(struct fb_info *fbi, int angle) ++{ ++ jzfb_rotate_change( angle/90 ); ++} ++#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ ++ ++static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ unsigned short *ptr, ctmp; ++ ++// print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp); ++ if (regno >= NR_PALETTE) ++ return 1; ++ ++ cfb->palette[regno].red = red ; ++ cfb->palette[regno].green = green; ++ cfb->palette[regno].blue = blue; ++ if (cfb->fb.var.bits_per_pixel <= 16) { ++ red >>= 8; ++ green >>= 8; ++ blue >>= 8; ++ ++ red &= 0xff; ++ green &= 0xff; ++ blue &= 0xff; ++ } ++ switch (cfb->fb.var.bits_per_pixel) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) { ++ ctmp = (77L * red + 150L * green + 29L * blue) >> 8; ++ ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) | ++ (ctmp >> 3); ++ } else { ++ /* RGB 565 */ ++ if (((red >> 3) == 0) && ((red >> 2) != 0)) ++ red = 1 << 3; ++ if (((blue >> 3) == 0) && ((blue >> 2) != 0)) ++ blue = 1 << 3; ++ ctmp = ((red >> 3) << 11) ++ | ((green >> 2) << 5) | (blue >> 3); ++ } ++ ++ ptr = (unsigned short *)lcd_palette; ++ ptr = (unsigned short *)(((u32)ptr)|0xa0000000); ++ ptr[regno] = ctmp; ++ ++ break; ++ ++ case 15: ++ if (regno < 16) ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ ((red >> 3) << 10) | ++ ((green >> 3) << 5) | ++ (blue >> 3); ++ break; ++ case 16: ++ if (regno < 16) { ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ ((red >> 3) << 11) | ++ ((green >> 2) << 5) | ++ (blue >> 3); ++ } ++ break; ++ case 18: ++ case 24: ++ case 32: ++ if (regno < 16) ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = ++ (red << 16) | ++ (green << 8) | ++ (blue << 0); ++ ++/* if (regno < 16) { ++ unsigned val; ++ val = chan_to_field(red, &cfb->fb.var.red); ++ val |= chan_to_field(green, &cfb->fb.var.green); ++ val |= chan_to_field(blue, &cfb->fb.var.blue); ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = val; ++ } ++*/ ++ ++ break; ++ } ++ return 0; ++} ++ ++ ++static int jzfb_ioctl (struct fb_info *fb, unsigned int cmd, unsigned long arg ) ++{ ++ int ret = 0; ++ void __user *argp = (void __user *)arg; ++ ++ switch (cmd) { ++ case FBIOSETBACKLIGHT: ++ __lcd_set_backlight_level(arg); /* We support 8 levels here. */ ++ break; ++ case FBIODISPON: ++ __lcd_display_on(); ++ break; ++ case FBIODISPOFF: ++ __lcd_display_off(); ++ break; ++ case FBIOPRINT_REGS: ++ print_regs(); ++ break; ++ case FBIOGETBUFADDRS: ++ if ( copy_to_user(argp, &jz_lcd_buffer_addrs, ++ sizeof(struct jz_lcd_buffer_addrs_t)) ) ++ return -EFAULT; ++ break; ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ case FBIOROTATE: ++ ret = jzfb_rotate_change(arg); ++ break; ++#endif /* defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ ++ default: ++ printk("Warn: Command(%x) not support\n", cmd); ++ ret = -1; ++ break; ++ } ++ return ret; ++ ++} ++ ++/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ ++static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); ++ ++ /* frame buffer memory */ ++ start = cfb->fb.fix.smem_start; ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ return -EINVAL; ++ off += start; ++ ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ ++ ++#if 1 ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ ++// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Through */ ++#endif ++ ++ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++/* checks var and eventually tweaks it to something supported, ++ * DO NOT MODIFY PAR */ ++static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ print_dbg("jzfb_check_var"); ++ return 0; ++} ++ ++ ++/* ++ * set the video mode according to info->var ++ */ ++static int jzfb_set_par(struct fb_info *info) ++{ ++ print_dbg("jzfb_set_par"); ++ return 0; ++} ++ ++ ++/* ++ * (Un)Blank the display. ++ * Fix me: should we use VESA value? ++ */ ++static int jzfb_blank(int blank_mode, struct fb_info *info) ++{ ++ ++ dprintk("fb_blank %d %p", blank_mode, info); ++ ++ switch (blank_mode) { ++ ++ case FB_BLANK_UNBLANK: ++ //case FB_BLANK_NORMAL: ++ /* Turn on panel */ ++ __lcd_set_ena(); ++ __lcd_display_on(); ++ break; ++ ++ case FB_BLANK_NORMAL: ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ case FB_BLANK_POWERDOWN: ++#if 0 ++ /* Turn off panel */ ++ __lcd_set_dis(); ++ __lcd_display_off(); ++#endif ++ break; ++ default: ++ break; ++ ++ } ++ return 0; ++} ++ ++/* ++ * pan display ++ */ ++static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ int dy; ++ ++ if (!var || !cfb) { ++ return -EINVAL; ++ } ++ ++ if (var->xoffset - cfb->fb.var.xoffset) { ++ /* No support for X panning for now! */ ++ return -EINVAL; ++ } ++ ++ dy = var->yoffset - cfb->fb.var.yoffset; ++ print_dbg("var.yoffset: %d", dy); ++ if (dy) { ++ ++ print_dbg("Panning screen of %d lines", dy); ++ ++ lcd_frame_desc0->databuf += (cfb->fb.fix.line_length * dy); ++ /* TODO: Wait for current frame to finished */ ++ } ++ ++ return 0; ++} ++ ++ ++/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ ++static struct fb_ops jzfb_ops = { ++ .owner = THIS_MODULE, ++ .fb_setcolreg = jzfb_setcolreg, ++ .fb_check_var = jzfb_check_var, ++ .fb_set_par = jzfb_set_par, ++ .fb_blank = jzfb_blank, ++ .fb_pan_display = jzfb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_mmap = jzfb_mmap, ++ .fb_ioctl = jzfb_ioctl, ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ .fb_rotate = jzfb_fb_rotate, ++#endif ++}; ++ ++static int jzfb_set_var(struct fb_var_screeninfo *var, int con, ++ struct fb_info *info) ++{ ++ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; ++ int chgvar = 0; ++ ++ var->height = jzfb.h ; ++ var->width = jzfb.w ; ++ var->bits_per_pixel = jzfb.bpp; ++ ++ var->vmode = FB_VMODE_NONINTERLACED; ++ var->activate = cfb->fb.var.activate; ++ var->xres = var->width; ++ var->yres = var->height; ++ var->xres_virtual = var->width; ++ var->yres_virtual = var->height; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->pixclock = 0; ++ var->left_margin = 0; ++ var->right_margin = 0; ++ var->upper_margin = 0; ++ var->lower_margin = 0; ++ var->hsync_len = 0; ++ var->vsync_len = 0; ++ var->sync = 0; ++ var->activate &= ~FB_ACTIVATE_TEST; ++ ++ /* ++ * CONUPDATE and SMOOTH_XPAN are equal. However, ++ * SMOOTH_XPAN is only used internally by fbcon. ++ */ ++ if (var->vmode & FB_VMODE_CONUPDATE) { ++ var->vmode |= FB_VMODE_YWRAP; ++ var->xoffset = cfb->fb.var.xoffset; ++ var->yoffset = cfb->fb.var.yoffset; ++ } ++ ++ if (var->activate & FB_ACTIVATE_TEST) ++ return 0; ++ ++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) ++ return -EINVAL; ++ ++ if (cfb->fb.var.xres != var->xres) ++ chgvar = 1; ++ if (cfb->fb.var.yres != var->yres) ++ chgvar = 1; ++ if (cfb->fb.var.xres_virtual != var->xres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.yres_virtual != var->yres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) ++ chgvar = 1; ++ ++ var->red.msb_right = 0; ++ var->green.msb_right = 0; ++ var->blue.msb_right = 0; ++ ++ switch(var->bits_per_pixel){ ++ case 1: /* Mono */ ++ cfb->fb.fix.visual = FB_VISUAL_MONO01; ++ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; ++ break; ++ case 2: /* Mono */ ++ var->red.offset = 0; ++ var->red.length = 2; ++ var->green.offset = 0; ++ var->green.length = 2; ++ var->blue.offset = 0; ++ var->blue.length = 2; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; ++ break; ++ case 4: /* PSEUDOCOLOUR*/ ++ var->red.offset = 0; ++ var->red.length = 4; ++ var->green.offset = 0; ++ var->green.length = 4; ++ var->blue.offset = 0; ++ var->blue.length = 4; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = var->xres / 2; ++ break; ++ case 8: /* PSEUDOCOLOUR, 256 */ ++ var->red.offset = 0; ++ var->red.length = 8; ++ var->green.offset = 0; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; ++ ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ cfb->fb.fix.line_length = var->xres ; ++ break; ++ case 15: /* DIRECTCOLOUR, 32k */ ++ var->bits_per_pixel = 15; ++ var->red.offset = 10; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 5; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ ++ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 2; ++ break; ++ case 16: /* DIRECTCOLOUR, 64k */ ++ var->bits_per_pixel = 16; ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 2; ++ break; ++ case 18: ++ case 24: ++ case 32: ++ /* DIRECTCOLOUR, 16M */ ++ var->bits_per_pixel = 32; ++ ++ var->red.offset = 16; ++ var->red.length = 8; ++ var->green.offset = 8; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; ++ var->transp.offset = 24; ++ var->transp.length = 8; ++ ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ cfb->fb.fix.line_length = var->xres_virtual * 4; ++ break; ++ ++ default: /* in theory this should never happen */ ++ printk(KERN_WARNING "%s: don't support for %dbpp\n", ++ cfb->fb.fix.id, var->bits_per_pixel); ++ break; ++ } ++ ++ cfb->fb.var = *var; ++ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; ++ ++ /* ++ * Update the old var. The fbcon drivers still use this. ++ * Once they are using cfb->fb.var, this can be dropped. ++ * --rmk ++ */ ++ //display->var = cfb->fb.var; ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); ++ dprintk("jzfb_set_var: after fb_set_cmap...\n"); ++ ++ return 0; ++} ++ ++static struct lcd_cfb_info * jzfb_alloc_fb_info(void) ++{ ++ struct lcd_cfb_info *cfb; ++ ++ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); ++ ++ if (!cfb) ++ return NULL; ++ ++ jzlcd_info = cfb; ++ ++ memset(cfb, 0, sizeof(struct lcd_cfb_info) ); ++ ++ cfb->currcon = -1; ++ ++ ++ strcpy(cfb->fb.fix.id, "jz-lcd"); ++ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ cfb->fb.fix.type_aux = 0; ++ cfb->fb.fix.xpanstep = 1; ++ cfb->fb.fix.ypanstep = 1; ++ cfb->fb.fix.ywrapstep = 0; ++ cfb->fb.fix.accel = FB_ACCEL_NONE; ++ ++ cfb->fb.var.nonstd = 0; ++ cfb->fb.var.activate = FB_ACTIVATE_NOW; ++ cfb->fb.var.height = -1; ++ cfb->fb.var.width = -1; ++ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; ++ ++ cfb->fb.fbops = &jzfb_ops; ++ cfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ ++ cfb->fb.pseudo_palette = (void *)(cfb + 1); ++ ++ switch (jzfb.bpp) { ++ case 1: ++ fb_alloc_cmap(&cfb->fb.cmap, 4, 0); ++ break; ++ case 2: ++ fb_alloc_cmap(&cfb->fb.cmap, 8, 0); ++ break; ++ case 4: ++ fb_alloc_cmap(&cfb->fb.cmap, 32, 0); ++ break; ++ case 8: ++ ++ default: ++ fb_alloc_cmap(&cfb->fb.cmap, 256, 0); ++ break; ++ } ++ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); ++ ++ return cfb; ++} ++ ++/* ++ * Map screen memory ++ */ ++static int jzfb_map_smem(struct lcd_cfb_info *cfb) ++{ ++ struct page * map = NULL; ++ unsigned char *tmp; ++ unsigned int page_shift, needroom, t; ++#if defined(CONFIG_SOC_JZ4740) ++ if (jzfb.bpp == 18 || jzfb.bpp == 24) ++ t = 32; ++ else ++ t = jzfb.bpp; ++#else ++ if (jzfb.bpp == 15) ++ t = 16; ++ else ++ t = jzfb.bpp; ++#endif ++ ++ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; ++ for (page_shift = 0; page_shift < 12; page_shift++) ++ if ((PAGE_SIZE << page_shift) >= needroom) ++ break; ++ ++ /* lcd_palette room total 4KB: ++ * 0 -- 512: lcd palette ++ * 1024 -- [1024+16*3]: lcd descripters ++ * [1024+16*3] -- 4096: reserved ++ */ ++ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); ++ if ((!lcd_palette)) ++ return -ENOMEM; ++ ++ memset((void *)lcd_palette, 0, PAGE_SIZE); ++ map = virt_to_page(lcd_palette); ++ set_bit(PG_reserved, &map->flags); ++ lcd_desc_base = (struct lcd_desc *)(lcd_palette + 1024); ++ ++ jz_lcd_buffer_addrs.fb_num = CONFIG_JZLCD_FRAMEBUFFER_MAX; ++ printk("jzlcd use %d framebuffer:\n", CONFIG_JZLCD_FRAMEBUFFER_MAX); ++ /* alloc frame buffer space */ ++ for ( t = 0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { ++ lcd_frame[t] = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ if ((!lcd_frame[t])) { ++ printk("no mem for fb[%d]\n", t); ++ return -ENOMEM; ++ } ++// memset((void *)lcd_frame[t], 0, PAGE_SIZE << page_shift); ++ for (tmp=(unsigned char *)lcd_frame[t]; ++ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ set_bit(PG_reserved, &map->flags); ++ } ++ jz_lcd_buffer_addrs.fb_phys_addr[t] = virt_to_phys((void *)lcd_frame[t]); ++ printk("jzlcd fb[%d] phys addr =0x%08x\n", ++ t, jz_lcd_buffer_addrs.fb_phys_addr[t]); ++ } ++#if !defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame[0]); ++ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); ++ cfb->fb.screen_base = ++ (unsigned char *)(((unsigned int)lcd_frame[0] & 0x1fffffff) | 0xa0000000); ++#else /* Framebuffer rotate */ ++ lcd_frame_user_fb = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); ++ if ((!lcd_frame_user_fb)) { ++ printk("no mem for fb[%d]\n", t); ++ return -ENOMEM; ++ } ++ memset((void *)lcd_frame_user_fb, 0, PAGE_SIZE << page_shift); ++ for (tmp=(unsigned char *)lcd_frame_user_fb; ++ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ set_bit(PG_reserved, &map->flags); ++ } ++ ++ printk("Rotate userfb phys addr =0x%08x\n", ++ (unsigned int)virt_to_phys((void *)lcd_frame_user_fb)); ++ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame_user_fb); ++ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); ++ cfb->fb.screen_base = (unsigned char *)(((unsigned int)lcd_frame_user_fb & 0x1fffffff) | 0xa0000000); ++ ++#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ ++ if (!cfb->fb.screen_base) { ++ printk("%s: unable to map screen memory\n", cfb->fb.fix.id); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void jzfb_free_fb_info(struct lcd_cfb_info *cfb) ++{ ++ if (cfb) { ++ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); ++ kfree(cfb); ++ } ++} ++ ++static void jzfb_unmap_smem(struct lcd_cfb_info *cfb) ++{ ++ struct page * map = NULL; ++ unsigned char *tmp; ++ unsigned int page_shift, needroom, t; ++#if defined(CONFIG_SOC_JZ4740) ++ if (jzfb.bpp == 18 || jzfb.bpp == 24) ++ t = 32; ++ else ++ t = jzfb.bpp; ++#else ++ if (jzfb.bpp == 15) ++ t = 16; ++ else ++ t = jzfb.bpp; ++#endif ++ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; ++ for (page_shift = 0; page_shift < 12; page_shift++) ++ if ((PAGE_SIZE << page_shift) >= needroom) ++ break; ++ ++ if (cfb && cfb->fb.screen_base) { ++ iounmap(cfb->fb.screen_base); ++ cfb->fb.screen_base = NULL; ++ release_mem_region(cfb->fb.fix.smem_start, ++ cfb->fb.fix.smem_len); ++ } ++ ++ if (lcd_palette) { ++ map = virt_to_page(lcd_palette); ++ clear_bit(PG_reserved, &map->flags); ++ free_pages((int)lcd_palette, 0); ++ } ++ ++ for ( t=0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { ++ if (lcd_frame[t]) { ++ for (tmp=(unsigned char *)lcd_frame[t]; ++ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ clear_bit(PG_reserved, &map->flags); ++ } ++ free_pages((int)lcd_frame[t], page_shift); ++ } ++ } ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ if (lcd_frame_user_fb) { ++ for (tmp=(unsigned char *)lcd_frame_user_fb; ++ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); ++ tmp += PAGE_SIZE) { ++ map = virt_to_page(tmp); ++ clear_bit(PG_reserved, &map->flags); ++ } ++ free_pages((int)lcd_frame_user_fb, page_shift); ++ } ++ ++#endif ++} ++ ++static void lcd_descriptor_init(void) ++{ ++ int i; ++ unsigned int pal_size; ++ unsigned int frm_size, ln_size; ++ unsigned char dual_panel = 0; ++ ++ i = jzfb.bpp; ++#if defined(CONFIG_SOC_JZ4740) ++ if (i == 18 || i == 24) ++ i = 32; ++#else ++ if (i == 15) ++ i = 16; ++#endif ++ frm_size = (jzfb.w*jzfb.h*i)>>3; ++ ln_size = (jzfb.w*i)>>3; ++ ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) { ++ dual_panel = 1; ++ frm_size >>= 1; ++ } ++ ++ frm_size = frm_size / 4; ++ ln_size = ln_size / 4; ++ ++ switch (jzfb.bpp) { ++ case 1: ++ pal_size = 4; ++ break; ++ case 2: ++ pal_size = 8; ++ break; ++ case 4: ++ pal_size = 32; ++ break; ++ case 8: ++ default: ++ pal_size = 512; ++ } ++ ++ pal_size /= 4; ++ ++ lcd_frame_desc0 = lcd_desc_base + 0; ++ lcd_frame_desc1 = lcd_desc_base + 1; ++ lcd_palette_desc = lcd_desc_base + 2; ++ ++ jz_lcd_buffer_addrs.lcd_desc_phys_addr = (unsigned int)virt_to_phys(lcd_frame_desc0); ++ ++ /* Palette Descriptor */ ++ lcd_palette_desc->next_desc = (int)virt_to_phys(lcd_frame_desc0); ++ lcd_palette_desc->databuf = (int)virt_to_phys((void *)lcd_palette); ++ lcd_palette_desc->frame_id = (unsigned int)0xdeadbeaf; ++ lcd_palette_desc->cmd = pal_size|LCD_CMD_PAL; /* Palette Descriptor */ ++ ++ /* Frame Descriptor 0 */ ++ if (jzfb.bpp <= 8) ++ lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_palette_desc); ++ else ++ lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_frame_desc0); ++ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]); ++ lcd_frame_desc0->frame_id = (unsigned int)0xbeafbeaf; ++ lcd_frame_desc0->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size; ++ dma_cache_wback_inv((unsigned int)(lcd_palette_desc),0x10); ++ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0),0x10); ++ ++ if (!(dual_panel)) ++ return; ++ ++ /* Frame Descriptor 1 */ ++ lcd_frame_desc1->next_desc = (int)virt_to_phys(lcd_frame_desc1); ++ lcd_frame_desc1->databuf = virt_to_phys((void *)(lcd_frame[0] + frm_size * 4)); ++ lcd_frame_desc1->frame_id = (unsigned int)0xdeaddead; ++ lcd_frame_desc1->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size; ++ dma_cache_wback_inv((unsigned int)(lcd_frame_desc1),0x10); ++} ++ ++static int lcd_hw_init(void) ++{ ++ unsigned int val = 0; ++ unsigned int pclk; ++ unsigned int stnH; ++ int ret = 0; ++ ++ /* Setting Control register */ ++ switch (jzfb.bpp) { ++ case 1: ++ val |= LCD_CTRL_BPP_1; ++ break; ++ case 2: ++ val |= LCD_CTRL_BPP_2; ++ break; ++ case 4: ++ val |= LCD_CTRL_BPP_4; ++ break; ++ case 8: ++ val |= LCD_CTRL_BPP_8; ++ break; ++ case 15: ++ val |= LCD_CTRL_RGB555; ++ case 16: ++ val |= LCD_CTRL_BPP_16; ++ break; ++#if defined(CONFIG_SOC_JZ4740) ++ case 17 ... 32: ++ val |= LCD_CTRL_BPP_18_24; /* target is 4bytes/pixel */ ++ break; ++#endif ++ default: ++ printk("The BPP %d is not supported\n", jzfb.bpp); ++ val |= LCD_CTRL_BPP_16; ++ break; ++ } ++ ++ switch (jzfb.cfg & MODE_MASK) { ++ case MODE_STN_MONO_DUAL: ++ case MODE_STN_COLOR_DUAL: ++ case MODE_STN_MONO_SINGLE: ++ case MODE_STN_COLOR_SINGLE: ++ switch (jzfb.bpp) { ++ case 1: ++ case 2: ++ val |= LCD_CTRL_FRC_2; ++ break; ++ case 4: ++ val |= LCD_CTRL_FRC_4; ++ break; ++ case 8: ++ default: ++ val |= LCD_CTRL_FRC_16; ++ break; ++ } ++ break; ++ } ++ ++ val |= LCD_CTRL_BST_16; /* Burst Length is 16WORD=64Byte */ ++ ++ switch (jzfb.cfg & MODE_MASK) { ++ case MODE_STN_MONO_DUAL: ++ case MODE_STN_COLOR_DUAL: ++ case MODE_STN_MONO_SINGLE: ++ case MODE_STN_COLOR_SINGLE: ++ switch (jzfb.cfg & STN_DAT_PINMASK) { ++#define align2(n) (n)=((((n)+1)>>1)<<1) ++#define align4(n) (n)=((((n)+3)>>2)<<2) ++#define align8(n) (n)=((((n)+7)>>3)<<3) ++ case STN_DAT_PIN1: ++ /* Do not adjust the hori-param value. */ ++ break; ++ case STN_DAT_PIN2: ++ align2(jzfb.hsw); ++ align2(jzfb.elw); ++ align2(jzfb.blw); ++ break; ++ case STN_DAT_PIN4: ++ align4(jzfb.hsw); ++ align4(jzfb.elw); ++ align4(jzfb.blw); ++ break; ++ case STN_DAT_PIN8: ++ align8(jzfb.hsw); ++ align8(jzfb.elw); ++ align8(jzfb.blw); ++ break; ++ } ++ break; ++ } ++ ++ val |= 1 << 26; /* Output FIFO underrun protection */ ++ REG_LCD_CTRL = val; ++ ++ switch (jzfb.cfg & MODE_MASK) { ++ case MODE_STN_MONO_DUAL: ++ case MODE_STN_COLOR_DUAL: ++ case MODE_STN_MONO_SINGLE: ++ case MODE_STN_COLOR_SINGLE: ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL)) ++ stnH = jzfb.h >> 1; ++ else ++ stnH = jzfb.h; ++ ++ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw; ++ REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw); ++ ++ /* Screen setting */ ++ REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw); ++ REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w); ++ REG_LCD_DAV = (0 << 16) | (stnH); ++ ++ /* AC BIAs signal */ ++ REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw); ++ ++ break; ++ ++ case MODE_TFT_GEN: ++ case MODE_TFT_SHARP: ++ case MODE_TFT_CASIO: ++ case MODE_TFT_SAMSUNG: ++ case MODE_8BIT_SERIAL_TFT: ++ case MODE_TFT_18BIT: ++ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw; ++#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42) ++ REG_LCD_DAV = (0 << 16) | ( jzfb.h ); ++#else ++ REG_LCD_DAV = ((jzfb.vsw + jzfb.bfw) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h); ++#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ ++ REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw); ++ REG_LCD_HSYNC = (0 << 16) | jzfb.hsw; ++ REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w); ++ break; ++ } ++ ++ switch (jzfb.cfg & MODE_MASK) { ++ case MODE_TFT_SAMSUNG: ++ { ++ unsigned int total, tp_s, tp_e, ckv_s, ckv_e; ++ unsigned int rev_s, rev_e, inv_s, inv_e; ++ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw; ++ tp_s = jzfb.blw + jzfb.w + 1; ++ tp_e = tp_s + 1; ++ ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); ++ ckv_e = tp_s + total; ++ rev_s = tp_s - 11; /* -11.5 clk */ ++ rev_e = rev_s + total; ++ inv_s = tp_s; ++ inv_e = inv_s + total; ++ REG_LCD_CLS = (tp_s << 16) | tp_e; ++ REG_LCD_PS = (ckv_s << 16) | ckv_e; ++ REG_LCD_SPL = (rev_s << 16) | rev_e; ++ REG_LCD_REV = (inv_s << 16) | inv_e; ++ jzfb.cfg |= STFT_REVHI | STFT_SPLHI; ++ break; ++ } ++ case MODE_TFT_SHARP: ++ { ++ unsigned int total, cls_s, cls_e, ps_s, ps_e; ++ unsigned int spl_s, spl_e, rev_s, rev_e; ++ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw; ++#if !defined(CONFIG_JZLCD_INNOLUX_AT080TN42) ++ spl_s = 1; ++ spl_e = spl_s + 1; ++ cls_s = 0; ++ cls_e = total - 60; /* > 4us (pclk = 80ns) */ ++ ps_s = cls_s; ++ ps_e = cls_e; ++ rev_s = total - 40; /* > 3us (pclk = 80ns) */ ++ rev_e = rev_s + total; ++ jzfb.cfg |= STFT_PSHI; ++#else /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ ++ spl_s = total - 5; /* LD */ ++ spl_e = total - 3; ++ cls_s = 32; /* CKV */ ++ cls_e = 145; ++ ps_s = 0; /* OEV */ ++ ps_e = 45; ++ rev_s = 0; /* POL */ ++ rev_e = 0; ++#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ ++ REG_LCD_SPL = (spl_s << 16) | spl_e; ++ REG_LCD_CLS = (cls_s << 16) | cls_e; ++ REG_LCD_PS = (ps_s << 16) | ps_e; ++ REG_LCD_REV = (rev_s << 16) | rev_e; ++ break; ++ } ++ case MODE_TFT_CASIO: ++ break; ++ } ++ ++ /* Configure the LCD panel */ ++ REG_LCD_CFG = jzfb.cfg; ++ ++ /* Timing setting */ ++ __cpm_stop_lcd(); ++ ++ val = jzfb.fclk; /* frame clk */ ++ ++ if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) { ++ pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) * ++ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */ ++ } ++ else { ++ /* serial mode: Hsync period = 3*Width_Pixel */ ++ pclk = val * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) * ++ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */ ++ } ++ ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL)) ++ pclk = (pclk * 3); ++ ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) ++ pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4); ++ ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) ++ pclk >>= 1; ++#if defined(CONFIG_SOC_JZ4730) ++ val = __cpm_get_pllout() / pclk; ++ REG_CPM_CFCR2 = val - 1; ++ val = __cpm_get_pllout() / (pclk * 4); ++ val = __cpm_divisor_encode(val); ++ __cpm_set_lcdclk_div(val); ++ REG_CPM_CFCR |= CPM_CFCR_UPE; ++#elif defined(CONFIG_SOC_JZ4740) ++ val = ( __cpm_get_pllout2()) / pclk; ++ val--; ++ if ( val > 0x3ff ) { ++ printk("pixel clock divid is too large, set it to 0x3ff\n"); ++ val = 0x3ff; ++ } ++ __cpm_set_pixdiv(val); ++ ++ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ ++ val =__cpm_get_pllout() / val; ++ if ( val > 0x1f ) { ++ printk("lcd clock divide is too large, set it to 0x1f\n"); ++ val = 0x1f; ++ } ++ __cpm_set_ldiv( val ); ++ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ ++ ++#else ++ printk("drivers/video/Jzlcd.c, CONFIG_MIPS, please set chip type.\n"); ++#endif /*#ifdef CONFIG_MIPS_JZ4730 */ ++ ++ jz_clocks.pixclk = __cpm_get_pixclk(); ++ jz_clocks.lcdclk = __cpm_get_lcdclk(); ++ printk("LCDC: PixClock:%d LcdClock:%d\n", ++ jz_clocks.pixclk, jz_clocks.lcdclk); ++ ++ __cpm_start_lcd(); ++ udelay(1000); ++ return ret; ++} ++ ++static irqreturn_t lcd_interrupt_handler(int irq, void *dev_id) ++{ ++ unsigned int state; ++ ++ state = REG_LCD_STATE; ++ ++ if (state & LCD_STATE_EOF) /* End of frame */ ++ REG_LCD_STATE = state & ~LCD_STATE_EOF; ++ ++ if (state & LCD_STATE_IFU0) { ++ dprintk("InFiFo0 underrun\n"); ++ REG_LCD_STATE = state & ~LCD_STATE_IFU0; ++ } ++ ++ if (state & LCD_STATE_OFU) { /* Out fifo underrun */ ++ REG_LCD_STATE = state & ~LCD_STATE_OFU; ++ dprintk("Out FiFo underrun.\n"); ++ } ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_PM ++ ++/* ++ * Suspend the LCDC. ++ */ ++static int jzfb_suspend(void) ++{ ++ __lcd_clr_ena(); /* Quick Disable */ ++ __lcd_display_off(); ++ __cpm_stop_lcd(); ++ ++ return 0; ++} ++ ++/* ++ * Resume the LCDC. ++ */ ++#ifdef CONFIG_SOC_JZ4730 ++static int jzfb_resume(void) ++{ ++ __cpm_start_lcd(); ++ ++ __lcd_display_pin_init(); ++ ++ __lcd_display_on(); ++ ++ lcd_hw_init(); ++ ++ if (jzfb.bpp <= 8) ++ REG_LCD_DA0 = virt_to_phys(lcd_palette_desc); ++ else ++ REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0); ++ ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) ++ REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1); ++ ++ __lcd_set_ena(); ++ return 0; ++} ++ ++#else ++/* ++ * Resume the LCDC. ++ */ ++static int jzfb_resume(void) ++{ ++ __cpm_start_lcd(); ++ __gpio_set_pin(GPIO_DISP_OFF_N); ++ __lcd_special_on(); ++ __lcd_set_ena(); ++ mdelay(200); ++ __lcd_set_backlight_level(80); ++ ++ return 0; ++} ++#endif /* CONFIG_MIPS_JZ4730 */ ++ ++/* ++ * Power management hook. Note that we won't be called from IRQ context, ++ * unlike the blank functions above, so we may sleep. ++ */ ++static int jzlcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct lcd_cfb_info *cfb = pm_dev->data; ++ ++ if (!cfb) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jzfb_suspend(); ++ break; ++ ++ case PM_RESUME: ++ ret = jzfb_resume(); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#else ++#define jzfb_suspend NULL ++#define jzfb_resume NULL ++#endif /* CONFIG_PM */ ++ ++static int __init jzfb_init(void) ++{ ++ struct lcd_cfb_info *cfb; ++ int err = 0; ++ ++ /* In special mode, we only need init special pin, ++ * as general lcd pin has init in uboot */ ++#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) ++ switch (jzfb.cfg & MODE_MASK) { ++ case LCD_CFG_MODE_SPECIAL_TFT_1: ++ case LCD_CFG_MODE_SPECIAL_TFT_2: ++ case LCD_CFG_MODE_SPECIAL_TFT_3: ++ __gpio_as_lcd_special(); ++ break; ++ default: ++ ; ++ } ++#endif ++ __lcd_display_pin_init(); ++ ++ cfb = jzfb_alloc_fb_info(); ++ if (!cfb) ++ goto failed; ++ ++ err = jzfb_map_smem(cfb); ++ if (err) ++ goto failed; ++ ++ jzfb_set_var(&cfb->fb.var, -1, &cfb->fb); ++ ++ lcd_descriptor_init(); ++ ++ err = lcd_hw_init(); ++ if (err) ++ goto failed; ++ ++ if (jzfb.bpp <= 8) ++ REG_LCD_DA0 = virt_to_phys(lcd_palette_desc); ++ else ++ REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0); ++ ++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) ++ REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1); ++ ++ __lcd_set_ena(); ++ ++ if (request_irq(IRQ_LCD, lcd_interrupt_handler, IRQF_DISABLED, ++ "lcd", 0)) { ++ err = -EBUSY; ++ goto failed; ++ } ++ ++ __lcd_enable_ofu_intr(); /* enable OutFifo underrun */ ++// __lcd_enable_ifu0_intr(); /* needn't enable InFifo underrun */ ++ ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ jzfb_rotate_change(rotate_angle); ++ /* sleep n??? */ ++#endif ++ err = register_framebuffer(&cfb->fb); ++ if (err < 0) { ++ dprintk("jzfb_init(): register framebuffer err.\n"); ++ goto failed; ++ } ++ ++ printk("fb%d: %s frame buffer device, using %dK of video memory\n", ++ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10); ++ ++#ifdef CONFIG_PM ++ /* ++ * Note that the console registers this as well, but we want to ++ * power down the display prior to sleeping. ++ */ ++ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback); ++ if (cfb->pm) ++ cfb->pm->data = cfb; ++#endif ++ ++ __lcd_display_off(); ++ ++ return 0; ++ ++failed: ++ jzfb_unmap_smem(cfb); ++ jzfb_free_fb_info(cfb); ++ ++ return err; ++} ++ ++#if 0 ++static int jzfb_remove(struct device *dev) ++{ ++ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); ++ jzfb_unmap_smem(cfb); ++ jzfb_free_fb_info(cfb); ++ return 0; ++} ++#endif ++ ++#if 0 ++static struct device_driver jzfb_driver = { ++ .name = "jz-lcd", ++ .bus = &platform_bus_type, ++ .probe = jzfb_probe, ++ .remove = jzfb_remove, ++ .suspend = jzfb_suspend, ++ .resume = jzfb_resume, ++}; ++#endif ++ ++static void __exit jzfb_cleanup(void) ++{ ++#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) ++ kthread_stop(jzlcd_info->rotate_daemon_thread); ++#endif ++// driver_unregister(&jzfb_driver); ++// jzfb_remove(); ++} ++ ++module_init(jzfb_init); ++module_exit(jzfb_cleanup); ++ ++MODULE_DESCRIPTION("JzSOC LCD Controller driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/jzlcd.h b/drivers/video/jzlcd.h +new file mode 100644 +index 0000000..a4ef75f +--- /dev/null ++++ b/drivers/video/jzlcd.h +@@ -0,0 +1,800 @@ ++/* ++ * linux/drivers/video/jzlcd.h -- Ingenic On-Chip LCD frame buffer device ++ * ++ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#ifndef __JZLCD_H__ ++#define __JZLCD_H__ ++ ++#include ++ ++#define NR_PALETTE 256 ++ ++struct lcd_desc{ ++ unsigned int next_desc; /* LCDDAx */ ++ unsigned int databuf; /* LCDSAx */ ++ unsigned int frame_id; /* LCDFIDx */ ++ unsigned int cmd; /* LCDCMDx */ ++}; ++ ++#define MODE_MASK 0x0f ++#define MODE_TFT_GEN 0x00 ++#define MODE_TFT_SHARP 0x01 ++#define MODE_TFT_CASIO 0x02 ++#define MODE_TFT_SAMSUNG 0x03 ++#define MODE_CCIR656_NONINT 0x04 ++#define MODE_CCIR656_INT 0x05 ++#define MODE_STN_COLOR_SINGLE 0x08 ++#define MODE_STN_MONO_SINGLE 0x09 ++#define MODE_STN_COLOR_DUAL 0x0a ++#define MODE_STN_MONO_DUAL 0x0b ++#define MODE_8BIT_SERIAL_TFT 0x0c ++ ++#define MODE_TFT_18BIT (1<<7) ++ ++#define STN_DAT_PIN1 (0x00 << 4) ++#define STN_DAT_PIN2 (0x01 << 4) ++#define STN_DAT_PIN4 (0x02 << 4) ++#define STN_DAT_PIN8 (0x03 << 4) ++#define STN_DAT_PINMASK STN_DAT_PIN8 ++ ++#define STFT_PSHI (1 << 15) ++#define STFT_CLSHI (1 << 14) ++#define STFT_SPLHI (1 << 13) ++#define STFT_REVHI (1 << 12) ++ ++#define SYNC_MASTER (0 << 16) ++#define SYNC_SLAVE (1 << 16) ++ ++#define DE_P (0 << 9) ++#define DE_N (1 << 9) ++ ++#define PCLK_P (0 << 10) ++#define PCLK_N (1 << 10) ++ ++#define HSYNC_P (0 << 11) ++#define HSYNC_N (1 << 11) ++ ++#define VSYNC_P (0 << 8) ++#define VSYNC_N (1 << 8) ++ ++#define DATA_NORMAL (0 << 17) ++#define DATA_INVERSE (1 << 17) ++ ++ ++/* Jz LCDFB supported I/O controls. */ ++#define FBIOSETBACKLIGHT 0x4688 ++#define FBIODISPON 0x4689 ++#define FBIODISPOFF 0x468a ++#define FBIORESET 0x468b ++#define FBIOPRINT_REGS 0x468c ++#define FBIOGETBUFADDRS 0x468d ++#define FBIOROTATE 0x46a0 /* rotated fb */ ++ ++struct jz_lcd_buffer_addrs_t { ++ int fb_num; ++ unsigned int lcd_desc_phys_addr; ++ unsigned int fb_phys_addr[CONFIG_JZLCD_FRAMEBUFFER_MAX]; ++}; ++ ++ ++/* ++ * LCD panel specific definition ++ */ ++#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW) ++ ++#if defined(CONFIG_JZ4730_PMP) ++#define LCD_RESET_PIN 63 ++#endif ++ ++#define __lcd_special_on() \ ++do { \ ++ __gpio_set_pin(LCD_RESET_PIN); \ ++ __gpio_as_output(LCD_RESET_PIN); \ ++ __gpio_clear_pin(LCD_RESET_PIN); \ ++ udelay(100); \ ++ __gpio_set_pin(LCD_RESET_PIN); \ ++} while (0) ++ ++#endif /* CONFIG_JZLCD_TRULY_TFTG320240DTSW */ ++ ++#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04) ++ ++#if defined(CONFIG_JZ4730_FPRINT) ++#define PortSDI 60 ++#define PortSCL 61 ++#define PortCS 62 ++#define PortRST 63 ++#define PortSht 64 ++#endif ++ ++#if defined(CONFIG_JZ4730_GPS) ++#define PortSDI 74 ++#define PortSCL 72 ++#define PortCS 73 ++#define PortRST 60 ++#define PortSht 59 ++#endif ++ ++#ifndef PortSDI ++#define PortSDI 0 ++#endif ++#ifndef PortSCL ++#define PortSCL 0 ++#endif ++#ifndef PortCS ++#define PortCS 0 ++#endif ++#ifndef PortRST ++#define PortRST 0 ++#endif ++#ifndef PortSht ++#define PortSht 0 ++#endif ++ ++#define __lcd_special_pin_init() \ ++do { \ ++ __gpio_as_output(PortSDI); /* SDI */\ ++ __gpio_as_output(PortSCL); /* SCL */ \ ++ __gpio_as_output(PortCS); /* CS */ \ ++ __gpio_as_output(PortRST); /* Reset */ \ ++ __gpio_as_output(PortSht); /* Shut Down # */ \ ++ __gpio_set_pin(PortCS); \ ++ __gpio_set_pin(PortSCL); \ ++ __gpio_set_pin(PortSDI); \ ++} while (0) ++ ++#define __spi_out(val) \ ++do { \ ++ int __i__; \ ++ unsigned int _t_ = (val); \ ++ __gpio_clear_pin(PortCS); \ ++ udelay(25); \ ++ for (__i__ = 0; __i__ < 24; __i__++ ) { \ ++ __gpio_clear_pin(PortSCL); \ ++ if (_t_ & 0x800000) \ ++ __gpio_set_pin(PortSDI); \ ++ else \ ++ __gpio_clear_pin(PortSDI); \ ++ _t_ <<= 1; \ ++ udelay(25); \ ++ __gpio_set_pin(PortSCL); \ ++ udelay(25); \ ++ } \ ++ __gpio_set_pin(PortCS); \ ++ udelay(25); \ ++ __gpio_set_pin(PortSDI); \ ++ udelay(25); \ ++ __gpio_set_pin(PortSCL); \ ++} while (0) ++ ++#define __spi_id_op_data(rs, rw, val) \ ++ __spi_out((0x1d<<18)|((rs)<<17)|((rw)<<16)|(val)) ++ ++#define __spi_write_reg(reg, val) \ ++do { \ ++ __spi_id_op_data(0, 0, (reg)); \ ++ __spi_id_op_data(1, 0, (val)); \ ++} while (0) ++ ++#define __lcd_special_on() \ ++do { \ ++ __gpio_set_pin(PortSht); \ ++ __gpio_clear_pin(PortRST); \ ++ mdelay(10); \ ++ __gpio_set_pin(PortRST); \ ++ mdelay(1); \ ++ __spi_write_reg(0x09, 0); \ ++ mdelay(10); \ ++ __spi_write_reg(0x09, 0x4000); \ ++ __spi_write_reg(0x0a, 0x2000); \ ++ mdelay(40); \ ++ __spi_write_reg(0x09, 0x4055); \ ++ mdelay(50); \ ++ __spi_write_reg(0x01, 0x409d); \ ++ __spi_write_reg(0x02, 0x0204); \ ++ __spi_write_reg(0x03, 0x0100); \ ++ __spi_write_reg(0x04, 0x3000); \ ++ __spi_write_reg(0x05, 0x4003); \ ++ __spi_write_reg(0x06, 0x000a); \ ++ __spi_write_reg(0x07, 0x0021); \ ++ __spi_write_reg(0x08, 0x0c00); \ ++ __spi_write_reg(0x10, 0x0103); \ ++ __spi_write_reg(0x11, 0x0301); \ ++ __spi_write_reg(0x12, 0x1f0f); \ ++ __spi_write_reg(0x13, 0x1f0f); \ ++ __spi_write_reg(0x14, 0x0707); \ ++ __spi_write_reg(0x15, 0x0307); \ ++ __spi_write_reg(0x16, 0x0707); \ ++ __spi_write_reg(0x17, 0x0000); \ ++ __spi_write_reg(0x18, 0x0004); \ ++ __spi_write_reg(0x19, 0x0000); \ ++ mdelay(60); \ ++ __spi_write_reg(0x09, 0x4a55); \ ++ __spi_write_reg(0x05, 0x5003); \ ++} while (0) ++ ++#define __lcd_special_off() \ ++do { \ ++ __spi_write_reg(0x09, 0x4055); \ ++ __spi_write_reg(0x05, 0x4003); \ ++ __spi_write_reg(0x0a, 0x0000); \ ++ mdelay(10); \ ++ __spi_write_reg(0x09, 0x4000); \ ++ __gpio_clear_pin(PortSht); \ ++} while (0) ++ ++#endif /* CONFIG_JZLCD_SAMSUNG_LTV350QVF04 */ ++ ++#if defined(CONFIG_JZLCD_AUO_A030FL01_V1) ++#if defined(CONFIG_JZ4740_PAVO) /* board pavo */ ++ #define SPEN (32*1+18) /*LCD_CS*/ ++ #define SPCK (32*1+17) /*LCD_SCL*/ ++ #define SPDA (32*2+12) /*LCD_SDA*/ ++ #define LCD_RET (32*2+23) /*use for lcd reset*/ ++#elif defined(CONFIG_JZ4740_LYRA) /* board lyra */ ++ #define SPEN (32*3+19) //LCD_CS ++ #define SPCK (32*3+18) //LCD_SCL ++ #define SPDA (32*3+20) //LCD_SDA ++ #define LCD_RET (32*3+31) //use for lcd reset ++#else ++#error "driver/video/Jzlcd.h, please define SPI pins on your board." ++#endif ++ ++#define __spi_write_reg(reg, val) \ ++ do { \ ++ unsigned char no; \ ++ unsigned short value; \ ++ unsigned char a=0; \ ++ unsigned char b=0; \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ a=reg; \ ++ b=val; \ ++ __gpio_set_pin(SPEN); \ ++ __gpio_clear_pin(SPCK); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPDA); \ ++ __gpio_clear_pin(SPEN); \ ++ udelay(50); \ ++ value=((a<<8)|(b&0xFF)); \ ++ for(no=0;no<16;no++) \ ++ { \ ++ if((value&0x8000)==0x8000){ \ ++ __gpio_set_pin(SPDA);} \ ++ else{ \ ++ __gpio_clear_pin(SPDA); } \ ++ udelay(400); \ ++ __gpio_set_pin(SPCK); \ ++ value=(value<<1); \ ++ udelay(50); \ ++ __gpio_clear_pin(SPCK); \ ++ } \ ++ __gpio_set_pin(SPEN); \ ++ udelay(400); \ ++ } while (0) ++#define __spi_read_reg(reg,val) \ ++ do{ \ ++ unsigned char no; \ ++ unsigned short value; \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ value = ((reg << 0) | (1 << 7)); \ ++ val = 0; \ ++ __gpio_as_output(SPDA); \ ++ __gpio_set_pin(SPEN); \ ++ __gpio_set_pin(SPCK); \ ++ udelay(1); \ ++ __gpio_clear_pin(SPDA); \ ++ __gpio_clear_pin(SPEN); \ ++ udelay(1); \ ++ for (no = 0; no < 16; no++ ) { \ ++ __gpio_clear_pin(SPCK); \ ++ udelay(1); \ ++ if(no < 8) \ ++ { \ ++ if (value & 0x80) /* send data */ \ ++ __gpio_set_pin(SPDA); \ ++ else \ ++ __gpio_clear_pin(SPDA); \ ++ value = (value << 1); \ ++ udelay(1); \ ++ __gpio_set_pin(SPCK); \ ++ udelay(1); \ ++ } \ ++ else \ ++ { \ ++ __gpio_as_input(SPDA); \ ++ udelay(1); \ ++ __gpio_set_pin(SPCK); \ ++ udelay(1); \ ++ val = (val << 1); \ ++ val |= __gpio_get_pin(SPDA); \ ++ udelay(1); \ ++ } \ ++ udelay(400); \ ++ } \ ++ __gpio_as_output(SPDA); \ ++ __gpio_set_pin(SPEN); \ ++ udelay(400); \ ++ } while(0) ++ ++#define __lcd_special_pin_init() \ ++ do { \ ++ __gpio_as_output(SPEN); /* use SPDA */ \ ++ __gpio_as_output(SPCK); /* use SPCK */ \ ++ __gpio_as_output(SPDA); /* use SPDA */ \ ++ __gpio_as_output(LCD_RET); \ ++ udelay(50); \ ++ __gpio_clear_pin(LCD_RET); \ ++ udelay(100); \ ++ __gpio_set_pin(LCD_RET); \ ++ } while (0) ++#define __lcd_special_on() \ ++ do { \ ++ udelay(50); \ ++ __gpio_clear_pin(LCD_RET); \ ++ udelay(100); \ ++ __gpio_set_pin(LCD_RET); \ ++ __spi_write_reg(0x0D, 0x44); \ ++ __spi_write_reg(0x0D, 0x4D); \ ++ __spi_write_reg(0x0B, 0x06); \ ++ __spi_write_reg(0x40, 0xC0); \ ++ __spi_write_reg(0x42, 0x43); \ ++ __spi_write_reg(0x44, 0x28); \ ++ __spi_write_reg(0x0D, 0x4F); \ ++} while (0) ++ ++ #define __lcd_special_off() \ ++ do { \ ++ __spi_write_reg(0x04, 0x4C); \ ++ } while (0) ++ ++#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */ ++ ++//#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) ++#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) || defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL) ++ ++#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) /* board pmp */ ++ #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 */ ++#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 ++#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 ++ #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) || defined(CONFIG_JZ4740_QI_LB60) ++#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(20); \ ++} while (0) ++ ++#define __lcd_display_off() \ ++do { \ ++ __lcd_special_off(); \ ++ __lcd_close_backlight(); \ ++ __gpio_clear_pin(GPIO_DISP_OFF_N); \ ++} while (0) ++ ++#endif /* CONFIG_MIPS_JZ4740_LEO */ ++ ++#if defined(CONFIG_JZLCD_MSTN_240x128) ++ ++#if 0 /* The final version does not use software emulation of VCOM. */ ++ ++#define GPIO_VSYNC 59 ++#define GPIO_VCOM 90 ++ ++#define REG_VCOM REG_GPIO_GPDR((GPIO_VCOM>>5)) ++#define VCOM_BIT (1 << (GPIO_VCOM & 0x1f)) ++static unsigned int vcom_static; ++static void vsync_irq(int irq, void *dev_id, struct pt_regs *reg) ++{ ++ vcom_static = REG_VCOM; ++ vcom_static ^= VCOM_BIT; ++ REG_VCOM = vcom_static; ++} ++ ++#define __lcd_display_pin_init() \ ++ __gpio_as_irq_rise_edge(GPIO_VSYNC); \ ++ __gpio_as_output(GPIO_VCOM); \ ++ { \ ++ static int inited = 0; \ ++ if (!inited) { \ ++ inited = 1; \ ++ if (request_irq(IRQ_GPIO_0 + GPIO_VSYNC, vsync_irq, SA_INTERRUPT, \ ++ "vsync", 0)) { \ ++ err = -EBUSY; \ ++ goto failed; \ ++ }}} ++ ++#endif ++ ++/* We uses AC BIAs pin to generate VCOM signal, so above code should be removed. ++ */ ++#endif ++/***************************************************************************** ++ * LCD display pin dummy macros ++ *****************************************************************************/ ++#ifndef __lcd_display_pin_init ++#define __lcd_display_pin_init() ++#endif ++#ifndef __lcd_display_on ++#define __lcd_display_on() ++#endif ++#ifndef __lcd_display_off ++#define __lcd_display_off() ++#endif ++#ifndef __lcd_set_backlight_level ++#define __lcd_set_backlight_level(n) ++#endif ++ ++#endif /* __JZLCD_H__ */ +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index b1ccc04..64eb1ab 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -45,6 +45,15 @@ comment "Watchdog Device Drivers" + + # Architecture Independent + ++config JZ_WDT ++ bool 'JzSoC On-Chip watchdog' ++ help ++ Watchdog timer embedded into JZSOC chips. This will reboot your ++ system when the timeout is reached. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called jz_wdt. ++ + config SOFT_WATCHDOG + tristate "Software watchdog" + help +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index 3d77429..e217064 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -10,6 +10,9 @@ + # that also fails then you can fall back to the software watchdog + # to give you some cover. + ++# JZ-watchdog timer ++obj-$(CONFIG_JZ_WDT) += jz_wdt.o ++ + # ISA-based Watchdog Cards + obj-$(CONFIG_PCWATCHDOG) += pcwd.o + obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +diff --git a/drivers/watchdog/jz_wdt.c b/drivers/watchdog/jz_wdt.c +new file mode 100644 +index 0000000..593bb87 +--- /dev/null ++++ b/drivers/watchdog/jz_wdt.c +@@ -0,0 +1,203 @@ ++/* ++ * linux/drivers/char/jz_wdt.c ++ * ++ * Watchdog driver for the Ingenic JzSOC ++ * ++ * Author: Wei Jianli ++ * ++ * 2005 (c) Ingenic Semiconductor. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ */ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ ++ ++static unsigned int timer_margin = TIMER_MARGIN; /* in seconds */ ++static unsigned int timer_rate; ++static unsigned int pre_margin; ++static unsigned long jz_wdt_users = 0; ++ ++#ifdef MODULE ++MODULE_PARM(timer_margin, "i"); ++#endif ++ ++static void ++jz_wdt_ping(void) ++{ ++ printk("jz_wdt_ping\n"); ++ /* reload counter with (new) margin */ ++#ifdef CONFIG_SOC_JZ4730 ++ pre_margin = 0xffffffff - timer_rate * timer_margin; ++ __wdt_set_count(pre_margin); ++#endif ++#ifdef CONFIG_SOC_JZ4740 ++ pre_margin = timer_rate * timer_margin; ++ __wdt_set_count(0); ++ __wdt_set_data(pre_margin); ++#endif ++} ++ ++/* ++ * Allow only one person to hold it open ++ */ ++ ++static int ++jz_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(1, &jz_wdt_users)) ++ return -EBUSY; ++ ++ printk("jz_wdt_open\n"); ++#ifdef CONFIG_SOC_JZ4730 ++ if (REG_CPM_OCR & CPM_OCR_EXT_RTC_CLK) ++ timer_rate = 32768; ++ else ++ timer_rate = JZ_EXTAL/128; ++#endif ++ ++#ifdef CONFIG_SOC_JZ4740 ++ /* Initialize the wdt clocks */ ++ __wdt_select_rtcclk(); ++ __wdt_select_clk_div1024(); ++ __tcu_start_wdt_clock(); ++ timer_rate = 32; /* 32768 / 1024 */ ++#endif ++ ++ jz_wdt_ping(); ++ __wdt_start(); ++ ++ return 0; ++} ++ ++static int ++jz_wdt_release(struct inode *inode, struct file *file) ++{ ++ /* ++ * Shut off the timer. ++ * Lock it in if it's a module and we defined ...NOWAYOUT ++ */ ++ jz_wdt_ping(); ++#ifndef CONFIG_WATCHDOG_NOWAYOUT ++ /* SW can't stop wdt once it was started */ ++#endif ++ jz_wdt_users = 0; ++ return 0; ++} ++ ++static ssize_t ++jz_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos) ++{ ++ /* Can't seek (pwrite) on this device */ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ ++ printk("jz_wdt_write\n"); ++ ++ /* Refresh counter */ ++ if (len) { ++ jz_wdt_ping(); ++ return 1; ++ } ++ return 0; ++} ++ ++static int ++jz_wdt_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int new_margin; ++ static struct watchdog_info ident = { ++ .identity = "JzSOC Watchdog", ++ .options = WDIOF_SETTIMEOUT, ++ .firmware_version = 0, ++ }; ++ ++ switch (cmd) { ++ default: ++ return -ENOIOCTLCMD; ++ case WDIOC_GETSUPPORT: ++ return copy_to_user((struct watchdog_info *) arg, &ident, ++ sizeof (ident)); ++ case WDIOC_GETSTATUS: ++ return put_user(0, (int *) arg); ++ case WDIOC_GETBOOTSTATUS: ++#ifdef CONFIG_SOC_JZ4730 ++ return put_user(REG_CPM_RSTR, (int *) arg); ++#endif ++#ifdef CONFIG_SOC_JZ4740 ++ return put_user(REG_RTC_HWRSR, (int *) arg); ++#endif ++ case WDIOC_KEEPALIVE: ++ jz_wdt_ping(); ++ return 0; ++ case WDIOC_SETTIMEOUT: ++ if (get_user(new_margin, (int *) arg)) ++ return -EFAULT; ++ if (new_margin < 1) ++ return -EINVAL; ++ timer_margin = new_margin; ++ jz_wdt_ping(); ++ /* Fall */ ++ case WDIOC_GETTIMEOUT: ++ return put_user(timer_margin, (int *) arg); ++ } ++} ++ ++static struct file_operations jz_wdt_fops = { ++ .owner = THIS_MODULE, ++ .write = jz_wdt_write, ++ .ioctl = jz_wdt_ioctl, ++ .open = jz_wdt_open, ++ .release = jz_wdt_release, ++}; ++ ++static struct miscdevice jz_wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "jz_wdt", ++ .fops = &jz_wdt_fops ++}; ++ ++static int __init ++jz_wdt_init(void) ++{ ++ int ret; ++ ++ ret = misc_register(&jz_wdt_miscdev); ++ ++ if (ret) ++ return ret; ++ ++ printk("JzSOC Watchdog Timer: timer margin %d sec\n", timer_margin); ++ ++ return 0; ++} ++ ++static void __exit ++jz_wdt_exit(void) ++{ ++ misc_deregister(&jz_wdt_miscdev); ++} ++ ++module_init(jz_wdt_init); ++module_exit(jz_wdt_exit); ++ ++MODULE_AUTHOR("Wei Jianli"); ++MODULE_LICENSE("GPL"); +diff --git a/include/asm-mips/jzsoc.h b/include/asm-mips/jzsoc.h +new file mode 100644 +index 0000000..54df338 +--- /dev/null ++++ b/include/asm-mips/jzsoc.h +@@ -0,0 +1,49 @@ ++/* ++ * linux/include/asm-mips/jzsoc.h ++ * ++ * Ingenic's JZXXXX SoC common include. ++ * ++ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZSOC_H__ ++#define __ASM_JZSOC_H__ ++ ++/* ++ * SoC include ++ */ ++ ++#ifdef CONFIG_SOC_JZ4730 ++#include ++#endif ++ ++#ifdef CONFIG_SOC_JZ4740 ++#include ++#endif ++ ++#ifdef CONFIG_SOC_JZ4750 ++#include ++#endif ++ ++#ifdef CONFIG_SOC_JZ4750D ++#include ++#endif ++ ++/* ++ * Generic I/O routines ++ */ ++#define readb(addr) (*(volatile unsigned char *)(addr)) ++#define readw(addr) (*(volatile unsigned short *)(addr)) ++#define readl(addr) (*(volatile unsigned int *)(addr)) ++ ++#define writeb(b,addr) ((*(volatile unsigned char *)(addr)) = (b)) ++#define writew(b,addr) ((*(volatile unsigned short *)(addr)) = (b)) ++#define writel(b,addr) ((*(volatile unsigned int *)(addr)) = (b)) ++ ++#endif /* __ASM_JZSOC_H__ */ +diff --git a/include/asm-mips/mach-jz4730/board-pmp.h b/include/asm-mips/mach-jz4730/board-pmp.h +new file mode 100644 +index 0000000..44475d2 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/board-pmp.h +@@ -0,0 +1,83 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/board-pmp.h ++ * ++ * JZ4730-based PMP board ver 2.x definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_PMP_H__ ++#define __ASM_JZ4730_PMP_H__ ++ ++/*====================================================================== ++ * EXTAL frequency ++ */ ++#define JZ_EXTAL 12000000 /* EXTAL: 12 MHz */ ++#define JZ_EXTAL2 32768 /* EXTAL2: 32.768 KHz */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_PW_I 97 ++#define GPIO_PW_O 66 ++#define GPIO_LED_EN 92 ++#define GPIO_DISP_OFF_N 93 ++#define GPIO_PWM0 94 ++#define GPIO_RTC_IRQ 96 ++#define GPIO_USB_CLK_EN 29 ++#define GPIO_CHARG_STAT 125 ++#define GPIO_TS_PENIRQ 98 ++#define GPIO_UDC_HOTPLUG 86 ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++#define MSC_WP_PIN 82 ++#define MSC_POWEREN_PIN 91 ++#define MSC_HOTPLUG_PIN 90 ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + MSC_HOTPLUG_PIN) ++ ++/* enable slot power */ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_input(MSC_WP_PIN); \ ++ __gpio_as_output(MSC_POWEREN_PIN); \ ++} while (0) ++ ++/* enable slot power */ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(MSC_POWEREN_PIN); \ ++} while (0) ++ ++/* disable slot power */ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(MSC_POWEREN_PIN); \ ++} while (0) ++ ++/* detect card insertion or not */ ++#define __msc_card_detected(slot) \ ++({ \ ++ int ret; \ ++ if (slot == 0) { \ ++ __gpio_mask_irq(MSC_HOTPLUG_IRQ); \ ++ __gpio_as_input(MSC_HOTPLUG_PIN); \ ++ ret = __gpio_get_pin(MSC_HOTPLUG_PIN); \ ++ __gpio_unmask_irq(MSC_HOTPLUG_IRQ); \ ++ } \ ++ else { \ ++ ret = 1; \ ++ } \ ++ ret = !ret; \ ++ ret; \ ++}) ++ ++#endif /* __ASM_JZ4730_PMP_H__ */ +diff --git a/include/asm-mips/mach-jz4730/clock.h b/include/asm-mips/mach-jz4730/clock.h +new file mode 100644 +index 0000000..16971d0 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/clock.h +@@ -0,0 +1,184 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/clock.h ++ * ++ * JZ4730 clocks definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_CLOCK_H__ ++#define __ASM_JZ4730_CLOCK_H__ ++ ++#ifndef JZ_EXTAL ++#define JZ_EXTAL 3686400 ++#endif ++ ++#ifndef JZ_EXTAL2 ++#define JZ_EXTAL2 32768 ++#endif ++ ++/* ++ * JZ4730 clocks structure ++ */ ++typedef struct { ++ unsigned int iclk; /* CPU core clock */ ++ unsigned int sclk; /* AHB bus clock */ ++ unsigned int mclk; /* Memory bus clock */ ++ unsigned int pclk; /* APB bus clock */ ++ unsigned int devclk; /* Devcie clock to specific modules */ ++ unsigned int rtcclk; /* RTC module clock */ ++ unsigned int uartclk; /* UART module clock */ ++ unsigned int lcdclk; /* LCD module clock */ ++ unsigned int pixclk; /* LCD pixel clock */ ++ unsigned int usbclk; /* USB module clock */ ++ unsigned int i2sclk; /* I2S module clock */ ++ unsigned int mscclk; /* MMC/SD module clock */ ++} jz_clocks_t; ++ ++extern jz_clocks_t jz_clocks; ++ ++ ++static __inline__ unsigned int __cpm_get_pllout(void) ++{ ++ unsigned int nf, nr, no, pllout; ++ unsigned long plcr = REG_CPM_PLCR1; ++ unsigned long od[4] = {1, 2, 2, 4}; ++ if (plcr & CPM_PLCR1_PLL1EN) { ++ nf = (plcr & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT; ++ nr = (plcr & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT; ++ no = od[((plcr & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT)]; ++ pllout = (JZ_EXTAL) / ((nr+2) * no) * (nf+2); ++ } else ++ pllout = JZ_EXTAL; ++ return pllout; ++} ++ ++static __inline__ unsigned int __cpm_get_iclk(void) ++{ ++ unsigned int iclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned long cfcr = REG_CPM_CFCR; ++ unsigned long plcr = REG_CPM_PLCR1; ++ if (plcr & CPM_PLCR1_PLL1EN) ++ iclk = __cpm_get_pllout() / ++ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT]; ++ else ++ iclk = JZ_EXTAL; ++ return iclk; ++} ++ ++static __inline__ unsigned int __cpm_get_sclk(void) ++{ ++ unsigned int sclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned long cfcr = REG_CPM_CFCR; ++ unsigned long plcr = REG_CPM_PLCR1; ++ if (plcr & CPM_PLCR1_PLL1EN) ++ sclk = __cpm_get_pllout() / ++ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT]; ++ else ++ sclk = JZ_EXTAL; ++ return sclk; ++} ++ ++static __inline__ unsigned int __cpm_get_mclk(void) ++{ ++ unsigned int mclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned long cfcr = REG_CPM_CFCR; ++ unsigned long plcr = REG_CPM_PLCR1; ++ if (plcr & CPM_PLCR1_PLL1EN) ++ mclk = __cpm_get_pllout() / ++ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT]; ++ else ++ mclk = JZ_EXTAL; ++ return mclk; ++} ++ ++static __inline__ unsigned int __cpm_get_pclk(void) ++{ ++ unsigned int devclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned long cfcr = REG_CPM_CFCR; ++ unsigned long plcr = REG_CPM_PLCR1; ++ if (plcr & CPM_PLCR1_PLL1EN) ++ devclk = __cpm_get_pllout() / ++ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT]; ++ else ++ devclk = JZ_EXTAL; ++ return devclk; ++} ++ ++static __inline__ unsigned int __cpm_get_lcdclk(void) ++{ ++ unsigned int lcdclk; ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ unsigned long cfcr = REG_CPM_CFCR; ++ unsigned long plcr = REG_CPM_PLCR1; ++ if (plcr & CPM_PLCR1_PLL1EN) ++ lcdclk = __cpm_get_pllout() / ++ div[(cfcr & CPM_CFCR_LFR_MASK) >> CPM_CFCR_LFR_BIT]; ++ else ++ lcdclk = JZ_EXTAL; ++ return lcdclk; ++} ++ ++static __inline__ unsigned int __cpm_get_pixclk(void) ++{ ++ unsigned int pixclk; ++ unsigned long cfcr2 = REG_CPM_CFCR2; ++ pixclk = __cpm_get_pllout() / (cfcr2 + 1); ++ return pixclk; ++} ++ ++static __inline__ unsigned int __cpm_get_devclk(void) ++{ ++ return JZ_EXTAL; ++} ++ ++static __inline__ unsigned int __cpm_get_rtcclk(void) ++{ ++ return JZ_EXTAL2; ++} ++ ++static __inline__ unsigned int __cpm_get_uartclk(void) ++{ ++ return JZ_EXTAL; ++} ++ ++static __inline__ unsigned int __cpm_get_usbclk(void) ++{ ++ unsigned int usbclk; ++ unsigned long cfcr = REG_CPM_CFCR; ++ if (cfcr & CPM_CFCR_UCS) ++ usbclk = 48000000; ++ else ++ usbclk = __cpm_get_pllout() / ++ (((cfcr &CPM_CFCR_UFR_MASK) >> CPM_CFCR_UFR_BIT) + 1); ++ return usbclk; ++} ++ ++static __inline__ unsigned int __cpm_get_i2sclk(void) ++{ ++ unsigned int i2sclk; ++ unsigned long cfcr = REG_CPM_CFCR; ++ i2sclk = __cpm_get_pllout() / ++ ((cfcr & CPM_CFCR_I2S) ? 2: 1); ++ return i2sclk; ++} ++ ++static __inline__ unsigned int __cpm_get_mscclk(void) ++{ ++ if (REG_CPM_CFCR & CPM_CFCR_MSC) ++ return 24000000; ++ else ++ return 16000000; ++} ++ ++#endif /* __ASM_JZ4730_CLOCK_H__ */ +diff --git a/include/asm-mips/mach-jz4730/dma.h b/include/asm-mips/mach-jz4730/dma.h +new file mode 100644 +index 0000000..511152e +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/dma.h +@@ -0,0 +1,272 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/dma.h ++ * ++ * JZ4730 DMA definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_DMA_H__ ++#define __ASM_JZ4730_DMA_H__ ++ ++#include ++#include /* need byte IO */ ++#include /* And spinlocks */ ++#include ++#include ++ ++#define DMA_UNIT_32 32 ++#define DMA_UNIT_16 16 ++ ++ ++/* block-mode EOP: high DREQ: high DACK: low*/ ++#define DMA_BLOCK_CONF \ ++ DMAC_DCCSR_TM | \ ++ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN | \ ++ DMAC_DCCSR_ERDM_HLEVEL | DMAC_DCCSR_EACKS ++ ++/* single-mode EOP: high DREQ: high DACK: low */ ++#define DMA_SINGLE_CONF \ ++ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN | \ ++ DMAC_DCCSR_ERDM_HLEVEL | DMAC_DCCSR_EACKS ++ ++#define DMA_8bit_RX_CONF \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_8 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_8bit_TX_CONF \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_8 | \ ++ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_16bit_RX_CONF \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_16bit_TX_CONF \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_16 | \ ++ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_32bit_RX_CONF \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_32b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_32bit_TX_CONF \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_32b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_16BYTE_RX_CONF \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_8 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_16BYTE_TX_CONF \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_8 | \ ++ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_AIC_32_16BYTE_TX_CMD \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_AIC_32_16BYTE_RX_CMD \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ ++ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_AIC_16BIT_TX_CMD \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ ++ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_AIC_16BIT_RX_CMD \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ ++ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_RX_CMD \ ++ DMAC_DCCSR_DAM | \ ++ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ ++ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_TX_CMD \ ++ DMAC_DCCSR_SAM | \ ++ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ ++ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN ++ ++/* DMA Device ID's follow */ ++enum { ++ DMA_ID_UART0_TX = 0, ++ DMA_ID_UART0_RX, ++ DMA_ID_UART1_TX, ++ DMA_ID_UART1_RX, ++ DMA_ID_UART2_TX, ++ DMA_ID_UART2_RX, ++ DMA_ID_UART3_TX, ++ DMA_ID_UART3_RX, ++ DMA_ID_SSI_TX, ++ DMA_ID_SSI_RX, ++ DMA_ID_MSC_TX, ++ DMA_ID_MSC_RX, ++ DMA_ID_AIC_TX, ++ DMA_ID_AIC_RX, ++ DMA_ID_BLOCK, /* DREQ */ ++ DMA_ID_SINGLE, /* DREQ */ ++ DMA_ID_PCMCIA0_TX, ++ DMA_ID_PCMCIA0_RX, ++ DMA_ID_PCMCIA1_TX, ++ DMA_ID_PCMCIA2_RX, ++ DMA_ID_AUTO, ++ DMA_ID_RAW_SET, ++ NUM_DMA_DEV ++}; ++ ++/* dummy DCCSR bit, i386 style DMA macros compitable */ ++#define DMA_MODE_READ 0 /* I/O to memory, no autoinit, ++ * increment, single mode */ ++#define DMA_MODE_WRITE 1 /* memory to I/O, no autoinit, ++ * increment, single mode */ ++#define DMA_MODE_CASCADE 2 /* pass thru DREQ->HRQ, ++ * DACK<-HLDA only */ ++#define DMA_AUTOINIT 3 ++#define DMA_MODE_MASK 3 ++ ++struct jz_dma_chan { ++ int dev_id; /* this channel is allocated if >=0, ++ * free otherwise */ ++ unsigned int io; ++ const char *dev_str; ++ int irq; ++ void *irq_dev; ++ unsigned int fifo_addr; ++ unsigned int mode; ++ unsigned int source; ++}; ++ ++extern struct jz_dma_chan jz_dma_table[]; ++ ++extern int jz_request_dma(int dev_id, ++ const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id); ++extern void jz_free_dma(unsigned int dmanr); ++ ++extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data); ++extern void dump_jz_dma_channel(unsigned int dmanr); ++ ++extern void enable_dma(unsigned int dmanr); ++extern void disable_dma(unsigned int dmanr); ++extern void set_dma_addr(unsigned int dmanr, unsigned int a); ++extern void set_dma_count(unsigned int dmanr, unsigned int count); ++extern void set_dma_mode(unsigned int dmanr, unsigned int mode); ++extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern int get_dma_residue(unsigned int dmanr); ++ ++extern spinlock_t dma_spin_lock; ++ ++static __inline__ unsigned long claim_dma_lock(void) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&dma_spin_lock, flags); ++ return flags; ++} ++ ++static __inline__ void release_dma_lock(unsigned long flags) ++{ ++ spin_unlock_irqrestore(&dma_spin_lock, flags); ++} ++ ++/* Clear the 'DMA Pointer Flip Flop'. ++ * Write 0 for LSB/MSB, 1 for MSB/LSB access. ++ */ ++#define clear_dma_ff(channel) ++ ++static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) ++{ ++ if (dmanr > NUM_DMA ++ || jz_dma_table[dmanr].dev_id < 0) ++ return NULL; ++ return &jz_dma_table[dmanr]; ++} ++ ++static __inline__ int dma_halted(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 1; ++ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; ++} ++ ++static __inline__ unsigned int get_dma_mode(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ return chan->mode; ++} ++ ++static __inline__ void clear_dma_done(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++} ++ ++static __inline__ void clear_dma_halt(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); ++ REG_DMAC_DMACR &= ~(DMAC_DMACR_HTR); ++} ++static __inline__ void clear_dma_flag(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++ REG_DMAC_DMACR &= ~(DMAC_DMACR_HTR | DMAC_DMACR_AER); ++} ++ ++static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) ++{ ++} ++ ++static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ unsigned long dccsr; ++ if (!chan) ++ return 0; ++ ++ dccsr = REG_DMAC_DCCSR(chan->io); ++ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); ++} ++ ++static __inline__ int get_dma_done_irq(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return -1; ++ ++ return chan->irq; ++} ++ ++#endif /* __ASM_JZ4730_DMA_H__ */ +diff --git a/include/asm-mips/mach-jz4730/jz4730.h b/include/asm-mips/mach-jz4730/jz4730.h +new file mode 100644 +index 0000000..5688f01 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/jz4730.h +@@ -0,0 +1,40 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/jz4730.h ++ * ++ * JZ4730 common definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_H__ ++#define __ASM_JZ4730_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*------------------------------------------------------------------ ++ * Platform definitions ++ */ ++#ifdef CONFIG_JZ4730_PMP ++#include ++#endif ++ ++/* Add other platform definition here ... */ ++ ++ ++/*------------------------------------------------------------------ ++ * Follows are related to platform definitions ++ */ ++ ++#include ++#include ++ ++#endif /* __ASM_JZ4730_H__ */ +diff --git a/include/asm-mips/mach-jz4730/misc.h b/include/asm-mips/mach-jz4730/misc.h +new file mode 100644 +index 0000000..ea01474 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/misc.h +@@ -0,0 +1,28 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/misc.h ++ * ++ * JZ4730 miscillaneous definitions. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_MISC_H__ ++#define __ASM_JZ4730_MISC_H__ ++ ++/* ++ * I2C routines ++ */ ++ ++extern void i2c_open(void); ++extern void i2c_close(void); ++extern void i2c_setclk(unsigned int i2cclk); ++extern int i2c_read(unsigned char, unsigned char *, unsigned char, int); ++extern int i2c_write(unsigned char, unsigned char *, unsigned char, int); ++ ++#endif /* __ASM_JZ4730_MISC_H__ */ +diff --git a/include/asm-mips/mach-jz4730/ops.h b/include/asm-mips/mach-jz4730/ops.h +new file mode 100644 +index 0000000..625419e +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/ops.h +@@ -0,0 +1,2541 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/ops.h ++ * ++ * JZ4730 module operations definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_OPS_H__ ++#define __ASM_JZ4730_OPS_H__ ++ ++/*************************************************************************** ++ * MSC ++ ***************************************************************************/ ++ ++#define __msc_start_op() \ ++ ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) ++ ++#define __msc_set_resto(to) ( REG_MSC_RESTO = to ) ++#define __msc_set_rdto(to) ( REG_MSC_RDTO = to ) ++#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd ) ++#define __msc_set_arg(arg) ( REG_MSC_ARG = arg ) ++#define __msc_set_nob(nob) ( REG_MSC_NOB = nob ) ++#define __msc_get_nob() ( REG_MSC_NOB ) ++#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len ) ++#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat ) ++#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT ) ++#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT ) ++ ++#define __msc_set_cmdat_bus_width1() \ ++do { \ ++ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_bus_width4() \ ++do { \ ++ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN ) ++#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT ) ++#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY ) ++#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN ) ++ ++/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ ++#define __msc_set_cmdat_res_format(r) \ ++do { \ ++ REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ ++ REG_MSC_CMDAT |= (r); \ ++} while(0) ++ ++#define __msc_clear_cmdat() \ ++ REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ ++ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ ++ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) ++ ++#define __msc_get_imask() ( REG_MSC_IMASK ) ++#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff ) ++#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 ) ++#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES ) ++#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES ) ++#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE ) ++#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE ) ++ ++/* n=0,1,2,3,4,5,6,7 */ ++#define __msc_set_clkrt(n) \ ++do { \ ++ REG_MSC_CLKRT = n; \ ++} while(0) ++ ++#define __msc_get_ireg() ( REG_MSC_IREG ) ++#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ ) ++#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ ) ++#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE ) ++#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE ) ++ ++#define __msc_get_stat() ( REG_MSC_STAT ) ++#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0) ++#define __msc_stat_crc_err() \ ++ ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) ++#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR ) ++#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR ) ++#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES ) ++#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES ) ++#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ ) ++ ++#define __msc_rd_resfifo() ( REG_MSC_RES ) ++#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO ) ++#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v ) ++ ++#define __msc_reset() \ ++do { \ ++ REG_MSC_STRPCL = MSC_STRPCL_RESET; \ ++ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \ ++} while (0) ++ ++#define __msc_start_clk() \ ++do { \ ++ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \ ++} while (0) ++ ++#define __msc_stop_clk() \ ++do { \ ++ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \ ++} while (0) ++ ++#define MMC_CLK 19169200 ++#define SD_CLK 24576000 ++ ++/* msc_clk should little than pclk and little than clk retrieve from card */ ++#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ ++do { \ ++ unsigned int rate, pclk, i; \ ++ pclk = dev_clk; \ ++ rate = type?SD_CLK:MMC_CLK; \ ++ if (msc_clk && msc_clk < pclk) \ ++ pclk = msc_clk; \ ++ i = 0; \ ++ while (pclk < rate) \ ++ { \ ++ i ++; \ ++ rate >>= 1; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++/* divide rate to little than or equal to 400kHz */ ++#define __msc_calc_slow_clk_divisor(type, lv) \ ++do { \ ++ unsigned int rate, i; \ ++ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ ++ i = 0; \ ++ while (rate > 0) \ ++ { \ ++ rate >>= 1; \ ++ i ++; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++/*************************************************************************** ++ * RTC ++ ***************************************************************************/ ++ ++#define __rtc_start() ( REG_RTC_RCR |= RTC_RCR_START ) ++#define __rtc_stop() ( REG_RTC_RCR &= ~RTC_RCR_START ) ++ ++#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) ++#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) ++#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) ++#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) ++ ++#define __rtc_enable_1hz_irq() ( REG_RTC_RCR |= RTC_RCR_HZIE ) ++#define __rtc_disable_1hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_HZIE ) ++ ++#define __rtc_is_alarm_flag() ( REG_RTC_RCR & RTC_RCR_AF ) ++#define __rtc_is_1hz_flag() ( REG_RTC_RCR & RTC_RCR_HZ ) ++#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) ++#define __rtc_clear_1hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_HZ ) ++ ++#define __rtc_set_second(s) ( REG_RTC_RSR = (s) ) ++#define __rtc_get_second() REG_RTC_RSR ++#define __rtc_set_alarm(s) ( REG_RTC_RSAR = (s) ) ++#define __rtc_get_alarm() REG_RTC_RSAR ++ ++#define __rtc_adjust_1hz(f32k) \ ++ ( REG_RTC_RGR = (REG_RTC_RGR & ~(RTC_REG_DIV_MASK | RTC_RGR_ADJ_MASK)) | f32k | 0 ) ++#define __rtc_lock_1hz() ( REG_RTC_RGR |= RTC_RGR_LOCK ) ++ ++ ++/*************************************************************************** ++ * FIR ++ ***************************************************************************/ ++ ++/* enable/disable fir unit */ ++#define __fir_enable() ( REG_FIR_CR1 |= FIR_CR1_FIRUE ) ++#define __fir_disable() ( REG_FIR_CR1 &= ~FIR_CR1_FIRUE ) ++ ++/* enable/disable address comparison */ ++#define __fir_enable_ac() ( REG_FIR_CR1 |= FIR_CR1_ACE ) ++#define __fir_disable_ac() ( REG_FIR_CR1 &= ~FIR_CR1_ACE ) ++ ++/* select frame end mode as underrun or normal */ ++#define __fir_set_eous() ( REG_FIR_CR1 |= FIR_CR1_EOUS ) ++#define __fir_clear_eous() ( REG_FIR_CR1 &= ~FIR_CR1_EOUS ) ++ ++/* enable/disable transmitter idle interrupt */ ++#define __fir_enable_tii() ( REG_FIR_CR1 |= FIR_CR1_TIIE ) ++#define __fir_disable_tii() ( REG_FIR_CR1 &= ~FIR_CR1_TIIE ) ++ ++/* enable/disable transmit FIFO service request interrupt */ ++#define __fir_enable_tfi() ( REG_FIR_CR1 |= FIR_CR1_TFIE ) ++#define __fir_disable_tfi() ( REG_FIR_CR1 &= ~FIR_CR1_TFIE ) ++ ++/* enable/disable receive FIFO service request interrupt */ ++#define __fir_enable_rfi() ( REG_FIR_CR1 |= FIR_CR1_RFIE ) ++#define __fir_disable_rfi() ( REG_FIR_CR1 &= ~FIR_CR1_RFIE ) ++ ++/* enable/disable tx function */ ++#define __fir_tx_enable() ( REG_FIR_CR1 |= FIR_CR1_TXE ) ++#define __fir_tx_disable() ( REG_FIR_CR1 &= ~FIR_CR1_TXE ) ++ ++/* enable/disable rx function */ ++#define __fir_rx_enable() ( REG_FIR_CR1 |= FIR_CR1_RXE ) ++#define __fir_rx_disable() ( REG_FIR_CR1 &= ~FIR_CR1_RXE ) ++ ++ ++/* enable/disable serial infrared interaction pulse (SIP) */ ++#define __fir_enable_sip() ( REG_FIR_CR2 |= FIR_CR2_SIPE ) ++#define __fir_disable_sip() ( REG_FIR_CR2 &= ~FIR_CR2_SIPE ) ++ ++/* un-inverted CRC value is sent out */ ++#define __fir_enable_bcrc() ( REG_FIR_CR2 |= FIR_CR2_BCRC ) ++ ++/* inverted CRC value is sent out */ ++#define __fir_disable_bcrc() ( REG_FIR_CR2 &= ~FIR_CR2_BCRC ) ++ ++/* enable/disable Transmit Frame Length Register */ ++#define __fir_enable_tflr() ( REG_FIR_CR2 |= FIR_CR2_TFLRS ) ++#define __fir_disable_tflr() ( REG_FIR_CR2 &= ~FIR_CR2_TFLRS ) ++ ++/* Preamble is transmitted in idle state */ ++#define __fir_set_iss() ( REG_FIR_CR2 |= FIR_CR2_ISS ) ++ ++/* Abort symbol is transmitted in idle state */ ++#define __fir_clear_iss() ( REG_FIR_CR2 &= ~FIR_CR2_ISS ) ++ ++/* enable/disable loopback mode */ ++#define __fir_enable_loopback() ( REG_FIR_CR2 |= FIR_CR2_LMS ) ++#define __fir_disable_loopback() ( REG_FIR_CR2 &= ~FIR_CR2_LMS ) ++ ++/* select transmit pin polarity */ ++#define __fir_tpp_negative() ( REG_FIR_CR2 |= FIR_CR2_TPPS ) ++#define __fir_tpp_positive() ( REG_FIR_CR2 &= ~FIR_CR2_TPPS ) ++ ++/* select receive pin polarity */ ++#define __fir_rpp_negative() ( REG_FIR_CR2 |= FIR_CR2_RPPS ) ++#define __fir_rpp_positive() ( REG_FIR_CR2 &= ~FIR_CR2_RPPS ) ++ ++/* n=16,32,64,128 */ ++#define __fir_set_txfifo_trigger(n) \ ++do { \ ++ REG_FIR_CR2 &= ~FIR_CR2_TTRG_MASK; \ ++ REG_FIR_CR2 |= FIR_CR2_TTRG_##n; \ ++} while (0) ++ ++/* n=16,32,64,128 */ ++#define __fir_set_rxfifo_trigger(n) \ ++do { \ ++ REG_FIR_CR2 &= ~FIR_CR2_RTRG_MASK; \ ++ REG_FIR_CR2 |= FIR_CR2_RTRG_##n; \ ++} while (0) ++ ++ ++/* FIR status checking */ ++ ++#define __fir_test_rfw() ( REG_FIR_SR & FIR_SR_RFW ) ++#define __fir_test_rfa() ( REG_FIR_SR & FIR_SR_RFA ) ++#define __fir_test_tfrtl() ( REG_FIR_SR & FIR_SR_TFRTL ) ++#define __fir_test_rfrtl() ( REG_FIR_SR & FIR_SR_RFRTL ) ++#define __fir_test_urun() ( REG_FIR_SR & FIR_SR_URUN ) ++#define __fir_test_rfte() ( REG_FIR_SR & FIR_SR_RFTE ) ++#define __fir_test_orun() ( REG_FIR_SR & FIR_SR_ORUN ) ++#define __fir_test_crce() ( REG_FIR_SR & FIR_SR_CRCE ) ++#define __fir_test_fend() ( REG_FIR_SR & FIR_SR_FEND ) ++#define __fir_test_tff() ( REG_FIR_SR & FIR_SR_TFF ) ++#define __fir_test_rfe() ( REG_FIR_SR & FIR_SR_RFE ) ++#define __fir_test_tidle() ( REG_FIR_SR & FIR_SR_TIDLE ) ++#define __fir_test_rb() ( REG_FIR_SR & FIR_SR_RB ) ++ ++#define __fir_clear_status() \ ++do { \ ++ REG_FIR_SR |= FIR_SR_RFW | FIR_SR_RFA | FIR_SR_URUN; \ ++} while (0) ++ ++#define __fir_clear_rfw() ( REG_FIR_SR |= FIR_SR_RFW ) ++#define __fir_clear_rfa() ( REG_FIR_SR |= FIR_SR_RFA ) ++#define __fir_clear_urun() ( REG_FIR_SR |= FIR_SR_URUN ) ++ ++#define __fir_set_tflr(len) \ ++do { \ ++ REG_FIR_TFLR = len; \ ++} while (0) ++ ++#define __fir_set_addr(a) ( REG_FIR_AR = (a) ) ++ ++#define __fir_write_data(data) ( REG_FIR_TDR = data ) ++#define __fir_read_data(data) ( data = REG_FIR_RDR ) ++ ++/*************************************************************************** ++ * SCC ++ ***************************************************************************/ ++ ++#define __scc_enable(base) ( REG_SCC_CR(base) |= SCC_CR_SCCE ) ++#define __scc_disable(base) ( REG_SCC_CR(base) &= ~SCC_CR_SCCE ) ++ ++#define __scc_set_tx_mode(base) ( REG_SCC_CR(base) |= SCC_CR_TRS ) ++#define __scc_set_rx_mode(base) ( REG_SCC_CR(base) &= ~SCC_CR_TRS ) ++ ++#define __scc_enable_t2r(base) ( REG_SCC_CR(base) |= SCC_CR_T2R ) ++#define __scc_disable_t2r(base) ( REG_SCC_CR(base) &= ~SCC_CR_T2R ) ++ ++#define __scc_clk_as_devclk(base) \ ++do { \ ++ REG_SCC_CR(base) &= ~SCC_CR_FDIV_MASK; \ ++ REG_SCC_CR(base) |= SCC_CR_FDIV_1; \ ++} while (0) ++ ++#define __scc_clk_as_half_devclk(base) \ ++do { \ ++ REG_SCC_CR(base) &= ~SCC_CR_FDIV_MASK; \ ++ REG_SCC_CR(base) |= SCC_CR_FDIV_2; \ ++} while (0) ++ ++/* n=1,4,8,14 */ ++#define __scc_set_fifo_trigger(base, n) \ ++do { \ ++ REG_SCC_CR(base) &= ~SCC_CR_TRIG_MASK; \ ++ REG_SCC_CR(base) |= SCC_CR_TRIG_##n; \ ++} while (0) ++ ++#define __scc_set_protocol(base, p) \ ++do { \ ++ if (p) \ ++ REG_SCC_CR(base) |= SCC_CR_TP; \ ++ else \ ++ REG_SCC_CR(base) &= ~SCC_CR_TP; \ ++} while (0) ++ ++#define __scc_flush_fifo(base) ( REG_SCC_CR(base) |= SCC_CR_FLUSH ) ++ ++#define __scc_set_invert_mode(base) ( REG_SCC_CR(base) |= SCC_CR_CONV ) ++#define __scc_set_direct_mode(base) ( REG_SCC_CR(base) &= ~SCC_CR_CONV ) ++ ++#define SCC_ERR_INTRS \ ++ ( SCC_CR_ECIE | SCC_CR_EPIE | SCC_CR_RETIE | SCC_CR_EOIE ) ++#define SCC_ALL_INTRS \ ++ ( SCC_CR_TXIE | SCC_CR_RXIE | SCC_CR_TENDIE | SCC_CR_RTOIE | \ ++ SCC_CR_ECIE | SCC_CR_EPIE | SCC_CR_RETIE | SCC_CR_EOIE ) ++ ++#define __scc_enable_err_intrs(base) ( REG_SCC_CR(base) |= SCC_ERR_INTRS ) ++#define __scc_disable_err_intrs(base) ( REG_SCC_CR(base) &= ~SCC_ERR_INTRS ) ++ ++#define SCC_ALL_ERRORS \ ++ ( SCC_SR_ORER | SCC_SR_RTO | SCC_SR_PER | SCC_SR_RETR_3 | SCC_SR_ECNTO) ++ ++#define __scc_clear_errors(base) ( REG_SCC_SR(base) &= ~SCC_ALL_ERRORS ) ++ ++#define __scc_enable_all_intrs(base) ( REG_SCC_CR(base) |= SCC_ALL_INTRS ) ++#define __scc_disable_all_intrs(base) ( REG_SCC_CR(base) &= ~SCC_ALL_INTRS ) ++ ++#define __scc_enable_tx_intr(base) ( REG_SCC_CR(base) |= SCC_CR_TXIE | SCC_CR_TENDIE ) ++#define __scc_disable_tx_intr(base) ( REG_SCC_CR(base) &= ~(SCC_CR_TXIE | SCC_CR_TENDIE) ) ++ ++#define __scc_enable_rx_intr(base) ( REG_SCC_CR(base) |= SCC_CR_RXIE) ++#define __scc_disable_rx_intr(base) ( REG_SCC_CR(base) &= ~SCC_CR_RXIE) ++ ++#define __scc_set_tsend(base) ( REG_SCC_CR(base) |= SCC_CR_TSEND ) ++#define __scc_clear_tsend(base) ( REG_SCC_CR(base) &= ~SCC_CR_TSEND ) ++ ++#define __scc_set_clockstop(base) ( REG_SCC_CR(base) |= SCC_CR_CLKSTP ) ++#define __scc_clear_clockstop(base) ( REG_SCC_CR(base) &= ~SCC_CR_CLKSTP ) ++ ++#define __scc_clockstop_low(base) \ ++do { \ ++ REG_SCC_CR(base) &= ~SCC_CR_PX_MASK; \ ++ REG_SCC_CR(base) |= SCC_CR_PX_STOP_LOW; \ ++} while (0) ++ ++#define __scc_clockstop_high(base) \ ++do { \ ++ REG_SCC_CR(base) &= ~SCC_CR_PX_MASK; \ ++ REG_SCC_CR(base) |= SCC_CR_PX_STOP_HIGH; \ ++} while (0) ++ ++ ++/* SCC status checking */ ++#define __scc_check_transfer_status(base) ( REG_SCC_SR(base) & SCC_SR_TRANS ) ++#define __scc_check_rx_overrun_error(base) ( REG_SCC_SR(base) & SCC_SR_ORER ) ++#define __scc_check_rx_timeout(base) ( REG_SCC_SR(base) & SCC_SR_RTO ) ++#define __scc_check_parity_error(base) ( REG_SCC_SR(base) & SCC_SR_PER ) ++#define __scc_check_txfifo_trigger(base) ( REG_SCC_SR(base) & SCC_SR_TFTG ) ++#define __scc_check_rxfifo_trigger(base) ( REG_SCC_SR(base) & SCC_SR_RFTG ) ++#define __scc_check_tx_end(base) ( REG_SCC_SR(base) & SCC_SR_TEND ) ++#define __scc_check_retx_3(base) ( REG_SCC_SR(base) & SCC_SR_RETR_3 ) ++#define __scc_check_ecnt_overflow(base) ( REG_SCC_SR(base) & SCC_SR_ECNTO ) ++ ++ ++/*************************************************************************** ++ * WDT ++ ***************************************************************************/ ++ ++#define __wdt_set_count(count) ( REG_WDT_WTCNT = (count) ) ++#define __wdt_start() ( REG_WDT_WTCSR |= WDT_WTCSR_START ) ++#define __wdt_stop() ( REG_WDT_WTCSR &= ~WDT_WTCSR_START ) ++ ++ ++/*************************************************************************** ++ * OST ++ ***************************************************************************/ ++ ++#define __ost_enable_all() ( REG_OST_TER |= 0x07 ) ++#define __ost_disable_all() ( REG_OST_TER &= ~0x07 ) ++#define __ost_enable_channel(n) ( REG_OST_TER |= (1 << (n)) ) ++#define __ost_disable_channel(n) ( REG_OST_TER &= ~(1 << (n)) ) ++#define __ost_set_reload(n, val) ( REG_OST_TRDR(n) = (val) ) ++#define __ost_set_count(n, val) ( REG_OST_TCNT(n) = (val) ) ++#define __ost_get_count(n) ( REG_OST_TCNT(n) ) ++#define __ost_set_clock(n, cs) \ ++do { \ ++ REG_OST_TCSR(n) &= ~OST_TCSR_CKS_MASK; \ ++ REG_OST_TCSR(n) |= cs; \ ++} while (0) ++#define __ost_set_mode(n, val) ( REG_OST_TCSR(n) = (val) ) ++#define __ost_enable_interrupt(n) ( REG_OST_TCSR(n) |= OST_TCSR_UIE ) ++#define __ost_disable_interrupt(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_UIE ) ++#define __ost_uf_detected(n) ( REG_OST_TCSR(n) & OST_TCSR_UF ) ++#define __ost_clear_uf(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_UF ) ++#define __ost_is_busy(n) ( REG_OST_TCSR(n) & OST_TCSR_BUSY ) ++#define __ost_clear_busy(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_BUSY ) ++ ++ ++/*************************************************************************** ++ * UART ++ ***************************************************************************/ ++ ++#define __uart_enable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) ++#define __uart_disable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) ++ ++#define __uart_enable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) ++#define __uart_disable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) ++ ++#define __uart_enable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) ++#define __uart_disable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) ++ ++#define __uart_enable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) ++#define __uart_disable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) ++ ++#define __uart_set_8n1(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) ++ ++#define __uart_set_baud(n, devclk, baud) \ ++ do { \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ ++ } while (0) ++ ++#define __uart_parity_error(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) ++ ++#define __uart_clear_errors(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) ++ ++#define __uart_transmit_fifo_empty(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) ++ ++#define __uart_transmit_end(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) ++ ++#define __uart_transmit_char(n, ch) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) ++ ++#define __uart_receive_fifo_full(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_ready(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_char(n) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) ++ ++#define __uart_disable_irda() \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) ++#define __uart_enable_irda() \ ++ /* Tx high pulse as 0, Rx low pulse as 0 */ \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) ++ ++ ++/*************************************************************************** ++ * INTC ++ ***************************************************************************/ ++#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) ++#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) ++#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) ++ ++/*************************************************************************** ++ * CIM ++ ***************************************************************************/ ++ ++#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) ++#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) ++ ++#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT ) ++#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT ) ++ ++#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP ) ++#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP ) ++ ++#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP ) ++#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP ) ++ ++#define __cim_sample_data_at_pclk_falling_edge() \ ++ ( REG_CIM_CFG |= CIM_CFG_PCP ) ++#define __cim_sample_data_at_pclk_rising_edge() \ ++ ( REG_CIM_CFG &= ~CIM_CFG_PCP ) ++ ++#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO ) ++#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO ) ++ ++#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC ) ++#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC ) ++ ++/* n=0-7 */ ++#define __cim_set_data_packing_mode(n) \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \ ++ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \ ++} while (0) ++ ++#define __cim_enable_ccir656_progressive_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \ ++} while (0) ++ ++#define __cim_enable_ccir656_interlace_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \ ++} while (0) ++ ++#define __cim_enable_gated_clock_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \ ++} while (0) ++ ++#define __cim_enable_nongated_clock_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \ ++} while (0) ++ ++/* sclk:system bus clock ++ * mclk: CIM master clock ++ */ ++#define __cim_set_master_clk(sclk, mclk) \ ++do { \ ++ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \ ++ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \ ++} while (0) ++ ++#define __cim_enable_sof_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM ) ++#define __cim_disable_sof_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM ) ++ ++#define __cim_enable_eof_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM ) ++#define __cim_disable_eof_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM ) ++ ++#define __cim_enable_stop_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM ) ++#define __cim_disable_stop_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM ) ++ ++#define __cim_enable_trig_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM ) ++#define __cim_disable_trig_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM ) ++ ++#define __cim_enable_rxfifo_overflow_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM ) ++#define __cim_disable_rxfifo_overflow_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM ) ++ ++/* n=1-16 */ ++#define __cim_set_frame_rate(n) \ ++do { \ ++ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \ ++ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \ ++} while (0) ++ ++#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN ) ++#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN ) ++ ++#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST ) ++#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST ) ++ ++/* n=4,8,12,16,20,24,28,32 */ ++#define __cim_set_rxfifo_trigger(n) \ ++do { \ ++ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \ ++ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \ ++} while (0) ++ ++#define __cim_clear_state() ( REG_CIM_STATE = 0 ) ++ ++#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD ) ++#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY ) ++#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG ) ++#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF ) ++#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF ) ++#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP ) ++#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF ) ++#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF ) ++ ++#define __cim_get_iid() ( REG_CIM_IID ) ++#define __cim_get_image_data() ( REG_CIM_RXFIFO ) ++#define __cim_get_dam_cmd() ( REG_CIM_CMD ) ++ ++#define __cim_set_da(a) ( REG_CIM_DA = (a) ) ++ ++/*************************************************************************** ++ * PWM ++ ***************************************************************************/ ++ ++/* n is the pwm channel (0,1,..) */ ++#define __pwm_enable_module(n) ( REG_PWM_CTR(n) |= PWM_CTR_EN ) ++#define __pwm_disable_module(n) ( REG_PWM_CTR(n) &= ~PWM_CTR_EN ) ++#define __pwm_graceful_shutdown_mode(n) ( REG_PWM_CTR(n) &= ~PWM_CTR_SD ) ++#define __pwm_abrupt_shutdown_mode(n) ( REG_PWM_CTR(n) |= PWM_CTR_SD ) ++#define __pwm_set_full_duty(n) ( REG_PWM_DUT(n) |= PWM_DUT_FDUTY ) ++ ++#define __pwm_set_prescale(n, p) \ ++ ( REG_PWM_CTR(n) = ((REG_PWM_CTR(n) & ~PWM_CTR_PRESCALE_MASK) | (p) ) ) ++#define __pwm_set_period(n, p) \ ++ ( REG_PWM_PER(n) = ( (REG_PWM_PER(n) & ~PWM_PER_PERIOD_MASK) | (p) ) ) ++#define __pwm_set_duty(n, d) \ ++ ( REG_PWM_DUT(n) = ( (REG_PWM_DUT(n) & ~(PWM_DUT_FDUTY | PWM_DUT_DUTY_MASK)) | (d) ) ) ++ ++/*************************************************************************** ++ * EMC ++ ***************************************************************************/ ++ ++#define __emc_enable_split() ( REG_EMC_BCR = EMC_BCR_BRE ) ++#define __emc_disable_split() ( REG_EMC_BCR = 0 ) ++ ++#define __emc_smem_bus_width(n) /* 8, 16 or 32*/ \ ++ ( REG_EMC_SMCR = (REG_EMC_SMCR & EMC_SMCR_BW_MASK) | \ ++ EMC_SMCR_BW_##n##BIT ) ++#define __emc_smem_byte_control() \ ++ ( REG_EMC_SMCR = (REG_EMC_SMCR | EMC_SMCR_BCM ) ++#define __emc_normal_smem() \ ++ ( REG_EMC_SMCR = (REG_EMC_SMCR & ~EMC_SMCR_SMT ) ++#define __emc_burst_smem() \ ++ ( REG_EMC_SMCR = (REG_EMC_SMCR | EMC_SMCR_SMT ) ++#define __emc_smem_burstlen(n) /* 4, 8, 16 or 32 */ \ ++ ( REG_EMC_SMCR = (REG_EMC_SMCR & EMC_SMCR_BL_MASK) | (EMC_SMCR_BL_##n ) ++ ++/*************************************************************************** ++ * GPIO ++ ***************************************************************************/ ++ ++/* p is the port number (0,1,2,3) ++ * o is the pin offset (0-31) inside the port ++ * n is the absolute number of a pin (0-124), regardless of the port ++ * m is the interrupt manner (low/high/falling/rising) ++ */ ++ ++#define __gpio_port_data(p) ( REG_GPIO_GPDR(p) ) ++ ++#define __gpio_port_as_output(p, o) \ ++do { \ ++ unsigned int tmp; \ ++ REG_GPIO_GPIER(p) &= ~(1 << (o)); \ ++ REG_GPIO_GPDIR(p) |= (1 << (o)); \ ++ if (o < 16) { \ ++ tmp = REG_GPIO_GPALR(p); \ ++ tmp &= ~(3 << ((o) << 1)); \ ++ REG_GPIO_GPALR(p) = tmp; \ ++ } else { \ ++ tmp = REG_GPIO_GPAUR(p); \ ++ tmp &= ~(3 << (((o) - 16)<< 1)); \ ++ REG_GPIO_GPAUR(p) = tmp; \ ++ } \ ++} while (0) ++ ++#define __gpio_port_as_input(p, o) \ ++do { \ ++ unsigned int tmp; \ ++ REG_GPIO_GPIER(p) &= ~(1 << (o)); \ ++ REG_GPIO_GPDIR(p) &= ~(1 << (o)); \ ++ if (o < 16) { \ ++ tmp = REG_GPIO_GPALR(p); \ ++ tmp &= ~(3 << ((o) << 1)); \ ++ REG_GPIO_GPALR(p) = tmp; \ ++ } else { \ ++ tmp = REG_GPIO_GPAUR(p); \ ++ tmp &= ~(3 << (((o) - 16)<< 1)); \ ++ REG_GPIO_GPAUR(p) = tmp; \ ++ } \ ++} while (0) ++ ++#define __gpio_as_output(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_output(p, o); \ ++} while (0) ++ ++#define __gpio_as_input(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_input(p, o); \ ++} while (0) ++ ++#define __gpio_set_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_data(p) |= (1 << o); \ ++} while (0) ++ ++#define __gpio_clear_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_data(p) &= ~(1 << o); \ ++} while (0) ++ ++static __inline__ unsigned int __gpio_get_pin(unsigned int n) ++{ ++ unsigned int p, o; ++ p = (n) / 32; ++ o = (n) % 32; ++ if (__gpio_port_data(p) & (1 << o)) ++ return 1; ++ else ++ return 0; ++} ++ ++#define __gpio_set_irq_detect_manner(p, o, m) \ ++do { \ ++ unsigned int tmp; \ ++ if (o < 16) { \ ++ tmp = REG_GPIO_GPIDLR(p); \ ++ tmp &= ~(3 << ((o) << 1)); \ ++ tmp |= ((m) << ((o) << 1)); \ ++ REG_GPIO_GPIDLR(p) = tmp; \ ++ } else { \ ++ tmp = REG_GPIO_GPIDUR(p); \ ++ tmp &= ~(3 << (((o)-16) << 1)); \ ++ tmp |= ((m) << (((o)-16) << 1)); \ ++ REG_GPIO_GPIDUR(p) = tmp; \ ++ } \ ++} while (0) ++ ++#define __gpio_port_as_irq(p, o, m) \ ++do { \ ++ __gpio_port_as_input(p, o); \ ++ __gpio_set_irq_detect_manner(p, o, m); \ ++} while (0) ++ ++#define __gpio_as_irq(n, m) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_irq(p, o, m); \ ++} while (0) ++ ++ ++#define __gpio_as_irq_high_level(n) __gpio_as_irq(n, GPIO_IRQ_HILEVEL) ++#define __gpio_as_irq_low_level(n) __gpio_as_irq(n, GPIO_IRQ_LOLEVEL) ++#define __gpio_as_irq_fall_edge(n) __gpio_as_irq(n, GPIO_IRQ_FALLEDG) ++#define __gpio_as_irq_rise_edge(n) __gpio_as_irq(n, GPIO_IRQ_RAISEDG) ++ ++ ++#define __gpio_mask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_GPIER(p) &= ~(1 << o); \ ++} while (0) ++ ++#define __gpio_unmask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_GPIER(p) |= (1 << o); \ ++} while (0) ++ ++#define __gpio_ack_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_GPFR(p) |= (1 << o); \ ++} while (0) ++ ++ ++static __inline__ unsigned int __gpio_get_irq(void) ++{ ++ unsigned int tmp, i; ++ ++ tmp = REG_GPIO_GPFR(3); ++ for (i=0; i<32; i++) ++ if (tmp & (1 << i)) ++ return 0x60 + i; ++ tmp = REG_GPIO_GPFR(2); ++ for (i=0; i<32; i++) ++ if (tmp & (1 << i)) ++ return 0x40 + i; ++ tmp = REG_GPIO_GPFR(1); ++ for (i=0; i<32; i++) ++ if (tmp & (1 << i)) ++ return 0x20 + i; ++ tmp = REG_GPIO_GPFR(0); ++ for (i=0; i<32; i++) ++ if (tmp & (1 << i)) ++ return i; ++ return 0; ++} ++ ++#define __gpio_group_irq(n) \ ++({ \ ++ register int tmp, i; \ ++ tmp = REG_GPIO_GPFR((n)); \ ++ for (i=31;i>=0;i--) \ ++ if (tmp & (1 << i)) \ ++ break; \ ++ i; \ ++}) ++ ++#define __gpio_enable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_GPPUR(p) |= (1 << o); \ ++} while (0) ++ ++#define __gpio_disable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_GPPUR(p) &= ~(1 << o); \ ++} while (0) ++ ++ ++/* Init the alternate function pins */ ++ ++ ++#define __gpio_as_ssi() \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0xFC00FFFF; \ ++ REG_GPIO_GPALR(2) |= 0x01550000; \ ++} while (0) ++ ++#define __gpio_as_uart3() \ ++do { \ ++ REG_GPIO_GPAUR(0) &= 0xFFFF0000; \ ++ REG_GPIO_GPAUR(0) |= 0x00005555; \ ++} while (0) ++ ++#define __gpio_as_uart2() \ ++do { \ ++ REG_GPIO_GPALR(3) &= 0x3FFFFFFF; \ ++ REG_GPIO_GPALR(3) |= 0x40000000; \ ++ REG_GPIO_GPAUR(3) &= 0xF3FFFFFF; \ ++ REG_GPIO_GPAUR(3) |= 0x04000000; \ ++} while (0) ++ ++#define __gpio_as_uart1() \ ++do { \ ++ REG_GPIO_GPAUR(0) &= 0xFFF0FFFF; \ ++ REG_GPIO_GPAUR(0) |= 0x00050000; \ ++} while (0) ++ ++#define __gpio_as_uart0() \ ++do { \ ++ REG_GPIO_GPAUR(3) &= 0x0FFFFFFF; \ ++ REG_GPIO_GPAUR(3) |= 0x50000000; \ ++} while (0) ++ ++ ++#define __gpio_as_scc0() \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0xFFFFFFCC; \ ++ REG_GPIO_GPALR(2) |= 0x00000011; \ ++} while (0) ++ ++#define __gpio_as_scc1() \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0xFFFFFF33; \ ++ REG_GPIO_GPALR(2) |= 0x00000044; \ ++} while (0) ++ ++#define __gpio_as_scc() \ ++do { \ ++ __gpio_as_scc0(); \ ++ __gpio_as_scc1(); \ ++} while (0) ++ ++#define __gpio_as_dma() \ ++do { \ ++ REG_GPIO_GPALR(0) &= 0x00FFFFFF; \ ++ REG_GPIO_GPALR(0) |= 0x55000000; \ ++ REG_GPIO_GPAUR(0) &= 0xFF0FFFFF; \ ++ REG_GPIO_GPAUR(0) |= 0x00500000; \ ++} while (0) ++ ++#define __gpio_as_msc() \ ++do { \ ++ REG_GPIO_GPALR(1) &= 0xFFFF000F; \ ++ REG_GPIO_GPALR(1) |= 0x00005550; \ ++} while (0) ++ ++#define __gpio_as_pcmcia() \ ++do { \ ++ REG_GPIO_GPAUR(2) &= 0xF000FFFF; \ ++ REG_GPIO_GPAUR(2) |= 0x05550000; \ ++} while (0) ++ ++#define __gpio_as_emc(csmask) \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0x3FFFFFFF; \ ++ REG_GPIO_GPALR(2) |= 0x40000000; \ ++ REG_GPIO_GPAUR(2) &= 0xFFFF0000; \ ++ REG_GPIO_GPAUR(2) |= 0x00005555; \ ++} while (0) ++ ++#define __gpio_as_lcd_slave() \ ++do { \ ++ REG_GPIO_GPALR(1) &= 0x0000FFFF; \ ++ REG_GPIO_GPALR(1) |= 0x55550000; \ ++ REG_GPIO_GPAUR(1) &= 0x00000000; \ ++ REG_GPIO_GPAUR(1) |= 0x55555555; \ ++} while (0) ++ ++#define __gpio_as_lcd_master() \ ++do { \ ++ REG_GPIO_GPALR(1) &= 0x0000FFFF; \ ++ REG_GPIO_GPALR(1) |= 0x55550000; \ ++ REG_GPIO_GPAUR(1) &= 0x00000000; \ ++ REG_GPIO_GPAUR(1) |= 0x556A5555; \ ++} while (0) ++ ++#define __gpio_as_usb() \ ++do { \ ++ REG_GPIO_GPAUR(0) &= 0x00FFFFFF; \ ++ REG_GPIO_GPAUR(0) |= 0x55000000; \ ++} while (0) ++ ++#define __gpio_as_ac97() \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0xC3FF03FF; \ ++ REG_GPIO_GPALR(2) |= 0x24005400; \ ++} while (0) ++ ++#define __gpio_as_i2s_slave() \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; \ ++ REG_GPIO_GPALR(2) |= 0x14005100; \ ++} while (0) ++ ++#define __gpio_as_i2s_master() \ ++do { \ ++ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; \ ++ REG_GPIO_GPALR(2) |= 0x28005100; \ ++} while (0) ++ ++#define __gpio_as_eth() \ ++do { \ ++ REG_GPIO_GPAUR(3) &= 0xFC000000; \ ++ REG_GPIO_GPAUR(3) |= 0x01555555; \ ++} while (0) ++ ++#define __gpio_as_pwm() \ ++do { \ ++ REG_GPIO_GPAUR(2) &= 0x0FFFFFFF; \ ++ REG_GPIO_GPAUR(2) |= 0x50000000; \ ++} while (0) ++ ++#define __gpio_as_ps2() \ ++do { \ ++ REG_GPIO_GPALR(1) &= 0xFFFFFFF0; \ ++ REG_GPIO_GPALR(1) |= 0x00000005; \ ++} while (0) ++ ++#define __gpio_as_uprt() \ ++do { \ ++ REG_GPIO_GPALR(1) &= 0x0000000F; \ ++ REG_GPIO_GPALR(1) |= 0x55555550; \ ++ REG_GPIO_GPALR(3) &= 0xC0000000; \ ++ REG_GPIO_GPALR(3) |= 0x15555555; \ ++} while (0) ++ ++#define __gpio_as_cim() \ ++do { \ ++ REG_GPIO_GPALR(0) &= 0xFF000000; \ ++ REG_GPIO_GPALR(0) |= 0x00555555; \ ++} while (0) ++ ++/*************************************************************************** ++ * HARB ++ ***************************************************************************/ ++ ++#define __harb_usb0_udc() \ ++do { \ ++ REG_HARB_HAPOR &= ~HARB_HAPOR_UCHSEL; \ ++} while (0) ++ ++#define __harb_usb0_uhc() \ ++do { \ ++ REG_HARB_HAPOR |= HARB_HAPOR_UCHSEL; \ ++} while (0) ++ ++#define __harb_set_priority(n) \ ++do { \ ++ REG_HARB_HAPOR = ((REG_HARB_HAPOR & ~HARB_HAPOR_PRIO_MASK) | n); \ ++} while (0) ++ ++/*************************************************************************** ++ * I2C ++ ***************************************************************************/ ++ ++#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) ++#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) ++ ++#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) ++#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) ++#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) ++#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) ++ ++#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) ++#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) ++#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) ++ ++#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) ++#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) ++#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) ++ ++#define __i2c_set_clk(dev_clk, i2c_clk) \ ++ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) ++ ++#define __i2c_read() ( REG_I2C_DR ) ++#define __i2c_write(val) ( REG_I2C_DR = (val) ) ++ ++/*************************************************************************** ++ * UDC ++ ***************************************************************************/ ++ ++#define __udc_set_16bit_phy() ( REG_UDC_DevCFGR |= UDC_DevCFGR_PI ) ++#define __udc_set_8bit_phy() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_PI ) ++ ++#define __udc_enable_sync_frame() ( REG_UDC_DevCFGR |= UDC_DevCFGR_SS ) ++#define __udc_disable_sync_frame() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_SS ) ++ ++#define __udc_self_powered() ( REG_UDC_DevCFGR |= UDC_DevCFGR_SP ) ++#define __udc_bus_powered() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_SP ) ++ ++#define __udc_enable_remote_wakeup() ( REG_UDC_DevCFGR |= UDC_DevCFGR_RW ) ++#define __udc_disable_remote_wakeup() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_RW ) ++ ++#define __udc_set_speed_high() \ ++do { \ ++ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \ ++ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_HS; \ ++} while (0) ++ ++#define __udc_set_speed_full() \ ++do { \ ++ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \ ++ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_FS; \ ++} while (0) ++ ++#define __udc_set_speed_low() \ ++do { \ ++ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \ ++ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_LS; \ ++} while (0) ++ ++ ++#define __udc_set_dma_mode() ( REG_UDC_DevCR |= UDC_DevCR_DM ) ++#define __udc_set_slave_mode() ( REG_UDC_DevCR &= ~UDC_DevCR_DM ) ++#define __udc_set_big_endian() ( REG_UDC_DevCR |= UDC_DevCR_BE ) ++#define __udc_set_little_endian() ( REG_UDC_DevCR &= ~UDC_DevCR_BE ) ++#define __udc_generate_resume() ( REG_UDC_DevCR |= UDC_DevCR_RES ) ++#define __udc_clear_resume() ( REG_UDC_DevCR &= ~UDC_DevCR_RES ) ++ ++ ++#define __udc_get_enumarated_speed() ( REG_UDC_DevSR & UDC_DevSR_ENUMSPD_MASK ) ++#define __udc_suspend_detected() ( REG_UDC_DevSR & UDC_DevSR_SUSP ) ++#define __udc_get_alternate_setting() ( (REG_UDC_DevSR & UDC_DevSR_ALT_MASK) >> UDC_DevSR_ALT_BIT ) ++#define __udc_get_interface_number() ( (REG_UDC_DevSR & UDC_DevSR_INTF_MASK) >> UDC_DevSR_INTF_BIT ) ++#define __udc_get_config_number() ( (REG_UDC_DevSR & UDC_DevSR_CFG_MASK) >> UDC_DevSR_CFG_BIT ) ++ ++ ++#define __udc_sof_detected(r) ( (r) & UDC_DevIntR_SOF ) ++#define __udc_usb_suspend_detected(r) ( (r) & UDC_DevIntR_US ) ++#define __udc_usb_reset_detected(r) ( (r) & UDC_DevIntR_UR ) ++#define __udc_set_interface_detected(r) ( (r) & UDC_DevIntR_SI ) ++#define __udc_set_config_detected(r) ( (r) & UDC_DevIntR_SC ) ++ ++#define __udc_clear_sof() ( REG_UDC_DevIntR |= UDC_DevIntR_SOF ) ++#define __udc_clear_usb_suspend() ( REG_UDC_DevIntR |= UDC_DevIntR_US ) ++#define __udc_clear_usb_reset() ( REG_UDC_DevIntR |= UDC_DevIntR_UR ) ++#define __udc_clear_set_interface() ( REG_UDC_DevIntR |= UDC_DevIntR_SI ) ++#define __udc_clear_set_config() ( REG_UDC_DevIntR |= UDC_DevIntR_SC ) ++ ++#define __udc_mask_sof() ( REG_UDC_DevIntMR |= UDC_DevIntR_SOF ) ++#define __udc_mask_usb_suspend() ( REG_UDC_DevIntMR |= UDC_DevIntR_US ) ++#define __udc_mask_usb_reset() ( REG_UDC_DevIntMR |= UDC_DevIntR_UR ) ++#define __udc_mask_set_interface() ( REG_UDC_DevIntMR |= UDC_DevIntR_SI ) ++#define __udc_mask_set_config() ( REG_UDC_DevIntMR |= UDC_DevIntR_SC ) ++#define __udc_mask_all_dev_intrs() \ ++ ( REG_UDC_DevIntMR = UDC_DevIntR_SOF | UDC_DevIntR_US | \ ++ UDC_DevIntR_UR | UDC_DevIntR_SI | UDC_DevIntR_SC ) ++ ++#define __udc_unmask_sof() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SOF ) ++#define __udc_unmask_usb_suspend() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_US ) ++#define __udc_unmask_usb_reset() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_UR ) ++#define __udc_unmask_set_interface() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SI ) ++#define __udc_unmask_set_config() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SC ) ++#if 0 ++#define __udc_unmask_all_dev_intrs() \ ++ ( REG_UDC_DevIntMR = ~(UDC_DevIntR_SOF | UDC_DevIntR_US | \ ++ UDC_DevIntR_UR | UDC_DevIntR_SI | UDC_DevIntR_SC) ) ++#else ++#define __udc_unmask_all_dev_intrs() \ ++ ( REG_UDC_DevIntMR = 0x00000000 ) ++#endif ++ ++ ++#define __udc_ep0out_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 0)) & 0x1 ) ++#define __udc_ep5out_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 5)) & 0x1 ) ++#define __udc_ep6out_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 6)) & 0x1 ) ++#define __udc_ep7out_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 7)) & 0x1 ) ++ ++#define __udc_ep0in_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 0)) & 0x1 ) ++#define __udc_ep1in_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 1)) & 0x1 ) ++#define __udc_ep2in_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 2)) & 0x1 ) ++#define __udc_ep3in_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 3)) & 0x1 ) ++#define __udc_ep4in_irq_detected(epintr) \ ++ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 4)) & 0x1 ) ++ ++ ++#define __udc_mask_ep0out_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 0)) ) ++#define __udc_mask_ep5out_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 5)) ) ++#define __udc_mask_ep6out_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 6)) ) ++#define __udc_mask_ep7out_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 7)) ) ++ ++#define __udc_unmask_ep0out_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 0)) ) ++#define __udc_unmask_ep5out_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 5)) ) ++#define __udc_unmask_ep6out_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 6)) ) ++#define __udc_unmask_ep7out_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 7)) ) ++ ++#define __udc_mask_ep0in_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 0)) ) ++#define __udc_mask_ep1in_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 1)) ) ++#define __udc_mask_ep2in_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 2)) ) ++#define __udc_mask_ep3in_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 3)) ) ++#define __udc_mask_ep4in_irq() \ ++ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 4)) ) ++ ++#define __udc_unmask_ep0in_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 0)) ) ++#define __udc_unmask_ep1in_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 1)) ) ++#define __udc_unmask_ep2in_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 2)) ) ++#define __udc_unmask_ep3in_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 3)) ) ++#define __udc_unmask_ep4in_irq() \ ++ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 4)) ) ++ ++#define __udc_mask_all_ep_intrs() \ ++ ( REG_UDC_EPIntMR = 0xffffffff ) ++#define __udc_unmask_all_ep_intrs() \ ++ ( REG_UDC_EPIntMR = 0x00000000 ) ++ ++ ++/* ep0 only CTRL, ep1 only INTR, ep2/3/5/6 only BULK, ep4/7 only ISO */ ++#define __udc_config_endpoint_type() \ ++do { \ ++ REG_UDC_EP0InCR = (REG_UDC_EP0InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_CTRL; \ ++ REG_UDC_EP0OutCR = (REG_UDC_EP0OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_CTRL; \ ++ REG_UDC_EP1InCR = (REG_UDC_EP1InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_INTR; \ ++ REG_UDC_EP2InCR = (REG_UDC_EP2InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ ++ REG_UDC_EP3InCR = (REG_UDC_EP3InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ ++ REG_UDC_EP4InCR = (REG_UDC_EP4InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_ISO; \ ++ REG_UDC_EP5OutCR = (REG_UDC_EP5OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ ++ REG_UDC_EP6OutCR = (REG_UDC_EP6OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ ++ REG_UDC_EP7OutCR = (REG_UDC_EP7OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_ISO; \ ++} while (0) ++ ++#define __udc_enable_ep0out_snoop_mode() ( REG_UDC_EP0OutCR |= UDC_EPCR_SN ) ++#define __udc_enable_ep5out_snoop_mode() ( REG_UDC_EP5OutCR |= UDC_EPCR_SN ) ++#define __udc_enable_ep6out_snoop_mode() ( REG_UDC_EP6OutCR |= UDC_EPCR_SN ) ++#define __udc_enable_ep7out_snoop_mode() ( REG_UDC_EP7OutCR |= UDC_EPCR_SN ) ++ ++#define __udc_disable_ep0out_snoop_mode() ( REG_UDC_EP0OutCR &= ~UDC_EPCR_SN ) ++#define __udc_disable_ep5out_snoop_mode() ( REG_UDC_EP5OutCR &= ~UDC_EPCR_SN ) ++#define __udc_disable_ep6out_snoop_mode() ( REG_UDC_EP6OutCR &= ~UDC_EPCR_SN ) ++#define __udc_disable_ep7out_snoop_mode() ( REG_UDC_EP7OutCR &= ~UDC_EPCR_SN ) ++ ++#define __udc_flush_ep0in_fifo() ( REG_UDC_EP0InCR |= UDC_EPCR_F ) ++#define __udc_flush_ep1in_fifo() ( REG_UDC_EP1InCR |= UDC_EPCR_F ) ++#define __udc_flush_ep2in_fifo() ( REG_UDC_EP2InCR |= UDC_EPCR_F ) ++#define __udc_flush_ep3in_fifo() ( REG_UDC_EP3InCR |= UDC_EPCR_F ) ++#define __udc_flush_ep4in_fifo() ( REG_UDC_EP4InCR |= UDC_EPCR_F ) ++ ++#define __udc_unflush_ep0in_fifo() ( REG_UDC_EP0InCR &= ~UDC_EPCR_F ) ++#define __udc_unflush_ep1in_fifo() ( REG_UDC_EP1InCR &= ~UDC_EPCR_F ) ++#define __udc_unflush_ep2in_fifo() ( REG_UDC_EP2InCR &= ~UDC_EPCR_F ) ++#define __udc_unflush_ep3in_fifo() ( REG_UDC_EP3InCR &= ~UDC_EPCR_F ) ++#define __udc_unflush_ep4in_fifo() ( REG_UDC_EP4InCR &= ~UDC_EPCR_F ) ++ ++#define __udc_enable_ep0in_stall() ( REG_UDC_EP0InCR |= UDC_EPCR_S ) ++#define __udc_enable_ep0out_stall() ( REG_UDC_EP0OutCR |= UDC_EPCR_S ) ++#define __udc_enable_ep1in_stall() ( REG_UDC_EP1InCR |= UDC_EPCR_S ) ++#define __udc_enable_ep2in_stall() ( REG_UDC_EP2InCR |= UDC_EPCR_S ) ++#define __udc_enable_ep3in_stall() ( REG_UDC_EP3InCR |= UDC_EPCR_S ) ++#define __udc_enable_ep4in_stall() ( REG_UDC_EP4InCR |= UDC_EPCR_S ) ++#define __udc_enable_ep5out_stall() ( REG_UDC_EP5OutCR |= UDC_EPCR_S ) ++#define __udc_enable_ep6out_stall() ( REG_UDC_EP6OutCR |= UDC_EPCR_S ) ++#define __udc_enable_ep7out_stall() ( REG_UDC_EP7OutCR |= UDC_EPCR_S ) ++ ++#define __udc_disable_ep0in_stall() ( REG_UDC_EP0InCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep0out_stall() ( REG_UDC_EP0OutCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep1in_stall() ( REG_UDC_EP1InCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep2in_stall() ( REG_UDC_EP2InCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep3in_stall() ( REG_UDC_EP3InCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep4in_stall() ( REG_UDC_EP4InCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep5out_stall() ( REG_UDC_EP5OutCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep6out_stall() ( REG_UDC_EP6OutCR &= ~UDC_EPCR_S ) ++#define __udc_disable_ep7out_stall() ( REG_UDC_EP7OutCR &= ~UDC_EPCR_S ) ++ ++ ++#define __udc_ep0out_packet_size() \ ++ ( (REG_UDC_EP0OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) ++#define __udc_ep5out_packet_size() \ ++ ( (REG_UDC_EP5OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) ++#define __udc_ep6out_packet_size() \ ++ ( (REG_UDC_EP6OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) ++#define __udc_ep7out_packet_size() \ ++ ( (REG_UDC_EP7OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) ++ ++#define __udc_ep0in_received_intoken() ( (REG_UDC_EP0InSR & UDC_EPSR_IN) ) ++#define __udc_ep1in_received_intoken() ( (REG_UDC_EP1InSR & UDC_EPSR_IN) ) ++#define __udc_ep2in_received_intoken() ( (REG_UDC_EP2InSR & UDC_EPSR_IN) ) ++#define __udc_ep3in_received_intoken() ( (REG_UDC_EP3InSR & UDC_EPSR_IN) ) ++#define __udc_ep4in_received_intoken() ( (REG_UDC_EP4InSR & UDC_EPSR_IN) ) ++ ++#define __udc_ep0out_received_none() \ ++ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) ++#define __udc_ep0out_received_data() \ ++ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) ++#define __udc_ep0out_received_setup() \ ++ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) ++ ++#define __udc_ep5out_received_none() \ ++ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) ++#define __udc_ep5out_received_data() \ ++ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) ++#define __udc_ep5out_received_setup() \ ++ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) ++ ++#define __udc_ep6out_received_none() \ ++ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) ++#define __udc_ep6out_received_data() \ ++ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) ++#define __udc_ep6out_received_setup() \ ++ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) ++ ++#define __udc_ep7out_received_none() \ ++ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) ++#define __udc_ep7out_received_data() \ ++ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) ++#define __udc_ep7out_received_setup() \ ++ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) ++ ++/* ep7out ISO only */ ++#define __udc_ep7out_get_pid() \ ++ ( (REG_UDC_EP7OutSR & UDC_EPSR_PID_MASK) >> UDC_EPSR_PID_BIT ) ++ ++ ++#define __udc_ep0in_set_buffer_size(n) ( REG_UDC_EP0InBSR = (n) ) ++#define __udc_ep1in_set_buffer_size(n) ( REG_UDC_EP1InBSR = (n) ) ++#define __udc_ep2in_set_buffer_size(n) ( REG_UDC_EP2InBSR = (n) ) ++#define __udc_ep3in_set_buffer_size(n) ( REG_UDC_EP3InBSR = (n) ) ++#define __udc_ep4in_set_buffer_size(n) ( REG_UDC_EP4InBSR = (n) ) ++ ++#define __udc_ep0out_get_frame_number(n) ( UDC_EP0OutPFNR ) ++#define __udc_ep5out_get_frame_number(n) ( UDC_EP5OutPFNR ) ++#define __udc_ep6out_get_frame_number(n) ( UDC_EP6OutPFNR ) ++#define __udc_ep7out_get_frame_number(n) ( UDC_EP7OutPFNR ) ++ ++ ++#define __udc_ep0in_set_max_packet_size(n) ( REG_UDC_EP0InMPSR = (n) ) ++#define __udc_ep0out_set_max_packet_size(n) ( REG_UDC_EP0OutMPSR = (n) ) ++#define __udc_ep1in_set_max_packet_size(n) ( REG_UDC_EP1InMPSR = (n) ) ++#define __udc_ep2in_set_max_packet_size(n) ( REG_UDC_EP2InMPSR = (n) ) ++#define __udc_ep3in_set_max_packet_size(n) ( REG_UDC_EP3InMPSR = (n) ) ++#define __udc_ep4in_set_max_packet_size(n) ( REG_UDC_EP4InMPSR = (n) ) ++#define __udc_ep5out_set_max_packet_size(n) ( REG_UDC_EP5OutMPSR = (n) ) ++#define __udc_ep6out_set_max_packet_size(n) ( REG_UDC_EP6OutMPSR = (n) ) ++#define __udc_ep7out_set_max_packet_size(n) ( REG_UDC_EP7OutMPSR = (n) ) ++ ++/* set to 0xFFFF for UDC */ ++#define __udc_set_setup_command_address(n) ( REG_UDC_STCMAR = (n) ) ++ ++/* Init and configure EPxInfR(x=0,1,2,3,4,5,6,7) ++ * c: Configuration number to which this endpoint belongs ++ * i: Interface number to which this endpoint belongs ++ * a: Alternate setting to which this endpoint belongs ++ * p: max Packet size of this endpoint ++ */ ++ ++#define __udc_ep0info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP0InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP0InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP0InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP0InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP0InfR |= UDC_EPInfR_EPT_CTRL; \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP0InfR |= UDC_EPInfR_EPD_OUT; \ ++ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP0InfR |= (0 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep1info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP1InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP1InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP1InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP1InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP1InfR |= UDC_EPInfR_EPT_INTR; \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP1InfR |= UDC_EPInfR_EPD_IN; \ ++ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP1InfR |= (1 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep2info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP2InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP2InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP2InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP2InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP2InfR |= UDC_EPInfR_EPT_BULK; \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP2InfR |= UDC_EPInfR_EPD_IN; \ ++ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP2InfR |= (2 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep3info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP3InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP3InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP3InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP3InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP3InfR |= UDC_EPInfR_EPT_BULK; \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP3InfR |= UDC_EPInfR_EPD_IN; \ ++ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP3InfR |= (3 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep4info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP4InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP4InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP4InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP4InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP4InfR |= UDC_EPInfR_EPT_ISO; \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP4InfR |= UDC_EPInfR_EPD_IN; \ ++ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP4InfR |= (4 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep5info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP5InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP5InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP5InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP5InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP5InfR |= UDC_EPInfR_EPT_BULK; \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP5InfR |= UDC_EPInfR_EPD_OUT; \ ++ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP5InfR |= (5 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep6info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP6InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP6InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP6InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP6InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP6InfR |= UDC_EPInfR_EPT_BULK; \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP6InfR |= UDC_EPInfR_EPD_OUT; \ ++ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP6InfR |= (6 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++#define __udc_ep7info_init(c,i,a,p) \ ++do { \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_MPS_MASK; \ ++ REG_UDC_EP7InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_ALTS_MASK; \ ++ REG_UDC_EP7InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_IFN_MASK; \ ++ REG_UDC_EP7InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_CGN_MASK; \ ++ REG_UDC_EP7InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPT_MASK; \ ++ REG_UDC_EP7InfR |= UDC_EPInfR_EPT_ISO; \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPD; \ ++ REG_UDC_EP7InfR |= UDC_EPInfR_EPD_OUT; \ ++ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPN_MASK; \ ++ REG_UDC_EP7InfR |= (7 << UDC_EPInfR_EPN_BIT); \ ++} while (0) ++ ++ ++/*************************************************************************** ++ * DMAC ++ ***************************************************************************/ ++ ++/* n is the DMA channel (0 - 7) */ ++ ++#define __dmac_enable_all_channels() \ ++ ( REG_DMAC_DMACR |= DMAC_DMACR_DME | DMAC_DMACR_PR_ROUNDROBIN ) ++#define __dmac_disable_all_channels() \ ++ ( REG_DMAC_DMACR &= ~DMAC_DMACR_DME ) ++ ++/* p=0,1,2,3 */ ++#define __dmac_set_priority(p) \ ++do { \ ++ REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \ ++ REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \ ++} while (0) ++ ++#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HTR ) ++#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AER ) ++ ++#define __dmac_enable_channel(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_CHDE ) ++#define __dmac_disable_channel(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_CHDE ) ++#define __dmac_channel_enabled(n) \ ++ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_CHDE ) ++ ++#define __dmac_channel_enable_irq(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_TCIE ) ++#define __dmac_channel_disable_irq(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TCIE ) ++ ++#define __dmac_channel_transmit_halt_detected(n) \ ++ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_HLT ) ++#define __dmac_channel_transmit_end_detected(n) \ ++ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_TC ) ++#define __dmac_channel_address_error_detected(n) \ ++ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_AR ) ++ ++#define __dmac_channel_clear_transmit_halt(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT ) ++#define __dmac_channel_clear_transmit_end(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TC ) ++#define __dmac_channel_clear_address_error(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR ) ++ ++#define __dmac_channel_set_single_mode(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TM ) ++#define __dmac_channel_set_block_mode(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_TM ) ++ ++#define __dmac_channel_set_transfer_unit_32bit(n) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_32b; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16bit(n) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_16b; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_8bit(n) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_8b; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16byte(n) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_16B; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_32byte(n) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_32B; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_dest_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DWDH_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DWDH_##w; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_src_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SWDH_MASK; \ ++ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_SWDH_##w; \ ++} while (0) ++ ++/* v=0-15 */ ++#define __dmac_channel_set_rdil(n,v) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_RDIL_MASK; \ ++ REG_DMAC_DCCSR(n) |= ((v) << DMAC_DCCSR_RDIL_BIT); \ ++} while (0) ++ ++#define __dmac_channel_dest_addr_fixed(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DAM ) ++#define __dmac_channel_dest_addr_increment(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DAM ) ++ ++#define __dmac_channel_src_addr_fixed(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SAM ) ++#define __dmac_channel_src_addr_increment(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_SAM ) ++ ++#define __dmac_channel_set_eop_high(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EOPM ) ++#define __dmac_channel_set_eop_low(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EOPM ) ++ ++#define __dmac_channel_set_erdm(n,m) \ ++do { \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SWDH_MASK; \ ++ REG_DMAC_DCCSR(n) |= ((m) << DMAC_DCCSR_ERDM_BIT); \ ++} while (0) ++ ++#define __dmac_channel_set_eackm(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EACKM ) ++#define __dmac_channel_clear_eackm(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EACKM ) ++ ++#define __dmac_channel_set_eacks(n) \ ++ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EACKS ) ++#define __dmac_channel_clear_eacks(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EACKS ) ++ ++ ++#define __dmac_channel_irq_detected(n) \ ++ ( REG_DMAC_DCCSR(n) & (DMAC_DCCSR_TC | DMAC_DCCSR_AR) ) ++ ++static __inline__ int __dmac_get_irq(void) ++{ ++ int i; ++ for (i=0;i> AIC_SR_TFL_BIT ) ++#define __aic_get_receive_count() \ ++ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) ++ ++#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) ++#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) ++#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) ++#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) ++#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) ++ ++#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) ++ ++#define CODEC_READ_CMD (1 << 19) ++#define CODEC_WRITE_CMD (0 << 19) ++#define CODEC_REG_INDEX_BIT 12 ++#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ ++#define CODEC_REG_DATA_BIT 4 ++#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ ++ ++#define __ac97_out_rcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_wcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_data(value) \ ++do { \ ++ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ ++} while (0) ++ ++#define __ac97_in_data() \ ++ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) ++ ++#define __ac97_in_status_addr() \ ++ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) ++ ++#define __i2s_set_sample_rate(i2sclk, sync) \ ++ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) ++ ++#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) ++#define __aic_read_rfifo() ( REG_AIC_DR ) ++ ++// ++// Define next ops for AC97 compatible ++// ++ ++#define AC97_ACSR AIC_ACSR ++ ++#define __ac97_enable() __aic_enable(); __aic_select_ac97() ++#define __ac97_disable() __aic_disable() ++#define __ac97_reset() __aic_reset() ++ ++#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __ac97_enable_record() __aic_enable_record() ++#define __ac97_disable_record() __aic_disable_record() ++#define __ac97_enable_replay() __aic_enable_replay() ++#define __ac97_disable_replay() __aic_disable_replay() ++#define __ac97_enable_loopback() __aic_enable_loopback() ++#define __ac97_disable_loopback() __aic_disable_loopback() ++ ++#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __ac97_enable_receive_dma() __aic_enable_receive_dma() ++#define __ac97_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __ac97_transmit_request() __aic_transmit_request() ++#define __ac97_receive_request() __aic_receive_request() ++#define __ac97_transmit_underrun() __aic_transmit_underrun() ++#define __ac97_receive_overrun() __aic_receive_overrun() ++ ++#define __ac97_clear_errors() __aic_clear_errors() ++ ++#define __ac97_get_transmit_resident() __aic_get_transmit_resident() ++#define __ac97_get_receive_count() __aic_get_receive_count() ++ ++#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __ac97_enable_receive_intr() __aic_enable_receive_intr() ++#define __ac97_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __ac97_write_tfifo(v) __aic_write_tfifo(v) ++#define __ac97_read_rfifo() __aic_read_rfifo() ++ ++// ++// Define next ops for I2S compatible ++// ++ ++#define I2S_ACSR AIC_I2SSR ++ ++#define __i2s_enable() __aic_enable(); __aic_select_i2s() ++#define __i2s_disable() __aic_disable() ++#define __i2s_reset() __aic_reset() ++ ++#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __i2s_enable_record() __aic_enable_record() ++#define __i2s_disable_record() __aic_disable_record() ++#define __i2s_enable_replay() __aic_enable_replay() ++#define __i2s_disable_replay() __aic_disable_replay() ++#define __i2s_enable_loopback() __aic_enable_loopback() ++#define __i2s_disable_loopback() __aic_disable_loopback() ++ ++#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __i2s_enable_receive_dma() __aic_enable_receive_dma() ++#define __i2s_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __i2s_transmit_request() __aic_transmit_request() ++#define __i2s_receive_request() __aic_receive_request() ++#define __i2s_transmit_underrun() __aic_transmit_underrun() ++#define __i2s_receive_overrun() __aic_receive_overrun() ++ ++#define __i2s_clear_errors() __aic_clear_errors() ++ ++#define __i2s_get_transmit_resident() __aic_get_transmit_resident() ++#define __i2s_get_receive_count() __aic_get_receive_count() ++ ++#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __i2s_enable_receive_intr() __aic_enable_receive_intr() ++#define __i2s_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __i2s_write_tfifo(v) __aic_write_tfifo(v) ++#define __i2s_read_rfifo() __aic_read_rfifo() ++ ++#define __i2s_reset_codec() \ ++ do { \ ++ __gpio_as_output(70); /* SDATA_OUT */ \ ++ __gpio_as_input(71); /* SDATA_IN */ \ ++ __gpio_as_output(78); /* SYNC */ \ ++ __gpio_as_output(69); /* RESET# */ \ ++ __gpio_clear_pin(70); \ ++ __gpio_clear_pin(71); \ ++ __gpio_clear_pin(78); \ ++ __gpio_clear_pin(69); \ ++ __gpio_as_i2s_master(); \ ++ } while (0) ++ ++ ++/*************************************************************************** ++ * LCD ++ ***************************************************************************/ ++ ++#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS ) ++#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS ) ++ ++#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA ) ++#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA ) ++ ++/* n=1,2,4,8,16 */ ++#define __lcd_set_bpp(n) \ ++ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n ) ++ ++/* n=4,8,16 */ ++#define __lcd_set_burst_length(n) \ ++do { \ ++ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \ ++ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \ ++} while (0) ++ ++#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 ) ++#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 ) ++ ++#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP ) ++#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP ) ++ ++/* n=2,4,16 */ ++#define __lcd_set_stn_frc(n) \ ++do { \ ++ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \ ++ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \ ++} while (0) ++ ++ ++#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN ) ++#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN ) ++ ++#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN ) ++#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN ) ++ ++#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM ) ++#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM ) ++ ++#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM ) ++#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM ) ++ ++#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM ) ++#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM ) ++ ++#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 ) ++#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 ) ++ ++#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 ) ++#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 ) ++ ++#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM ) ++#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM ) ++ ++#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM ) ++#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM ) ++ ++ ++/* LCD status register indication */ ++ ++#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD ) ++#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD ) ++#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 ) ++#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 ) ++#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU ) ++#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF ) ++#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF ) ++ ++#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU ) ++#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF ) ++#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF ) ++ ++#define __lcd_panel_white() ( REG_LCD_DEV |= LCD_DEV_WHITE ) ++#define __lcd_panel_black() ( REG_LCD_DEV &= ~LCD_DEV_WHITE ) ++ ++/* n=1,2,4,8 for single mono-STN ++ * n=4,8 for dual mono-STN ++ */ ++#define __lcd_set_panel_datawidth(n) \ ++do { \ ++ REG_LCD_DEV &= ~LCD_DEV_PDW_MASK; \ ++ REG_LCD_DEV |= LCD_DEV_PDW_n##; \ ++} while (0) ++ ++/* m=LCD_DEV_MODE_GENERUIC_TFT_xxx */ ++#define __lcd_set_panel_mode(m) \ ++do { \ ++ REG_LCD_DEV &= ~LCD_DEV_MODE_MASK; \ ++ REG_LCD_DEV |= (m); \ ++} while(0) ++ ++/* n = 0-255 */ ++#define __lcd_disable_ac_bias() ( REG_LCD_IO = 0xff ) ++#define __lcd_set_ac_bias(n) \ ++do { \ ++ REG_LCD_IO &= ~LCD_IO_ACB_MASK; \ ++ REG_LCD_IO |= ((n) << LCD_IO_ACB_BIT); \ ++} while(0) ++ ++#define __lcd_io_set_dir() ( REG_LCD_IO |= LCD_IO_DIR ) ++#define __lcd_io_clr_dir() ( REG_LCD_IO &= ~LCD_IO_DIR ) ++ ++#define __lcd_io_set_dep() ( REG_LCD_IO |= LCD_IO_DEP ) ++#define __lcd_io_clr_dep() ( REG_LCD_IO &= ~LCD_IO_DEP ) ++ ++#define __lcd_io_set_vsp() ( REG_LCD_IO |= LCD_IO_VSP ) ++#define __lcd_io_clr_vsp() ( REG_LCD_IO &= ~LCD_IO_VSP ) ++ ++#define __lcd_io_set_hsp() ( REG_LCD_IO |= LCD_IO_HSP ) ++#define __lcd_io_clr_hsp() ( REG_LCD_IO &= ~LCD_IO_HSP ) ++ ++#define __lcd_io_set_pcp() ( REG_LCD_IO |= LCD_IO_PCP ) ++#define __lcd_io_clr_pcp() ( REG_LCD_IO &= ~LCD_IO_PCP ) ++ ++#define __lcd_vsync_get_vps() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT ) ++ ++#define __lcd_vsync_get_vpe() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) ++#define __lcd_vsync_set_vpe(n) \ ++do { \ ++ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ ++ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hps() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) ++#define __lcd_hsync_set_hps(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hpe() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) ++#define __lcd_hsync_set_hpe(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_ht() \ ++ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) ++#define __lcd_vat_set_ht(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_vt() \ ++ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) ++#define __lcd_vat_set_vt(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hds() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) ++#define __lcd_dah_set_hds(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hde() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) ++#define __lcd_dah_set_hde(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vds() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) ++#define __lcd_dav_set_vds(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vde() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) ++#define __lcd_dav_set_vde(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ ++} while (0) ++ ++#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) ++#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) ++ ++#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) ++#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) ++ ++#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) ++#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) ++ ++#define __lcd_cmd0_get_len() \ ++ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++#define __lcd_cmd1_get_len() \ ++ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++ ++ ++ ++/*************************************************************************** ++ * DES ++ ***************************************************************************/ ++ ++ ++/*************************************************************************** ++ * CPM ++ ***************************************************************************/ ++#define __cpm_plcr1_fd() \ ++ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT) ++#define __cpm_plcr1_rd() \ ++ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT) ++#define __cpm_plcr1_od() \ ++ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT) ++#define __cpm_cfcr_mfr() \ ++ ((REG_CPM_CFCR & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT) ++#define __cpm_cfcr_pfr() \ ++ ((REG_CPM_CFCR & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT) ++#define __cpm_cfcr_sfr() \ ++ ((REG_CPM_CFCR & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT) ++#define __cpm_cfcr_ifr() \ ++ ((REG_CPM_CFCR & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT) ++ ++static __inline__ unsigned int __cpm_divisor_encode(unsigned int n) ++{ ++ unsigned int encode[10] = {1,2,3,4,6,8,12,16,24,32}; ++ int i; ++ for (i=0;i<10;i++) ++ if (n < encode[i]) ++ break; ++ return i; ++} ++ ++#define __cpm_set_mclk_div(n) \ ++do { \ ++ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_MFR_MASK) | \ ++ ((n) << (CPM_CFCR_MFR_BIT)); \ ++} while (0) ++ ++#define __cpm_set_pclk_div(n) \ ++do { \ ++ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_PFR_MASK) | \ ++ ((n) << (CPM_CFCR_PFR_BIT)); \ ++} while (0) ++ ++#define __cpm_set_sclk_div(n) \ ++do { \ ++ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_SFR_MASK) | \ ++ ((n) << (CPM_CFCR_SFR_BIT)); \ ++} while (0) ++ ++#define __cpm_set_iclk_div(n) \ ++do { \ ++ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_IFR_MASK) | \ ++ ((n) << (CPM_CFCR_IFR_BIT)); \ ++} while (0) ++ ++#define __cpm_set_lcdclk_div(n) \ ++do { \ ++ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_LFR_MASK) | \ ++ ((n) << (CPM_CFCR_LFR_BIT)); \ ++} while (0) ++ ++#define __cpm_enable_cko1() (REG_CPM_CFCR |= CPM_CFCR_CKOEN1) ++#define __cpm_enable_cko2() (REG_CPM_CFCR |= CPM_CFCR_CKOEN2) ++#define __cpm_disable_cko1() (REG_CPM_CFCR &= ~CPM_CFCR_CKOEN1) ++#define __cpm_disable_cko2() (REG_CPM_CFCR &= ~CPM_CFCR_CKOEN2) ++ ++#define __cpm_select_msc_clk(type) \ ++do { \ ++ if (type == 0) \ ++ REG_CPM_CFCR &= ~CPM_CFCR_MSC; \ ++ else \ ++ REG_CPM_CFCR |= CPM_CFCR_MSC; \ ++ REG_CPM_CFCR |= CPM_CFCR_UPE; \ ++} while(0) ++ ++#define __cpm_idle_mode() \ ++ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \ ++ CPM_LPCR_LPM_IDLE) ++#define __cpm_sleep_mode() \ ++ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \ ++ CPM_LPCR_LPM_SLEEP) ++#define __cpm_hibernate_mode() \ ++ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \ ++ CPM_LPCR_LPM_HIBERNATE) ++ ++#define __cpm_start_uart0() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART0)) ++#define __cpm_start_uart1() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART1)) ++#define __cpm_start_uart2() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART2)) ++#define __cpm_start_uart3() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART3)) ++#define __cpm_start_ost() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_OST)) ++#define __cpm_start_dmac() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_DMAC)) ++#define __cpm_start_uhc() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UHC)) ++#define __cpm_start_lcd() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_LCD)) ++#define __cpm_start_i2c() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_I2C)) ++#define __cpm_start_aic_pclk() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_AICPCLK)) ++#define __cpm_start_aic_bitclk() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_AICBCLK)) ++#define __cpm_start_pwm0() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_PWM0)) ++#define __cpm_start_pwm1() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_PWM1)) ++#define __cpm_start_ssi() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_SSI)) ++#define __cpm_start_msc() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_MSC)) ++#define __cpm_start_scc() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_SCC)) ++#define __cpm_start_eth() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_ETH)) ++#define __cpm_start_kbc() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_KBC)) ++#define __cpm_start_cim() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_CIM)) ++#define __cpm_start_udc() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UDC)) ++#define __cpm_start_uprt() \ ++ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UPRT)) ++#define __cpm_start_all() (REG_CPM_MSCR = 0) ++ ++#define __cpm_stop_uart0() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART0)) ++#define __cpm_stop_uart1() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART1)) ++#define __cpm_stop_uart2() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART2)) ++#define __cpm_stop_uart3() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART3)) ++#define __cpm_stop_ost() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_OST)) ++#define __cpm_stop_dmac() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_DMAC)) ++#define __cpm_stop_uhc() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UHC)) ++#define __cpm_stop_lcd() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_LCD)) ++#define __cpm_stop_i2c() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_I2C)) ++#define __cpm_stop_aic_pclk() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_AICPCLK)) ++#define __cpm_stop_aic_bitclk() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_AICBCLK)) ++#define __cpm_stop_pwm0() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_PWM0)) ++#define __cpm_stop_pwm1() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_PWM1)) ++#define __cpm_stop_ssi() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_SSI)) ++#define __cpm_stop_msc() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_MSC)) ++#define __cpm_stop_scc() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_SCC)) ++#define __cpm_stop_eth() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_ETH)) ++#define __cpm_stop_kbc() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_KBC)) ++#define __cpm_stop_cim() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_CIM)) ++#define __cpm_stop_udc() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UDC)) ++#define __cpm_stop_uprt() \ ++ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UPRT)) ++#define __cpm_stop_all() (REG_CPM_MSCR = 0xffffffff) ++ ++#define __cpm_set_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ if (p == 0) \ ++ REG_CPM_GSR0 |= (1 << o); \ ++ else if (p == 1) \ ++ REG_CPM_GSR1 |= (1 << o); \ ++ else if (p == 2) \ ++ REG_CPM_GSR2 |= (1 << o); \ ++ else if (p == 3) \ ++ REG_CPM_GSR3 |= (1 << o); \ ++} while (0) ++ ++#define __cpm_clear_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ if (p == 0) \ ++ REG_CPM_GSR0 &= ~(1 << o); \ ++ else if (p == 1) \ ++ REG_CPM_GSR1 &= ~(1 << o); \ ++ else if (p == 2) \ ++ REG_CPM_GSR2 &= ~(1 << o); \ ++ else if (p == 3) \ ++ REG_CPM_GSR3 &= ~(1 << o); \ ++} while (0) ++ ++ ++/*************************************************************************** ++ * SSI ++ ***************************************************************************/ ++ ++#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE ) ++#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE ) ++#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL ) ++ ++#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK ) ++ ++#define __ssi_select_ce2() \ ++do { \ ++ REG_SSI_CR0 |= SSI_CR0_FSEL; \ ++ REG_SSI_CR1 &= ~SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_select_gpc() \ ++do { \ ++ REG_SSI_CR0 &= ~SSI_CR0_FSEL; \ ++ REG_SSI_CR1 |= SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_enable_tx_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE ) ++ ++#define __ssi_disable_tx_intr() \ ++ ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) ++ ++#define __ssi_enable_rx_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE ) ++ ++#define __ssi_disable_rx_intr() \ ++ ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) ++ ++#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP ) ++#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP ) ++ ++#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV ) ++#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV ) ++ ++#define __ssi_finish_receive() \ ++ ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_disable_recvfinish() \ ++ ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH ) ++#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH ) ++ ++#define __ssi_flush_fifo() \ ++ ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) ++ ++#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN ) ++ ++#define __ssi_spi_format() \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \ ++ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ ++ REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ ++} while (0) ++ ++/* TI's SSP format, must clear SSI_CR1.UNFIN */ ++#define __ssi_ssp_format() \ ++do { \ ++ REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ ++ REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \ ++} while (0) ++ ++/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ ++#define __ssi_microwire_format() \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \ ++ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ ++ REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ ++ REG_SSI_CR0 &= ~SSI_CR0_RFINE; \ ++} while (0) ++ ++/* CE# level (FRMHL), CE# in interval time (ITFRM), ++ clock phase and polarity (PHA POL), ++ interval time (SSIITR), interval characters/frame (SSIICR) */ ++ ++ /* frmhl,endian,mcom,flen,pha,pol MASK */ ++#define SSICR1_MISC_MASK \ ++ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ ++ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \ ++ ++#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \ ++do { \ ++ REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \ ++ REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \ ++ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ ++ ((pha) << 1) | (pol); \ ++} while(0) ++ ++/* Transfer with MSB or LSB first */ ++#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST ) ++#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST ) ++ ++#define __ssi_set_frame_length(n) \ ++ REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4) ++ ++/* n = 1 - 16 */ ++#define __ssi_set_microwire_command_length(n) \ ++ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) ) ++ ++/* Set the clock phase for SPI */ ++#define __ssi_set_spi_clock_phase(n) \ ++ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1) << 1 ))) ++ ++/* Set the clock polarity for SPI */ ++#define __ssi_set_spi_clock_polarity(n) \ ++ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | ((n&0x1) << 0 ))) ++ ++/* n = 1,4,8,14 */ ++#define __ssi_set_tx_trigger(n) \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \ ++ REG_SSI_CR1 |= SSI_CR1_TTRG_##n; \ ++} while (0) ++ ++/* n = 1,4,8,14 */ ++#define __ssi_set_rx_trigger(n) \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_RTRG_MASK; \ ++ REG_SSI_CR1 |= SSI_CR1_RTRG_##n; \ ++} while (0) ++ ++#define __ssi_get_txfifo_count() \ ++ ( (REG_SSI_SR & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT ) ++ ++#define __ssi_get_rxfifo_count() \ ++ ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) ++ ++#define __ssi_clear_errors() \ ++ ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) ++ ++#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END ) ++#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY ) ++ ++#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF ) ++#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE ) ++#define __ssi_rxfifo_noempty() ( REG_SSI_SR & SSI_SR_RFHF ) ++#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF ) ++#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE ) ++#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR ) ++#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER ) ++ ++#define __ssi_set_clk(dev_clk, ssi_clk) \ ++ ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 ) ++ ++#define __ssi_receive_data() REG_SSI_DR ++#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) ) ++ ++#endif /* __ASM_JZ4730_OPS_H__ */ +diff --git a/include/asm-mips/mach-jz4730/regs.h b/include/asm-mips/mach-jz4730/regs.h +new file mode 100644 +index 0000000..86bde91 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/regs.h +@@ -0,0 +1,2550 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/regs.h ++ * ++ * JZ4730 registers definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_REGS_H__ ++#define __ASM_JZ4730_REGS_H__ ++ ++#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY) ++#define REG8(addr) (addr) ++#define REG16(addr) (addr) ++#define REG32(addr) (addr) ++#else ++#define REG8(addr) *((volatile unsigned char *)(addr)) ++#define REG16(addr) *((volatile unsigned short *)(addr)) ++#define REG32(addr) *((volatile unsigned int *)(addr)) ++#endif ++ ++#define HARB_BASE 0xB3000000 ++#define EMC_BASE 0xB3010000 ++#define DMAC_BASE 0xB3020000 ++#define UHC_BASE 0xB3030000 ++#define UDC_BASE 0xB3040000 ++#define LCD_BASE 0xB3050000 ++#define CIM_BASE 0xB3060000 ++#define ETH_BASE 0xB3100000 ++#define NBM_BASE 0xB3F00000 ++ ++#define CPM_BASE 0xB0000000 ++#define INTC_BASE 0xB0001000 ++#define OST_BASE 0xB0002000 ++#define RTC_BASE 0xB0003000 ++#define WDT_BASE 0xB0004000 ++#define GPIO_BASE 0xB0010000 ++#define AIC_BASE 0xB0020000 ++#define MSC_BASE 0xB0021000 ++#define UART0_BASE 0xB0030000 ++#define UART1_BASE 0xB0031000 ++#define UART2_BASE 0xB0032000 ++#define UART3_BASE 0xB0033000 ++#define FIR_BASE 0xB0040000 ++#define SCC_BASE 0xB0041000 ++#define SCC0_BASE 0xB0041000 ++#define I2C_BASE 0xB0042000 ++#define SSI_BASE 0xB0043000 ++#define SCC1_BASE 0xB0044000 ++#define PWM0_BASE 0xB0050000 ++#define PWM1_BASE 0xB0051000 ++#define DES_BASE 0xB0060000 ++#define UPRT_BASE 0xB0061000 ++#define KBC_BASE 0xB0062000 ++ ++ ++ ++ ++/************************************************************************* ++ * MSC ++ *************************************************************************/ ++#define MSC_STRPCL (MSC_BASE + 0x000) ++#define MSC_STAT (MSC_BASE + 0x004) ++#define MSC_CLKRT (MSC_BASE + 0x008) ++#define MSC_CMDAT (MSC_BASE + 0x00C) ++#define MSC_RESTO (MSC_BASE + 0x010) ++#define MSC_RDTO (MSC_BASE + 0x014) ++#define MSC_BLKLEN (MSC_BASE + 0x018) ++#define MSC_NOB (MSC_BASE + 0x01C) ++#define MSC_SNOB (MSC_BASE + 0x020) ++#define MSC_IMASK (MSC_BASE + 0x024) ++#define MSC_IREG (MSC_BASE + 0x028) ++#define MSC_CMD (MSC_BASE + 0x02C) ++#define MSC_ARG (MSC_BASE + 0x030) ++#define MSC_RES (MSC_BASE + 0x034) ++#define MSC_RXFIFO (MSC_BASE + 0x038) ++#define MSC_TXFIFO (MSC_BASE + 0x03C) ++ ++#define REG_MSC_STRPCL REG16(MSC_STRPCL) ++#define REG_MSC_STAT REG32(MSC_STAT) ++#define REG_MSC_CLKRT REG16(MSC_CLKRT) ++#define REG_MSC_CMDAT REG32(MSC_CMDAT) ++#define REG_MSC_RESTO REG16(MSC_RESTO) ++#define REG_MSC_RDTO REG16(MSC_RDTO) ++#define REG_MSC_BLKLEN REG16(MSC_BLKLEN) ++#define REG_MSC_NOB REG16(MSC_NOB) ++#define REG_MSC_SNOB REG16(MSC_SNOB) ++#define REG_MSC_IMASK REG16(MSC_IMASK) ++#define REG_MSC_IREG REG16(MSC_IREG) ++#define REG_MSC_CMD REG8(MSC_CMD) ++#define REG_MSC_ARG REG32(MSC_ARG) ++#define REG_MSC_RES REG16(MSC_RES) ++#define REG_MSC_RXFIFO REG32(MSC_RXFIFO) ++#define REG_MSC_TXFIFO REG32(MSC_TXFIFO) ++ ++/* MSC Clock and Control Register (MSC_STRPCL) */ ++ ++#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) ++#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) ++#define MSC_STRPCL_START_READWAIT (1 << 5) ++#define MSC_STRPCL_STOP_READWAIT (1 << 4) ++#define MSC_STRPCL_RESET (1 << 3) ++#define MSC_STRPCL_START_OP (1 << 2) ++#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 ++#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) ++ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ ++ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ ++ ++/* MSC Status Register (MSC_STAT) */ ++ ++#define MSC_STAT_IS_RESETTING (1 << 15) ++#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) ++#define MSC_STAT_PRG_DONE (1 << 13) ++#define MSC_STAT_DATA_TRAN_DONE (1 << 12) ++#define MSC_STAT_END_CMD_RES (1 << 11) ++#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) ++#define MSC_STAT_IS_READWAIT (1 << 9) ++#define MSC_STAT_CLK_EN (1 << 8) ++#define MSC_STAT_DATA_FIFO_FULL (1 << 7) ++#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) ++#define MSC_STAT_CRC_RES_ERR (1 << 5) ++#define MSC_STAT_CRC_READ_ERROR (1 << 4) ++#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 ++#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) ++ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ ++#define MSC_STAT_TIME_OUT_RES (1 << 1) ++#define MSC_STAT_TIME_OUT_READ (1 << 0) ++ ++/* MSC Bus Clock Control Register (MSC_CLKRT) */ ++ ++#define MSC_CLKRT_CLK_RATE_BIT 0 ++#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) ++ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ ++ ++/* MSC Command Sequence Control Register (MSC_CMDAT) */ ++ ++#define MSC_CMDAT_IO_ABORT (1 << 11) ++#define MSC_CMDAT_BUS_WIDTH_BIT 9 ++#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) ++ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ ++ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ ++ #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) ++ #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) ++#define MSC_CMDAT_DMA_EN (1 << 8) ++#define MSC_CMDAT_INIT (1 << 7) ++#define MSC_CMDAT_BUSY (1 << 6) ++#define MSC_CMDAT_STREAM_BLOCK (1 << 5) ++#define MSC_CMDAT_WRITE (1 << 4) ++#define MSC_CMDAT_READ (0 << 4) ++#define MSC_CMDAT_DATA_EN (1 << 3) ++#define MSC_CMDAT_RESPONSE_BIT 0 ++#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) ++ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ ++ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ ++ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ ++ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ ++ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ ++ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ ++ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ ++ ++#define CMDAT_DMA_EN (1 << 8) ++#define CMDAT_INIT (1 << 7) ++#define CMDAT_BUSY (1 << 6) ++#define CMDAT_STREAM (1 << 5) ++#define CMDAT_WRITE (1 << 4) ++#define CMDAT_DATA_EN (1 << 3) ++ ++/* MSC Interrupts Mask Register (MSC_IMASK) */ ++ ++#define MSC_IMASK_SDIO (1 << 7) ++#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IMASK_END_CMD_RES (1 << 2) ++#define MSC_IMASK_PRG_DONE (1 << 1) ++#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) ++ ++ ++/* MSC Interrupts Status Register (MSC_IREG) */ ++ ++#define MSC_IREG_SDIO (1 << 7) ++#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IREG_END_CMD_RES (1 << 2) ++#define MSC_IREG_PRG_DONE (1 << 1) ++#define MSC_IREG_DATA_TRAN_DONE (1 << 0) ++ ++ ++ ++ ++/************************************************************************* ++ * RTC ++ *************************************************************************/ ++#define RTC_RCR (RTC_BASE + 0x00) ++#define RTC_RSR (RTC_BASE + 0x04) ++#define RTC_RSAR (RTC_BASE + 0x08) ++#define RTC_RGR (RTC_BASE + 0x0c) ++ ++#define REG_RTC_RCR REG32(RTC_RCR) ++#define REG_RTC_RSR REG32(RTC_RSR) ++#define REG_RTC_RSAR REG32(RTC_RSAR) ++#define REG_RTC_RGR REG32(RTC_RGR) ++ ++#define RTC_RCR_HZ (1 << 6) ++#define RTC_RCR_HZIE (1 << 5) ++#define RTC_RCR_AF (1 << 4) ++#define RTC_RCR_AIE (1 << 3) ++#define RTC_RCR_AE (1 << 2) ++#define RTC_RCR_START (1 << 0) ++ ++#define RTC_RGR_LOCK (1 << 31) ++#define RTC_RGR_ADJ_BIT 16 ++#define RTC_RGR_ADJ_MASK (0x3ff << RTC_RGR_ADJ_BIT) ++#define RTC_RGR_DIV_BIT 0 ++#define RTC_REG_DIV_MASK (0xff << RTC_RGR_DIV_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * FIR ++ *************************************************************************/ ++#define FIR_TDR (FIR_BASE + 0x000) ++#define FIR_RDR (FIR_BASE + 0x004) ++#define FIR_TFLR (FIR_BASE + 0x008) ++#define FIR_AR (FIR_BASE + 0x00C) ++#define FIR_CR1 (FIR_BASE + 0x010) ++#define FIR_CR2 (FIR_BASE + 0x014) ++#define FIR_SR (FIR_BASE + 0x018) ++ ++#define REG_FIR_TDR REG8(FIR_TDR) ++#define REG_FIR_RDR REG8(FIR_RDR) ++#define REG_FIR_TFLR REG16(FIR_TFLR) ++#define REG_FIR_AR REG8(FIR_AR) ++#define REG_FIR_CR1 REG8(FIR_CR1) ++#define REG_FIR_CR2 REG16(FIR_CR2) ++#define REG_FIR_SR REG16(FIR_SR) ++ ++/* FIR Control Register 1 (FIR_CR1) */ ++ ++#define FIR_CR1_FIRUE (1 << 7) ++#define FIR_CR1_ACE (1 << 6) ++#define FIR_CR1_EOUS (1 << 5) ++#define FIR_CR1_TIIE (1 << 4) ++#define FIR_CR1_TFIE (1 << 3) ++#define FIR_CR1_RFIE (1 << 2) ++#define FIR_CR1_TXE (1 << 1) ++#define FIR_CR1_RXE (1 << 0) ++ ++/* FIR Control Register 2 (FIR_CR2) */ ++ ++#define FIR_CR2_SIPE (1 << 10) ++#define FIR_CR2_BCRC (1 << 9) ++#define FIR_CR2_TFLRS (1 << 8) ++#define FIR_CR2_ISS (1 << 7) ++#define FIR_CR2_LMS (1 << 6) ++#define FIR_CR2_TPPS (1 << 5) ++#define FIR_CR2_RPPS (1 << 4) ++#define FIR_CR2_TTRG_BIT 2 ++#define FIR_CR2_TTRG_MASK (0x3 << FIR_CR2_TTRG_BIT) ++ #define FIR_CR2_TTRG_16 (0 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 16 */ ++ #define FIR_CR2_TTRG_32 (1 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 32 */ ++ #define FIR_CR2_TTRG_64 (2 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 64 */ ++ #define FIR_CR2_TTRG_128 (3 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 128 */ ++#define FIR_CR2_RTRG_BIT 0 ++#define FIR_CR2_RTRG_MASK (0x3 << FIR_CR2_RTRG_BIT) ++ #define FIR_CR2_RTRG_16 (0 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 16 */ ++ #define FIR_CR2_RTRG_32 (1 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 32 */ ++ #define FIR_CR2_RTRG_64 (2 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 64 */ ++ #define FIR_CR2_RTRG_128 (3 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 128 */ ++ ++/* FIR Status Register (FIR_SR) */ ++ ++#define FIR_SR_RFW (1 << 12) ++#define FIR_SR_RFA (1 << 11) ++#define FIR_SR_TFRTL (1 << 10) ++#define FIR_SR_RFRTL (1 << 9) ++#define FIR_SR_URUN (1 << 8) ++#define FIR_SR_RFTE (1 << 7) ++#define FIR_SR_ORUN (1 << 6) ++#define FIR_SR_CRCE (1 << 5) ++#define FIR_SR_FEND (1 << 4) ++#define FIR_SR_TFF (1 << 3) ++#define FIR_SR_RFE (1 << 2) ++#define FIR_SR_TIDLE (1 << 1) ++#define FIR_SR_RB (1 << 0) ++ ++ ++ ++ ++/************************************************************************* ++ * SCC ++ *************************************************************************/ ++#define SCC_DR(base) ((base) + 0x000) ++#define SCC_FDR(base) ((base) + 0x004) ++#define SCC_CR(base) ((base) + 0x008) ++#define SCC1_CR(base) ((base) + 0x008) ++#define SCC_SR(base) ((base) + 0x00C) ++#define SCC_TFR(base) ((base) + 0x010) ++#define SCC_EGTR(base) ((base) + 0x014) ++#define SCC_ECR(base) ((base) + 0x018) ++#define SCC_RTOR(base) ((base) + 0x01C) ++ ++#define REG_SCC_DR(base) REG8(SCC_DR(base)) ++#define REG_SCC_FDR(base) REG8(SCC_FDR(base)) ++#define REG_SCC_CR(base) REG32(SCC_CR(base)) ++#define REG_SCC1_CR(base) REG32(SCC1_CR(base)) ++#define REG_SCC_SR(base) REG16(SCC_SR(base)) ++#define REG_SCC_TFR(base) REG16(SCC_TFR(base)) ++#define REG_SCC_EGTR(base) REG8(SCC_EGTR(base)) ++#define REG_SCC_ECR(base) REG32(SCC_ECR(base)) ++#define REG_SCC_RTOR(base) REG8(SCC_RTOR(base)) ++ ++/* SCC FIFO Data Count Register (SCC_FDR) */ ++ ++#define SCC_FDR_EMPTY 0x00 ++#define SCC_FDR_FULL 0x10 ++ ++/* SCC Control Register (SCC_CR) */ ++ ++#define SCC_CR_SCCE (1 << 31) ++#define SCC_CR_TRS (1 << 30) ++#define SCC_CR_T2R (1 << 29) ++#define SCC_CR_FDIV_BIT 24 ++#define SCC_CR_FDIV_MASK (0x3 << SCC_CR_FDIV_BIT) ++ #define SCC_CR_FDIV_1 (0 << SCC_CR_FDIV_BIT) /* SCC_CLK frequency is the same as device clock */ ++ #define SCC_CR_FDIV_2 (1 << SCC_CR_FDIV_BIT) /* SCC_CLK frequency is half of device clock */ ++#define SCC_CR_FLUSH (1 << 23) ++#define SCC_CR_TRIG_BIT 16 ++#define SCC_CR_TRIG_MASK (0x3 << SCC_CR_TRIG_BIT) ++ #define SCC_CR_TRIG_1 (0 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 1 */ ++ #define SCC_CR_TRIG_4 (1 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 4 */ ++ #define SCC_CR_TRIG_8 (2 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 8 */ ++ #define SCC_CR_TRIG_14 (3 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 14 */ ++#define SCC_CR_TP (1 << 15) ++#define SCC_CR_CONV (1 << 14) ++#define SCC_CR_TXIE (1 << 13) ++#define SCC_CR_RXIE (1 << 12) ++#define SCC_CR_TENDIE (1 << 11) ++#define SCC_CR_RTOIE (1 << 10) ++#define SCC_CR_ECIE (1 << 9) ++#define SCC_CR_EPIE (1 << 8) ++#define SCC_CR_RETIE (1 << 7) ++#define SCC_CR_EOIE (1 << 6) ++#define SCC_CR_TSEND (1 << 3) ++#define SCC_CR_PX_BIT 1 ++#define SCC_CR_PX_MASK (0x3 << SCC_CR_PX_BIT) ++ #define SCC_CR_PX_NOT_SUPPORT (0 << SCC_CR_PX_BIT) /* SCC does not support clock stop */ ++ #define SCC_CR_PX_STOP_LOW (1 << SCC_CR_PX_BIT) /* SCC_CLK stops at state low */ ++ #define SCC_CR_PX_STOP_HIGH (2 << SCC_CR_PX_BIT) /* SCC_CLK stops at state high */ ++#define SCC_CR_CLKSTP (1 << 0) ++ ++/* SCC Status Register (SCC_SR) */ ++ ++#define SCC_SR_TRANS (1 << 15) ++#define SCC_SR_ORER (1 << 12) ++#define SCC_SR_RTO (1 << 11) ++#define SCC_SR_PER (1 << 10) ++#define SCC_SR_TFTG (1 << 9) ++#define SCC_SR_RFTG (1 << 8) ++#define SCC_SR_TEND (1 << 7) ++#define SCC_SR_RETR_3 (1 << 4) ++#define SCC_SR_ECNTO (1 << 0) ++ ++ ++ ++ ++/************************************************************************* ++ * ETH ++ *************************************************************************/ ++#define ETH_BMR (ETH_BASE + 0x1000) ++#define ETH_TPDR (ETH_BASE + 0x1004) ++#define ETH_RPDR (ETH_BASE + 0x1008) ++#define ETH_RAR (ETH_BASE + 0x100C) ++#define ETH_TAR (ETH_BASE + 0x1010) ++#define ETH_SR (ETH_BASE + 0x1014) ++#define ETH_CR (ETH_BASE + 0x1018) ++#define ETH_IER (ETH_BASE + 0x101C) ++#define ETH_MFCR (ETH_BASE + 0x1020) ++#define ETH_CTAR (ETH_BASE + 0x1050) ++#define ETH_CRAR (ETH_BASE + 0x1054) ++#define ETH_MCR (ETH_BASE + 0x0000) ++#define ETH_MAHR (ETH_BASE + 0x0004) ++#define ETH_MALR (ETH_BASE + 0x0008) ++#define ETH_HTHR (ETH_BASE + 0x000C) ++#define ETH_HTLR (ETH_BASE + 0x0010) ++#define ETH_MIAR (ETH_BASE + 0x0014) ++#define ETH_MIDR (ETH_BASE + 0x0018) ++#define ETH_FCR (ETH_BASE + 0x001C) ++#define ETH_VTR1 (ETH_BASE + 0x0020) ++#define ETH_VTR2 (ETH_BASE + 0x0024) ++#define ETH_WKFR (ETH_BASE + 0x0028) ++#define ETH_PMTR (ETH_BASE + 0x002C) ++ ++#define REG_ETH_BMR REG32(ETH_BMR) ++#define REG_ETH_TPDR REG32(ETH_TPDR) ++#define REG_ETH_RPDR REG32(ETH_RPDR) ++#define REG_ETH_RAR REG32(ETH_RAR) ++#define REG_ETH_TAR REG32(ETH_TAR) ++#define REG_ETH_SR REG32(ETH_SR) ++#define REG_ETH_CR REG32(ETH_CR) ++#define REG_ETH_IER REG32(ETH_IER) ++#define REG_ETH_MFCR REG32(ETH_MFCR) ++#define REG_ETH_CTAR REG32(ETH_CTAR) ++#define REG_ETH_CRAR REG32(ETH_CRAR) ++#define REG_ETH_MCR REG32(ETH_MCR) ++#define REG_ETH_MAHR REG32(ETH_MAHR) ++#define REG_ETH_MALR REG32(ETH_MALR) ++#define REG_ETH_HTHR REG32(ETH_HTHR) ++#define REG_ETH_HTLR REG32(ETH_HTLR) ++#define REG_ETH_MIAR REG32(ETH_MIAR) ++#define REG_ETH_MIDR REG32(ETH_MIDR) ++#define REG_ETH_FCR REG32(ETH_FCR) ++#define REG_ETH_VTR1 REG32(ETH_VTR1) ++#define REG_ETH_VTR2 REG32(ETH_VTR2) ++#define REG_ETH_WKFR REG32(ETH_WKFR) ++#define REG_ETH_PMTR REG32(ETH_PMTR) ++ ++/* Bus Mode Register (ETH_BMR) */ ++ ++#define ETH_BMR_DBO (1 << 20) ++#define ETH_BMR_PBL_BIT 8 ++#define ETH_BMR_PBL_MASK (0x3f << ETH_BMR_PBL_BIT) ++ #define ETH_BMR_PBL_1 (0x1 << ETH_BMR_PBL_BIT) ++ #define ETH_BMR_PBL_4 (0x4 << ETH_BMR_PBL_BIT) ++#define ETH_BMR_BLE (1 << 7) ++#define ETH_BMR_DSL_BIT 2 ++#define ETH_BMR_DSL_MASK (0x1f << ETH_BMR_DSL_BIT) ++ #define ETH_BMR_DSL_0 (0x0 << ETH_BMR_DSL_BIT) ++ #define ETH_BMR_DSL_1 (0x1 << ETH_BMR_DSL_BIT) ++ #define ETH_BMR_DSL_2 (0x2 << ETH_BMR_DSL_BIT) ++ #define ETH_BMR_DSL_4 (0x4 << ETH_BMR_DSL_BIT) ++ #define ETH_BMR_DSL_8 (0x8 << ETH_BMR_DSL_BIT) ++#define ETH_BMR_SWR (1 << 0) ++ ++/* DMA Status Register (ETH_SR) */ ++ ++#define ETH_SR_EB_BIT 23 ++#define ETH_SR_EB_MASK (0x7 << ETH_SR_EB_BIT) ++ #define ETH_SR_EB_TX_ABORT (0x1 << ETH_SR_EB_BIT) ++ #define ETH_SR_EB_RX_ABORT (0x2 << ETH_SR_EB_BIT) ++#define ETH_SR_TS_BIT 20 ++#define ETH_SR_TS_MASK (0x7 << ETH_SR_TS_BIT) ++ #define ETH_SR_TS_STOP (0x0 << ETH_SR_TS_BIT) ++ #define ETH_SR_TS_FTD (0x1 << ETH_SR_TS_BIT) ++ #define ETH_SR_TS_WEOT (0x2 << ETH_SR_TS_BIT) ++ #define ETH_SR_TS_QDAT (0x3 << ETH_SR_TS_BIT) ++ #define ETH_SR_TS_SUSPEND (0x6 << ETH_SR_TS_BIT) ++ #define ETH_SR_TS_CTD (0x7 << ETH_SR_TS_BIT) ++#define ETH_SR_RS_BIT 17 ++#define ETH_SR_RS_MASK (0x7 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_STOP (0x0 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_FRD (0x1 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_CEOR (0x2 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_WRP (0x3 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_SUSPEND (0x4 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_CRD (0x5 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_FCF (0x6 << ETH_SR_RS_BIT) ++ #define ETH_SR_RS_QRF (0x7 << ETH_SR_RS_BIT) ++#define ETH_SR_NIS (1 << 16) ++#define ETH_SR_AIS (1 << 15) ++#define ETH_SR_ERI (1 << 14) ++#define ETH_SR_FBE (1 << 13) ++#define ETH_SR_ETI (1 << 10) ++#define ETH_SR_RWT (1 << 9) ++#define ETH_SR_RPS (1 << 8) ++#define ETH_SR_RU (1 << 7) ++#define ETH_SR_RI (1 << 6) ++#define ETH_SR_UNF (1 << 5) ++#define ETH_SR_TJT (1 << 3) ++#define ETH_SR_TU (1 << 2) ++#define ETH_SR_TPS (1 << 1) ++#define ETH_SR_TI (1 << 0) ++ ++/* Control (Operation Mode) Register (ETH_CR) */ ++ ++#define ETH_CR_TTM (1 << 22) ++#define ETH_CR_SF (1 << 21) ++#define ETH_CR_TR_BIT 14 ++#define ETH_CR_TR_MASK (0x3 << ETH_CR_TR_BIT) ++#define ETH_CR_ST (1 << 13) ++#define ETH_CR_OSF (1 << 2) ++#define ETH_CR_SR (1 << 1) ++ ++/* Interrupt Enable Register (ETH_IER) */ ++ ++#define ETH_IER_NI (1 << 16) ++#define ETH_IER_AI (1 << 15) ++#define ETH_IER_ERE (1 << 14) ++#define ETH_IER_FBE (1 << 13) ++#define ETH_IER_ET (1 << 10) ++#define ETH_IER_RWE (1 << 9) ++#define ETH_IER_RS (1 << 8) ++#define ETH_IER_RU (1 << 7) ++#define ETH_IER_RI (1 << 6) ++#define ETH_IER_UN (1 << 5) ++#define ETH_IER_TJ (1 << 3) ++#define ETH_IER_TU (1 << 2) ++#define ETH_IER_TS (1 << 1) ++#define ETH_IER_TI (1 << 0) ++ ++/* Missed Frame and Buffer Overflow Counter Register (ETH_MFCR) */ ++ ++#define ETH_MFCR_OVERFLOW_BIT 17 ++#define ETH_MFCR_OVERFLOW_MASK (0x7ff << ETH_MFCR_OVERFLOW_BIT) ++#define ETH_MFCR_MFC_BIT 0 ++#define ETH_MFCR_MFC_MASK (0xffff << ETH_MFCR_MFC_BIT) ++ ++/* MAC Control Register (ETH_MCR) */ ++ ++#define ETH_MCR_RA (1 << 31) ++#define ETH_MCR_HBD (1 << 28) ++#define ETH_MCR_PS (1 << 27) ++#define ETH_MCR_DRO (1 << 23) ++#define ETH_MCR_OM_BIT 21 ++#define ETH_MCR_OM_MASK (0x3 << ETH_MCR_OM_BIT) ++ #define ETH_MCR_OM_NORMAL (0x0 << ETH_MCR_OM_BIT) ++ #define ETH_MCR_OM_INTERNAL (0x1 << ETH_MCR_OM_BIT) ++ #define ETH_MCR_OM_EXTERNAL (0x2 << ETH_MCR_OM_BIT) ++#define ETH_MCR_F (1 << 20) ++#define ETH_MCR_PM (1 << 19) ++#define ETH_MCR_PR (1 << 18) ++#define ETH_MCR_IF (1 << 17) ++#define ETH_MCR_PB (1 << 16) ++#define ETH_MCR_HO (1 << 15) ++#define ETH_MCR_HP (1 << 13) ++#define ETH_MCR_LCC (1 << 12) ++#define ETH_MCR_DBF (1 << 11) ++#define ETH_MCR_DTRY (1 << 10) ++#define ETH_MCR_ASTP (1 << 8) ++#define ETH_MCR_BOLMT_BIT 6 ++#define ETH_MCR_BOLMT_MASK (0x3 << ETH_MCR_BOLMT_BIT) ++ #define ETH_MCR_BOLMT_10 (0 << ETH_MCR_BOLMT_BIT) ++ #define ETH_MCR_BOLMT_8 (1 << ETH_MCR_BOLMT_BIT) ++ #define ETH_MCR_BOLMT_4 (2 << ETH_MCR_BOLMT_BIT) ++ #define ETH_MCR_BOLMT_1 (3 << ETH_MCR_BOLMT_BIT) ++#define ETH_MCR_DC (1 << 5) ++#define ETH_MCR_TE (1 << 3) ++#define ETH_MCR_RE (1 << 2) ++ ++/* MII Address Register (ETH_MIAR) */ ++ ++#define ETH_MIAR_PHY_ADDR_BIT 11 ++#define ETH_MIAR_PHY_ADDR_MASK (0x1f << ETH_MIAR_PHY_ADDR_BIT) ++#define ETH_MIAR_MII_REG_BIT 6 ++#define ETH_MIAR_MII_REG_MASK (0x1f << ETH_MIAR_MII_REG_BIT) ++#define ETH_MIAR_MII_WRITE (1 << 1) ++#define ETH_MIAR_MII_BUSY (1 << 0) ++ ++/* Flow Control Register (ETH_FCR) */ ++ ++#define ETH_FCR_PAUSE_TIME_BIT 16 ++#define ETH_FCR_PAUSE_TIME_MASK (0xffff << ETH_FCR_PAUSE_TIME_BIT) ++#define ETH_FCR_PCF (1 << 2) ++#define ETH_FCR_FCE (1 << 1) ++#define ETH_FCR_BUSY (1 << 0) ++ ++/* PMT Control and Status Register (ETH_PMTR) */ ++ ++#define ETH_PMTR_GU (1 << 9) ++#define ETH_PMTR_RF (1 << 6) ++#define ETH_PMTR_MF (1 << 5) ++#define ETH_PMTR_RWK (1 << 2) ++#define ETH_PMTR_MPK (1 << 1) ++ ++/* Receive Descriptor 0 (ETH_RD0) Bits */ ++ ++#define ETH_RD0_OWN (1 << 31) ++#define ETH_RD0_FF (1 << 30) ++#define ETH_RD0_FL_BIT 16 ++#define ETH_RD0_FL_MASK (0x3fff << ETH_RD0_FL_BIT) ++#define ETH_RD0_ES (1 << 15) ++#define ETH_RD0_DE (1 << 14) ++#define ETH_RD0_LE (1 << 12) ++#define ETH_RD0_RF (1 << 11) ++#define ETH_RD0_MF (1 << 10) ++#define ETH_RD0_FD (1 << 9) ++#define ETH_RD0_LD (1 << 8) ++#define ETH_RD0_TL (1 << 7) ++#define ETH_RD0_CS (1 << 6) ++#define ETH_RD0_FT (1 << 5) ++#define ETH_RD0_WT (1 << 4) ++#define ETH_RD0_ME (1 << 3) ++#define ETH_RD0_DB (1 << 2) ++#define ETH_RD0_CE (1 << 1) ++ ++/* Receive Descriptor 1 (ETH_RD1) Bits */ ++ ++#define ETH_RD1_RER (1 << 25) ++#define ETH_RD1_RCH (1 << 24) ++#define ETH_RD1_RBS2_BIT 11 ++#define ETH_RD1_RBS2_MASK (0x7ff << ETH_RD1_RBS2_BIT) ++#define ETH_RD1_RBS1_BIT 0 ++#define ETH_RD1_RBS1_MASK (0x7ff << ETH_RD1_RBS1_BIT) ++ ++/* Transmit Descriptor 0 (ETH_TD0) Bits */ ++ ++#define ETH_TD0_OWN (1 << 31) ++#define ETH_TD0_FA (1 << 15) ++#define ETH_TD0_LOC (1 << 11) ++#define ETH_TD0_NC (1 << 10) ++#define ETH_TD0_LC (1 << 9) ++#define ETH_TD0_EC (1 << 8) ++#define ETH_TD0_HBF (1 << 7) ++#define ETH_TD0_CC_BIT 3 ++#define ETH_TD0_CC_MASK (0xf << ETH_TD0_CC_BIT) ++#define ETH_TD0_ED (1 << 2) ++#define ETH_TD0_UF (1 << 1) ++#define ETH_TD0_DF (1 << 0) ++ ++/* Transmit Descriptor 1 (ETH_TD1) Bits */ ++ ++#define ETH_TD1_IC (1 << 31) ++#define ETH_TD1_LS (1 << 30) ++#define ETH_TD1_FS (1 << 29) ++#define ETH_TD1_AC (1 << 26) ++#define ETH_TD1_TER (1 << 25) ++#define ETH_TD1_TCH (1 << 24) ++#define ETH_TD1_DPD (1 << 23) ++#define ETH_TD1_TBS2_BIT 11 ++#define ETH_TD1_TBS2_MASK (0x7ff << ETH_TD1_TBS2_BIT) ++#define ETH_TD1_TBS1_BIT 0 ++#define ETH_TD1_TBS1_MASK (0x7ff << ETH_TD1_TBS1_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * WDT ++ *************************************************************************/ ++#define WDT_WTCSR (WDT_BASE + 0x00) ++#define WDT_WTCNT (WDT_BASE + 0x04) ++ ++#define REG_WDT_WTCSR REG8(WDT_WTCSR) ++#define REG_WDT_WTCNT REG32(WDT_WTCNT) ++ ++#define WDT_WTCSR_START (1 << 4) ++ ++ ++ ++ ++/************************************************************************* ++ * OST ++ *************************************************************************/ ++#define OST_TER (OST_BASE + 0x00) ++#define OST_TRDR(n) (OST_BASE + 0x10 + ((n) * 0x20)) ++#define OST_TCNT(n) (OST_BASE + 0x14 + ((n) * 0x20)) ++#define OST_TCSR(n) (OST_BASE + 0x18 + ((n) * 0x20)) ++#define OST_TCRB(n) (OST_BASE + 0x1c + ((n) * 0x20)) ++ ++#define REG_OST_TER REG8(OST_TER) ++#define REG_OST_TRDR(n) REG32(OST_TRDR((n))) ++#define REG_OST_TCNT(n) REG32(OST_TCNT((n))) ++#define REG_OST_TCSR(n) REG16(OST_TCSR((n))) ++#define REG_OST_TCRB(n) REG32(OST_TCRB((n))) ++ ++#define OST_TCSR_BUSY (1 << 7) ++#define OST_TCSR_UF (1 << 6) ++#define OST_TCSR_UIE (1 << 5) ++#define OST_TCSR_CKS_BIT 0 ++#define OST_TCSR_CKS_MASK (0x07 << OST_TCSR_CKS_BIT) ++ #define OST_TCSR_CKS_PCLK_4 (0 << OST_TCSR_CKS_BIT) ++ #define OST_TCSR_CKS_PCLK_16 (1 << OST_TCSR_CKS_BIT) ++ #define OST_TCSR_CKS_PCLK_64 (2 << OST_TCSR_CKS_BIT) ++ #define OST_TCSR_CKS_PCLK_256 (3 << OST_TCSR_CKS_BIT) ++ #define OST_TCSR_CKS_RTCCLK (4 << OST_TCSR_CKS_BIT) ++ #define OST_TCSR_CKS_EXTAL (5 << OST_TCSR_CKS_BIT) ++ ++#define OST_TCSR0 OST_TCSR(0) ++#define OST_TCSR1 OST_TCSR(1) ++#define OST_TCSR2 OST_TCSR(2) ++#define OST_TRDR0 OST_TRDR(0) ++#define OST_TRDR1 OST_TRDR(1) ++#define OST_TRDR2 OST_TRDR(2) ++#define OST_TCNT0 OST_TCNT(0) ++#define OST_TCNT1 OST_TCNT(1) ++#define OST_TCNT2 OST_TCNT(2) ++#define OST_TCRB0 OST_TCRB(0) ++#define OST_TCRB1 OST_TCRB(1) ++#define OST_TCRB2 OST_TCRB(2) ++ ++/************************************************************************* ++ * UART ++ *************************************************************************/ ++ ++#define IRDA_BASE UART0_BASE ++#define UART_BASE UART0_BASE ++#define UART_OFF 0x1000 ++ ++/* register offset */ ++#define OFF_RDR (0x00) /* R 8b H'xx */ ++#define OFF_TDR (0x00) /* W 8b H'xx */ ++#define OFF_DLLR (0x00) /* RW 8b H'00 */ ++#define OFF_DLHR (0x04) /* RW 8b H'00 */ ++#define OFF_IER (0x04) /* RW 8b H'00 */ ++#define OFF_ISR (0x08) /* R 8b H'01 */ ++#define OFF_FCR (0x08) /* W 8b H'00 */ ++#define OFF_LCR (0x0C) /* RW 8b H'00 */ ++#define OFF_MCR (0x10) /* RW 8b H'00 */ ++#define OFF_LSR (0x14) /* R 8b H'00 */ ++#define OFF_MSR (0x18) /* R 8b H'00 */ ++#define OFF_SPR (0x1C) /* RW 8b H'00 */ ++#define OFF_MCR (0x10) /* RW 8b H'00 */ ++#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */ ++ ++/* register address */ ++#define UART0_RDR (UART0_BASE + OFF_RDR) ++#define UART0_TDR (UART0_BASE + OFF_TDR) ++#define UART0_DLLR (UART0_BASE + OFF_DLLR) ++#define UART0_DLHR (UART0_BASE + OFF_DLHR) ++#define UART0_IER (UART0_BASE + OFF_IER) ++#define UART0_ISR (UART0_BASE + OFF_ISR) ++#define UART0_FCR (UART0_BASE + OFF_FCR) ++#define UART0_LCR (UART0_BASE + OFF_LCR) ++#define UART0_MCR (UART0_BASE + OFF_MCR) ++#define UART0_LSR (UART0_BASE + OFF_LSR) ++#define UART0_MSR (UART0_BASE + OFF_MSR) ++#define UART0_SPR (UART0_BASE + OFF_SPR) ++#define UART0_SIRCR (UART0_BASE + OFF_SIRCR) ++ ++#define UART1_RDR (UART1_BASE + OFF_RDR) ++#define UART1_TDR (UART1_BASE + OFF_TDR) ++#define UART1_DLLR (UART1_BASE + OFF_DLLR) ++#define UART1_DLHR (UART1_BASE + OFF_DLHR) ++#define UART1_IER (UART1_BASE + OFF_IER) ++#define UART1_ISR (UART1_BASE + OFF_ISR) ++#define UART1_FCR (UART1_BASE + OFF_FCR) ++#define UART1_LCR (UART1_BASE + OFF_LCR) ++#define UART1_MCR (UART1_BASE + OFF_MCR) ++#define UART1_LSR (UART1_BASE + OFF_LSR) ++#define UART1_MSR (UART1_BASE + OFF_MSR) ++#define UART1_SPR (UART1_BASE + OFF_SPR) ++#define UART1_SIRCR (UART1_BASE + OFF_SIRCR) ++ ++#define UART2_RDR (UART2_BASE + OFF_RDR) ++#define UART2_TDR (UART2_BASE + OFF_TDR) ++#define UART2_DLLR (UART2_BASE + OFF_DLLR) ++#define UART2_DLHR (UART2_BASE + OFF_DLHR) ++#define UART2_IER (UART2_BASE + OFF_IER) ++#define UART2_ISR (UART2_BASE + OFF_ISR) ++#define UART2_FCR (UART2_BASE + OFF_FCR) ++#define UART2_LCR (UART2_BASE + OFF_LCR) ++#define UART2_MCR (UART2_BASE + OFF_MCR) ++#define UART2_LSR (UART2_BASE + OFF_LSR) ++#define UART2_MSR (UART2_BASE + OFF_MSR) ++#define UART2_SPR (UART2_BASE + OFF_SPR) ++#define UART2_SIRCR (UART2_BASE + OFF_SIRCR) ++ ++#define UART3_RDR (UART3_BASE + OFF_RDR) ++#define UART3_TDR (UART3_BASE + OFF_TDR) ++#define UART3_DLLR (UART3_BASE + OFF_DLLR) ++#define UART3_DLHR (UART3_BASE + OFF_DLHR) ++#define UART3_IER (UART3_BASE + OFF_IER) ++#define UART3_ISR (UART3_BASE + OFF_ISR) ++#define UART3_FCR (UART3_BASE + OFF_FCR) ++#define UART3_LCR (UART3_BASE + OFF_LCR) ++#define UART3_MCR (UART3_BASE + OFF_MCR) ++#define UART3_LSR (UART3_BASE + OFF_LSR) ++#define UART3_MSR (UART3_BASE + OFF_MSR) ++#define UART3_SPR (UART3_BASE + OFF_SPR) ++#define UART3_SIRCR (UART3_BASE + OFF_SIRCR) ++ ++/* ++ * Define macros for UARTIER ++ * UART Interrupt Enable Register ++ */ ++#define UARTIER_RIE (1 << 0) /* 0: receive fifo "full" interrupt disable */ ++#define UARTIER_TIE (1 << 1) /* 0: transmit fifo "empty" interrupt disable */ ++#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ ++#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */ ++#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ ++ ++/* ++ * Define macros for UARTISR ++ * UART Interrupt Status Register ++ */ ++#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ ++#define UARTISR_IID (7 << 1) /* Source of Interrupt */ ++#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */ ++#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ ++#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */ ++#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ ++#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */ ++#define UARTISR_FFMS_NO_FIFO (0 << 6) ++#define UARTISR_FFMS_FIFO_MODE (3 << 6) ++ ++/* ++ * Define macros for UARTFCR ++ * UART FIFO Control Register ++ */ ++#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ ++#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ ++#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ ++#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ ++#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ ++#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ ++#define UARTFCR_RTRG_1 (0 << 6) ++#define UARTFCR_RTRG_4 (1 << 6) ++#define UARTFCR_RTRG_8 (2 << 6) ++#define UARTFCR_RTRG_15 (3 << 6) ++ ++/* ++ * Define macros for UARTLCR ++ * UART Line Control Register ++ */ ++#define UARTLCR_WLEN (3 << 0) /* word length */ ++#define UARTLCR_WLEN_5 (0 << 0) ++#define UARTLCR_WLEN_6 (1 << 0) ++#define UARTLCR_WLEN_7 (2 << 0) ++#define UARTLCR_WLEN_8 (3 << 0) ++#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 ++ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ ++#define UARTLCR_PE (1 << 3) /* 0: parity disable */ ++#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ ++#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ ++#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ ++#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ ++ ++/* ++ * Define macros for UARTLSR ++ * UART Line Status Register ++ */ ++#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ ++#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */ ++#define UARTLSR_PER (1 << 2) /* 0: no parity error */ ++#define UARTLSR_FER (1 << 3) /* 0; no framing error */ ++#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ ++#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ ++#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ ++#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ ++ ++/* ++ * Define macros for UARTMCR ++ * UART Modem Control Register ++ */ ++#define UARTMCR_DTR (1 << 0) /* 0: DTR_ ouput high */ ++#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high */ ++#define UARTMCR_OUT1 (1 << 2) /* 0: UARTMSR.RI is set to 0 and RI_ input high */ ++#define UARTMCR_OUT2 (1 << 3) /* 0: UARTMSR.DCD is set to 0 and DCD_ input high */ ++#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ ++#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */ ++ ++/* ++ * Define macros for UARTMSR ++ * UART Modem Status Register ++ */ ++#define UARTMSR_DCTS (1 << 0) /* 0: no change on CTS_ pin since last read of UARTMSR */ ++#define UARTMSR_DDSR (1 << 1) /* 0: no change on DSR_ pin since last read of UARTMSR */ ++#define UARTMSR_DRI (1 << 2) /* 0: no change on RI_ pin since last read of UARTMSR */ ++#define UARTMSR_DDCD (1 << 3) /* 0: no change on DCD_ pin since last read of UARTMSR */ ++#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */ ++#define UARTMSR_DSR (1 << 5) /* 0: DSR_ pin is high */ ++#define UARTMSR_RI (1 << 6) /* 0: RI_ pin is high */ ++#define UARTMSR_DCD (1 << 7) /* 0: DCD_ pin is high */ ++ ++/* ++ * Define macros for SIRCR ++ * Slow IrDA Control Register ++ */ ++#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: IrDA mode */ ++#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: IrDA mode */ ++#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length ++ 1: 0 pulse width is 1.6us for 115.2Kbps */ ++#define SIRCR_TXPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ ++#define SIRCR_RXPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ ++ ++ ++ ++/************************************************************************* ++ * INTC ++ *************************************************************************/ ++#define INTC_ISR (INTC_BASE + 0x00) ++#define INTC_IMR (INTC_BASE + 0x04) ++#define INTC_IMSR (INTC_BASE + 0x08) ++#define INTC_IMCR (INTC_BASE + 0x0c) ++#define INTC_IPR (INTC_BASE + 0x10) ++ ++#define REG_INTC_ISR REG32(INTC_ISR) ++#define REG_INTC_IMR REG32(INTC_IMR) ++#define REG_INTC_IMSR REG32(INTC_IMSR) ++#define REG_INTC_IMCR REG32(INTC_IMCR) ++#define REG_INTC_IPR REG32(INTC_IPR) ++ ++#define IRQ_I2C 1 ++#define IRQ_PS2 2 ++#define IRQ_UPRT 3 ++#define IRQ_CORE 4 ++#define IRQ_UART3 6 ++#define IRQ_UART2 7 ++#define IRQ_UART1 8 ++#define IRQ_UART0 9 ++#define IRQ_SCC1 10 ++#define IRQ_SCC0 11 ++#define IRQ_UDC 12 ++#define IRQ_UHC 13 ++#define IRQ_MSC 14 ++#define IRQ_RTC 15 ++#define IRQ_FIR 16 ++#define IRQ_SSI 17 ++#define IRQ_CIM 18 ++#define IRQ_ETH 19 ++#define IRQ_AIC 20 ++#define IRQ_DMAC 21 ++#define IRQ_OST2 22 ++#define IRQ_OST1 23 ++#define IRQ_OST0 24 ++#define IRQ_GPIO3 25 ++#define IRQ_GPIO2 26 ++#define IRQ_GPIO1 27 ++#define IRQ_GPIO0 28 ++#define IRQ_LCD 30 ++ ++ ++ ++ ++/************************************************************************* ++ * CIM ++ *************************************************************************/ ++#define CIM_CFG (CIM_BASE + 0x0000) ++#define CIM_CTRL (CIM_BASE + 0x0004) ++#define CIM_STATE (CIM_BASE + 0x0008) ++#define CIM_IID (CIM_BASE + 0x000C) ++#define CIM_RXFIFO (CIM_BASE + 0x0010) ++#define CIM_DA (CIM_BASE + 0x0020) ++#define CIM_FA (CIM_BASE + 0x0024) ++#define CIM_FID (CIM_BASE + 0x0028) ++#define CIM_CMD (CIM_BASE + 0x002C) ++ ++#define REG_CIM_CFG REG32(CIM_CFG) ++#define REG_CIM_CTRL REG32(CIM_CTRL) ++#define REG_CIM_STATE REG32(CIM_STATE) ++#define REG_CIM_IID REG32(CIM_IID) ++#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) ++#define REG_CIM_DA REG32(CIM_DA) ++#define REG_CIM_FA REG32(CIM_FA) ++#define REG_CIM_FID REG32(CIM_FID) ++#define REG_CIM_CMD REG32(CIM_CMD) ++ ++/* CIM Configuration Register (CIM_CFG) */ ++ ++#define CIM_CFG_INV_DAT (1 << 15) ++#define CIM_CFG_VSP (1 << 14) ++#define CIM_CFG_HSP (1 << 13) ++#define CIM_CFG_PCP (1 << 12) ++#define CIM_CFG_DUMMY_ZERO (1 << 9) ++#define CIM_CFG_EXT_VSYNC (1 << 8) ++#define CIM_CFG_PACK_BIT 4 ++#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) ++#define CIM_CFG_DSM_BIT 0 ++#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) ++ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ ++ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ ++ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ ++ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ ++ ++/* CIM Control Register (CIM_CTRL) */ ++ ++#define CIM_CTRL_MCLKDIV_BIT 24 ++#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) ++#define CIM_CTRL_FRC_BIT 16 ++#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) ++ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ ++ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ ++ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ ++ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ ++ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ ++ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ ++ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ ++ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ ++ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ ++ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ ++ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ ++ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ ++ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ ++ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ ++ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ ++ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ ++#define CIM_CTRL_VDDM (1 << 13) ++#define CIM_CTRL_DMA_SOFM (1 << 12) ++#define CIM_CTRL_DMA_EOFM (1 << 11) ++#define CIM_CTRL_DMA_STOPM (1 << 10) ++#define CIM_CTRL_RXF_TRIGM (1 << 9) ++#define CIM_CTRL_RXF_OFM (1 << 8) ++#define CIM_CTRL_RXF_TRIG_BIT 4 ++#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) ++ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ ++ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ ++ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ ++ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ ++ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ ++ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ ++ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ ++ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ ++#define CIM_CTRL_DMA_EN (1 << 2) ++#define CIM_CTRL_RXF_RST (1 << 1) ++#define CIM_CTRL_ENA (1 << 0) ++ ++/* CIM State Register (CIM_STATE) */ ++ ++#define CIM_STATE_DMA_SOF (1 << 6) ++#define CIM_STATE_DMA_EOF (1 << 5) ++#define CIM_STATE_DMA_STOP (1 << 4) ++#define CIM_STATE_RXF_OF (1 << 3) ++#define CIM_STATE_RXF_TRIG (1 << 2) ++#define CIM_STATE_RXF_EMPTY (1 << 1) ++#define CIM_STATE_VDD (1 << 0) ++ ++/* CIM DMA Command Register (CIM_CMD) */ ++ ++#define CIM_CMD_SOFINT (1 << 31) ++#define CIM_CMD_EOFINT (1 << 30) ++#define CIM_CMD_STOP (1 << 28) ++#define CIM_CMD_LEN_BIT 0 ++#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * PWM ++ *************************************************************************/ ++#define PWM_CTR(n) (PWM##n##_BASE + 0x000) ++#define PWM_PER(n) (PWM##n##_BASE + 0x004) ++#define PWM_DUT(n) (PWM##n##_BASE + 0x008) ++ ++#define REG_PWM_CTR(n) REG8(PWM_CTR(n)) ++#define REG_PWM_PER(n) REG16(PWM_PER(n)) ++#define REG_PWM_DUT(n) REG16(PWM_DUT(n)) ++ ++/* PWM Control Register (PWM_CTR) */ ++ ++#define PWM_CTR_EN (1 << 7) ++#define PWM_CTR_SD (1 << 6) ++#define PWM_CTR_PRESCALE_BIT 0 ++#define PWM_CTR_PRESCALE_MASK (0x3f << PWM_CTR_PRESCALE_BIT) ++ ++/* PWM Period Register (PWM_PER) */ ++ ++#define PWM_PER_PERIOD_BIT 0 ++#define PWM_PER_PERIOD_MASK (0x3ff << PWM_PER_PERIOD_BIT) ++ ++/* PWM Duty Register (PWM_DUT) */ ++ ++#define PWM_DUT_FDUTY (1 << 10) ++#define PWM_DUT_DUTY_BIT 0 ++#define PWM_DUT_DUTY_MASK (0x3ff << PWM_DUT_DUTY_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * EMC ++ *************************************************************************/ ++#define EMC_BCR (EMC_BASE + 0x00) ++#define EMC_SMCR0 (EMC_BASE + 0x10) ++#define EMC_SMCR1 (EMC_BASE + 0x14) ++#define EMC_SMCR2 (EMC_BASE + 0x18) ++#define EMC_SMCR3 (EMC_BASE + 0x1c) ++#define EMC_SMCR4 (EMC_BASE + 0x20) ++#define EMC_SMCR5 (EMC_BASE + 0x24) ++#define EMC_SMCR6 (EMC_BASE + 0x28) ++#define EMC_SMCR7 (EMC_BASE + 0x2c) ++#define EMC_SACR0 (EMC_BASE + 0x30) ++#define EMC_SACR1 (EMC_BASE + 0x34) ++#define EMC_SACR2 (EMC_BASE + 0x38) ++#define EMC_SACR3 (EMC_BASE + 0x3c) ++#define EMC_SACR4 (EMC_BASE + 0x40) ++#define EMC_SACR5 (EMC_BASE + 0x44) ++#define EMC_SACR6 (EMC_BASE + 0x48) ++#define EMC_SACR7 (EMC_BASE + 0x4c) ++#define EMC_NFCSR (EMC_BASE + 0x50) ++#define EMC_NFECC (EMC_BASE + 0x54) ++#define EMC_PCCR1 (EMC_BASE + 0x60) ++#define EMC_PCCR2 (EMC_BASE + 0x64) ++#define EMC_PCCR3 (EMC_BASE + 0x68) ++#define EMC_PCCR4 (EMC_BASE + 0x6c) ++#define EMC_DMCR (EMC_BASE + 0x80) ++#define EMC_RTCSR (EMC_BASE + 0x84) ++#define EMC_RTCNT (EMC_BASE + 0x88) ++#define EMC_RTCOR (EMC_BASE + 0x8c) ++#define EMC_DMAR1 (EMC_BASE + 0x90) ++#define EMC_DMAR2 (EMC_BASE + 0x94) ++#define EMC_DMAR3 (EMC_BASE + 0x98) ++#define EMC_DMAR4 (EMC_BASE + 0x9c) ++ ++#define EMC_SDMR0 (EMC_BASE + 0xa000) ++#define EMC_SDMR1 (EMC_BASE + 0xb000) ++#define EMC_SDMR2 (EMC_BASE + 0xc000) ++#define EMC_SDMR3 (EMC_BASE + 0xd000) ++ ++#define REG_EMC_BCR REG32(EMC_BCR) ++#define REG_EMC_SMCR0 REG32(EMC_SMCR0) ++#define REG_EMC_SMCR1 REG32(EMC_SMCR1) ++#define REG_EMC_SMCR2 REG32(EMC_SMCR2) ++#define REG_EMC_SMCR3 REG32(EMC_SMCR3) ++#define REG_EMC_SMCR4 REG32(EMC_SMCR4) ++#define REG_EMC_SMCR5 REG32(EMC_SMCR5) ++#define REG_EMC_SMCR6 REG32(EMC_SMCR6) ++#define REG_EMC_SMCR7 REG32(EMC_SMCR7) ++#define REG_EMC_SACR0 REG32(EMC_SACR0) ++#define REG_EMC_SACR1 REG32(EMC_SACR1) ++#define REG_EMC_SACR2 REG32(EMC_SACR2) ++#define REG_EMC_SACR3 REG32(EMC_SACR3) ++#define REG_EMC_SACR4 REG32(EMC_SACR4) ++#define REG_EMC_SACR5 REG32(EMC_SACR5) ++#define REG_EMC_SACR6 REG32(EMC_SACR6) ++#define REG_EMC_SACR7 REG32(EMC_SACR7) ++#define REG_EMC_NFCSR REG32(EMC_NFCSR) ++#define REG_EMC_NFECC REG32(EMC_NFECC) ++#define REG_EMC_DMCR REG32(EMC_DMCR) ++#define REG_EMC_RTCSR REG16(EMC_RTCSR) ++#define REG_EMC_RTCNT REG16(EMC_RTCNT) ++#define REG_EMC_RTCOR REG16(EMC_RTCOR) ++#define REG_EMC_DMAR1 REG32(EMC_DMAR1) ++#define REG_EMC_DMAR2 REG32(EMC_DMAR2) ++#define REG_EMC_DMAR3 REG32(EMC_DMAR3) ++#define REG_EMC_DMAR4 REG32(EMC_DMAR4) ++#define REG_EMC_PCCR1 REG32(EMC_PCCR1) ++#define REG_EMC_PCCR2 REG32(EMC_PCCR2) ++#define REG_EMC_PCCR3 REG32(EMC_PCCR3) ++#define REG_EMC_PCCR4 REG32(EMC_PCCR4) ++ ++ ++#define EMC_BCR_BRE (1 << 1) ++ ++#define EMC_SMCR_STRV_BIT 24 ++#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) ++#define EMC_SMCR_TAW_BIT 20 ++#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) ++#define EMC_SMCR_TBP_BIT 16 ++#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) ++#define EMC_SMCR_TAH_BIT 12 ++#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) ++#define EMC_SMCR_TAS_BIT 8 ++#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) ++#define EMC_SMCR_BW_BIT 6 ++#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) ++#define EMC_SMCR_BCM (1 << 3) ++#define EMC_SMCR_BL_BIT 1 ++#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) ++#define EMC_SMCR_SMT (1 << 0) ++ ++#define EMC_SACR_BASE_BIT 8 ++#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) ++#define EMC_SACR_MASK_BIT 0 ++#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) ++ ++#define EMC_NFCSR_RB (1 << 7) ++#define EMC_NFCSR_BOOT_SEL_BIT 4 ++#define EMC_NFCSR_BOOT_SEL_MASK (0x07 << EMC_NFCSR_BOOT_SEL_BIT) ++#define EMC_NFCSR_ERST (1 << 3) ++#define EMC_NFCSR_ECCE (1 << 2) ++#define EMC_NFCSR_FCE (1 << 1) ++#define EMC_NFCSR_NFE (1 << 0) ++ ++#define EMC_NFECC_ECC2_BIT 16 ++#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT) ++#define EMC_NFECC_ECC1_BIT 8 ++#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT) ++#define EMC_NFECC_ECC0_BIT 0 ++#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT) ++ ++#define EMC_DMCR_BW_BIT 31 ++#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) ++#define EMC_DMCR_CA_BIT 26 ++#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) ++#define EMC_DMCR_RMODE (1 << 25) ++#define EMC_DMCR_RFSH (1 << 24) ++#define EMC_DMCR_MRSET (1 << 23) ++#define EMC_DMCR_RA_BIT 20 ++#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) ++#define EMC_DMCR_BA_BIT 19 ++#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) ++#define EMC_DMCR_PDM (1 << 18) ++#define EMC_DMCR_EPIN (1 << 17) ++#define EMC_DMCR_TRAS_BIT 13 ++#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) ++#define EMC_DMCR_RCD_BIT 11 ++#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) ++#define EMC_DMCR_TPC_BIT 8 ++#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) ++#define EMC_DMCR_TRWL_BIT 5 ++#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) ++#define EMC_DMCR_TRC_BIT 2 ++#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) ++#define EMC_DMCR_TCL_BIT 0 ++#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) ++ ++#define EMC_RTCSR_CMF (1 << 7) ++#define EMC_RTCSR_CKS_BIT 0 ++#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) ++ ++#define EMC_DMAR_BASE_BIT 8 ++#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) ++#define EMC_DMAR_MASK_BIT 0 ++#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) ++ ++#define EMC_SDMR_BM (1 << 9) ++#define EMC_SDMR_OM_BIT 7 ++#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) ++ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) ++#define EMC_SDMR_CAS_BIT 4 ++#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) ++#define EMC_SDMR_BT_BIT 3 ++#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) ++ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) ++ #define EMC_SDMR_BT_INTR (1 << EMC_SDMR_BT_BIT) ++#define EMC_SDMR_BL_BIT 0 ++#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) ++ ++#define EMC_SDMR_CAS2_16BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS2_32BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++#define EMC_SDMR_CAS3_16BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS3_32BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++ ++#define EMC_PCCR12_AMW (1 << 31) ++#define EMC_PCCR12_AMAS_BIT 28 ++#define EMC_PCCR12_AMAS_MASK (0x07 << EMC_PCCR12_AMAS_BIT) ++#define EMC_PCCR12_AMAH_BIT 24 ++#define EMC_PCCR12_AMAH_MASK (0x07 << EMC_PCCR12_AMAH_BIT) ++#define EMC_PCCR12_AMPW_BIT 20 ++#define EMC_PCCR12_AMPW_MASK (0x0f << EMC_PCCR12_AMPW_BIT) ++#define EMC_PCCR12_AMRT_BIT 16 ++#define EMC_PCCR12_AMRT_MASK (0x0f << EMC_PCCR12_AMRT_BIT) ++#define EMC_PCCR12_CMW (1 << 15) ++#define EMC_PCCR12_CMAS_BIT 12 ++#define EMC_PCCR12_CMAS_MASK (0x07 << EMC_PCCR12_CMAS_BIT) ++#define EMC_PCCR12_CMAH_BIT 8 ++#define EMC_PCCR12_CMAH_MASK (0x07 << EMC_PCCR12_CMAH_BIT) ++#define EMC_PCCR12_CMPW_BIT 4 ++#define EMC_PCCR12_CMPW_MASK (0x0f << EMC_PCCR12_CMPW_BIT) ++#define EMC_PCCR12_CMRT_BIT 0 ++#define EMC_PCCR12_CMRT_MASK (0x07 << EMC_PCCR12_CMRT_BIT) ++ ++#define EMC_PCCR34_DRS_BIT 16 ++#define EMC_PCCR34_DRS_MASK (0x03 << EMC_PCCR34_DRS_BIT) ++ #define EMC_PCCR34_DRS_SPKR (1 << EMC_PCCR34_DRS_BIT) ++ #define EMC_PCCR34_DRS_IOIS16 (2 << EMC_PCCR34_DRS_BIT) ++ #define EMC_PCCR34_DRS_INPACK (3 << EMC_PCCR34_DRS_BIT) ++#define EMC_PCCR34_IOIS16 (1 << 15) ++#define EMC_PCCR34_IOW (1 << 14) ++#define EMC_PCCR34_TCB_BIT 12 ++#define EMC_PCCR34_TCB_MASK (0x03 << EMC_PCCR34_TCB_BIT) ++#define EMC_PCCR34_IORT_BIT 8 ++#define EMC_PCCR34_IORT_MASK (0x07 << EMC_PCCR34_IORT_BIT) ++#define EMC_PCCR34_IOAE_BIT 6 ++#define EMC_PCCR34_IOAE_MASK (0x03 << EMC_PCCR34_IOAE_BIT) ++ #define EMC_PCCR34_IOAE_NONE (0 << EMC_PCCR34_IOAE_BIT) ++ #define EMC_PCCR34_IOAE_1 (1 << EMC_PCCR34_IOAE_BIT) ++ #define EMC_PCCR34_IOAE_2 (2 << EMC_PCCR34_IOAE_BIT) ++ #define EMC_PCCR34_IOAE_5 (3 << EMC_PCCR34_IOAE_BIT) ++#define EMC_PCCR34_IOAH_BIT 4 ++#define EMC_PCCR34_IOAH_MASK (0x03 << EMC_PCCR34_IOAH_BIT) ++ #define EMC_PCCR34_IOAH_NONE (0 << EMC_PCCR34_IOAH_BIT) ++ #define EMC_PCCR34_IOAH_1 (1 << EMC_PCCR34_IOAH_BIT) ++ #define EMC_PCCR34_IOAH_2 (2 << EMC_PCCR34_IOAH_BIT) ++ #define EMC_PCCR34_IOAH_5 (3 << EMC_PCCR34_IOAH_BIT) ++#define EMC_PCCR34_IOPW_BIT 0 ++#define EMC_PCCR34_IOPW_MASK (0x0f << EMC_PCCR34_IOPW_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * GPIO ++ *************************************************************************/ ++#define GPIO_GPDR(n) (GPIO_BASE + (0x00 + (n)*0x30)) ++#define GPIO_GPDIR(n) (GPIO_BASE + (0x04 + (n)*0x30)) ++#define GPIO_GPODR(n) (GPIO_BASE + (0x08 + (n)*0x30)) ++#define GPIO_GPPUR(n) (GPIO_BASE + (0x0c + (n)*0x30)) ++#define GPIO_GPALR(n) (GPIO_BASE + (0x10 + (n)*0x30)) ++#define GPIO_GPAUR(n) (GPIO_BASE + (0x14 + (n)*0x30)) ++#define GPIO_GPIDLR(n) (GPIO_BASE + (0x18 + (n)*0x30)) ++#define GPIO_GPIDUR(n) (GPIO_BASE + (0x1c + (n)*0x30)) ++#define GPIO_GPIER(n) (GPIO_BASE + (0x20 + (n)*0x30)) ++#define GPIO_GPIMR(n) (GPIO_BASE + (0x24 + (n)*0x30)) ++#define GPIO_GPFR(n) (GPIO_BASE + (0x28 + (n)*0x30)) ++ ++#define REG_GPIO_GPDR(n) REG32(GPIO_GPDR((n))) ++#define REG_GPIO_GPDIR(n) REG32(GPIO_GPDIR((n))) ++#define REG_GPIO_GPODR(n) REG32(GPIO_GPODR((n))) ++#define REG_GPIO_GPPUR(n) REG32(GPIO_GPPUR((n))) ++#define REG_GPIO_GPALR(n) REG32(GPIO_GPALR((n))) ++#define REG_GPIO_GPAUR(n) REG32(GPIO_GPAUR((n))) ++#define REG_GPIO_GPIDLR(n) REG32(GPIO_GPIDLR((n))) ++#define REG_GPIO_GPIDUR(n) REG32(GPIO_GPIDUR((n))) ++#define REG_GPIO_GPIER(n) REG32(GPIO_GPIER((n))) ++#define REG_GPIO_GPIMR(n) REG32(GPIO_GPIMR((n))) ++#define REG_GPIO_GPFR(n) REG32(GPIO_GPFR((n))) ++ ++#define GPIO_IRQ_LOLEVEL 0 ++#define GPIO_IRQ_HILEVEL 1 ++#define GPIO_IRQ_FALLEDG 2 ++#define GPIO_IRQ_RAISEDG 3 ++ ++#define IRQ_GPIO_0 48 ++#define NUM_GPIO 128 ++ ++#define GPIO_GPDR0 GPIO_GPDR(0) ++#define GPIO_GPDR1 GPIO_GPDR(1) ++#define GPIO_GPDR2 GPIO_GPDR(2) ++#define GPIO_GPDR3 GPIO_GPDR(3) ++#define GPIO_GPDIR0 GPIO_GPDIR(0) ++#define GPIO_GPDIR1 GPIO_GPDIR(1) ++#define GPIO_GPDIR2 GPIO_GPDIR(2) ++#define GPIO_GPDIR3 GPIO_GPDIR(3) ++#define GPIO_GPODR0 GPIO_GPODR(0) ++#define GPIO_GPODR1 GPIO_GPODR(1) ++#define GPIO_GPODR2 GPIO_GPODR(2) ++#define GPIO_GPODR3 GPIO_GPODR(3) ++#define GPIO_GPPUR0 GPIO_GPPUR(0) ++#define GPIO_GPPUR1 GPIO_GPPUR(1) ++#define GPIO_GPPUR2 GPIO_GPPUR(2) ++#define GPIO_GPPUR3 GPIO_GPPUR(3) ++#define GPIO_GPALR0 GPIO_GPALR(0) ++#define GPIO_GPALR1 GPIO_GPALR(1) ++#define GPIO_GPALR2 GPIO_GPALR(2) ++#define GPIO_GPALR3 GPIO_GPALR(3) ++#define GPIO_GPAUR0 GPIO_GPAUR(0) ++#define GPIO_GPAUR1 GPIO_GPAUR(1) ++#define GPIO_GPAUR2 GPIO_GPAUR(2) ++#define GPIO_GPAUR3 GPIO_GPAUR(3) ++#define GPIO_GPIDLR0 GPIO_GPIDLR(0) ++#define GPIO_GPIDLR1 GPIO_GPIDLR(1) ++#define GPIO_GPIDLR2 GPIO_GPIDLR(2) ++#define GPIO_GPIDLR3 GPIO_GPIDLR(3) ++#define GPIO_GPIDUR0 GPIO_GPIDUR(0) ++#define GPIO_GPIDUR1 GPIO_GPIDUR(1) ++#define GPIO_GPIDUR2 GPIO_GPIDUR(2) ++#define GPIO_GPIDUR3 GPIO_GPIDUR(3) ++#define GPIO_GPIER0 GPIO_GPIER(0) ++#define GPIO_GPIER1 GPIO_GPIER(1) ++#define GPIO_GPIER2 GPIO_GPIER(2) ++#define GPIO_GPIER3 GPIO_GPIER(3) ++#define GPIO_GPIMR0 GPIO_GPIMR(0) ++#define GPIO_GPIMR1 GPIO_GPIMR(1) ++#define GPIO_GPIMR2 GPIO_GPIMR(2) ++#define GPIO_GPIMR3 GPIO_GPIMR(3) ++#define GPIO_GPFR0 GPIO_GPFR(0) ++#define GPIO_GPFR1 GPIO_GPFR(1) ++#define GPIO_GPFR2 GPIO_GPFR(2) ++#define GPIO_GPFR3 GPIO_GPFR(3) ++ ++ ++/************************************************************************* ++ * HARB ++ *************************************************************************/ ++#define HARB_HAPOR (HARB_BASE + 0x000) ++#define HARB_HMCTR (HARB_BASE + 0x010) ++#define HARB_HME8H (HARB_BASE + 0x014) ++#define HARB_HMCR1 (HARB_BASE + 0x018) ++#define HARB_HMER2 (HARB_BASE + 0x01C) ++#define HARB_HMER3 (HARB_BASE + 0x020) ++#define HARB_HMLTR (HARB_BASE + 0x024) ++ ++#define REG_HARB_HAPOR REG32(HARB_HAPOR) ++#define REG_HARB_HMCTR REG32(HARB_HMCTR) ++#define REG_HARB_HME8H REG32(HARB_HME8H) ++#define REG_HARB_HMCR1 REG32(HARB_HMCR1) ++#define REG_HARB_HMER2 REG32(HARB_HMER2) ++#define REG_HARB_HMER3 REG32(HARB_HMER3) ++#define REG_HARB_HMLTR REG32(HARB_HMLTR) ++ ++/* HARB Priority Order Register (HARB_HAPOR) */ ++ ++#define HARB_HAPOR_UCHSEL (1 << 7) ++#define HARB_HAPOR_PRIO_BIT 0 ++#define HARB_HAPOR_PRIO_MASK (0xf << HARB_HAPOR_PRIO_BIT) ++ ++/* AHB Monitor Control Register (HARB_HMCTR) */ ++ ++#define HARB_HMCTR_HET3_BIT 20 ++#define HARB_HMCTR_HET3_MASK (0xf << HARB_HMCTR_HET3_BIT) ++#define HARB_HMCTR_HMS3_BIT 16 ++#define HARB_HMCTR_HMS3_MASK (0xf << HARB_HMCTR_HMS3_BIT) ++#define HARB_HMCTR_HET2_BIT 12 ++#define HARB_HMCTR_HET2_MASK (0xf << HARB_HMCTR_HET2_BIT) ++#define HARB_HMCTR_HMS2_BIT 8 ++#define HARB_HMCTR_HMS2_MASK (0xf << HARB_HMCTR_HMS2_BIT) ++#define HARB_HMCTR_HOVF3 (1 << 7) ++#define HARB_HMCTR_HOVF2 (1 << 6) ++#define HARB_HMCTR_HOVF1 (1 << 5) ++#define HARB_HMCTR_HRST (1 << 4) ++#define HARB_HMCTR_HEE3 (1 << 2) ++#define HARB_HMCTR_HEE2 (1 << 1) ++#define HARB_HMCTR_HEE1 (1 << 0) ++ ++/* AHB Monitor Event 8bits High Register (HARB_HME8H) */ ++ ++#define HARB_HME8H_HC8H1_BIT 16 ++#define HARB_HME8H_HC8H1_MASK (0xff << HARB_HME8H_HC8H1_BIT) ++#define HARB_HME8H_HC8H2_BIT 8 ++#define HARB_HME8H_HC8H2_MASK (0xff << HARB_HME8H_HC8H2_BIT) ++#define HARB_HME8H_HC8H3_BIT 0 ++#define HARB_HME8H_HC8H3_MASK (0xff << HARB_HME8H_HC8H3_BIT) ++ ++/* AHB Monitor Latency Register (HARB_HMLTR) */ ++ ++#define HARB_HMLTR_HLT2_BIT 16 ++#define HARB_HMLTR_HLT2_MASK (0xffff << HARB_HMLTR_HLT2_BIT) ++#define HARB_HMLTR_HLT3_BIT 0 ++#define HARB_HMLTR_HLT3_MASK (0xffff << HARB_HMLTR_HLT3_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * I2C ++ *************************************************************************/ ++#define I2C_DR (I2C_BASE + 0x000) ++#define I2C_CR (I2C_BASE + 0x004) ++#define I2C_SR (I2C_BASE + 0x008) ++#define I2C_GR (I2C_BASE + 0x00C) ++ ++#define REG_I2C_DR REG8(I2C_DR) ++#define REG_I2C_CR REG8(I2C_CR) ++#define REG_I2C_SR REG8(I2C_SR) ++#define REG_I2C_GR REG16(I2C_GR) ++ ++/* I2C Control Register (I2C_CR) */ ++ ++#define I2C_CR_IEN (1 << 4) ++#define I2C_CR_STA (1 << 3) ++#define I2C_CR_STO (1 << 2) ++#define I2C_CR_AC (1 << 1) ++#define I2C_CR_I2CE (1 << 0) ++ ++/* I2C Status Register (I2C_SR) */ ++ ++#define I2C_SR_STX (1 << 4) ++#define I2C_SR_BUSY (1 << 3) ++#define I2C_SR_TEND (1 << 2) ++#define I2C_SR_DRF (1 << 1) ++#define I2C_SR_ACKF (1 << 0) ++ ++ ++ ++ ++/************************************************************************* ++ * UDC ++ *************************************************************************/ ++#define UDC_EP0InCR (UDC_BASE + 0x00) ++#define UDC_EP0InSR (UDC_BASE + 0x04) ++#define UDC_EP0InBSR (UDC_BASE + 0x08) ++#define UDC_EP0InMPSR (UDC_BASE + 0x0c) ++#define UDC_EP0InDesR (UDC_BASE + 0x14) ++#define UDC_EP1InCR (UDC_BASE + 0x20) ++#define UDC_EP1InSR (UDC_BASE + 0x24) ++#define UDC_EP1InBSR (UDC_BASE + 0x28) ++#define UDC_EP1InMPSR (UDC_BASE + 0x2c) ++#define UDC_EP1InDesR (UDC_BASE + 0x34) ++#define UDC_EP2InCR (UDC_BASE + 0x40) ++#define UDC_EP2InSR (UDC_BASE + 0x44) ++#define UDC_EP2InBSR (UDC_BASE + 0x48) ++#define UDC_EP2InMPSR (UDC_BASE + 0x4c) ++#define UDC_EP2InDesR (UDC_BASE + 0x54) ++#define UDC_EP3InCR (UDC_BASE + 0x60) ++#define UDC_EP3InSR (UDC_BASE + 0x64) ++#define UDC_EP3InBSR (UDC_BASE + 0x68) ++#define UDC_EP3InMPSR (UDC_BASE + 0x6c) ++#define UDC_EP3InDesR (UDC_BASE + 0x74) ++#define UDC_EP4InCR (UDC_BASE + 0x80) ++#define UDC_EP4InSR (UDC_BASE + 0x84) ++#define UDC_EP4InBSR (UDC_BASE + 0x88) ++#define UDC_EP4InMPSR (UDC_BASE + 0x8c) ++#define UDC_EP4InDesR (UDC_BASE + 0x94) ++ ++#define UDC_EP0OutCR (UDC_BASE + 0x200) ++#define UDC_EP0OutSR (UDC_BASE + 0x204) ++#define UDC_EP0OutPFNR (UDC_BASE + 0x208) ++#define UDC_EP0OutMPSR (UDC_BASE + 0x20c) ++#define UDC_EP0OutSBPR (UDC_BASE + 0x210) ++#define UDC_EP0OutDesR (UDC_BASE + 0x214) ++#define UDC_EP5OutCR (UDC_BASE + 0x2a0) ++#define UDC_EP5OutSR (UDC_BASE + 0x2a4) ++#define UDC_EP5OutPFNR (UDC_BASE + 0x2a8) ++#define UDC_EP5OutMPSR (UDC_BASE + 0x2ac) ++#define UDC_EP5OutDesR (UDC_BASE + 0x2b4) ++#define UDC_EP6OutCR (UDC_BASE + 0x2c0) ++#define UDC_EP6OutSR (UDC_BASE + 0x2c4) ++#define UDC_EP6OutPFNR (UDC_BASE + 0x2c8) ++#define UDC_EP6OutMPSR (UDC_BASE + 0x2cc) ++#define UDC_EP6OutDesR (UDC_BASE + 0x2d4) ++#define UDC_EP7OutCR (UDC_BASE + 0x2e0) ++#define UDC_EP7OutSR (UDC_BASE + 0x2e4) ++#define UDC_EP7OutPFNR (UDC_BASE + 0x2e8) ++#define UDC_EP7OutMPSR (UDC_BASE + 0x2ec) ++#define UDC_EP7OutDesR (UDC_BASE + 0x2f4) ++ ++#define UDC_DevCFGR (UDC_BASE + 0x400) ++#define UDC_DevCR (UDC_BASE + 0x404) ++#define UDC_DevSR (UDC_BASE + 0x408) ++#define UDC_DevIntR (UDC_BASE + 0x40c) ++#define UDC_DevIntMR (UDC_BASE + 0x410) ++#define UDC_EPIntR (UDC_BASE + 0x414) ++#define UDC_EPIntMR (UDC_BASE + 0x418) ++ ++#define UDC_STCMAR (UDC_BASE + 0x500) ++#define UDC_EP0InfR (UDC_BASE + 0x504) ++#define UDC_EP1InfR (UDC_BASE + 0x508) ++#define UDC_EP2InfR (UDC_BASE + 0x50c) ++#define UDC_EP3InfR (UDC_BASE + 0x510) ++#define UDC_EP4InfR (UDC_BASE + 0x514) ++#define UDC_EP5InfR (UDC_BASE + 0x518) ++#define UDC_EP6InfR (UDC_BASE + 0x51c) ++#define UDC_EP7InfR (UDC_BASE + 0x520) ++ ++#define UDC_TXCONFIRM (UDC_BASE + 0x41C) ++#define UDC_TXZLP (UDC_BASE + 0x420) ++#define UDC_RXCONFIRM (UDC_BASE + 0x41C) ++ ++#define UDC_RXFIFO (UDC_BASE + 0x800) ++#define UDC_TXFIFOEP0 (UDC_BASE + 0x840) ++ ++#define REG_UDC_EP0InCR REG32(UDC_EP0InCR) ++#define REG_UDC_EP0InSR REG32(UDC_EP0InSR) ++#define REG_UDC_EP0InBSR REG32(UDC_EP0InBSR) ++#define REG_UDC_EP0InMPSR REG32(UDC_EP0InMPSR) ++#define REG_UDC_EP0InDesR REG32(UDC_EP0InDesR) ++#define REG_UDC_EP1InCR REG32(UDC_EP1InCR) ++#define REG_UDC_EP1InSR REG32(UDC_EP1InSR) ++#define REG_UDC_EP1InBSR REG32(UDC_EP1InBSR) ++#define REG_UDC_EP1InMPSR REG32(UDC_EP1InMPSR) ++#define REG_UDC_EP1InDesR REG32(UDC_EP1InDesR) ++#define REG_UDC_EP2InCR REG32(UDC_EP2InCR) ++#define REG_UDC_EP2InSR REG32(UDC_EP2InSR) ++#define REG_UDC_EP2InBSR REG32(UDC_EP2InBSR) ++#define REG_UDC_EP2InMPSR REG32(UDC_EP2InMPSR) ++#define REG_UDC_EP2InDesR REG32(UDC_EP2InDesR) ++#define REG_UDC_EP3InCR REG32(UDC_EP3InCR) ++#define REG_UDC_EP3InSR REG32(UDC_EP3InSR) ++#define REG_UDC_EP3InBSR REG32(UDC_EP3InBSR) ++#define REG_UDC_EP3InMPSR REG32(UDC_EP3InMPSR) ++#define REG_UDC_EP3InDesR REG32(UDC_EP3InDesR) ++#define REG_UDC_EP4InCR REG32(UDC_EP4InCR) ++#define REG_UDC_EP4InSR REG32(UDC_EP4InSR) ++#define REG_UDC_EP4InBSR REG32(UDC_EP4InBSR) ++#define REG_UDC_EP4InMPSR REG32(UDC_EP4InMPSR) ++#define REG_UDC_EP4InDesR REG32(UDC_EP4InDesR) ++ ++#define REG_UDC_EP0OutCR REG32(UDC_EP0OutCR) ++#define REG_UDC_EP0OutSR REG32(UDC_EP0OutSR) ++#define REG_UDC_EP0OutPFNR REG32(UDC_EP0OutPFNR) ++#define REG_UDC_EP0OutMPSR REG32(UDC_EP0OutMPSR) ++#define REG_UDC_EP0OutSBPR REG32(UDC_EP0OutSBPR) ++#define REG_UDC_EP0OutDesR REG32(UDC_EP0OutDesR) ++#define REG_UDC_EP5OutCR REG32(UDC_EP5OutCR) ++#define REG_UDC_EP5OutSR REG32(UDC_EP5OutSR) ++#define REG_UDC_EP5OutPFNR REG32(UDC_EP5OutPFNR) ++#define REG_UDC_EP5OutMPSR REG32(UDC_EP5OutMPSR) ++#define REG_UDC_EP5OutDesR REG32(UDC_EP5OutDesR) ++#define REG_UDC_EP6OutCR REG32(UDC_EP6OutCR) ++#define REG_UDC_EP6OutSR REG32(UDC_EP6OutSR) ++#define REG_UDC_EP6OutPFNR REG32(UDC_EP6OutPFNR) ++#define REG_UDC_EP6OutMPSR REG32(UDC_EP6OutMPSR) ++#define REG_UDC_EP6OutDesR REG32(UDC_EP6OutDesR) ++#define REG_UDC_EP7OutCR REG32(UDC_EP7OutCR) ++#define REG_UDC_EP7OutSR REG32(UDC_EP7OutSR) ++#define REG_UDC_EP7OutPFNR REG32(UDC_EP7OutPFNR) ++#define REG_UDC_EP7OutMPSR REG32(UDC_EP7OutMPSR) ++#define REG_UDC_EP7OutDesR REG32(UDC_EP7OutDesR) ++ ++#define REG_UDC_DevCFGR REG32(UDC_DevCFGR) ++#define REG_UDC_DevCR REG32(UDC_DevCR) ++#define REG_UDC_DevSR REG32(UDC_DevSR) ++#define REG_UDC_DevIntR REG32(UDC_DevIntR) ++#define REG_UDC_DevIntMR REG32(UDC_DevIntMR) ++#define REG_UDC_EPIntR REG32(UDC_EPIntR) ++#define REG_UDC_EPIntMR REG32(UDC_EPIntMR) ++ ++#define REG_UDC_STCMAR REG32(UDC_STCMAR) ++#define REG_UDC_EP0InfR REG32(UDC_EP0InfR) ++#define REG_UDC_EP1InfR REG32(UDC_EP1InfR) ++#define REG_UDC_EP2InfR REG32(UDC_EP2InfR) ++#define REG_UDC_EP3InfR REG32(UDC_EP3InfR) ++#define REG_UDC_EP4InfR REG32(UDC_EP4InfR) ++#define REG_UDC_EP5InfR REG32(UDC_EP5InfR) ++#define REG_UDC_EP6InfR REG32(UDC_EP6InfR) ++#define REG_UDC_EP7InfR REG32(UDC_EP7InfR) ++ ++#define UDC_DevCFGR_PI (1 << 5) ++#define UDC_DevCFGR_SS (1 << 4) ++#define UDC_DevCFGR_SP (1 << 3) ++#define UDC_DevCFGR_RW (1 << 2) ++#define UDC_DevCFGR_SPD_BIT 0 ++#define UDC_DevCFGR_SPD_MASK (0x03 << UDC_DevCFGR_SPD_BIT) ++ #define UDC_DevCFGR_SPD_HS (0 << UDC_DevCFGR_SPD_BIT) ++ #define UDC_DevCFGR_SPD_LS (2 << UDC_DevCFGR_SPD_BIT) ++ #define UDC_DevCFGR_SPD_FS (3 << UDC_DevCFGR_SPD_BIT) ++ ++#define UDC_DevCR_DM (1 << 9) ++#define UDC_DevCR_BE (1 << 5) ++#define UDC_DevCR_RES (1 << 0) ++ ++#define UDC_DevSR_ENUMSPD_BIT 13 ++#define UDC_DevSR_ENUMSPD_MASK (0x03 << UDC_DevSR_ENUMSPD_BIT) ++ #define UDC_DevSR_ENUMSPD_HS (0 << UDC_DevSR_ENUMSPD_BIT) ++ #define UDC_DevSR_ENUMSPD_LS (2 << UDC_DevSR_ENUMSPD_BIT) ++ #define UDC_DevSR_ENUMSPD_FS (3 << UDC_DevSR_ENUMSPD_BIT) ++#define UDC_DevSR_SUSP (1 << 12) ++#define UDC_DevSR_ALT_BIT 8 ++#define UDC_DevSR_ALT_MASK (0x0f << UDC_DevSR_ALT_BIT) ++#define UDC_DevSR_INTF_BIT 4 ++#define UDC_DevSR_INTF_MASK (0x0f << UDC_DevSR_INTF_BIT) ++#define UDC_DevSR_CFG_BIT 0 ++#define UDC_DevSR_CFG_MASK (0x0f << UDC_DevSR_CFG_BIT) ++ ++#define UDC_DevIntR_ENUM (1 << 6) ++#define UDC_DevIntR_SOF (1 << 5) ++#define UDC_DevIntR_US (1 << 4) ++#define UDC_DevIntR_UR (1 << 3) ++#define UDC_DevIntR_SI (1 << 1) ++#define UDC_DevIntR_SC (1 << 0) ++ ++#define UDC_EPIntR_OUTEP_BIT 16 ++#define UDC_EPIntR_OUTEP_MASK (0xffff << UDC_EPIntR_OUTEP_BIT) ++#define UDC_EPIntR_OUTEP0 0x00010000 ++#define UDC_EPIntR_OUTEP5 0x00200000 ++#define UDC_EPIntR_OUTEP6 0x00400000 ++#define UDC_EPIntR_OUTEP7 0x00800000 ++#define UDC_EPIntR_INEP_BIT 0 ++#define UDC_EPIntR_INEP_MASK (0xffff << UDC_EPIntR_INEP_BIT) ++#define UDC_EPIntR_INEP0 0x00000001 ++#define UDC_EPIntR_INEP1 0x00000002 ++#define UDC_EPIntR_INEP2 0x00000004 ++#define UDC_EPIntR_INEP3 0x00000008 ++#define UDC_EPIntR_INEP4 0x00000010 ++ ++ ++#define UDC_EPIntMR_OUTEP_BIT 16 ++#define UDC_EPIntMR_OUTEP_MASK (0xffff << UDC_EPIntMR_OUTEP_BIT) ++#define UDC_EPIntMR_INEP_BIT 0 ++#define UDC_EPIntMR_INEP_MASK (0xffff << UDC_EPIntMR_INEP_BIT) ++ ++#define UDC_EPCR_ET_BIT 4 ++#define UDC_EPCR_ET_MASK (0x03 << UDC_EPCR_ET_BIT) ++ #define UDC_EPCR_ET_CTRL (0 << UDC_EPCR_ET_BIT) ++ #define UDC_EPCR_ET_ISO (1 << UDC_EPCR_ET_BIT) ++ #define UDC_EPCR_ET_BULK (2 << UDC_EPCR_ET_BIT) ++ #define UDC_EPCR_ET_INTR (3 << UDC_EPCR_ET_BIT) ++#define UDC_EPCR_SN (1 << 2) ++#define UDC_EPCR_F (1 << 1) ++#define UDC_EPCR_S (1 << 0) ++ ++#define UDC_EPSR_RXPKTSIZE_BIT 11 ++#define UDC_EPSR_RXPKTSIZE_MASK (0x7ff << UDC_EPSR_RXPKTSIZE_BIT) ++#define UDC_EPSR_IN (1 << 6) ++#define UDC_EPSR_OUT_BIT 4 ++#define UDC_EPSR_OUT_MASK (0x03 << UDC_EPSR_OUT_BIT) ++ #define UDC_EPSR_OUT_NONE (0 << UDC_EPSR_OUT_BIT) ++ #define UDC_EPSR_OUT_RCVDATA (1 << UDC_EPSR_OUT_BIT) ++ #define UDC_EPSR_OUT_RCVSETUP (2 << UDC_EPSR_OUT_BIT) ++#define UDC_EPSR_PID_BIT 0 ++#define UDC_EPSR_PID_MASK (0x0f << UDC_EPSR_PID_BIT) ++ ++#define UDC_EPInfR_MPS_BIT 19 ++#define UDC_EPInfR_MPS_MASK (0x3ff << UDC_EPInfR_MPS_BIT) ++#define UDC_EPInfR_ALTS_BIT 15 ++#define UDC_EPInfR_ALTS_MASK (0x0f << UDC_EPInfR_ALTS_BIT) ++#define UDC_EPInfR_IFN_BIT 11 ++#define UDC_EPInfR_IFN_MASK (0x0f << UDC_EPInfR_IFN_BIT) ++#define UDC_EPInfR_CGN_BIT 7 ++#define UDC_EPInfR_CGN_MASK (0x0f << UDC_EPInfR_CGN_BIT) ++#define UDC_EPInfR_EPT_BIT 5 ++#define UDC_EPInfR_EPT_MASK (0x03 << UDC_EPInfR_EPT_BIT) ++ #define UDC_EPInfR_EPT_CTRL (0 << UDC_EPInfR_EPT_BIT) ++ #define UDC_EPInfR_EPT_ISO (1 << UDC_EPInfR_EPT_BIT) ++ #define UDC_EPInfR_EPT_BULK (2 << UDC_EPInfR_EPT_BIT) ++ #define UDC_EPInfR_EPT_INTR (3 << UDC_EPInfR_EPT_BIT) ++#define UDC_EPInfR_EPD (1 << 4) ++ #define UDC_EPInfR_EPD_OUT (0 << 4) ++ #define UDC_EPInfR_EPD_IN (1 << 4) ++ ++#define UDC_EPInfR_EPN_BIT 0 ++#define UDC_EPInfR_EPN_MASK (0xf << UDC_EPInfR_EPN_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * DMAC ++ *************************************************************************/ ++#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) ++#define DMAC_DDAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) ++#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) ++#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) ++#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) ++#define DMAC_DMAIPR (DMAC_BASE + 0xf8) ++#define DMAC_DMACR (DMAC_BASE + 0xfc) ++ ++#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n))) ++#define REG_DMAC_DDAR(n) REG32(DMAC_DDAR((n))) ++#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n))) ++#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n))) ++#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n))) ++#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR) ++#define REG_DMAC_DMACR REG32(DMAC_DMACR) ++ ++#define DMAC_DRSR_RS_BIT 0 ++#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_EXTREXTR (0 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_PCMCIAOUT (4 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_PCMCIAIN (5 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_DESOUT (10 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_DESIN (11 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_OST2 (28 << DMAC_DRSR_RS_BIT) ++ ++#define DMAC_DCCSR_EACKS (1 << 31) ++#define DMAC_DCCSR_EACKM (1 << 30) ++#define DMAC_DCCSR_ERDM_BIT 28 ++#define DMAC_DCCSR_ERDM_MASK (0x03 << DMAC_DCCSR_ERDM_BIT) ++ #define DMAC_DCCSR_ERDM_LLEVEL (0 << DMAC_DCCSR_ERDM_BIT) ++ #define DMAC_DCCSR_ERDM_FEDGE (1 << DMAC_DCCSR_ERDM_BIT) ++ #define DMAC_DCCSR_ERDM_HLEVEL (2 << DMAC_DCCSR_ERDM_BIT) ++ #define DMAC_DCCSR_ERDM_REDGE (3 << DMAC_DCCSR_ERDM_BIT) ++#define DMAC_DCCSR_EOPM (1 << 27) ++#define DMAC_DCCSR_SAM (1 << 23) ++#define DMAC_DCCSR_DAM (1 << 22) ++#define DMAC_DCCSR_RDIL_BIT 16 ++#define DMAC_DCCSR_RDIL_MASK (0x0f << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_IGN (0 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_2 (1 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_4 (2 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_8 (3 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_12 (4 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_16 (5 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_20 (6 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_24 (7 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_28 (8 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_32 (9 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_48 (10 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_60 (11 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_64 (12 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_124 (13 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_128 (14 << DMAC_DCCSR_RDIL_BIT) ++ #define DMAC_DCCSR_RDIL_200 (15 << DMAC_DCCSR_RDIL_BIT) ++#define DMAC_DCCSR_SWDH_BIT 14 ++#define DMAC_DCCSR_SWDH_MASK (0x03 << DMAC_DCCSR_SWDH_BIT) ++ #define DMAC_DCCSR_SWDH_32 (0 << DMAC_DCCSR_SWDH_BIT) ++ #define DMAC_DCCSR_SWDH_8 (1 << DMAC_DCCSR_SWDH_BIT) ++ #define DMAC_DCCSR_SWDH_16 (2 << DMAC_DCCSR_SWDH_BIT) ++#define DMAC_DCCSR_DWDH_BIT 12 ++#define DMAC_DCCSR_DWDH_MASK (0x03 << DMAC_DCCSR_DWDH_BIT) ++ #define DMAC_DCCSR_DWDH_32 (0 << DMAC_DCCSR_DWDH_BIT) ++ #define DMAC_DCCSR_DWDH_8 (1 << DMAC_DCCSR_DWDH_BIT) ++ #define DMAC_DCCSR_DWDH_16 (2 << DMAC_DCCSR_DWDH_BIT) ++#define DMAC_DCCSR_DS_BIT 8 ++#define DMAC_DCCSR_DS_MASK (0x07 << DMAC_DCCSR_DS_BIT) ++ #define DMAC_DCCSR_DS_32b (0 << DMAC_DCCSR_DS_BIT) ++ #define DMAC_DCCSR_DS_8b (1 << DMAC_DCCSR_DS_BIT) ++ #define DMAC_DCCSR_DS_16b (2 << DMAC_DCCSR_DS_BIT) ++ #define DMAC_DCCSR_DS_16B (3 << DMAC_DCCSR_DS_BIT) ++ #define DMAC_DCCSR_DS_32B (4 << DMAC_DCCSR_DS_BIT) ++#define DMAC_DCCSR_TM (1 << 7) ++#define DMAC_DCCSR_AR (1 << 4) ++#define DMAC_DCCSR_TC (1 << 3) ++#define DMAC_DCCSR_HLT (1 << 2) ++#define DMAC_DCCSR_TCIE (1 << 1) ++#define DMAC_DCCSR_CHDE (1 << 0) ++ ++#define DMAC_DMAIPR_CINT_BIT 8 ++#define DMAC_DMAIPR_CINT_MASK (0xff << DMAC_DMAIPR_CINT_BIT) ++ ++#define DMAC_DMACR_PR_BIT 8 ++#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_01234567 (0 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_02314675 (1 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_20136457 (2 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_ROUNDROBIN (3 << DMAC_DMACR_PR_BIT) ++#define DMAC_DMACR_HTR (1 << 3) ++#define DMAC_DMACR_AER (1 << 2) ++#define DMAC_DMACR_DME (1 << 0) ++ ++#define IRQ_DMA_0 32 ++#define NUM_DMA 6 ++ ++#define DMAC_DSAR0 DMAC_DSAR(0) ++#define DMAC_DDAR0 DMAC_DDAR(0) ++#define DMAC_DTCR0 DMAC_DTCR(0) ++#define DMAC_DRSR0 DMAC_DRSR(0) ++#define DMAC_DCCSR0 DMAC_DCCSR(0) ++ ++#define DMAC_DSAR1 DMAC_DSAR(1) ++#define DMAC_DDAR1 DMAC_DDAR(1) ++#define DMAC_DTCR1 DMAC_DTCR(1) ++#define DMAC_DRSR1 DMAC_DRSR(1) ++#define DMAC_DCCSR1 DMAC_DCCSR(1) ++ ++#define DMAC_DSAR2 DMAC_DSAR(2) ++#define DMAC_DDAR2 DMAC_DDAR(2) ++#define DMAC_DTCR2 DMAC_DTCR(2) ++#define DMAC_DRSR2 DMAC_DRSR(2) ++#define DMAC_DCCSR2 DMAC_DCCSR(2) ++ ++#define DMAC_DSAR3 DMAC_DSAR(3) ++#define DMAC_DDAR3 DMAC_DDAR(3) ++#define DMAC_DTCR3 DMAC_DTCR(3) ++#define DMAC_DRSR3 DMAC_DRSR(3) ++#define DMAC_DCCSR3 DMAC_DCCSR(3) ++ ++#define DMAC_DSAR4 DMAC_DSAR(4) ++#define DMAC_DDAR4 DMAC_DDAR(4) ++#define DMAC_DTCR4 DMAC_DTCR(4) ++#define DMAC_DRSR4 DMAC_DRSR(4) ++#define DMAC_DCCSR4 DMAC_DCCSR(4) ++ ++#define DMAC_DSAR5 DMAC_DSAR(5) ++#define DMAC_DDAR5 DMAC_DDAR(5) ++#define DMAC_DTCR5 DMAC_DTCR(5) ++#define DMAC_DRSR5 DMAC_DRSR(5) ++#define DMAC_DCCSR5 DMAC_DCCSR(5) ++ ++#define DMAC_DSAR6 DMAC_DSAR(6) ++#define DMAC_DDAR6 DMAC_DDAR(6) ++#define DMAC_DTCR6 DMAC_DTCR(6) ++#define DMAC_DRSR6 DMAC_DRSR(6) ++#define DMAC_DCCSR6 DMAC_DCCSR(6) ++ ++#define DMAC_DSAR7 DMAC_DSAR(7) ++#define DMAC_DDAR7 DMAC_DDAR(7) ++#define DMAC_DTCR7 DMAC_DTCR(7) ++#define DMAC_DRSR7 DMAC_DRSR(7) ++#define DMAC_DCCSR7 DMAC_DCCSR(7) ++ ++ ++ ++/************************************************************************* ++ * AIC ++ *************************************************************************/ ++#define AIC_FR (AIC_BASE + 0x000) ++#define AIC_CR (AIC_BASE + 0x004) ++#define AIC_ACCR1 (AIC_BASE + 0x008) ++#define AIC_ACCR2 (AIC_BASE + 0x00C) ++#define AIC_I2SCR (AIC_BASE + 0x010) ++#define AIC_SR (AIC_BASE + 0x014) ++#define AIC_ACSR (AIC_BASE + 0x018) ++#define AIC_I2SSR (AIC_BASE + 0x01C) ++#define AIC_ACCAR (AIC_BASE + 0x020) ++#define AIC_ACCDR (AIC_BASE + 0x024) ++#define AIC_ACSAR (AIC_BASE + 0x028) ++#define AIC_ACSDR (AIC_BASE + 0x02C) ++#define AIC_I2SDIV (AIC_BASE + 0x030) ++#define AIC_DR (AIC_BASE + 0x034) ++ ++#define REG_AIC_FR REG32(AIC_FR) ++#define REG_AIC_CR REG32(AIC_CR) ++#define REG_AIC_ACCR1 REG32(AIC_ACCR1) ++#define REG_AIC_ACCR2 REG32(AIC_ACCR2) ++#define REG_AIC_I2SCR REG32(AIC_I2SCR) ++#define REG_AIC_SR REG32(AIC_SR) ++#define REG_AIC_ACSR REG32(AIC_ACSR) ++#define REG_AIC_I2SSR REG32(AIC_I2SSR) ++#define REG_AIC_ACCAR REG32(AIC_ACCAR) ++#define REG_AIC_ACCDR REG32(AIC_ACCDR) ++#define REG_AIC_ACSAR REG32(AIC_ACSAR) ++#define REG_AIC_ACSDR REG32(AIC_ACSDR) ++#define REG_AIC_I2SDIV REG32(AIC_I2SDIV) ++#define REG_AIC_DR REG32(AIC_DR) ++ ++/* AIC Controller Configuration Register (AIC_FR) */ ++ ++#define AIC_FR_RFTH_BIT 12 ++#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT) ++#define AIC_FR_TFTH_BIT 8 ++#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT) ++#define AIC_FR_AUSEL (1 << 4) ++#define AIC_FR_RST (1 << 3) ++#define AIC_FR_BCKD (1 << 2) ++#define AIC_FR_SYNCD (1 << 1) ++#define AIC_FR_ENB (1 << 0) ++ ++/* AIC Controller Common Control Register (AIC_CR) */ ++ ++#define AIC_CR_RDMS (1 << 15) ++#define AIC_CR_TDMS (1 << 14) ++#define AIC_CR_FLUSH (1 << 8) ++#define AIC_CR_EROR (1 << 6) ++#define AIC_CR_ETUR (1 << 5) ++#define AIC_CR_ERFS (1 << 4) ++#define AIC_CR_ETFS (1 << 3) ++#define AIC_CR_ENLBF (1 << 2) ++#define AIC_CR_ERPL (1 << 1) ++#define AIC_CR_EREC (1 << 0) ++ ++/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ ++ ++#define AIC_ACCR1_RS_BIT 16 ++#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) ++ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit */ ++ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit */ ++ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit */ ++ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit */ ++ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit */ ++ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit */ ++#define AIC_ACCR1_XS_BIT 0 ++#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) ++ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit */ ++ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit */ ++ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit */ ++ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit */ ++ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit */ ++ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit */ ++ ++/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ ++ ++#define AIC_ACCR2_ERSTO (1 << 18) ++#define AIC_ACCR2_ESADR (1 << 17) ++#define AIC_ACCR2_ECADT (1 << 16) ++#define AIC_ACCR2_OASS_BIT 8 ++#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) ++ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_IASS_BIT 6 ++#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) ++ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_SO (1 << 3) ++#define AIC_ACCR2_SR (1 << 2) ++#define AIC_ACCR2_SS (1 << 1) ++#define AIC_ACCR2_SA (1 << 0) ++ ++/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ ++ ++#define AIC_I2SCR_STPBK (1 << 12) ++#define AIC_I2SCR_WL_BIT 1 ++#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) ++ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ ++ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ ++ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ ++ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ ++ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ ++#define AIC_I2SCR_AMSL (1 << 0) ++ ++/* AIC Controller FIFO Status Register (AIC_SR) */ ++ ++#define AIC_SR_RFL_BIT 24 ++#define AIC_SR_RFL_MASK (0x1f << AIC_SR_RFL_BIT) ++#define AIC_SR_TFL_BIT 8 ++#define AIC_SR_TFL_MASK (0x1f << AIC_SR_TFL_BIT) ++#define AIC_SR_ROR (1 << 6) ++#define AIC_SR_TUR (1 << 5) ++#define AIC_SR_RFS (1 << 4) ++#define AIC_SR_TFS (1 << 3) ++ ++/* AIC Controller AC-link Status Register (AIC_ACSR) */ ++ ++#define AIC_ACSR_CRDY (1 << 20) ++#define AIC_ACSR_CLPM (1 << 19) ++#define AIC_ACSR_RSTO (1 << 18) ++#define AIC_ACSR_SADR (1 << 17) ++#define AIC_ACSR_CADT (1 << 16) ++ ++/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ ++ ++#define AIC_I2SSR_BSY (1 << 2) ++ ++/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ ++ ++#define AIC_ACCAR_CAR_BIT 0 ++#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) ++ ++/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ ++ ++#define AIC_ACCDR_CDR_BIT 0 ++#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) ++ ++/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ ++ ++#define AIC_ACSAR_SAR_BIT 0 ++#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) ++ ++/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ ++ ++#define AIC_ACSDR_SDR_BIT 0 ++#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) ++ ++/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ ++ ++#define AIC_I2SDIV_DIV_BIT 0 ++#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) ++ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ ++ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ ++ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ ++ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ ++ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ ++ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ ++ ++ ++ ++ ++/************************************************************************* ++ * LCD ++ *************************************************************************/ ++#define LCD_CFG (LCD_BASE + 0x00) ++#define LCD_VSYNC (LCD_BASE + 0x04) ++#define LCD_HSYNC (LCD_BASE + 0x08) ++#define LCD_VAT (LCD_BASE + 0x0c) ++#define LCD_DAH (LCD_BASE + 0x10) ++#define LCD_DAV (LCD_BASE + 0x14) ++#define LCD_PS (LCD_BASE + 0x18) ++#define LCD_CLS (LCD_BASE + 0x1c) ++#define LCD_SPL (LCD_BASE + 0x20) ++#define LCD_REV (LCD_BASE + 0x24) ++#define LCD_CTRL (LCD_BASE + 0x30) ++#define LCD_STATE (LCD_BASE + 0x34) ++#define LCD_IID (LCD_BASE + 0x38) ++#define LCD_DA0 (LCD_BASE + 0x40) ++#define LCD_SA0 (LCD_BASE + 0x44) ++#define LCD_FID0 (LCD_BASE + 0x48) ++#define LCD_CMD0 (LCD_BASE + 0x4c) ++#define LCD_DA1 (LCD_BASE + 0x50) ++#define LCD_SA1 (LCD_BASE + 0x54) ++#define LCD_FID1 (LCD_BASE + 0x58) ++#define LCD_CMD1 (LCD_BASE + 0x5c) ++ ++#define REG_LCD_CFG REG32(LCD_CFG) ++#define REG_LCD_VSYNC REG32(LCD_VSYNC) ++#define REG_LCD_HSYNC REG32(LCD_HSYNC) ++#define REG_LCD_VAT REG32(LCD_VAT) ++#define REG_LCD_DAH REG32(LCD_DAH) ++#define REG_LCD_DAV REG32(LCD_DAV) ++#define REG_LCD_PS REG32(LCD_PS) ++#define REG_LCD_CLS REG32(LCD_CLS) ++#define REG_LCD_SPL REG32(LCD_SPL) ++#define REG_LCD_REV REG32(LCD_REV) ++#define REG_LCD_CTRL REG32(LCD_CTRL) ++#define REG_LCD_STATE REG32(LCD_STATE) ++#define REG_LCD_IID REG32(LCD_IID) ++#define REG_LCD_DA0 REG32(LCD_DA0) ++#define REG_LCD_SA0 REG32(LCD_SA0) ++#define REG_LCD_FID0 REG32(LCD_FID0) ++#define REG_LCD_CMD0 REG32(LCD_CMD0) ++#define REG_LCD_DA1 REG32(LCD_DA1) ++#define REG_LCD_SA1 REG32(LCD_SA1) ++#define REG_LCD_FID1 REG32(LCD_FID1) ++#define REG_LCD_CMD1 REG32(LCD_CMD1) ++ ++#define LCD_CFG_PDW_BIT 4 ++#define LCD_CFG_PDW_MASK (0x03 << LCD_DEV_PDW_BIT) ++ #define LCD_CFG_PDW_1 (0 << LCD_DEV_PDW_BIT) ++ #define LCD_CFG_PDW_2 (1 << LCD_DEV_PDW_BIT) ++ #define LCD_CFG_PDW_4 (2 << LCD_DEV_PDW_BIT) ++ #define LCD_CFG_PDW_8 (3 << LCD_DEV_PDW_BIT) ++#define LCD_CFG_MODE_BIT 0 ++#define LCD_CFG_MODE_MASK (0x0f << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_SHARP_HR (1 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_DEV_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_DEV_MODE_BIT) ++ ++#define LCD_VSYNC_VPS_BIT 16 ++#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT) ++#define LCD_VSYNC_VPE_BIT 0 ++#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT) ++ ++#define LCD_HSYNC_HPS_BIT 16 ++#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT) ++#define LCD_HSYNC_HPE_BIT 0 ++#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT) ++ ++#define LCD_VAT_HT_BIT 16 ++#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT) ++#define LCD_VAT_VT_BIT 0 ++#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT) ++ ++#define LCD_DAH_HDS_BIT 16 ++#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) ++#define LCD_DAH_HDE_BIT 0 ++#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) ++ ++#define LCD_DAV_VDS_BIT 16 ++#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) ++#define LCD_DAV_VDE_BIT 0 ++#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) ++ ++#define LCD_CTRL_BST_BIT 28 ++#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) ++ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) ++ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) ++ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) ++#define LCD_CTRL_RGB555 (1 << 27) ++#define LCD_CTRL_OFUP (1 << 26) ++#define LCD_CTRL_FRC_BIT 24 ++#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) ++ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) ++ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) ++ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) ++#define LCD_CTRL_PDD_BIT 16 ++#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) ++#define LCD_CTRL_EOFM (1 << 13) ++#define LCD_CTRL_SOFM (1 << 12) ++#define LCD_CTRL_OFUM (1 << 11) ++#define LCD_CTRL_IFUM0 (1 << 10) ++#define LCD_CTRL_IFUM1 (1 << 9) ++#define LCD_CTRL_LDDM (1 << 8) ++#define LCD_CTRL_QDM (1 << 7) ++#define LCD_CTRL_BEDN (1 << 6) ++#define LCD_CTRL_PEDN (1 << 5) ++#define LCD_CTRL_DIS (1 << 4) ++#define LCD_CTRL_ENA (1 << 3) ++#define LCD_CTRL_BPP_BIT 0 ++#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) ++ ++#define LCD_STATE_QD (1 << 7) ++#define LCD_STATE_EOF (1 << 5) ++#define LCD_STATE_SOF (1 << 4) ++#define LCD_STATE_OFU (1 << 3) ++#define LCD_STATE_IFU0 (1 << 2) ++#define LCD_STATE_IFU1 (1 << 1) ++#define LCD_STATE_LDD (1 << 0) ++ ++#define LCD_CMD_SOFINT (1 << 31) ++#define LCD_CMD_EOFINT (1 << 30) ++#define LCD_CMD_PAL (1 << 28) ++#define LCD_CMD_LEN_BIT 0 ++#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * DES ++ *************************************************************************/ ++#define DES_CR1 (DES_BASE + 0x000) ++#define DES_CR2 (DES_BASE + 0x004) ++#define DES_SR (DES_BASE + 0x008) ++#define DES_K1L (DES_BASE + 0x010) ++#define DES_K1R (DES_BASE + 0x014) ++#define DES_K2L (DES_BASE + 0x018) ++#define DES_K2R (DES_BASE + 0x01C) ++#define DES_K3L (DES_BASE + 0x020) ++#define DES_K3R (DES_BASE + 0x024) ++#define DES_IVL (DES_BASE + 0x028) ++#define DES_IVR (DES_BASE + 0x02C) ++#define DES_DIN (DES_BASE + 0x030) ++#define DES_DOUT (DES_BASE + 0x034) ++ ++#define REG_DES_CR1 REG32(DES_CR1) ++#define REG_DES_CR2 REG32(DES_CR2) ++#define REG_DES_SR REG32(DES_SR) ++#define REG_DES_K1L REG32(DES_K1L) ++#define REG_DES_K1R REG32(DES_K1R) ++#define REG_DES_K2L REG32(DES_K2L) ++#define REG_DES_K2R REG32(DES_K2R) ++#define REG_DES_K3L REG32(DES_K3L) ++#define REG_DES_K3R REG32(DES_K3R) ++#define REG_DES_IVL REG32(DES_IVL) ++#define REG_DES_IVR REG32(DES_IVR) ++#define REG_DES_DIN REG32(DES_DIN) ++#define REG_DES_DOUT REG32(DES_DOUT) ++ ++/* DES Control Register 1 (DES_CR1) */ ++ ++#define DES_CR1_EN (1 << 0) ++ ++/* DES Control Register 2 (DES_CR2) */ ++ ++#define DES_CR2_ENDEC (1 << 3) ++#define DES_CR2_MODE (1 << 2) ++#define DES_CR2_ALG (1 << 1) ++#define DES_CR2_DMAE (1 << 0) ++ ++/* DES State Register (DES_SR) */ ++ ++#define DES_SR_IN_FULL (1 << 5) ++#define DES_SR_IN_LHF (1 << 4) ++#define DES_SR_IN_EMPTY (1 << 3) ++#define DES_SR_OUT_FULL (1 << 2) ++#define DES_SR_OUT_GHF (1 << 1) ++#define DES_SR_OUT_EMPTY (1 << 0) ++ ++ ++ ++ ++/************************************************************************* ++ * CPM ++ *************************************************************************/ ++#define CPM_CFCR (CPM_BASE+0x00) ++#define CPM_PLCR1 (CPM_BASE+0x10) ++#define CPM_OCR (CPM_BASE+0x1c) ++#define CPM_CFCR2 (CPM_BASE+0x60) ++#define CPM_LPCR (CPM_BASE+0x04) ++#define CPM_RSTR (CPM_BASE+0x08) ++#define CPM_MSCR (CPM_BASE+0x20) ++#define CPM_SCR (CPM_BASE+0x24) ++#define CPM_WRER (CPM_BASE+0x28) ++#define CPM_WFER (CPM_BASE+0x2c) ++#define CPM_WER (CPM_BASE+0x30) ++#define CPM_WSR (CPM_BASE+0x34) ++#define CPM_GSR0 (CPM_BASE+0x38) ++#define CPM_GSR1 (CPM_BASE+0x3c) ++#define CPM_GSR2 (CPM_BASE+0x40) ++#define CPM_SPR (CPM_BASE+0x44) ++#define CPM_GSR3 (CPM_BASE+0x48) ++ ++#define REG_CPM_CFCR REG32(CPM_CFCR) ++#define REG_CPM_PLCR1 REG32(CPM_PLCR1) ++#define REG_CPM_OCR REG32(CPM_OCR) ++#define REG_CPM_CFCR2 REG32(CPM_CFCR2) ++#define REG_CPM_LPCR REG32(CPM_LPCR) ++#define REG_CPM_RSTR REG32(CPM_RSTR) ++#define REG_CPM_MSCR REG32(CPM_MSCR) ++#define REG_CPM_SCR REG32(CPM_SCR) ++#define REG_CPM_WRER REG32(CPM_WRER) ++#define REG_CPM_WFER REG32(CPM_WFER) ++#define REG_CPM_WER REG32(CPM_WER) ++#define REG_CPM_WSR REG32(CPM_WSR) ++#define REG_CPM_GSR0 REG32(CPM_GSR0) ++#define REG_CPM_GSR1 REG32(CPM_GSR1) ++#define REG_CPM_GSR2 REG32(CPM_GSR2) ++#define REG_CPM_SPR REG32(CPM_SPR) ++#define REG_CPM_GSR3 REG32(CPM_GSR3) ++ ++#define CPM_CFCR_SSI (1 << 31) ++#define CPM_CFCR_LCD (1 << 30) ++#define CPM_CFCR_I2S (1 << 29) ++#define CPM_CFCR_UCS (1 << 28) ++#define CPM_CFCR_UFR_BIT 25 ++#define CPM_CFCR_UFR_MASK (0x07 << CPM_CFCR_UFR_BIT) ++#define CPM_CFCR_MSC (1 << 24) ++#define CPM_CFCR_CKOEN2 (1 << 23) ++#define CPM_CFCR_CKOEN1 (1 << 22) ++#define CPM_CFCR_UPE (1 << 20) ++#define CPM_CFCR_MFR_BIT 16 ++#define CPM_CFCR_MFR_MASK (0x0f << CPM_CFCR_MFR_BIT) ++#define CPM_CFCR_LFR_BIT 12 ++#define CPM_CFCR_LFR_MASK (0x0f << CPM_CFCR_LFR_BIT) ++#define CPM_CFCR_PFR_BIT 8 ++#define CPM_CFCR_PFR_MASK (0x0f << CPM_CFCR_PFR_BIT) ++#define CPM_CFCR_SFR_BIT 4 ++#define CPM_CFCR_SFR_MASK (0x0f << CPM_CFCR_SFR_BIT) ++#define CPM_CFCR_IFR_BIT 0 ++#define CPM_CFCR_IFR_MASK (0x0f << CPM_CFCR_IFR_BIT) ++ ++#define CPM_PLCR1_PLL1FD_BIT 23 ++#define CPM_PLCR1_PLL1FD_MASK (0x1ff << CPM_PLCR1_PLL1FD_BIT) ++#define CPM_PLCR1_PLL1RD_BIT 18 ++#define CPM_PLCR1_PLL1RD_MASK (0x1f << CPM_PLCR1_PLL1RD_BIT) ++#define CPM_PLCR1_PLL1OD_BIT 16 ++#define CPM_PLCR1_PLL1OD_MASK (0x03 << CPM_PLCR1_PLL1OD_BIT) ++#define CPM_PLCR1_PLL1S (1 << 10) ++#define CPM_PLCR1_PLL1BP (1 << 9) ++#define CPM_PLCR1_PLL1EN (1 << 8) ++#define CPM_PLCR1_PLL1ST_BIT 0 ++#define CPM_PLCR1_PLL1ST_MASK (0xff << CPM_PLCR1_PLL1ST_BIT) ++ ++#define CPM_OCR_O1ST_BIT 16 ++#define CPM_OCR_O1ST_MASK (0xff << CPM_OCR_O1ST_BIT) ++#define CPM_OCR_EXT_RTC_CLK (1<<8) ++#define CPM_OCR_SUSPEND_PHY1 (1<<7) ++#define CPM_OCR_SUSPEND_PHY0 (1<<6) ++ ++#define CPM_CFCR2_PXFR_BIT 0 ++#define CPM_CFCR2_PXFR_MASK (0x1ff << CPM_CFCR2_PXFR_BIT) ++ ++#define CPM_LPCR_DUTY_BIT 3 ++#define CPM_LPCR_DUTY_MASK (0x1f << CPM_LPCR_DUTY_BIT) ++#define CPM_LPCR_DOZE (1 << 2) ++#define CPM_LPCR_LPM_BIT 0 ++#define CPM_LPCR_LPM_MASK (0x03 << CPM_LPCR_LPM_BIT) ++ #define CPM_LPCR_LPM_IDLE (0 << CPM_LPCR_LPM_BIT) ++ #define CPM_LPCR_LPM_SLEEP (1 << CPM_LPCR_LPM_BIT) ++ #define CPM_LPCR_LPM_HIBERNATE (2 << CPM_LPCR_LPM_BIT) ++ ++#define CPM_RSTR_SR (1 << 2) ++#define CPM_RSTR_WR (1 << 1) ++#define CPM_RSTR_HR (1 << 0) ++ ++#define CPM_MSCR_MSTP_BIT 0 ++#define CPM_MSCR_MSTP_MASK (0x1ffffff << CPM_MSCR_MSTP_BIT) ++ #define CPM_MSCR_MSTP_UART0 0 ++ #define CPM_MSCR_MSTP_UART1 1 ++ #define CPM_MSCR_MSTP_UART2 2 ++ #define CPM_MSCR_MSTP_OST 3 ++ #define CPM_MSCR_MSTP_DMAC 5 ++ #define CPM_MSCR_MSTP_UHC 6 ++ #define CPM_MSCR_MSTP_LCD 7 ++ #define CPM_MSCR_MSTP_I2C 8 ++ #define CPM_MSCR_MSTP_AICPCLK 9 ++ #define CPM_MSCR_MSTP_PWM0 10 ++ #define CPM_MSCR_MSTP_PWM1 11 ++ #define CPM_MSCR_MSTP_SSI 12 ++ #define CPM_MSCR_MSTP_MSC 13 ++ #define CPM_MSCR_MSTP_SCC 14 ++ #define CPM_MSCR_MSTP_AICBCLK 18 ++ #define CPM_MSCR_MSTP_UART3 20 ++ #define CPM_MSCR_MSTP_ETH 21 ++ #define CPM_MSCR_MSTP_KBC 22 ++ #define CPM_MSCR_MSTP_CIM 23 ++ #define CPM_MSCR_MSTP_UDC 24 ++ #define CPM_MSCR_MSTP_UPRT 25 ++ ++#define CPM_SCR_O1SE (1 << 4) ++#define CPM_SCR_HGP (1 << 3) ++#define CPM_SCR_HZP (1 << 2) ++#define CPM_SCR_HZM (1 << 1) ++ ++#define CPM_WRER_RE_BIT 0 ++#define CPM_WRER_RE_MASK (0xffff << CPM_WRER_RE_BIT) ++ ++#define CPM_WFER_FE_BIT 0 ++#define CPM_WFER_FE_MASK (0xffff << CPM_WFER_FE_BIT) ++ ++#define CPM_WER_WERTC (1 << 31) ++#define CPM_WER_WEETH (1 << 30) ++#define CPM_WER_WE_BIT 0 ++#define CPM_WER_WE_MASK (0xffff << CPM_WER_WE_BIT) ++ ++#define CPM_WSR_WSRTC (1 << 31) ++#define CPM_WSR_WSETH (1 << 30) ++#define CPM_WSR_WS_BIT 0 ++#define CPM_WSR_WS_MASK (0xffff << CPM_WSR_WS_BIT) ++ ++ ++ ++ ++/************************************************************************* ++ * SSI ++ *************************************************************************/ ++#define SSI_DR (SSI_BASE + 0x000) ++#define SSI_CR0 (SSI_BASE + 0x004) ++#define SSI_CR1 (SSI_BASE + 0x008) ++#define SSI_SR (SSI_BASE + 0x00C) ++#define SSI_ITR (SSI_BASE + 0x010) ++#define SSI_ICR (SSI_BASE + 0x014) ++#define SSI_GR (SSI_BASE + 0x018) ++ ++#define REG_SSI_DR REG32(SSI_DR) ++#define REG_SSI_CR0 REG16(SSI_CR0) ++#define REG_SSI_CR1 REG32(SSI_CR1) ++#define REG_SSI_SR REG32(SSI_SR) ++#define REG_SSI_ITR REG16(SSI_ITR) ++#define REG_SSI_ICR REG8(SSI_ICR) ++#define REG_SSI_GR REG16(SSI_GR) ++ ++/* SSI Data Register (SSI_DR) */ ++ ++#define SSI_DR_GPC_BIT 0 ++#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) ++ ++/* SSI Control Register 0 (SSI_CR0) */ ++ ++#define SSI_CR0_SSIE (1 << 15) ++#define SSI_CR0_TIE (1 << 14) ++#define SSI_CR0_RIE (1 << 13) ++#define SSI_CR0_TEIE (1 << 12) ++#define SSI_CR0_REIE (1 << 11) ++#define SSI_CR0_LOOP (1 << 10) ++#define SSI_CR0_RFINE (1 << 9) ++#define SSI_CR0_RFINC (1 << 8) ++#define SSI_CR0_FSEL (1 << 6) ++#define SSI_CR0_TFLUSH (1 << 2) ++#define SSI_CR0_RFLUSH (1 << 1) ++#define SSI_CR0_DISREV (1 << 0) ++ ++/* SSI Control Register 1 (SSI_CR1) */ ++ ++#define SSI_CR1_FRMHL_BIT 30 ++#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) ++ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ ++#define SSI_CR1_TFVCK_BIT 28 ++#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) ++#define SSI_CR1_TCKFI_BIT 26 ++#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) ++#define SSI_CR1_LFST (1 << 25) ++#define SSI_CR1_ITFRM (1 << 24) ++#define SSI_CR1_UNFIN (1 << 23) ++#define SSI_CR1_MULTS (1 << 22) ++#define SSI_CR1_FMAT_BIT 20 ++#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) ++ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ ++ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ ++ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ ++ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ ++#define SSI_CR1_MCOM_BIT 12 ++#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) ++ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ ++ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ ++ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ ++ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ ++ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ ++ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ ++ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ ++ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ ++ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ ++ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ ++ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ ++ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ ++ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ ++ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ ++ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ ++ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ ++#define SSI_CR1_TTRG_BIT 10 ++#define SSI_CR1_TTRG_MASK (0x3 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT)/* Less than or equal to 1 */ ++ #define SSI_CR1_TTRG_4 (1 << SSI_CR1_TTRG_BIT) /* Less than or equal to 4 */ ++ #define SSI_CR1_TTRG_8 (2 << SSI_CR1_TTRG_BIT) /* Less than or equal to 8 */ ++ #define SSI_CR1_TTRG_14 (3 << SSI_CR1_TTRG_BIT) /* Less than or equal to 14 */ ++#define SSI_CR1_RTRG_BIT 8 ++#define SSI_CR1_RTRG_MASK (0x3 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) /* More than or equal to 1 */ ++ #define SSI_CR1_RTRG_4 (1 << SSI_CR1_RTRG_BIT) /* More than or equal to 4 */ ++ #define SSI_CR1_RTRG_8 (2 << SSI_CR1_RTRG_BIT) /* More than or equal to 8 */ ++ #define SSI_CR1_RTRG_14 (3 << SSI_CR1_RTRG_BIT) /* More than or equal to 14 */ ++#define SSI_CR1_FLEN_BIT 4 ++#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) ++#define SSI_CR1_PHA (1 << 1) ++#define SSI_CR1_POL (1 << 0) ++ ++/* SSI Status Register (SSI_SR) */ ++ ++#define SSI_SR_TFIFONUM_BIT 13 ++#define SSI_SR_TFIFONUM_MASK (0x1f << SSI_SR_TFIFONUM_BIT) ++#define SSI_SR_RFIFONUM_BIT 8 ++#define SSI_SR_RFIFONUM_MASK (0x1f << SSI_SR_RFIFONUM_BIT) ++#define SSI_SR_END (1 << 7) ++#define SSI_SR_BUSY (1 << 6) ++#define SSI_SR_TFF (1 << 5) ++#define SSI_SR_RFE (1 << 4) ++#define SSI_SR_TFHE (1 << 3) ++#define SSI_SR_RFHF (1 << 2) ++#define SSI_SR_UNDR (1 << 1) ++#define SSI_SR_OVER (1 << 0) ++ ++/* SSI Interval Time Control Register (SSI_ITR) */ ++ ++#define SSI_ITR_CNTCLK (1 << 15) ++#define SSI_ITR_IVLTM_BIT 0 ++#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) ++ ++#endif /* __ASM_JZ4730_REGS_H__ */ +diff --git a/include/asm-mips/mach-jz4730/serial.h b/include/asm-mips/mach-jz4730/serial.h +new file mode 100644 +index 0000000..4a0afc3 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/serial.h +@@ -0,0 +1,33 @@ ++/* ++ * linux/include/asm-mips/mach-jz4730/serial.h ++ * ++ * JZ4730 serial port definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4730_SERIAL_H__ ++#define __ASM_JZ4730_SERIAL_H__ ++ ++#define JZ_BASE_BAUD (JZ_EXTAL/16) ++#define JZ_SERIAL_PORT_DEFNS \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART1, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART1_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART2, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART2_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART3, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART3_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, ++ ++#endif /* __ASM_JZ4730_SERIAL_H__ */ +diff --git a/include/asm-mips/mach-jz4730/war.h b/include/asm-mips/mach-jz4730/war.h +new file mode 100644 +index 0000000..3a5bc17 +--- /dev/null ++++ b/include/asm-mips/mach-jz4730/war.h +@@ -0,0 +1,25 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H ++#define __ASM_MIPS_MACH_JZ4740_WAR_H ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 0 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ +diff --git a/include/asm-mips/mach-jz4740/board-dipper.h b/include/asm-mips/mach-jz4740/board-dipper.h +new file mode 100644 +index 0000000..ae84f24 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/board-dipper.h +@@ -0,0 +1,69 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/board-dipper.h ++ * ++ * JZ4725-based (16bit) Dipper board ver 1.x definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4725_DIPPER_H__ ++#define __ASM_JZ4725_DIPPER_H__ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++/*====================================================================== ++ * GPIO JZ4725 ++ */ ++#define GPIO_SD_VCC_EN_N 85 /* GPC21 */ ++#define GPIO_SD_CD_N 91 /* GPC27 */ ++#define GPIO_SD_WP 112 /* GPD16 */ ++#define GPIO_USB_DETE 124 /* GPD28 */ ++#define GPIO_DC_DETE_N 103 /* GPD7 */ ++#define GPIO_CHARG_STAT_N 86 /* GPC22 */ ++#define GPIO_DISP_OFF_N 118 /* GPD22 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC_WP_PIN GPIO_SD_WP ++#define MSC_HOTPLUG_PIN GPIO_SD_CD_N ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) ++ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++} while (0) ++ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4740_DIPPER_H__ */ +diff --git a/include/asm-mips/mach-jz4740/board-leo.h b/include/asm-mips/mach-jz4740/board-leo.h +new file mode 100644 +index 0000000..4b883e2 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/board-leo.h +@@ -0,0 +1,56 @@ ++#ifndef __ASM_JZ4740_LEO_H__ ++#define __ASM_JZ4740_LEO_H__ ++ ++/* ++ * Define your board specific codes here !!! ++ */ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_DISP_OFF_N 100 ++#define GPIO_SD_VCC_EN_N 119 ++#define GPIO_SD_CD_N 120 ++#define GPIO_SD_WP 111 ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC_WP_PIN GPIO_SD_WP ++#define MSC_HOTPLUG_PIN GPIO_SD_CD_N ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) ++ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++} while (0) ++ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++ if (__gpio_get_pin(GPIO_SD_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4740_BOARD_LEO_H__ */ +diff --git a/include/asm-mips/mach-jz4740/board-lyra.h b/include/asm-mips/mach-jz4740/board-lyra.h +new file mode 100644 +index 0000000..29e0ce0 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/board-lyra.h +@@ -0,0 +1,70 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/board-lyra.h ++ * ++ * JZ4740-based LYRA board ver 2.x definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_LYRA_H__ ++#define __ASM_JZ4740_LYRA_H__ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ ++#define GPIO_SD_CD_N 110 /* GPD14 */ ++#define GPIO_SD_WP 112 /* GPD16 */ ++#define GPIO_USB_DETE 102 /* GPD6 */ ++#define GPIO_DC_DETE_N 103 /* GPD7 */ ++#define GPIO_CHARG_STAT_N 111 /* GPD15 */ ++#define GPIO_DISP_OFF_N 118 /* GPD22 */ ++#define GPIO_LED_EN 124 /* GPD28 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC_WP_PIN GPIO_SD_WP ++#define MSC_HOTPLUG_PIN GPIO_SD_CD_N ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) ++ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++} while (0) ++ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (!(__gpio_get_pin(GPIO_SD_CD_N))) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4740_LYRA_H__ */ +diff --git a/include/asm-mips/mach-jz4740/board-pavo.h b/include/asm-mips/mach-jz4740/board-pavo.h +new file mode 100644 +index 0000000..f33831b +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/board-pavo.h +@@ -0,0 +1,70 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/board-pavo.h ++ * ++ * JZ4730-based PAVO board ver 2.x definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_PAVO_H__ ++#define __ASM_JZ4740_PAVO_H__ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ ++#define GPIO_SD_CD_N 110 /* GPD14 */ ++#define GPIO_SD_WP 112 /* GPD16 */ ++#define GPIO_USB_DETE 102 /* GPD6 */ ++#define GPIO_DC_DETE_N 103 /* GPD7 */ ++#define GPIO_CHARG_STAT_N 111 /* GPD15 */ ++#define GPIO_DISP_OFF_N 118 /* GPD22 */ ++#define GPIO_LED_EN 124 /* GPD28 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC_WP_PIN GPIO_SD_WP ++#define MSC_HOTPLUG_PIN GPIO_SD_CD_N ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) ++ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++} while (0) ++ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4740_PAVO_H__ */ +diff --git a/include/asm-mips/mach-jz4740/board-virgo.h b/include/asm-mips/mach-jz4740/board-virgo.h +new file mode 100644 +index 0000000..acd7bb7 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/board-virgo.h +@@ -0,0 +1,67 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/board-virgo.h ++ * ++ * JZ4720-based VIRGO board ver 1.x definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4720_VIRGO_H__ ++#define __ASM_JZ4720_VIRGO_H__ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++/*====================================================================== ++ * GPIO VIRGO(JZ4720) ++ */ ++#define GPIO_SD_VCC_EN_N 115 /* GPD19 */ ++#define GPIO_SD_CD_N 116 /* GPD20 */ ++#define GPIO_USB_DETE 114 /* GPD18 */ ++#define GPIO_DC_DETE_N 120 /* GPD24 */ ++#define GPIO_DISP_OFF_N 118 /* GPD22 */ ++#define GPIO_LED_EN 117 /* GPD21 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC_HOTPLUG_PIN GPIO_SD_CD_N ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) ++ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++} while (0) ++ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4720_VIRGO_H__ */ +diff --git a/include/asm-mips/mach-jz4740/clock.h b/include/asm-mips/mach-jz4740/clock.h +new file mode 100644 +index 0000000..11ffe88 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/clock.h +@@ -0,0 +1,173 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/clock.h ++ * ++ * JZ4740 clocks definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_CLOCK_H__ ++#define __ASM_JZ4740_CLOCK_H__ ++ ++#ifndef JZ_EXTAL ++//#define JZ_EXTAL 3686400 /* 3.6864 MHz */ ++#define JZ_EXTAL 12000000 /* 3.6864 MHz */ ++#endif ++#ifndef JZ_EXTAL2 ++#define JZ_EXTAL2 32768 /* 32.768 KHz */ ++#endif ++ ++/* ++ * JZ4740 clocks structure ++ */ ++typedef struct { ++ unsigned int cclk; /* CPU clock */ ++ unsigned int hclk; /* System bus clock */ ++ unsigned int pclk; /* Peripheral bus clock */ ++ unsigned int mclk; /* Flash/SRAM/SDRAM clock */ ++ unsigned int lcdclk; /* LCDC module clock */ ++ unsigned int pixclk; /* LCD pixel clock */ ++ unsigned int i2sclk; /* AIC module clock */ ++ unsigned int usbclk; /* USB module clock */ ++ unsigned int mscclk; /* MSC module clock */ ++ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ ++ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ ++} jz_clocks_t; ++ ++extern jz_clocks_t jz_clocks; ++ ++ ++/* PLL output frequency */ ++static __inline__ unsigned int __cpm_get_pllout(void) ++{ ++ unsigned long m, n, no, pllout; ++ unsigned long cppcr = REG_CPM_CPPCR; ++ unsigned long od[4] = {1, 2, 2, 4}; ++ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { ++ m = __cpm_get_pllm() + 2; ++ n = __cpm_get_plln() + 2; ++ no = od[__cpm_get_pllod()]; ++ pllout = ((JZ_EXTAL) / (n * no)) * m; ++ } else ++ pllout = JZ_EXTAL; ++ return pllout; ++} ++ ++/* PLL output frequency for MSC/I2S/LCD/USB */ ++static __inline__ unsigned int __cpm_get_pllout2(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_PCS) ++ return __cpm_get_pllout(); ++ else ++ return __cpm_get_pllout()/2; ++} ++ ++/* CPU core clock */ ++static __inline__ unsigned int __cpm_get_cclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_cdiv()]; ++} ++ ++/* AHB system bus clock */ ++static __inline__ unsigned int __cpm_get_hclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_hdiv()]; ++} ++ ++/* Memory bus clock */ ++static __inline__ unsigned int __cpm_get_mclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_mdiv()]; ++} ++ ++/* APB peripheral bus clock */ ++static __inline__ unsigned int __cpm_get_pclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_pdiv()]; ++} ++ ++/* LCDC module clock */ ++static __inline__ unsigned int __cpm_get_lcdclk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); ++} ++ ++/* LCD pixel clock */ ++static __inline__ unsigned int __cpm_get_pixclk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); ++} ++ ++/* I2S clock */ ++static __inline__ unsigned int __cpm_get_i2sclk(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { ++ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); ++ } ++ else { ++ return JZ_EXTAL; ++ } ++} ++ ++/* USB clock */ ++static __inline__ unsigned int __cpm_get_usbclk(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { ++ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); ++ } ++ else { ++ return JZ_EXTAL; ++ } ++} ++ ++/* MSC clock */ ++static __inline__ unsigned int __cpm_get_mscclk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_mscdiv() + 1); ++} ++ ++/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ ++static __inline__ unsigned int __cpm_get_extalclk(void) ++{ ++ return JZ_EXTAL; ++} ++ ++/* RTC clock for CPM,INTC,RTC,TCU,WDT */ ++static __inline__ unsigned int __cpm_get_rtcclk(void) ++{ ++ return JZ_EXTAL2; ++} ++ ++/* ++ * Output 24MHz for SD and 16MHz for MMC. ++ */ ++static inline void __cpm_select_msc_clk(int sd) ++{ ++ unsigned int pllout2 = __cpm_get_pllout2(); ++ unsigned int div = 0; ++ ++ if (sd) { ++ div = pllout2 / 24000000; ++ } ++ else { ++ div = pllout2 / 16000000; ++ } ++ ++ REG_CPM_MSCCDR = div - 1; ++} ++ ++#endif /* __ASM_JZ4740_CLOCK_H__ */ +diff --git a/include/asm-mips/mach-jz4740/dma.h b/include/asm-mips/mach-jz4740/dma.h +new file mode 100644 +index 0000000..b82b984 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/dma.h +@@ -0,0 +1,265 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/dma.h ++ * ++ * JZ4740 DMA definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_DMA_H__ ++#define __ASM_JZ4740_DMA_H__ ++ ++#include ++#include /* need byte IO */ ++#include /* And spinlocks */ ++#include ++#include ++ ++/* ++ * Descriptor structure for JZ4740 DMA engine ++ * Note: this structure must always be aligned to a 16-bytes boundary. ++ */ ++ ++typedef struct { ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++ volatile u32 dsadr; /* DSAR value for the current transfer */ ++ volatile u32 dtadr; /* DTAR value for the current transfer */ ++ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ ++} jz_dma_desc; ++ ++ ++/* DMA Device ID's follow */ ++enum { ++ DMA_ID_UART0_TX = 0, ++ DMA_ID_UART0_RX, ++ DMA_ID_SSI_TX, ++ DMA_ID_SSI_RX, ++ DMA_ID_AIC_TX, ++ DMA_ID_AIC_RX, ++ DMA_ID_MSC_TX, ++ DMA_ID_MSC_RX, ++ DMA_ID_TCU_OVERFLOW, ++ DMA_ID_AUTO, ++ DMA_ID_RAW_SET, ++ DMA_ID_MAX ++}; ++ ++/* DMA modes, simulated by sw */ ++#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ ++#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ ++#define DMA_AUTOINIT 0x2 ++#define DMA_MODE_MASK 0x3 ++ ++struct jz_dma_chan { ++ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ ++ unsigned int io; /* DMA channel number */ ++ const char *dev_str; /* string describes the DMA channel */ ++ int irq; /* DMA irq number */ ++ void *irq_dev; /* DMA private device structure */ ++ unsigned int fifo_addr; /* physical fifo address of the requested device */ ++ unsigned int cntl; /* DMA controll */ ++ unsigned int mode; /* DMA configuration */ ++ unsigned int source; /* DMA request source */ ++}; ++ ++extern struct jz_dma_chan jz_dma_table[]; ++ ++ ++#define DMA_8BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_8BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_32_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_32_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++extern int jz_request_dma(int dev_id, ++ const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id); ++extern void jz_free_dma(unsigned int dmanr); ++ ++extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data); ++extern void dump_jz_dma_channel(unsigned int dmanr); ++ ++extern void enable_dma(unsigned int dmanr); ++extern void disable_dma(unsigned int dmanr); ++extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); ++extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); ++extern void set_dma_mode(unsigned int dmanr, unsigned int mode); ++extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern unsigned int get_dma_residue(unsigned int dmanr); ++ ++extern spinlock_t dma_spin_lock; ++ ++static __inline__ unsigned long claim_dma_lock(void) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&dma_spin_lock, flags); ++ return flags; ++} ++ ++static __inline__ void release_dma_lock(unsigned long flags) ++{ ++ spin_unlock_irqrestore(&dma_spin_lock, flags); ++} ++ ++/* Clear the 'DMA Pointer Flip Flop'. ++ * Write 0 for LSB/MSB, 1 for MSB/LSB access. ++ */ ++#define clear_dma_ff(channel) ++ ++static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) ++{ ++ if (dmanr > MAX_DMA_NUM ++ || jz_dma_table[dmanr].dev_id < 0) ++ return NULL; ++ return &jz_dma_table[dmanr]; ++} ++ ++static __inline__ int dma_halted(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 1; ++ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; ++} ++ ++static __inline__ unsigned int get_dma_mode(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ return chan->mode; ++} ++ ++static __inline__ void clear_dma_done(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++} ++ ++static __inline__ void clear_dma_halt(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); ++ REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT); ++} ++ ++static __inline__ void clear_dma_flag(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++ REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); ++} ++ ++static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) ++{ ++} ++ ++static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) ++{ ++ unsigned long dccsr; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ dccsr = REG_DMAC_DCCSR(chan->io); ++ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++} ++ ++static __inline__ int get_dma_done_irq(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return -1; ++ return chan->irq; ++} ++ ++#endif /* __ASM_JZ4740_DMA_H__ */ +diff --git a/include/asm-mips/mach-jz4740/jz4740.h b/include/asm-mips/mach-jz4740/jz4740.h +new file mode 100644 +index 0000000..d38d5f1 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/jz4740.h +@@ -0,0 +1,60 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/jz4740.h ++ * ++ * JZ4740 common definition. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_H__ ++#define __ASM_JZ4740_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*------------------------------------------------------------------ ++ * Platform definitions ++ */ ++#ifdef CONFIG_JZ4740_PAVO ++#include ++#endif ++ ++#ifdef CONFIG_JZ4740_LEO ++#include ++#endif ++ ++#ifdef CONFIG_JZ4740_LYRA ++#include ++#endif ++ ++#ifdef CONFIG_JZ4725_DIPPER ++#include ++#endif ++ ++#ifdef CONFIG_JZ4720_VIRGO ++#include ++#endif ++ ++#ifdef CONFIG_JZ4740_QI_LB60 ++#include ++#endif ++ ++/* Add other platform definition here ... */ ++ ++ ++/*------------------------------------------------------------------ ++ * Follows are related to platform definitions ++ */ ++ ++#include ++#include ++ ++#endif /* __ASM_JZ4740_H__ */ +diff --git a/include/asm-mips/mach-jz4740/misc.h b/include/asm-mips/mach-jz4740/misc.h +new file mode 100644 +index 0000000..8f14a5a +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/misc.h +@@ -0,0 +1,43 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/misc.h ++ * ++ * Ingenic's JZ4740 common include. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_MISC_H__ ++#define __ASM_JZ4740_MISC_H__ ++ ++/*========================================================== ++ * I2C ++ *===========================================================*/ ++ ++#define I2C_EEPROM_DEV 0xA /* b'1010 */ ++#define I2C_RTC_DEV 0xD /* b'1101 */ ++#define DIMM0_SPD_ADDR 0 ++#define DIMM1_SPD_ADDR 1 ++#define DIMM2_SPD_ADDR 2 ++#define DIMM3_SPD_ADDR 3 ++#define JZ_HCI_ADDR 7 ++ ++#define DIMM_SPD_LEN 128 ++#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ ++#define I2C_RTC_LEN 16 ++#define HCI_MAC_OFFSET 64 ++ ++extern void i2c_open(void); ++extern void i2c_close(void); ++extern void i2c_setclk(unsigned int i2cclk); ++extern int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++extern int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++ ++#endif /* __ASM_JZ4740_MISC_H__ */ +diff --git a/include/asm-mips/mach-jz4740/ops.h b/include/asm-mips/mach-jz4740/ops.h +new file mode 100644 +index 0000000..6ff050a +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/ops.h +@@ -0,0 +1,2224 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/ops.h ++ * ++ * Ingenic's JZ4740 common include. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++#ifndef __JZ4740_OPS_H__ ++#define __JZ4740_OPS_H__ ++ ++/* ++ * Definition of Module Operations ++ */ ++ ++/*************************************************************************** ++ * GPIO ++ ***************************************************************************/ ++ ++//------------------------------------------------------ ++// GPIO Pins Description ++// ++// PORT 0: ++// ++// PIN/BIT N FUNC0 FUNC1 ++// 0 D0 - ++// 1 D1 - ++// 2 D2 - ++// 3 D3 - ++// 4 D4 - ++// 5 D5 - ++// 6 D6 - ++// 7 D7 - ++// 8 D8 - ++// 9 D9 - ++// 10 D10 - ++// 11 D11 - ++// 12 D12 - ++// 13 D13 - ++// 14 D14 - ++// 15 D15 - ++// 16 D16 - ++// 17 D17 - ++// 18 D18 - ++// 19 D19 - ++// 20 D20 - ++// 21 D21 - ++// 22 D22 - ++// 23 D23 - ++// 24 D24 - ++// 25 D25 - ++// 26 D26 - ++// 27 D27 - ++// 28 D28 - ++// 29 D29 - ++// 30 D30 - ++// 31 D31 - ++// ++//------------------------------------------------------ ++// PORT 1: ++// ++// PIN/BIT N FUNC0 FUNC1 ++// 0 A0 - ++// 1 A1 - ++// 2 A2 - ++// 3 A3 - ++// 4 A4 - ++// 5 A5 - ++// 6 A6 - ++// 7 A7 - ++// 8 A8 - ++// 9 A9 - ++// 10 A10 - ++// 11 A11 - ++// 12 A12 - ++// 13 A13 - ++// 14 A14 - ++// 15 A15/CL - ++// 16 A16/AL - ++// 17 LCD_CLS A21 ++// 18 LCD_SPL A22 ++// 19 DCS# - ++// 20 RAS# - ++// 21 CAS# - ++// 22 RDWE#/BUFD# - ++// 23 CKE - ++// 24 CKO - ++// 25 CS1# - ++// 26 CS2# - ++// 27 CS3# - ++// 28 CS4# - ++// 29 RD# - ++// 30 WR# - ++// 31 WE0# - ++// ++// Note: PIN15&16 are CL&AL when connecting to NAND flash. ++//------------------------------------------------------ ++// PORT 2: ++// ++// PIN/BIT N FUNC0 FUNC1 ++// 0 LCD_D0 - ++// 1 LCD_D1 - ++// 2 LCD_D2 - ++// 3 LCD_D3 - ++// 4 LCD_D4 - ++// 5 LCD_D5 - ++// 6 LCD_D6 - ++// 7 LCD_D7 - ++// 8 LCD_D8 - ++// 9 LCD_D9 - ++// 10 LCD_D10 - ++// 11 LCD_D11 - ++// 12 LCD_D12 - ++// 13 LCD_D13 - ++// 14 LCD_D14 - ++// 15 LCD_D15 - ++// 16 LCD_D16 - ++// 17 LCD_D17 - ++// 18 LCD_PCLK - ++// 19 LCD_HSYNC - ++// 20 LCD_VSYNC - ++// 21 LCD_DE - ++// 22 LCD_PS A19 ++// 23 LCD_REV A20 ++// 24 WE1# - ++// 25 WE2# - ++// 26 WE3# - ++// 27 WAIT# - ++// 28 FRE# - ++// 29 FWE# - ++// 30(NOTE:FRB#) - - ++// 31 - - ++// ++// NOTE(1): PIN30 is used for FRB# when connecting to NAND flash. ++//------------------------------------------------------ ++// PORT 3: ++// ++// PIN/BIT N FUNC0 FUNC1 ++// 0 CIM_D0 - ++// 1 CIM_D1 - ++// 2 CIM_D2 - ++// 3 CIM_D3 - ++// 4 CIM_D4 - ++// 5 CIM_D5 - ++// 6 CIM_D6 - ++// 7 CIM_D7 - ++// 8 MSC_CMD - ++// 9 MSC_CLK - ++// 10 MSC_D0 - ++// 11 MSC_D1 - ++// 12 MSC_D2 - ++// 13 MSC_D3 - ++// 14 CIM_MCLK - ++// 15 CIM_PCLK - ++// 16 CIM_VSYNC - ++// 17 CIM_HSYNC - ++// 18 SSI_CLK SCLK_RSTN ++// 19 SSI_CE0# BIT_CLK(AIC) ++// 20 SSI_DT SDATA_OUT(AIC) ++// 21 SSI_DR SDATA_IN(AIC) ++// 22 SSI_CE1#&GPC SYNC(AIC) ++// 23 PWM0 I2C_SDA ++// 24 PWM1 I2C_SCK ++// 25 PWM2 UART0_TxD ++// 26 PWM3 UART0_RxD ++// 27 PWM4 A17 ++// 28 PWM5 A18 ++// 29 - - ++// 30 PWM6 UART0_CTS/UART1_RxD ++// 31 PWM7 UART0_RTS/UART1_TxD ++// ++////////////////////////////////////////////////////////// ++ ++/* ++ * p is the port number (0,1,2,3) ++ * o is the pin offset (0-31) inside the port ++ * n is the absolute number of a pin (0-127), regardless of the port ++ */ ++ ++//------------------------------------------- ++// Function Pins Mode ++ ++#define __gpio_as_func0(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXSELC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_func1(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++} while (0) ++ ++/* ++ * D0 ~ D31, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, ++ * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# ++ */ ++#define __gpio_as_sdram_32bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0xffffffff; \ ++ REG_GPIO_PXSELC(0) = 0xffffffff; \ ++ REG_GPIO_PXPES(0) = 0xffffffff; \ ++ REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ ++ REG_GPIO_PXSELC(1) = 0x81f9ffff; \ ++ REG_GPIO_PXPES(1) = 0x81f9ffff; \ ++ REG_GPIO_PXFUNS(2) = 0x07000000; \ ++ REG_GPIO_PXSELC(2) = 0x07000000; \ ++ REG_GPIO_PXPES(2) = 0x07000000; \ ++} while (0) ++ ++/* ++ * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, ++ * RDWE#, CKO#, WE0#, WE1# ++ */ ++#define __gpio_as_sdram_16bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0x5442bfaa; \ ++ REG_GPIO_PXSELC(0) = 0x5442bfaa; \ ++ REG_GPIO_PXPES(0) = 0x5442bfaa; \ ++ REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ ++ REG_GPIO_PXSELC(1) = 0x81f9ffff; \ ++ REG_GPIO_PXPES(1) = 0x81f9ffff; \ ++ REG_GPIO_PXFUNS(2) = 0x01000000; \ ++ REG_GPIO_PXSELC(2) = 0x01000000; \ ++ REG_GPIO_PXPES(2) = 0x01000000; \ ++} while (0) ++ ++/* ++ * CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# ++ */ ++#define __gpio_as_nand() \ ++do { \ ++ REG_GPIO_PXFUNS(1) = 0x02018000; \ ++ REG_GPIO_PXSELC(1) = 0x02018000; \ ++ REG_GPIO_PXPES(1) = 0x02018000; \ ++ REG_GPIO_PXFUNS(2) = 0x30000000; \ ++ REG_GPIO_PXSELC(2) = 0x30000000; \ ++ REG_GPIO_PXPES(2) = 0x30000000; \ ++ REG_GPIO_PXFUNC(2) = 0x40000000; \ ++ REG_GPIO_PXSELC(2) = 0x40000000; \ ++ REG_GPIO_PXDIRC(2) = 0x40000000; \ ++ REG_GPIO_PXPES(2) = 0x40000000; \ ++ REG_GPIO_PXFUNS(1) = 0x00400000; \ ++ REG_GPIO_PXSELC(1) = 0x00400000; \ ++} while (0) ++ ++/* ++ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 ++ */ ++#define __gpio_as_nor_8bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0x000000ff; \ ++ REG_GPIO_PXSELC(0) = 0x000000ff; \ ++ REG_GPIO_PXPES(0) = 0x000000ff; \ ++ REG_GPIO_PXFUNS(1) = 0x7041ffff; \ ++ REG_GPIO_PXSELC(1) = 0x7041ffff; \ ++ REG_GPIO_PXPES(1) = 0x7041ffff; \ ++ REG_GPIO_PXFUNS(1) = 0x00060000; \ ++ REG_GPIO_PXSELS(1) = 0x00060000; \ ++ REG_GPIO_PXPES(1) = 0x00060000; \ ++ REG_GPIO_PXFUNS(2) = 0x08000000; \ ++ REG_GPIO_PXSELC(2) = 0x08000000; \ ++ REG_GPIO_PXPES(2) = 0x08000000; \ ++ REG_GPIO_PXFUNS(2) = 0x00c00000; \ ++ REG_GPIO_PXSELS(2) = 0x00c00000; \ ++ REG_GPIO_PXPES(2) = 0x00c00000; \ ++ REG_GPIO_PXFUNS(3) = 0x18000000; \ ++ REG_GPIO_PXSELS(3) = 0x18000000; \ ++ REG_GPIO_PXPES(3) = 0x18000000; \ ++} while (0) ++ ++/* ++ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 ++ */ ++#define __gpio_as_nor_16bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ ++ REG_GPIO_PXSELC(0) = 0x0000ffff; \ ++ REG_GPIO_PXPES(0) = 0x0000ffff; \ ++ REG_GPIO_PXFUNS(1) = 0x7041ffff; \ ++ REG_GPIO_PXSELC(1) = 0x7041ffff; \ ++ REG_GPIO_PXPES(1) = 0x7041ffff; \ ++ REG_GPIO_PXFUNS(1) = 0x00060000; \ ++ REG_GPIO_PXSELS(1) = 0x00060000; \ ++ REG_GPIO_PXPES(1) = 0x00060000; \ ++ REG_GPIO_PXFUNS(2) = 0x08000000; \ ++ REG_GPIO_PXSELC(2) = 0x08000000; \ ++ REG_GPIO_PXPES(2) = 0x08000000; \ ++ REG_GPIO_PXFUNS(2) = 0x00c00000; \ ++ REG_GPIO_PXSELS(2) = 0x00c00000; \ ++ REG_GPIO_PXPES(2) = 0x00c00000; \ ++ REG_GPIO_PXFUNS(3) = 0x18000000; \ ++ REG_GPIO_PXSELS(3) = 0x18000000; \ ++ REG_GPIO_PXPES(3) = 0x18000000; \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART_RxD0 ++ */ ++#define __gpio_as_uart0() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x06000000; \ ++ REG_GPIO_PXSELS(3) = 0x06000000; \ ++ REG_GPIO_PXPES(3) = 0x06000000; \ ++} while (0) ++ ++/* ++ * UART0_CTS, UART0_RTS ++ */ ++#define __gpio_as_ctsrts() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0xc0000000; \ ++ REG_GPIO_PXSELS(3) = 0xc0000000; \ ++ REG_GPIO_PXTRGC(3) = 0xc0000000; \ ++ REG_GPIO_PXPES(3) = 0xc0000000; \ ++} while (0) ++ ++/* ++ * UART1_TxD, UART1_RxD1 ++ */ ++#define __gpio_as_uart1() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0xc0000000; \ ++ REG_GPIO_PXSELC(3) = 0xc0000000; \ ++ REG_GPIO_PXTRGS(3) = 0xc0000000; \ ++ REG_GPIO_PXPES(3) = 0xc0000000; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_16bit() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x003cffff; \ ++ REG_GPIO_PXSELC(2) = 0x003cffff; \ ++ REG_GPIO_PXPES(2) = 0x003cffff; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_18bit() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x003fffff; \ ++ REG_GPIO_PXSELC(2) = 0x003fffff; \ ++ REG_GPIO_PXPES(2) = 0x003fffff; \ ++} while (0) ++ ++/* ++ * LCD_PS, LCD_REV, LCD_CLS, LCD_SPL ++ */ ++#define __gpio_as_lcd_special() \ ++do { \ ++ REG_GPIO_PXFUNS(1) = 0x00060000; \ ++ REG_GPIO_PXSELC(1) = 0x00060000; \ ++ REG_GPIO_PXPES(1) = 0x00060000; \ ++ REG_GPIO_PXFUNS(2) = 0x00c00000; \ ++ REG_GPIO_PXSELC(2) = 0x00c00000; \ ++ REG_GPIO_PXPES(2) = 0x00c00000; \ ++} while (0) ++ ++/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ ++#define __gpio_as_slcd_8bit() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x001800ff; \ ++ REG_GPIO_PXSELC(2) = 0x001800ff; \ ++} while (0) ++ ++/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ ++#define __gpio_as_slcd_9bit() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x001801ff; \ ++ REG_GPIO_PXSELC(2) = 0x001801ff; \ ++} while (0) ++ ++/* LCD_D0~LCD_D15, SLCD_RS, SLCD_CS */ ++#define __gpio_as_slcd_16bit() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x0018ffff; \ ++ REG_GPIO_PXSELC(2) = 0x0018ffff; \ ++} while (0) ++ ++/* LCD_D0~LCD_D17, SLCD_RS, SLCD_CS */ ++#define __gpio_as_slcd_18bit() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x001bffff; \ ++ REG_GPIO_PXSELC(2) = 0x001bffff; \ ++} while (0) ++ ++/* ++ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC ++ */ ++#define __gpio_as_cim() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x0003c0ff; \ ++ REG_GPIO_PXSELC(3) = 0x0003c0ff; \ ++ REG_GPIO_PXPES(3) = 0x0003c0ff; \ ++} while (0) ++ ++/* ++ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET ++ */ ++#define __gpio_as_aic() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x007c0000; \ ++ REG_GPIO_PXSELS(3) = 0x007c0000; \ ++ REG_GPIO_PXPES(3) = 0x007c0000; \ ++} while (0) ++ ++/* ++ * MSC_CMD, MSC_CLK, MSC_D0 ~ MSC_D3 ++ */ ++#define __gpio_as_msc() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x00003f00; \ ++ REG_GPIO_PXSELC(3) = 0x00003f00; \ ++ REG_GPIO_PXPES(3) = 0x00003f00; \ ++} while (0) ++ ++/* ++ * SSI_CS0, SSI_CLK, SSI_DT, SSI_DR ++ */ ++#define __gpio_as_ssi() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003c0000; \ ++ REG_GPIO_PXSELC(3) = 0x003c0000; \ ++ REG_GPIO_PXPES(3) = 0x003c0000; \ ++} while (0) ++ ++/* ++ * I2C_SCK, I2C_SDA ++ */ ++#define __gpio_as_i2c() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x01800000; \ ++ REG_GPIO_PXSELS(3) = 0x01800000; \ ++ REG_GPIO_PXPES(3) = 0x01800000; \ ++} while (0) ++ ++/* ++ * PWM0 ++ */ ++#define __gpio_as_pwm0() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x00800000; \ ++ REG_GPIO_PXSELC(3) = 0x00800000; \ ++ REG_GPIO_PXPES(3) = 0x00800000; \ ++} while (0) ++ ++/* ++ * PWM1 ++ */ ++#define __gpio_as_pwm1() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x01000000; \ ++ REG_GPIO_PXSELC(3) = 0x01000000; \ ++ REG_GPIO_PXPES(3) = 0x01000000; \ ++} while (0) ++ ++/* ++ * PWM2 ++ */ ++#define __gpio_as_pwm2() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x02000000; \ ++ REG_GPIO_PXSELC(3) = 0x02000000; \ ++ REG_GPIO_PXPES(3) = 0x02000000; \ ++} while (0) ++ ++/* ++ * PWM3 ++ */ ++#define __gpio_as_pwm3() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x04000000; \ ++ REG_GPIO_PXSELC(3) = 0x04000000; \ ++ REG_GPIO_PXPES(3) = 0x04000000; \ ++} while (0) ++ ++/* ++ * PWM4 ++ */ ++#define __gpio_as_pwm4() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x08000000; \ ++ REG_GPIO_PXSELC(3) = 0x08000000; \ ++ REG_GPIO_PXPES(3) = 0x08000000; \ ++} while (0) ++ ++/* ++ * PWM5 ++ */ ++#define __gpio_as_pwm5() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x10000000; \ ++ REG_GPIO_PXSELC(3) = 0x10000000; \ ++ REG_GPIO_PXPES(3) = 0x10000000; \ ++} while (0) ++ ++/* ++ * PWM6 ++ */ ++#define __gpio_as_pwm6() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x40000000; \ ++ REG_GPIO_PXSELC(3) = 0x40000000; \ ++ REG_GPIO_PXPES(3) = 0x40000000; \ ++} while (0) ++ ++/* ++ * PWM7 ++ */ ++#define __gpio_as_pwm7() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x80000000; \ ++ REG_GPIO_PXSELC(3) = 0x80000000; \ ++ REG_GPIO_PXPES(3) = 0x80000000; \ ++} while (0) ++ ++/* ++ * n = 0 ~ 7 ++ */ ++#define __gpio_as_pwm(n) __gpio_as_pwm##n() ++ ++//------------------------------------------- ++// GPIO or Interrupt Mode ++ ++#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) ++ ++#define __gpio_port_as_output(p, o) \ ++do { \ ++ REG_GPIO_PXFUNC(p) = (1 << (o)); \ ++ REG_GPIO_PXSELC(p) = (1 << (o)); \ ++ REG_GPIO_PXDIRS(p) = (1 << (o)); \ ++} while (0) ++ ++#define __gpio_port_as_input(p, o) \ ++do { \ ++ REG_GPIO_PXFUNC(p) = (1 << (o)); \ ++ REG_GPIO_PXSELC(p) = (1 << (o)); \ ++ REG_GPIO_PXDIRC(p) = (1 << (o)); \ ++} while (0) ++ ++#define __gpio_as_output(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_output(p, o); \ ++} while (0) ++ ++#define __gpio_as_input(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_input(p, o); \ ++} while (0) ++ ++#define __gpio_set_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXDATS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_clear_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXDATC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_get_pin(n) \ ++({ \ ++ unsigned int p, o, v; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ if (__gpio_get_port(p) & (1 << o)) \ ++ v = 1; \ ++ else \ ++ v = 0; \ ++ v; \ ++}) ++ ++#define __gpio_as_irq_high_level(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRS(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_low_level(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRC(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_rise_edge(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRS(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_fall_edge(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRC(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_mask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_unmask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_ack_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_get_irq() \ ++({ \ ++ unsigned int p, i, tmp, v = 0; \ ++ for (p = 3; p >= 0; p--) { \ ++ tmp = REG_GPIO_PXFLG(p); \ ++ for (i = 0; i < 32; i++) \ ++ if (tmp & (1 << i)) \ ++ v = (32*p + i); \ ++ } \ ++ v; \ ++}) ++ ++#define __gpio_group_irq(n) \ ++({ \ ++ register int tmp, i; \ ++ tmp = REG_GPIO_PXFLG((n)); \ ++ for (i=31;i>=0;i--) \ ++ if (tmp & (1 << i)) \ ++ break; \ ++ i; \ ++}) ++ ++#define __gpio_enable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXPEC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_disable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXPES(p) = (1 << o); \ ++} while (0) ++ ++ ++/*************************************************************************** ++ * CPM ++ ***************************************************************************/ ++#define __cpm_get_pllm() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) ++#define __cpm_get_plln() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) ++#define __cpm_get_pllod() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) ++ ++#define __cpm_get_cdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) ++#define __cpm_get_hdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) ++#define __cpm_get_pdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) ++#define __cpm_get_mdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) ++#define __cpm_get_ldiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) ++#define __cpm_get_udiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) ++#define __cpm_get_i2sdiv() \ ++ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) ++#define __cpm_get_pixdiv() \ ++ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) ++#define __cpm_get_mscdiv() \ ++ ((REG_CPM_MSCCDR & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) ++#define __cpm_get_uhcdiv() \ ++ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) ++#define __cpm_get_ssidiv() \ ++ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) ++ ++#define __cpm_set_cdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) ++#define __cpm_set_hdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) ++#define __cpm_set_pdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) ++#define __cpm_set_mdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) ++#define __cpm_set_ldiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) ++#define __cpm_set_udiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) ++#define __cpm_set_i2sdiv(v) \ ++ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) ++#define __cpm_set_pixdiv(v) \ ++ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) ++#define __cpm_set_mscdiv(v) \ ++ (REG_CPM_MSCCDR = (REG_CPM_MSCCDR & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) ++#define __cpm_set_uhcdiv(v) \ ++ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) ++#define __cpm_ssiclk_select_exclk() \ ++ (REG_CPM_SSICDR &= ~CPM_SSICDR_SCS) ++#define __cpm_ssiclk_select_pllout() \ ++ (REG_CPM_SSICDR |= CPM_SSICDR_SCS) ++#define __cpm_set_ssidiv(v) \ ++ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) ++ ++#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) ++#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) ++#define __cpm_enable_cko() (REG_CPM_CPCCR |= CPM_CPCCR_CLKOEN) ++#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) ++#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) ++#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) ++#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) ++#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) ++ ++#define __cpm_pll_is_on() (REG_CPM_CPPCR & CPM_CPPCR_PLLS) ++#define __cpm_pll_bypass() (REG_CPM_CPPCR |= CPM_CPPCR_PLLBP) ++#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) ++ ++#define __cpm_get_cclk_doze_duty() \ ++ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) ++#define __cpm_set_cclk_doze_duty(v) \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) ++ ++#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) ++#define __cpm_idle_mode() \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) ++#define __cpm_sleep_mode() \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) ++ ++#define __cpm_stop_all() (REG_CPM_CLKGR = 0x7fff) ++#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) ++#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) ++#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) ++#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) ++#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) ++#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) ++#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) ++#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) ++#define __cpm_stop_msc() (REG_CPM_CLKGR |= CPM_CLKGR_MSC) ++#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) ++#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) ++#define __cpm_stop_ssi() (REG_CPM_CLKGR |= CPM_CLKGR_SSI) ++#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) ++#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) ++#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) ++#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) ++ ++#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) ++#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) ++#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) ++#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) ++#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) ++#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) ++#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) ++#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) ++#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) ++#define __cpm_start_msc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC) ++#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) ++#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) ++#define __cpm_start_ssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI) ++#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) ++#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) ++#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) ++#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) ++ ++#define __cpm_get_o1st() \ ++ ((REG_CPM_SCR & CPM_SCR_O1ST_MASK) >> CPM_SCR_O1ST_BIT) ++#define __cpm_set_o1st(v) \ ++ (REG_CPM_SCR = (REG_CPM_SCR & ~CPM_SCR_O1ST_MASK) | ((v) << (CPM_SCR_O1ST_BIT))) ++#define __cpm_suspend_usbphy() (REG_CPM_SCR |= CPM_SCR_USBPHY_SUSPEND) ++#define __cpm_enable_osc_in_sleep() (REG_CPM_SCR |= CPM_SCR_OSC_ENABLE) ++ ++ ++/*************************************************************************** ++ * TCU ++ ***************************************************************************/ ++// where 'n' is the TCU channel ++#define __tcu_select_extalclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) ++#define __tcu_select_rtcclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) ++#define __tcu_select_pclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) ++ ++#define __tcu_select_clk_div1(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) ++#define __tcu_select_clk_div4(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) ++#define __tcu_select_clk_div16(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) ++#define __tcu_select_clk_div64(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) ++#define __tcu_select_clk_div256(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) ++#define __tcu_select_clk_div1024(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) ++ ++#define __tcu_enable_pwm_output(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN ) ++#define __tcu_disable_pwm_output(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN ) ++ ++#define __tcu_init_pwm_output_high(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH ) ++#define __tcu_init_pwm_output_low(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH ) ++ ++#define __tcu_set_pwm_output_shutdown_graceful(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD ) ++#define __tcu_set_pwm_output_shutdown_abrupt(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD ) ++ ++#define __tcu_start_counter(n) ( REG_TCU_TESR |= (1 << (n)) ) ++#define __tcu_stop_counter(n) ( REG_TCU_TECR |= (1 << (n)) ) ++ ++#define __tcu_half_match_flag(n) ( REG_TCU_TFR & (1 << ((n) + 16)) ) ++#define __tcu_full_match_flag(n) ( REG_TCU_TFR & (1 << (n)) ) ++#define __tcu_set_half_match_flag(n) ( REG_TCU_TFSR = (1 << ((n) + 16)) ) ++#define __tcu_set_full_match_flag(n) ( REG_TCU_TFSR = (1 << (n)) ) ++#define __tcu_clear_half_match_flag(n) ( REG_TCU_TFCR = (1 << ((n) + 16)) ) ++#define __tcu_clear_full_match_flag(n) ( REG_TCU_TFCR = (1 << (n)) ) ++#define __tcu_mask_half_match_irq(n) ( REG_TCU_TMSR = (1 << ((n) + 16)) ) ++#define __tcu_mask_full_match_irq(n) ( REG_TCU_TMSR = (1 << (n)) ) ++#define __tcu_unmask_half_match_irq(n) ( REG_TCU_TMCR = (1 << ((n) + 16)) ) ++#define __tcu_unmask_full_match_irq(n) ( REG_TCU_TMCR = (1 << (n)) ) ++ ++#define __tcu_wdt_clock_stopped() ( REG_TCU_TSR & TCU_TSSR_WDTSC ) ++#define __tcu_timer_clock_stopped(n) ( REG_TCU_TSR & (1 << (n)) ) ++ ++#define __tcu_start_wdt_clock() ( REG_TCU_TSCR = TCU_TSSR_WDTSC ) ++#define __tcu_start_timer_clock(n) ( REG_TCU_TSCR = (1 << (n)) ) ++ ++#define __tcu_stop_wdt_clock() ( REG_TCU_TSSR = TCU_TSSR_WDTSC ) ++#define __tcu_stop_timer_clock(n) ( REG_TCU_TSSR = (1 << (n)) ) ++ ++#define __tcu_get_count(n) ( REG_TCU_TCNT((n)) ) ++#define __tcu_set_count(n,v) ( REG_TCU_TCNT((n)) = (v) ) ++#define __tcu_set_full_data(n,v) ( REG_TCU_TDFR((n)) = (v) ) ++#define __tcu_set_half_data(n,v) ( REG_TCU_TDHR((n)) = (v) ) ++ ++ ++/*************************************************************************** ++ * WDT ++ ***************************************************************************/ ++#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) ++#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) ++#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) ++#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) ++ ++#define __wdt_select_extalclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) ++#define __wdt_select_rtcclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) ++#define __wdt_select_pclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) ++ ++#define __wdt_select_clk_div1() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) ++#define __wdt_select_clk_div4() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) ++#define __wdt_select_clk_div16() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) ++#define __wdt_select_clk_div64() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) ++#define __wdt_select_clk_div256() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) ++#define __wdt_select_clk_div1024() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) ++ ++ ++/*************************************************************************** ++ * UART ++ ***************************************************************************/ ++ ++#define __uart_enable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) ++#define __uart_disable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) ++ ++#define __uart_enable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) ++#define __uart_disable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) ++ ++#define __uart_enable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) ++#define __uart_disable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) ++ ++#define __uart_enable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) ++#define __uart_disable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) ++ ++#define __uart_set_8n1(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) ++ ++#define __uart_set_baud(n, devclk, baud) \ ++ do { \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ ++ } while (0) ++ ++#define __uart_parity_error(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) ++ ++#define __uart_clear_errors(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) ++ ++#define __uart_transmit_fifo_empty(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) ++ ++#define __uart_transmit_end(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) ++ ++#define __uart_transmit_char(n, ch) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) ++ ++#define __uart_receive_fifo_full(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_ready(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_char(n) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) ++ ++#define __uart_disable_irda() \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) ++#define __uart_enable_irda() \ ++ /* Tx high pulse as 0, Rx low pulse as 0 */ \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) ++ ++ ++/*************************************************************************** ++ * DMAC ++ ***************************************************************************/ ++ ++/* n is the DMA channel (0 - 5) */ ++ ++#define __dmac_enable_module() \ ++ ( REG_DMAC_DMACR |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_RR ) ++#define __dmac_disable_module() \ ++ ( REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE ) ++ ++/* p=0,1,2,3 */ ++#define __dmac_set_priority(p) \ ++do { \ ++ REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \ ++ REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \ ++} while (0) ++ ++#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HLT ) ++#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AR ) ++ ++#define __dmac_enable_descriptor(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) ++#define __dmac_disable_descriptor(n) \ ++ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) ++ ++#define __dmac_enable_channel(n) \ ++ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN ) ++#define __dmac_disable_channel(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN ) ++#define __dmac_channel_enabled(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) ++ ++#define __dmac_channel_enable_irq(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) ++#define __dmac_channel_disable_irq(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) ++ ++#define __dmac_channel_transmit_halt_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) ++#define __dmac_channel_transmit_end_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) ++#define __dmac_channel_address_error_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) ++#define __dmac_channel_count_terminated_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) ++#define __dmac_channel_descriptor_invalid_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) ++ ++#define __dmac_channel_clear_transmit_halt(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT ) ++#define __dmac_channel_clear_transmit_end(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) ++#define __dmac_channel_clear_address_error(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR ) ++#define __dmac_channel_clear_count_terminated(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) ++#define __dmac_channel_clear_descriptor_invalid(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) ++ ++#define __dmac_channel_set_single_mode(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TM ) ++#define __dmac_channel_set_block_mode(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TM ) ++ ++#define __dmac_channel_set_transfer_unit_32bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_8bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16byte(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_32byte(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_dest_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_src_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ ++} while (0) ++ ++/* v=0-15 */ ++#define __dmac_channel_set_rdil(n,v) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ ++ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ ++} while (0) ++ ++#define __dmac_channel_dest_addr_fixed(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) ++#define __dmac_channel_dest_addr_increment(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) ++ ++#define __dmac_channel_src_addr_fixed(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) ++#define __dmac_channel_src_addr_increment(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) ++ ++#define __dmac_channel_set_doorbell(n) \ ++ ( REG_DMAC_DMADBSR = (1 << (n)) ) ++ ++#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR & (1 << (n)) ) ++#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR &= ~(1 << (n)) ) ++ ++static __inline__ int __dmac_get_irq(void) ++{ ++ int i; ++ for (i = 0; i < MAX_DMA_NUM; i++) ++ if (__dmac_channel_irq_detected(i)) ++ return i; ++ return -1; ++} ++ ++ ++/*************************************************************************** ++ * AIC (AC'97 & I2S Controller) ++ ***************************************************************************/ ++ ++#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) ++#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) ++ ++#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) ++#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) ++ ++#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) ++#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) ++ ++#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) ++#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) ++#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) ++ ++#define __aic_reset() \ ++do { \ ++ REG_AIC_FR |= AIC_FR_RST; \ ++} while(0) ++ ++ ++#define __aic_set_transmit_trigger(n) \ ++do { \ ++ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ ++ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ ++} while(0) ++ ++#define __aic_set_receive_trigger(n) \ ++do { \ ++ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ ++ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ ++} while(0) ++ ++#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) ++#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) ++#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) ++#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) ++#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) ++#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) ++ ++#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) ++#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) ++ ++#define __aic_enable_transmit_intr() \ ++ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) ++#define __aic_disable_transmit_intr() \ ++ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) ++#define __aic_enable_receive_intr() \ ++ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) ++#define __aic_disable_receive_intr() \ ++ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) ++ ++#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) ++#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) ++#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) ++#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) ++ ++#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) ++#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) ++#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) ++#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) ++#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) ++#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) ++ ++#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 ++#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 ++#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 ++#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 ++#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 ++#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 ++ ++#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 ++#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 ++#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 ++#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 ++#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 ++#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 ++ ++#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) ++#define __ac97_set_xs_mono() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ ++} while(0) ++#define __ac97_set_xs_stereo() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ ++} while(0) ++ ++/* In fact, only stereo is support now. */ ++#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) ++#define __ac97_set_rs_mono() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ ++} while(0) ++#define __ac97_set_rs_stereo() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ ++} while(0) ++ ++#define __ac97_warm_reset_codec() \ ++ do { \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ ++ udelay(2); \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ ++ } while (0) ++ ++#define __ac97_cold_reset_codec() \ ++ do { \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ ++ udelay(2); \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ ++ } while (0) ++ ++/* n=8,16,18,20 */ ++#define __ac97_set_iass(n) \ ++ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) ++#define __ac97_set_oass(n) \ ++ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) ++ ++#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) ++#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) ++ ++/* n=8,16,18,20,24 */ ++/*#define __i2s_set_sample_size(n) \ ++ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ ++ ++#define __i2s_set_oss_sample_size(n) \ ++ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) ++#define __i2s_set_iss_sample_size(n) \ ++ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) ++ ++#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) ++#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) ++ ++#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) ++#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) ++#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) ++#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) ++ ++#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) ++ ++#define __aic_get_transmit_resident() \ ++ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) ++#define __aic_get_receive_count() \ ++ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) ++ ++#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) ++#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) ++#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) ++#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) ++#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) ++#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) ++#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) ++ ++#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) ++ ++#define CODEC_READ_CMD (1 << 19) ++#define CODEC_WRITE_CMD (0 << 19) ++#define CODEC_REG_INDEX_BIT 12 ++#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ ++#define CODEC_REG_DATA_BIT 4 ++#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ ++ ++#define __ac97_out_rcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_wcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_data(value) \ ++do { \ ++ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ ++} while (0) ++ ++#define __ac97_in_data() \ ++ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) ++ ++#define __ac97_in_status_addr() \ ++ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) ++ ++#define __i2s_set_sample_rate(i2sclk, sync) \ ++ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) ++ ++#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) ++#define __aic_read_rfifo() ( REG_AIC_DR ) ++ ++#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) ++#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) ++ ++// ++// Define next ops for AC97 compatible ++// ++ ++#define AC97_ACSR AIC_ACSR ++ ++#define __ac97_enable() __aic_enable(); __aic_select_ac97() ++#define __ac97_disable() __aic_disable() ++#define __ac97_reset() __aic_reset() ++ ++#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __ac97_enable_record() __aic_enable_record() ++#define __ac97_disable_record() __aic_disable_record() ++#define __ac97_enable_replay() __aic_enable_replay() ++#define __ac97_disable_replay() __aic_disable_replay() ++#define __ac97_enable_loopback() __aic_enable_loopback() ++#define __ac97_disable_loopback() __aic_disable_loopback() ++ ++#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __ac97_enable_receive_dma() __aic_enable_receive_dma() ++#define __ac97_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __ac97_transmit_request() __aic_transmit_request() ++#define __ac97_receive_request() __aic_receive_request() ++#define __ac97_transmit_underrun() __aic_transmit_underrun() ++#define __ac97_receive_overrun() __aic_receive_overrun() ++ ++#define __ac97_clear_errors() __aic_clear_errors() ++ ++#define __ac97_get_transmit_resident() __aic_get_transmit_resident() ++#define __ac97_get_receive_count() __aic_get_receive_count() ++ ++#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __ac97_enable_receive_intr() __aic_enable_receive_intr() ++#define __ac97_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __ac97_write_tfifo(v) __aic_write_tfifo(v) ++#define __ac97_read_rfifo() __aic_read_rfifo() ++ ++// ++// Define next ops for I2S compatible ++// ++ ++#define I2S_ACSR AIC_I2SSR ++ ++#define __i2s_enable() __aic_enable(); __aic_select_i2s() ++#define __i2s_disable() __aic_disable() ++#define __i2s_reset() __aic_reset() ++ ++#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __i2s_enable_record() __aic_enable_record() ++#define __i2s_disable_record() __aic_disable_record() ++#define __i2s_enable_replay() __aic_enable_replay() ++#define __i2s_disable_replay() __aic_disable_replay() ++#define __i2s_enable_loopback() __aic_enable_loopback() ++#define __i2s_disable_loopback() __aic_disable_loopback() ++ ++#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __i2s_enable_receive_dma() __aic_enable_receive_dma() ++#define __i2s_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __i2s_transmit_request() __aic_transmit_request() ++#define __i2s_receive_request() __aic_receive_request() ++#define __i2s_transmit_underrun() __aic_transmit_underrun() ++#define __i2s_receive_overrun() __aic_receive_overrun() ++ ++#define __i2s_clear_errors() __aic_clear_errors() ++ ++#define __i2s_get_transmit_resident() __aic_get_transmit_resident() ++#define __i2s_get_receive_count() __aic_get_receive_count() ++ ++#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __i2s_enable_receive_intr() __aic_enable_receive_intr() ++#define __i2s_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __i2s_write_tfifo(v) __aic_write_tfifo(v) ++#define __i2s_read_rfifo() __aic_read_rfifo() ++ ++#define __i2s_reset_codec() \ ++ do { \ ++ } while (0) ++ ++ ++/*************************************************************************** ++ * ICDC ++ ***************************************************************************/ ++#define __i2s_internal_codec() __aic_internal_codec() ++#define __i2s_external_codec() __aic_external_codec() ++ ++/*************************************************************************** ++ * INTC ++ ***************************************************************************/ ++#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) ++#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) ++#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) ++ ++ ++/*************************************************************************** ++ * I2C ++ ***************************************************************************/ ++ ++#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) ++#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) ++ ++#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) ++#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) ++#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) ++#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) ++ ++#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) ++#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) ++#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) ++ ++#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) ++#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) ++#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) ++ ++#define __i2c_set_clk(dev_clk, i2c_clk) \ ++ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) ++ ++#define __i2c_read() ( REG_I2C_DR ) ++#define __i2c_write(val) ( REG_I2C_DR = (val) ) ++ ++ ++/*************************************************************************** ++ * MSC ++ ***************************************************************************/ ++ ++#define __msc_start_op() \ ++ ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) ++ ++#define __msc_set_resto(to) ( REG_MSC_RESTO = to ) ++#define __msc_set_rdto(to) ( REG_MSC_RDTO = to ) ++#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd ) ++#define __msc_set_arg(arg) ( REG_MSC_ARG = arg ) ++#define __msc_set_nob(nob) ( REG_MSC_NOB = nob ) ++#define __msc_get_nob() ( REG_MSC_NOB ) ++#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len ) ++#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat ) ++#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT ) ++#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT ) ++ ++#define __msc_set_cmdat_bus_width1() \ ++do { \ ++ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_bus_width4() \ ++do { \ ++ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN ) ++#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT ) ++#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY ) ++#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN ) ++ ++/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ ++#define __msc_set_cmdat_res_format(r) \ ++do { \ ++ REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ ++ REG_MSC_CMDAT |= (r); \ ++} while(0) ++ ++#define __msc_clear_cmdat() \ ++ REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ ++ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ ++ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) ++ ++#define __msc_get_imask() ( REG_MSC_IMASK ) ++#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff ) ++#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 ) ++#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES ) ++#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES ) ++#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE ) ++#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE ) ++ ++/* n=0,1,2,3,4,5,6,7 */ ++#define __msc_set_clkrt(n) \ ++do { \ ++ REG_MSC_CLKRT = n; \ ++} while(0) ++ ++#define __msc_get_ireg() ( REG_MSC_IREG ) ++#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ ) ++#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ ) ++#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE ) ++#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE ) ++ ++#define __msc_get_stat() ( REG_MSC_STAT ) ++#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0) ++#define __msc_stat_crc_err() \ ++ ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) ++#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR ) ++#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR ) ++#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES ) ++#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES ) ++#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ ) ++ ++#define __msc_rd_resfifo() ( REG_MSC_RES ) ++#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO ) ++#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v ) ++ ++#define __msc_reset() \ ++do { \ ++ REG_MSC_STRPCL = MSC_STRPCL_RESET; \ ++ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \ ++} while (0) ++ ++#define __msc_start_clk() \ ++do { \ ++ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \ ++} while (0) ++ ++#define __msc_stop_clk() \ ++do { \ ++ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \ ++} while (0) ++ ++#define MMC_CLK 19169200 ++#define SD_CLK 24576000 ++ ++/* msc_clk should little than pclk and little than clk retrieve from card */ ++#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ ++do { \ ++ unsigned int rate, pclk, i; \ ++ pclk = dev_clk; \ ++ rate = type?SD_CLK:MMC_CLK; \ ++ if (msc_clk && msc_clk < pclk) \ ++ pclk = msc_clk; \ ++ i = 0; \ ++ while (pclk < rate) \ ++ { \ ++ i ++; \ ++ rate >>= 1; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++/* divide rate to little than or equal to 400kHz */ ++#define __msc_calc_slow_clk_divisor(type, lv) \ ++do { \ ++ unsigned int rate, i; \ ++ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ ++ i = 0; \ ++ while (rate > 0) \ ++ { \ ++ rate >>= 1; \ ++ i ++; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++ ++/*************************************************************************** ++ * SSI ++ ***************************************************************************/ ++ ++#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE ) ++#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE ) ++#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL ) ++ ++#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK ) ++ ++#define __ssi_select_ce2() \ ++do { \ ++ REG_SSI_CR0 |= SSI_CR0_FSEL; \ ++ REG_SSI_CR1 &= ~SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_select_gpc() \ ++do { \ ++ REG_SSI_CR0 &= ~SSI_CR0_FSEL; \ ++ REG_SSI_CR1 |= SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_enable_tx_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE ) ++ ++#define __ssi_disable_tx_intr() \ ++ ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) ++ ++#define __ssi_enable_rx_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE ) ++ ++#define __ssi_disable_rx_intr() \ ++ ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) ++ ++#define __ssi_enable_txfifo_half_empty_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_TIE ) ++#define __ssi_disable_txfifo_half_empty_intr() \ ++ ( REG_SSI_CR0 &= ~SSI_CR0_TIE ) ++#define __ssi_enable_tx_error_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_TEIE ) ++#define __ssi_disable_tx_error_intr() \ ++ ( REG_SSI_CR0 &= ~SSI_CR0_TEIE ) ++ ++#define __ssi_enable_rxfifo_half_full_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_RIE ) ++#define __ssi_disable_rxfifo_half_full_intr() \ ++ ( REG_SSI_CR0 &= ~SSI_CR0_RIE ) ++#define __ssi_enable_rx_error_intr() \ ++ ( REG_SSI_CR0 |= SSI_CR0_REIE ) ++#define __ssi_disable_rx_error_intr() \ ++ ( REG_SSI_CR0 &= ~SSI_CR0_REIE ) ++ ++#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP ) ++#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP ) ++ ++#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV ) ++#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV ) ++ ++#define __ssi_finish_receive() \ ++ ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_disable_recvfinish() \ ++ ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH ) ++#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH ) ++ ++#define __ssi_flush_fifo() \ ++ ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) ++ ++#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN ) ++#define __ssi_wait_transmit() ( REG_SSI_CR1 |= SSI_CR1_UNFIN ) ++ ++#define __ssi_spi_format() \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \ ++ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ ++ REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ ++} while (0) ++ ++/* TI's SSP format, must clear SSI_CR1.UNFIN */ ++#define __ssi_ssp_format() \ ++do { \ ++ REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ ++ REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \ ++} while (0) ++ ++/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ ++#define __ssi_microwire_format() \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \ ++ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ ++ REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ ++ REG_SSI_CR0 &= ~SSI_CR0_RFINE; \ ++} while (0) ++ ++/* CE# level (FRMHL), CE# in interval time (ITFRM), ++ clock phase and polarity (PHA POL), ++ interval time (SSIITR), interval characters/frame (SSIICR) */ ++ ++ /* frmhl,endian,mcom,flen,pha,pol MASK */ ++#define SSICR1_MISC_MASK \ ++ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ ++ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \ ++ ++#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \ ++do { \ ++ REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \ ++ REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \ ++ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ ++ ((pha) << 1) | (pol); \ ++} while(0) ++ ++/* Transfer with MSB or LSB first */ ++#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST ) ++#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST ) ++ ++#define __ssi_set_frame_length(n) \ ++ REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4) ++ ++/* n = 1 - 16 */ ++#define __ssi_set_microwire_command_length(n) \ ++ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) ) ++ ++/* Set the clock phase for SPI */ ++#define __ssi_set_spi_clock_phase(n) \ ++ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1)<< 1))) ++ ++/* Set the clock polarity for SPI */ ++#define __ssi_set_spi_clock_polarity(n) \ ++ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | (n&0x1)) ) ++ ++/* n = ix8 */ ++#define __ssi_set_tx_trigger(n) \ ++do { \ ++ REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \ ++ REG_SSI_CR1 |= (n/8)<> SSI_SR_TFIFONUM_BIT ) ++ ++#define __ssi_get_rxfifo_count() \ ++ ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) ++ ++#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END ) ++#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY ) ++ ++#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF ) ++#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE ) ++#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF ) ++#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE ) ++#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR ) ++#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER ) ++#define __ssi_clear_underrun() ( REG_SSI_SR = ~SSI_SR_UNDR ) ++#define __ssi_clear_overrun() ( REG_SSI_SR = ~SSI_SR_OVER ) ++#define __ssi_clear_errors() \ ++ ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) ++ ++ ++#define __ssi_set_clk(dev_clk, ssi_clk) \ ++ ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 ) ++ ++#define __ssi_receive_data() REG_SSI_DR ++#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) ) ++ ++ ++/*************************************************************************** ++ * CIM ++ ***************************************************************************/ ++ ++#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) ++#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) ++ ++#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT ) ++#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT ) ++ ++#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP ) ++#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP ) ++ ++#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP ) ++#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP ) ++ ++#define __cim_sample_data_at_pclk_falling_edge() \ ++ ( REG_CIM_CFG |= CIM_CFG_PCP ) ++#define __cim_sample_data_at_pclk_rising_edge() \ ++ ( REG_CIM_CFG &= ~CIM_CFG_PCP ) ++ ++#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO ) ++#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO ) ++ ++#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC ) ++#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC ) ++ ++/* n=0-7 */ ++#define __cim_set_data_packing_mode(n) \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \ ++ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \ ++} while (0) ++ ++#define __cim_enable_ccir656_progressive_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \ ++} while (0) ++ ++#define __cim_enable_ccir656_interlace_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \ ++} while (0) ++ ++#define __cim_enable_gated_clock_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \ ++} while (0) ++ ++#define __cim_enable_nongated_clock_mode() \ ++do { \ ++ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ ++ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \ ++} while (0) ++ ++/* sclk:system bus clock ++ * mclk: CIM master clock ++ */ ++#define __cim_set_master_clk(sclk, mclk) \ ++do { \ ++ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \ ++ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \ ++} while (0) ++ ++#define __cim_enable_sof_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM ) ++#define __cim_disable_sof_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM ) ++ ++#define __cim_enable_eof_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM ) ++#define __cim_disable_eof_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM ) ++ ++#define __cim_enable_stop_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM ) ++#define __cim_disable_stop_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM ) ++ ++#define __cim_enable_trig_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM ) ++#define __cim_disable_trig_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM ) ++ ++#define __cim_enable_rxfifo_overflow_intr() \ ++ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM ) ++#define __cim_disable_rxfifo_overflow_intr() \ ++ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM ) ++ ++/* n=1-16 */ ++#define __cim_set_frame_rate(n) \ ++do { \ ++ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \ ++ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \ ++} while (0) ++ ++#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN ) ++#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN ) ++ ++#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST ) ++#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST ) ++ ++/* n=4,8,12,16,20,24,28,32 */ ++#define __cim_set_rxfifo_trigger(n) \ ++do { \ ++ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \ ++ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \ ++} while (0) ++ ++#define __cim_clear_state() ( REG_CIM_STATE = 0 ) ++ ++#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD ) ++#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY ) ++#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG ) ++#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF ) ++#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF ) ++#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP ) ++#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF ) ++#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF ) ++ ++#define __cim_get_iid() ( REG_CIM_IID ) ++#define __cim_get_image_data() ( REG_CIM_RXFIFO ) ++#define __cim_get_dam_cmd() ( REG_CIM_CMD ) ++ ++#define __cim_set_da(a) ( REG_CIM_DA = (a) ) ++ ++/*************************************************************************** ++ * LCD ++ ***************************************************************************/ ++#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= (1<> LCD_VSYNC_VPS_BIT ) ++ ++#define __lcd_vsync_get_vpe() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) ++#define __lcd_vsync_set_vpe(n) \ ++do { \ ++ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ ++ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hps() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) ++#define __lcd_hsync_set_hps(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hpe() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) ++#define __lcd_hsync_set_hpe(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_ht() \ ++ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) ++#define __lcd_vat_set_ht(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_vt() \ ++ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) ++#define __lcd_vat_set_vt(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hds() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) ++#define __lcd_dah_set_hds(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hde() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) ++#define __lcd_dah_set_hde(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vds() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) ++#define __lcd_dav_set_vds(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vde() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) ++#define __lcd_dav_set_vde(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ ++} while (0) ++ ++#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) ++#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) ++ ++#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) ++#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) ++ ++#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) ++#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) ++ ++#define __lcd_cmd0_get_len() \ ++ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++#define __lcd_cmd1_get_len() \ ++ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++ ++/******************************************************* ++ * SMART LCD ++ *******************************************************/ ++ ++#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN) ++#define __slcd_dma_disable() \ ++do {\ ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); \ ++ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \ ++} while(0) ++ ++/******************************************************* ++ * SMART LCD ++ *******************************************************/ ++ ++#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN) ++#define __slcd_dma_disable() \ ++do {\ ++ while (REG_SLCD_STATE & SLCD_STATE_BUSY); \ ++ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \ ++} while(0) ++ ++/*************************************************************************** ++ * RTC ops ++ ***************************************************************************/ ++ ++#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) ++#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) ++#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) ++#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) ++#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) ++#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) ++#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) ++#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) ++#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) ++ ++#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) ++#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) ++#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) ++#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) ++ ++#define __rtc_get_second() ( REG_RTC_RSR ) ++#define __rtc_set_second(v) ( REG_RTC_RSR = v ) ++ ++#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) ++#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) ++ ++#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) ++#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) ++#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) ++#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) ++#define __rtc_set_adjc_val(v) \ ++ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) ++#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) ++#define __rtc_set_nc1Hz_val(v) \ ++ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) ++ ++#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) ++ ++#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) ++#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) ++#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) ++#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) ++ ++#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) ++#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) ++ ++#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) ++#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) ++#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) ++#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) ++#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) ++ ++#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) ++#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) ++ ++ ++ ++#endif /* __JZ4740_OPS_H__ */ +diff --git a/include/asm-mips/mach-jz4740/regs.h b/include/asm-mips/mach-jz4740/regs.h +new file mode 100644 +index 0000000..07528bc +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/regs.h +@@ -0,0 +1,2392 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/regs.h ++ * ++ * Ingenic's JZ4740 common include. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __JZ4740_REGS_H__ ++#define __JZ4740_REGS_H__ ++ ++#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY) ++#define REG8(addr) (addr) ++#define REG16(addr) (addr) ++#define REG32(addr) (addr) ++#else ++#define REG8(addr) *((volatile unsigned char *)(addr)) ++#define REG16(addr) *((volatile unsigned short *)(addr)) ++#define REG32(addr) *((volatile unsigned int *)(addr)) ++#endif ++ ++/* ++ * Define the module base addresses ++ */ ++#define CPM_BASE 0xB0000000 ++#define INTC_BASE 0xB0001000 ++#define TCU_BASE 0xB0002000 ++#define WDT_BASE 0xB0002000 ++#define RTC_BASE 0xB0003000 ++#define GPIO_BASE 0xB0010000 ++#define AIC_BASE 0xB0020000 ++#define ICDC_BASE 0xB0020000 ++#define MSC_BASE 0xB0021000 ++#define UART0_BASE 0xB0030000 ++#define UART1_BASE 0xB0031000 ++#define I2C_BASE 0xB0042000 ++#define SSI_BASE 0xB0043000 ++#define SADC_BASE 0xB0070000 ++#define EMC_BASE 0xB3010000 ++#define DMAC_BASE 0xB3020000 ++#define UHC_BASE 0xB3030000 ++#define UDC_BASE 0xB3040000 ++#define LCD_BASE 0xB3050000 ++#define SLCD_BASE 0xB3050000 ++#define CIM_BASE 0xB3060000 ++#define IPU_BASE 0xB3080000 ++#define ETH_BASE 0xB3100000 ++ ++ ++/************************************************************************* ++ * INTC (Interrupt Controller) ++ *************************************************************************/ ++#define INTC_ISR (INTC_BASE + 0x00) ++#define INTC_IMR (INTC_BASE + 0x04) ++#define INTC_IMSR (INTC_BASE + 0x08) ++#define INTC_IMCR (INTC_BASE + 0x0c) ++#define INTC_IPR (INTC_BASE + 0x10) ++ ++#define REG_INTC_ISR REG32(INTC_ISR) ++#define REG_INTC_IMR REG32(INTC_IMR) ++#define REG_INTC_IMSR REG32(INTC_IMSR) ++#define REG_INTC_IMCR REG32(INTC_IMCR) ++#define REG_INTC_IPR REG32(INTC_IPR) ++ ++// 1st-level interrupts ++#define IRQ_I2C 1 ++#define IRQ_UHC 3 ++#define IRQ_UART1 8 ++#define IRQ_UART0 9 ++#define IRQ_SADC 12 ++#define IRQ_MSC 14 ++#define IRQ_RTC 15 ++#define IRQ_SSI 16 ++#define IRQ_CIM 17 ++#define IRQ_AIC 18 ++#define IRQ_ETH 19 ++#define IRQ_DMAC 20 ++#define IRQ_TCU2 21 ++#define IRQ_TCU1 22 ++#define IRQ_TCU0 23 ++#define IRQ_UDC 24 ++#define IRQ_GPIO3 25 ++#define IRQ_GPIO2 26 ++#define IRQ_GPIO1 27 ++#define IRQ_GPIO0 28 ++#define IRQ_IPU 29 ++#define IRQ_LCD 30 ++ ++// 2nd-level interrupts ++#define IRQ_DMA_0 32 /* 32 to 37 for DMAC channel 0 to 5 */ ++#define IRQ_GPIO_0 48 /* 48 to 175 for GPIO pin 0 to 127 */ ++ ++#define NUM_DMA 6 ++#define NUM_GPIO 128 ++/************************************************************************* ++ * RTC ++ *************************************************************************/ ++#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */ ++#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */ ++#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */ ++#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */ ++ ++#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */ ++#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */ ++#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */ ++#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */ ++#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */ ++#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */ ++ ++#define REG_RTC_RCR REG32(RTC_RCR) ++#define REG_RTC_RSR REG32(RTC_RSR) ++#define REG_RTC_RSAR REG32(RTC_RSAR) ++#define REG_RTC_RGR REG32(RTC_RGR) ++#define REG_RTC_HCR REG32(RTC_HCR) ++#define REG_RTC_HWFCR REG32(RTC_HWFCR) ++#define REG_RTC_HRCR REG32(RTC_HRCR) ++#define REG_RTC_HWCR REG32(RTC_HWCR) ++#define REG_RTC_HWRSR REG32(RTC_HWRSR) ++#define REG_RTC_HSPR REG32(RTC_HSPR) ++ ++/* RTC Control Register */ ++#define RTC_RCR_WRDY_BIT 7 ++#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */ ++#define RTC_RCR_1HZ_BIT 6 ++#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */ ++#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */ ++#define RTC_RCR_AF_BIT 4 ++#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */ ++#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */ ++#define RTC_RCR_AE (1 << 2) /* Alarm Enable */ ++#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */ ++ ++/* RTC Regulator Register */ ++#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */ ++#define RTC_RGR_ADJC_BIT 16 ++#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT) ++#define RTC_RGR_NC1HZ_BIT 0 ++#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT) ++ ++/* Hibernate Control Register */ ++#define RTC_HCR_PD (1 << 0) /* Power Down */ ++ ++/* Hibernate Wakeup Filter Counter Register */ ++#define RTC_HWFCR_BIT 5 ++#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT) ++ ++/* Hibernate Reset Counter Register */ ++#define RTC_HRCR_BIT 5 ++#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT) ++ ++/* Hibernate Wakeup Control Register */ ++#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */ ++ ++/* Hibernate Wakeup Status Register */ ++#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */ ++#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */ ++#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */ ++#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */ ++ ++ ++/************************************************************************* ++ * CPM (Clock reset and Power control Management) ++ *************************************************************************/ ++#define CPM_CPCCR (CPM_BASE+0x00) ++#define CPM_CPPCR (CPM_BASE+0x10) ++#define CPM_I2SCDR (CPM_BASE+0x60) ++#define CPM_LPCDR (CPM_BASE+0x64) ++#define CPM_MSCCDR (CPM_BASE+0x68) ++#define CPM_UHCCDR (CPM_BASE+0x6C) ++#define CPM_SSICDR (CPM_BASE+0x74) ++ ++#define CPM_LCR (CPM_BASE+0x04) ++#define CPM_CLKGR (CPM_BASE+0x20) ++#define CPM_SCR (CPM_BASE+0x24) ++ ++#define CPM_HCR (CPM_BASE+0x30) ++#define CPM_HWFCR (CPM_BASE+0x34) ++#define CPM_HRCR (CPM_BASE+0x38) ++#define CPM_HWCR (CPM_BASE+0x3c) ++#define CPM_HWSR (CPM_BASE+0x40) ++#define CPM_HSPR (CPM_BASE+0x44) ++ ++#define CPM_RSR (CPM_BASE+0x08) ++ ++ ++#define REG_CPM_CPCCR REG32(CPM_CPCCR) ++#define REG_CPM_CPPCR REG32(CPM_CPPCR) ++#define REG_CPM_I2SCDR REG32(CPM_I2SCDR) ++#define REG_CPM_LPCDR REG32(CPM_LPCDR) ++#define REG_CPM_MSCCDR REG32(CPM_MSCCDR) ++#define REG_CPM_UHCCDR REG32(CPM_UHCCDR) ++#define REG_CPM_SSICDR REG32(CPM_SSICDR) ++ ++#define REG_CPM_LCR REG32(CPM_LCR) ++#define REG_CPM_CLKGR REG32(CPM_CLKGR) ++#define REG_CPM_SCR REG32(CPM_SCR) ++#define REG_CPM_HCR REG32(CPM_HCR) ++#define REG_CPM_HWFCR REG32(CPM_HWFCR) ++#define REG_CPM_HRCR REG32(CPM_HRCR) ++#define REG_CPM_HWCR REG32(CPM_HWCR) ++#define REG_CPM_HWSR REG32(CPM_HWSR) ++#define REG_CPM_HSPR REG32(CPM_HSPR) ++ ++#define REG_CPM_RSR REG32(CPM_RSR) ++ ++ ++/* Clock Control Register */ ++#define CPM_CPCCR_I2CS (1 << 31) ++#define CPM_CPCCR_CLKOEN (1 << 30) ++#define CPM_CPCCR_UCS (1 << 29) ++#define CPM_CPCCR_UDIV_BIT 23 ++#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT) ++#define CPM_CPCCR_CE (1 << 22) ++#define CPM_CPCCR_PCS (1 << 21) ++#define CPM_CPCCR_LDIV_BIT 16 ++#define CPM_CPCCR_LDIV_MASK (0x1f << CPM_CPCCR_LDIV_BIT) ++#define CPM_CPCCR_MDIV_BIT 12 ++#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT) ++#define CPM_CPCCR_PDIV_BIT 8 ++#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT) ++#define CPM_CPCCR_HDIV_BIT 4 ++#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT) ++#define CPM_CPCCR_CDIV_BIT 0 ++#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT) ++ ++/* I2S Clock Divider Register */ ++#define CPM_I2SCDR_I2SDIV_BIT 0 ++#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT) ++ ++/* LCD Pixel Clock Divider Register */ ++#define CPM_LPCDR_PIXDIV_BIT 0 ++#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT) ++ ++/* MSC Clock Divider Register */ ++#define CPM_MSCCDR_MSCDIV_BIT 0 ++#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT) ++ ++/* UHC Clock Divider Register */ ++#define CPM_UHCCDR_UHCDIV_BIT 0 ++#define CPM_UHCCDR_UHCDIV_MASK (0xf << CPM_UHCCDR_UHCDIV_BIT) ++ ++/* SSI Clock Divider Register */ ++#define CPM_SSICDR_SCS (1<<31) /* SSI clock source selection, 0:EXCLK, 1: PLL */ ++#define CPM_SSICDR_SSIDIV_BIT 0 ++#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT) ++ ++/* PLL Control Register */ ++#define CPM_CPPCR_PLLM_BIT 23 ++#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT) ++#define CPM_CPPCR_PLLN_BIT 18 ++#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT) ++#define CPM_CPPCR_PLLOD_BIT 16 ++#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT) ++#define CPM_CPPCR_PLLS (1 << 10) ++#define CPM_CPPCR_PLLBP (1 << 9) ++#define CPM_CPPCR_PLLEN (1 << 8) ++#define CPM_CPPCR_PLLST_BIT 0 ++#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT) ++ ++/* Low Power Control Register */ ++#define CPM_LCR_DOZE_DUTY_BIT 3 ++#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT) ++#define CPM_LCR_DOZE_ON (1 << 2) ++#define CPM_LCR_LPM_BIT 0 ++#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT) ++ #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT) ++ #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT) ++ ++/* Clock Gate Register */ ++#define CPM_CLKGR_UART1 (1 << 15) ++#define CPM_CLKGR_UHC (1 << 14) ++#define CPM_CLKGR_IPU (1 << 13) ++#define CPM_CLKGR_DMAC (1 << 12) ++#define CPM_CLKGR_UDC (1 << 11) ++#define CPM_CLKGR_LCD (1 << 10) ++#define CPM_CLKGR_CIM (1 << 9) ++#define CPM_CLKGR_SADC (1 << 8) ++#define CPM_CLKGR_MSC (1 << 7) ++#define CPM_CLKGR_AIC1 (1 << 6) ++#define CPM_CLKGR_AIC2 (1 << 5) ++#define CPM_CLKGR_SSI (1 << 4) ++#define CPM_CLKGR_I2C (1 << 3) ++#define CPM_CLKGR_RTC (1 << 2) ++#define CPM_CLKGR_TCU (1 << 1) ++#define CPM_CLKGR_UART0 (1 << 0) ++ ++/* Sleep Control Register */ ++#define CPM_SCR_O1ST_BIT 8 ++#define CPM_SCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT) ++#define CPM_SCR_USBPHY_ENABLE (1 << 6) ++#define CPM_SCR_OSC_ENABLE (1 << 4) ++ ++/* Hibernate Control Register */ ++#define CPM_HCR_PD (1 << 0) ++ ++/* Wakeup Filter Counter Register in Hibernate Mode */ ++#define CPM_HWFCR_TIME_BIT 0 ++#define CPM_HWFCR_TIME_MASK (0x3ff << CPM_HWFCR_TIME_BIT) ++ ++/* Reset Counter Register in Hibernate Mode */ ++#define CPM_HRCR_TIME_BIT 0 ++#define CPM_HRCR_TIME_MASK (0x7f << CPM_HRCR_TIME_BIT) ++ ++/* Wakeup Control Register in Hibernate Mode */ ++#define CPM_HWCR_WLE_LOW (0 << 2) ++#define CPM_HWCR_WLE_HIGH (1 << 2) ++#define CPM_HWCR_PIN_WAKEUP (1 << 1) ++#define CPM_HWCR_RTC_WAKEUP (1 << 0) ++ ++/* Wakeup Status Register in Hibernate Mode */ ++#define CPM_HWSR_WSR_PIN (1 << 1) ++#define CPM_HWSR_WSR_RTC (1 << 0) ++ ++/* Reset Status Register */ ++#define CPM_RSR_HR (1 << 2) ++#define CPM_RSR_WR (1 << 1) ++#define CPM_RSR_PR (1 << 0) ++ ++ ++/************************************************************************* ++ * TCU (Timer Counter Unit) ++ *************************************************************************/ ++#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */ ++#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */ ++#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */ ++#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */ ++#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */ ++#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */ ++#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */ ++#define TCU_TDFR1 (TCU_BASE + 0x50) ++#define TCU_TDHR1 (TCU_BASE + 0x54) ++#define TCU_TCNT1 (TCU_BASE + 0x58) ++#define TCU_TCSR1 (TCU_BASE + 0x5C) ++#define TCU_TDFR2 (TCU_BASE + 0x60) ++#define TCU_TDHR2 (TCU_BASE + 0x64) ++#define TCU_TCNT2 (TCU_BASE + 0x68) ++#define TCU_TCSR2 (TCU_BASE + 0x6C) ++#define TCU_TDFR3 (TCU_BASE + 0x70) ++#define TCU_TDHR3 (TCU_BASE + 0x74) ++#define TCU_TCNT3 (TCU_BASE + 0x78) ++#define TCU_TCSR3 (TCU_BASE + 0x7C) ++#define TCU_TDFR4 (TCU_BASE + 0x80) ++#define TCU_TDHR4 (TCU_BASE + 0x84) ++#define TCU_TCNT4 (TCU_BASE + 0x88) ++#define TCU_TCSR4 (TCU_BASE + 0x8C) ++#define TCU_TDFR5 (TCU_BASE + 0x90) ++#define TCU_TDHR5 (TCU_BASE + 0x94) ++#define TCU_TCNT5 (TCU_BASE + 0x98) ++#define TCU_TCSR5 (TCU_BASE + 0x9C) ++ ++#define REG_TCU_TSR REG32(TCU_TSR) ++#define REG_TCU_TSSR REG32(TCU_TSSR) ++#define REG_TCU_TSCR REG32(TCU_TSCR) ++#define REG_TCU_TER REG8(TCU_TER) ++#define REG_TCU_TESR REG8(TCU_TESR) ++#define REG_TCU_TECR REG8(TCU_TECR) ++#define REG_TCU_TFR REG32(TCU_TFR) ++#define REG_TCU_TFSR REG32(TCU_TFSR) ++#define REG_TCU_TFCR REG32(TCU_TFCR) ++#define REG_TCU_TMR REG32(TCU_TMR) ++#define REG_TCU_TMSR REG32(TCU_TMSR) ++#define REG_TCU_TMCR REG32(TCU_TMCR) ++#define REG_TCU_TDFR0 REG16(TCU_TDFR0) ++#define REG_TCU_TDHR0 REG16(TCU_TDHR0) ++#define REG_TCU_TCNT0 REG16(TCU_TCNT0) ++#define REG_TCU_TCSR0 REG16(TCU_TCSR0) ++#define REG_TCU_TDFR1 REG16(TCU_TDFR1) ++#define REG_TCU_TDHR1 REG16(TCU_TDHR1) ++#define REG_TCU_TCNT1 REG16(TCU_TCNT1) ++#define REG_TCU_TCSR1 REG16(TCU_TCSR1) ++#define REG_TCU_TDFR2 REG16(TCU_TDFR2) ++#define REG_TCU_TDHR2 REG16(TCU_TDHR2) ++#define REG_TCU_TCNT2 REG16(TCU_TCNT2) ++#define REG_TCU_TCSR2 REG16(TCU_TCSR2) ++#define REG_TCU_TDFR3 REG16(TCU_TDFR3) ++#define REG_TCU_TDHR3 REG16(TCU_TDHR3) ++#define REG_TCU_TCNT3 REG16(TCU_TCNT3) ++#define REG_TCU_TCSR3 REG16(TCU_TCSR3) ++#define REG_TCU_TDFR4 REG16(TCU_TDFR4) ++#define REG_TCU_TDHR4 REG16(TCU_TDHR4) ++#define REG_TCU_TCNT4 REG16(TCU_TCNT4) ++#define REG_TCU_TCSR4 REG16(TCU_TCSR4) ++ ++// n = 0,1,2,3,4,5 ++#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */ ++#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */ ++#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */ ++#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */ ++ ++#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n))) ++#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n))) ++#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n))) ++#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n))) ++ ++// Register definitions ++#define TCU_TCSR_PWM_SD (1 << 9) ++#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) ++#define TCU_TCSR_PWM_EN (1 << 7) ++#define TCU_TCSR_PRESCALE_BIT 3 ++#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT) ++ #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT) ++ #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT) ++ #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT) ++ #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT) ++ #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT) ++ #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT) ++#define TCU_TCSR_EXT_EN (1 << 2) ++#define TCU_TCSR_RTC_EN (1 << 1) ++#define TCU_TCSR_PCK_EN (1 << 0) ++ ++#define TCU_TER_TCEN5 (1 << 5) ++#define TCU_TER_TCEN4 (1 << 4) ++#define TCU_TER_TCEN3 (1 << 3) ++#define TCU_TER_TCEN2 (1 << 2) ++#define TCU_TER_TCEN1 (1 << 1) ++#define TCU_TER_TCEN0 (1 << 0) ++ ++#define TCU_TESR_TCST5 (1 << 5) ++#define TCU_TESR_TCST4 (1 << 4) ++#define TCU_TESR_TCST3 (1 << 3) ++#define TCU_TESR_TCST2 (1 << 2) ++#define TCU_TESR_TCST1 (1 << 1) ++#define TCU_TESR_TCST0 (1 << 0) ++ ++#define TCU_TECR_TCCL5 (1 << 5) ++#define TCU_TECR_TCCL4 (1 << 4) ++#define TCU_TECR_TCCL3 (1 << 3) ++#define TCU_TECR_TCCL2 (1 << 2) ++#define TCU_TECR_TCCL1 (1 << 1) ++#define TCU_TECR_TCCL0 (1 << 0) ++ ++#define TCU_TFR_HFLAG5 (1 << 21) ++#define TCU_TFR_HFLAG4 (1 << 20) ++#define TCU_TFR_HFLAG3 (1 << 19) ++#define TCU_TFR_HFLAG2 (1 << 18) ++#define TCU_TFR_HFLAG1 (1 << 17) ++#define TCU_TFR_HFLAG0 (1 << 16) ++#define TCU_TFR_FFLAG5 (1 << 5) ++#define TCU_TFR_FFLAG4 (1 << 4) ++#define TCU_TFR_FFLAG3 (1 << 3) ++#define TCU_TFR_FFLAG2 (1 << 2) ++#define TCU_TFR_FFLAG1 (1 << 1) ++#define TCU_TFR_FFLAG0 (1 << 0) ++ ++#define TCU_TFSR_HFLAG5 (1 << 21) ++#define TCU_TFSR_HFLAG4 (1 << 20) ++#define TCU_TFSR_HFLAG3 (1 << 19) ++#define TCU_TFSR_HFLAG2 (1 << 18) ++#define TCU_TFSR_HFLAG1 (1 << 17) ++#define TCU_TFSR_HFLAG0 (1 << 16) ++#define TCU_TFSR_FFLAG5 (1 << 5) ++#define TCU_TFSR_FFLAG4 (1 << 4) ++#define TCU_TFSR_FFLAG3 (1 << 3) ++#define TCU_TFSR_FFLAG2 (1 << 2) ++#define TCU_TFSR_FFLAG1 (1 << 1) ++#define TCU_TFSR_FFLAG0 (1 << 0) ++ ++#define TCU_TFCR_HFLAG5 (1 << 21) ++#define TCU_TFCR_HFLAG4 (1 << 20) ++#define TCU_TFCR_HFLAG3 (1 << 19) ++#define TCU_TFCR_HFLAG2 (1 << 18) ++#define TCU_TFCR_HFLAG1 (1 << 17) ++#define TCU_TFCR_HFLAG0 (1 << 16) ++#define TCU_TFCR_FFLAG5 (1 << 5) ++#define TCU_TFCR_FFLAG4 (1 << 4) ++#define TCU_TFCR_FFLAG3 (1 << 3) ++#define TCU_TFCR_FFLAG2 (1 << 2) ++#define TCU_TFCR_FFLAG1 (1 << 1) ++#define TCU_TFCR_FFLAG0 (1 << 0) ++ ++#define TCU_TMR_HMASK5 (1 << 21) ++#define TCU_TMR_HMASK4 (1 << 20) ++#define TCU_TMR_HMASK3 (1 << 19) ++#define TCU_TMR_HMASK2 (1 << 18) ++#define TCU_TMR_HMASK1 (1 << 17) ++#define TCU_TMR_HMASK0 (1 << 16) ++#define TCU_TMR_FMASK5 (1 << 5) ++#define TCU_TMR_FMASK4 (1 << 4) ++#define TCU_TMR_FMASK3 (1 << 3) ++#define TCU_TMR_FMASK2 (1 << 2) ++#define TCU_TMR_FMASK1 (1 << 1) ++#define TCU_TMR_FMASK0 (1 << 0) ++ ++#define TCU_TMSR_HMST5 (1 << 21) ++#define TCU_TMSR_HMST4 (1 << 20) ++#define TCU_TMSR_HMST3 (1 << 19) ++#define TCU_TMSR_HMST2 (1 << 18) ++#define TCU_TMSR_HMST1 (1 << 17) ++#define TCU_TMSR_HMST0 (1 << 16) ++#define TCU_TMSR_FMST5 (1 << 5) ++#define TCU_TMSR_FMST4 (1 << 4) ++#define TCU_TMSR_FMST3 (1 << 3) ++#define TCU_TMSR_FMST2 (1 << 2) ++#define TCU_TMSR_FMST1 (1 << 1) ++#define TCU_TMSR_FMST0 (1 << 0) ++ ++#define TCU_TMCR_HMCL5 (1 << 21) ++#define TCU_TMCR_HMCL4 (1 << 20) ++#define TCU_TMCR_HMCL3 (1 << 19) ++#define TCU_TMCR_HMCL2 (1 << 18) ++#define TCU_TMCR_HMCL1 (1 << 17) ++#define TCU_TMCR_HMCL0 (1 << 16) ++#define TCU_TMCR_FMCL5 (1 << 5) ++#define TCU_TMCR_FMCL4 (1 << 4) ++#define TCU_TMCR_FMCL3 (1 << 3) ++#define TCU_TMCR_FMCL2 (1 << 2) ++#define TCU_TMCR_FMCL1 (1 << 1) ++#define TCU_TMCR_FMCL0 (1 << 0) ++ ++#define TCU_TSR_WDTS (1 << 16) ++#define TCU_TSR_STOP5 (1 << 5) ++#define TCU_TSR_STOP4 (1 << 4) ++#define TCU_TSR_STOP3 (1 << 3) ++#define TCU_TSR_STOP2 (1 << 2) ++#define TCU_TSR_STOP1 (1 << 1) ++#define TCU_TSR_STOP0 (1 << 0) ++ ++#define TCU_TSSR_WDTSS (1 << 16) ++#define TCU_TSSR_STPS5 (1 << 5) ++#define TCU_TSSR_STPS4 (1 << 4) ++#define TCU_TSSR_STPS3 (1 << 3) ++#define TCU_TSSR_STPS2 (1 << 2) ++#define TCU_TSSR_STPS1 (1 << 1) ++#define TCU_TSSR_STPS0 (1 << 0) ++ ++#define TCU_TSSR_WDTSC (1 << 16) ++#define TCU_TSSR_STPC5 (1 << 5) ++#define TCU_TSSR_STPC4 (1 << 4) ++#define TCU_TSSR_STPC3 (1 << 3) ++#define TCU_TSSR_STPC2 (1 << 2) ++#define TCU_TSSR_STPC1 (1 << 1) ++#define TCU_TSSR_STPC0 (1 << 0) ++ ++ ++/************************************************************************* ++ * WDT (WatchDog Timer) ++ *************************************************************************/ ++#define WDT_TDR (WDT_BASE + 0x00) ++#define WDT_TCER (WDT_BASE + 0x04) ++#define WDT_TCNT (WDT_BASE + 0x08) ++#define WDT_TCSR (WDT_BASE + 0x0C) ++ ++#define REG_WDT_TDR REG16(WDT_TDR) ++#define REG_WDT_TCER REG8(WDT_TCER) ++#define REG_WDT_TCNT REG16(WDT_TCNT) ++#define REG_WDT_TCSR REG16(WDT_TCSR) ++ ++// Register definition ++#define WDT_TCSR_PRESCALE_BIT 3 ++#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT) ++ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT) ++ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT) ++ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT) ++ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT) ++ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT) ++ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT) ++#define WDT_TCSR_EXT_EN (1 << 2) ++#define WDT_TCSR_RTC_EN (1 << 1) ++#define WDT_TCSR_PCK_EN (1 << 0) ++ ++#define WDT_TCER_TCEN (1 << 0) ++ ++ ++/************************************************************************* ++ * DMAC (DMA Controller) ++ *************************************************************************/ ++ ++#define MAX_DMA_NUM 6 /* max 6 channels */ ++ ++#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) /* DMA source address */ ++#define DMAC_DTAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) /* DMA target address */ ++#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) /* DMA transfer count */ ++#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) /* DMA request source */ ++#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) /* DMA control/status */ ++#define DMAC_DCMD(n) (DMAC_BASE + (0x14 + (n) * 0x20)) /* DMA command */ ++#define DMAC_DDA(n) (DMAC_BASE + (0x18 + (n) * 0x20)) /* DMA descriptor address */ ++#define DMAC_DMACR (DMAC_BASE + 0x0300) /* DMA control register */ ++#define DMAC_DMAIPR (DMAC_BASE + 0x0304) /* DMA interrupt pending */ ++#define DMAC_DMADBR (DMAC_BASE + 0x0308) /* DMA doorbell */ ++#define DMAC_DMADBSR (DMAC_BASE + 0x030C) /* DMA doorbell set */ ++ ++// channel 0 ++#define DMAC_DSAR0 DMAC_DSAR(0) ++#define DMAC_DTAR0 DMAC_DTAR(0) ++#define DMAC_DTCR0 DMAC_DTCR(0) ++#define DMAC_DRSR0 DMAC_DRSR(0) ++#define DMAC_DCCSR0 DMAC_DCCSR(0) ++#define DMAC_DCMD0 DMAC_DCMD(0) ++#define DMAC_DDA0 DMAC_DDA(0) ++ ++// channel 1 ++#define DMAC_DSAR1 DMAC_DSAR(1) ++#define DMAC_DTAR1 DMAC_DTAR(1) ++#define DMAC_DTCR1 DMAC_DTCR(1) ++#define DMAC_DRSR1 DMAC_DRSR(1) ++#define DMAC_DCCSR1 DMAC_DCCSR(1) ++#define DMAC_DCMD1 DMAC_DCMD(1) ++#define DMAC_DDA1 DMAC_DDA(1) ++ ++// channel 2 ++#define DMAC_DSAR2 DMAC_DSAR(2) ++#define DMAC_DTAR2 DMAC_DTAR(2) ++#define DMAC_DTCR2 DMAC_DTCR(2) ++#define DMAC_DRSR2 DMAC_DRSR(2) ++#define DMAC_DCCSR2 DMAC_DCCSR(2) ++#define DMAC_DCMD2 DMAC_DCMD(2) ++#define DMAC_DDA2 DMAC_DDA(2) ++ ++// channel 3 ++#define DMAC_DSAR3 DMAC_DSAR(3) ++#define DMAC_DTAR3 DMAC_DTAR(3) ++#define DMAC_DTCR3 DMAC_DTCR(3) ++#define DMAC_DRSR3 DMAC_DRSR(3) ++#define DMAC_DCCSR3 DMAC_DCCSR(3) ++#define DMAC_DCMD3 DMAC_DCMD(3) ++#define DMAC_DDA3 DMAC_DDA(3) ++ ++// channel 4 ++#define DMAC_DSAR4 DMAC_DSAR(4) ++#define DMAC_DTAR4 DMAC_DTAR(4) ++#define DMAC_DTCR4 DMAC_DTCR(4) ++#define DMAC_DRSR4 DMAC_DRSR(4) ++#define DMAC_DCCSR4 DMAC_DCCSR(4) ++#define DMAC_DCMD4 DMAC_DCMD(4) ++#define DMAC_DDA4 DMAC_DDA(4) ++ ++// channel 5 ++#define DMAC_DSAR5 DMAC_DSAR(5) ++#define DMAC_DTAR5 DMAC_DTAR(5) ++#define DMAC_DTCR5 DMAC_DTCR(5) ++#define DMAC_DRSR5 DMAC_DRSR(5) ++#define DMAC_DCCSR5 DMAC_DCCSR(5) ++#define DMAC_DCMD5 DMAC_DCMD(5) ++#define DMAC_DDA5 DMAC_DDA(5) ++ ++#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n))) ++#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n))) ++#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n))) ++#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n))) ++#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n))) ++#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n))) ++#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n))) ++#define REG_DMAC_DMACR REG32(DMAC_DMACR) ++#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR) ++#define REG_DMAC_DMADBR REG32(DMAC_DMADBR) ++#define REG_DMAC_DMADBSR REG32(DMAC_DMADBSR) ++ ++// DMA request source register ++#define DMAC_DRSR_RS_BIT 0 ++#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT) ++ #define DMAC_DRSR_RS_SLCD (30 << DMAC_DRSR_RS_BIT) ++ ++// DMA channel control/status register ++#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */ ++#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */ ++#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT) ++#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */ ++#define DMAC_DCCSR_AR (1 << 4) /* address error */ ++#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */ ++#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */ ++#define DMAC_DCCSR_CT (1 << 1) /* count terminated */ ++#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */ ++ ++// DMA channel command register ++#define DMAC_DCMD_SAI (1 << 23) /* source address increment */ ++#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */ ++#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */ ++#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT) ++ #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT) ++#define DMAC_DCMD_SWDH_BIT 14 /* source port width */ ++#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT) ++ #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT) ++ #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT) ++ #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT) ++#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */ ++#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT) ++ #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT) ++ #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT) ++ #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT) ++#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */ ++#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT) ++ #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT) ++ #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT) ++ #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT) ++ #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT) ++ #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT) ++#define DMAC_DCMD_TM (1 << 7) /* transfer mode: 0-single 1-block */ ++#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */ ++#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */ ++#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */ ++#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */ ++#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */ ++ ++// DMA descriptor address register ++#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */ ++#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT) ++#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */ ++#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT) ++ ++// DMA control register ++#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */ ++#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_023145 (1 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_201345 (2 << DMAC_DMACR_PR_BIT) ++ #define DMAC_DMACR_PR_RR (3 << DMAC_DMACR_PR_BIT) /* round robin */ ++#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */ ++#define DMAC_DMACR_AR (1 << 2) /* address error flag */ ++#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */ ++ ++// DMA doorbell register ++#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */ ++#define DMAC_DMADBR_DB4 (1 << 5) /* doorbell for channel 4 */ ++#define DMAC_DMADBR_DB3 (1 << 5) /* doorbell for channel 3 */ ++#define DMAC_DMADBR_DB2 (1 << 5) /* doorbell for channel 2 */ ++#define DMAC_DMADBR_DB1 (1 << 5) /* doorbell for channel 1 */ ++#define DMAC_DMADBR_DB0 (1 << 5) /* doorbell for channel 0 */ ++ ++// DMA doorbell set register ++#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */ ++#define DMAC_DMADBSR_DBS4 (1 << 5) /* enable doorbell for channel 4 */ ++#define DMAC_DMADBSR_DBS3 (1 << 5) /* enable doorbell for channel 3 */ ++#define DMAC_DMADBSR_DBS2 (1 << 5) /* enable doorbell for channel 2 */ ++#define DMAC_DMADBSR_DBS1 (1 << 5) /* enable doorbell for channel 1 */ ++#define DMAC_DMADBSR_DBS0 (1 << 5) /* enable doorbell for channel 0 */ ++ ++// DMA interrupt pending register ++#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */ ++#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */ ++#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */ ++#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */ ++#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */ ++#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */ ++ ++ ++/************************************************************************* ++ * GPIO (General-Purpose I/O Ports) ++ *************************************************************************/ ++#define MAX_GPIO_NUM 128 ++ ++//n = 0,1,2,3 ++#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */ ++#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */ ++#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */ ++#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */ ++#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */ ++#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */ ++#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */ ++#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */ ++#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */ ++#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */ ++#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */ ++#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */ ++#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */ ++#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */ ++#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */ ++#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */ ++#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */ ++#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */ ++#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */ ++#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */ ++#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */ ++#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */ ++#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */ ++#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */ ++ ++#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */ ++#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */ ++#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n))) ++#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n))) ++#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */ ++#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n))) ++#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n))) ++#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */ ++#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n))) ++#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n))) ++#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */ ++#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n))) ++#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n))) ++#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/ ++#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n))) ++#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n))) ++#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */ ++#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n))) ++#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n))) ++#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */ ++#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n))) ++#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n))) ++#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */ ++#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */ ++ ++ ++/************************************************************************* ++ * UART ++ *************************************************************************/ ++ ++#define IRDA_BASE UART0_BASE ++#define UART_BASE UART0_BASE ++#define UART_OFF 0x1000 ++ ++/* Register Offset */ ++#define OFF_RDR (0x00) /* R 8b H'xx */ ++#define OFF_TDR (0x00) /* W 8b H'xx */ ++#define OFF_DLLR (0x00) /* RW 8b H'00 */ ++#define OFF_DLHR (0x04) /* RW 8b H'00 */ ++#define OFF_IER (0x04) /* RW 8b H'00 */ ++#define OFF_ISR (0x08) /* R 8b H'01 */ ++#define OFF_FCR (0x08) /* W 8b H'00 */ ++#define OFF_LCR (0x0C) /* RW 8b H'00 */ ++#define OFF_MCR (0x10) /* RW 8b H'00 */ ++#define OFF_LSR (0x14) /* R 8b H'00 */ ++#define OFF_MSR (0x18) /* R 8b H'00 */ ++#define OFF_SPR (0x1C) /* RW 8b H'00 */ ++#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */ ++#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */ ++#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */ ++ ++/* Register Address */ ++#define UART0_RDR (UART0_BASE + OFF_RDR) ++#define UART0_TDR (UART0_BASE + OFF_TDR) ++#define UART0_DLLR (UART0_BASE + OFF_DLLR) ++#define UART0_DLHR (UART0_BASE + OFF_DLHR) ++#define UART0_IER (UART0_BASE + OFF_IER) ++#define UART0_ISR (UART0_BASE + OFF_ISR) ++#define UART0_FCR (UART0_BASE + OFF_FCR) ++#define UART0_LCR (UART0_BASE + OFF_LCR) ++#define UART0_MCR (UART0_BASE + OFF_MCR) ++#define UART0_LSR (UART0_BASE + OFF_LSR) ++#define UART0_MSR (UART0_BASE + OFF_MSR) ++#define UART0_SPR (UART0_BASE + OFF_SPR) ++#define UART0_SIRCR (UART0_BASE + OFF_SIRCR) ++#define UART0_UMR (UART0_BASE + OFF_UMR) ++#define UART0_UACR (UART0_BASE + OFF_UACR) ++ ++/* ++ * Define macros for UARTIER ++ * UART Interrupt Enable Register ++ */ ++#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */ ++#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */ ++#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ ++#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */ ++#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ ++ ++/* ++ * Define macros for UARTISR ++ * UART Interrupt Status Register ++ */ ++#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ ++#define UARTISR_IID (7 << 1) /* Source of Interrupt */ ++#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */ ++#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ ++#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */ ++#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ ++#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */ ++#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */ ++#define UARTISR_FFMS_NO_FIFO (0 << 6) ++#define UARTISR_FFMS_FIFO_MODE (3 << 6) ++ ++/* ++ * Define macros for UARTFCR ++ * UART FIFO Control Register ++ */ ++#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ ++#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ ++#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ ++#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ ++#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ ++#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ ++#define UARTFCR_RTRG_1 (0 << 6) ++#define UARTFCR_RTRG_4 (1 << 6) ++#define UARTFCR_RTRG_8 (2 << 6) ++#define UARTFCR_RTRG_15 (3 << 6) ++ ++/* ++ * Define macros for UARTLCR ++ * UART Line Control Register ++ */ ++#define UARTLCR_WLEN (3 << 0) /* word length */ ++#define UARTLCR_WLEN_5 (0 << 0) ++#define UARTLCR_WLEN_6 (1 << 0) ++#define UARTLCR_WLEN_7 (2 << 0) ++#define UARTLCR_WLEN_8 (3 << 0) ++#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 ++ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ ++#define UARTLCR_STOP1 (0 << 2) ++#define UARTLCR_STOP2 (1 << 2) ++#define UARTLCR_PE (1 << 3) /* 0: parity disable */ ++#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ ++#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ ++#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ ++#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ ++ ++/* ++ * Define macros for UARTLSR ++ * UART Line Status Register ++ */ ++#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ ++#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */ ++#define UARTLSR_PER (1 << 2) /* 0: no parity error */ ++#define UARTLSR_FER (1 << 3) /* 0; no framing error */ ++#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ ++#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ ++#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ ++#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ ++ ++/* ++ * Define macros for UARTMCR ++ * UART Modem Control Register ++ */ ++#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */ ++#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ ++#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */ ++ ++/* ++ * Define macros for UARTMSR ++ * UART Modem Status Register ++ */ ++#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */ ++#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */ ++ ++/* ++ * Define macros for SIRCR ++ * Slow IrDA Control Register ++ */ ++#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */ ++#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */ ++#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length ++ 1: 0 pulse width is 1.6us for 115.2Kbps */ ++#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ ++#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ ++ ++ ++/************************************************************************* ++ * AIC (AC97/I2S Controller) ++ *************************************************************************/ ++#define AIC_FR (AIC_BASE + 0x000) ++#define AIC_CR (AIC_BASE + 0x004) ++#define AIC_ACCR1 (AIC_BASE + 0x008) ++#define AIC_ACCR2 (AIC_BASE + 0x00C) ++#define AIC_I2SCR (AIC_BASE + 0x010) ++#define AIC_SR (AIC_BASE + 0x014) ++#define AIC_ACSR (AIC_BASE + 0x018) ++#define AIC_I2SSR (AIC_BASE + 0x01C) ++#define AIC_ACCAR (AIC_BASE + 0x020) ++#define AIC_ACCDR (AIC_BASE + 0x024) ++#define AIC_ACSAR (AIC_BASE + 0x028) ++#define AIC_ACSDR (AIC_BASE + 0x02C) ++#define AIC_I2SDIV (AIC_BASE + 0x030) ++#define AIC_DR (AIC_BASE + 0x034) ++ ++#define REG_AIC_FR REG32(AIC_FR) ++#define REG_AIC_CR REG32(AIC_CR) ++#define REG_AIC_ACCR1 REG32(AIC_ACCR1) ++#define REG_AIC_ACCR2 REG32(AIC_ACCR2) ++#define REG_AIC_I2SCR REG32(AIC_I2SCR) ++#define REG_AIC_SR REG32(AIC_SR) ++#define REG_AIC_ACSR REG32(AIC_ACSR) ++#define REG_AIC_I2SSR REG32(AIC_I2SSR) ++#define REG_AIC_ACCAR REG32(AIC_ACCAR) ++#define REG_AIC_ACCDR REG32(AIC_ACCDR) ++#define REG_AIC_ACSAR REG32(AIC_ACSAR) ++#define REG_AIC_ACSDR REG32(AIC_ACSDR) ++#define REG_AIC_I2SDIV REG32(AIC_I2SDIV) ++#define REG_AIC_DR REG32(AIC_DR) ++ ++/* AIC Controller Configuration Register (AIC_FR) */ ++ ++#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */ ++#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT) ++#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */ ++#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT) ++#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */ ++#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */ ++#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */ ++#define AIC_FR_RST (1 << 3) /* AIC registers reset */ ++#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */ ++#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */ ++#define AIC_FR_ENB (1 << 0) /* AIC enable bit */ ++ ++/* AIC Controller Common Control Register (AIC_CR) */ ++ ++#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */ ++#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT) ++ #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT) ++ #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT) ++ #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT) ++ #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT) ++ #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT) ++#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */ ++#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT) ++ #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT) ++ #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT) ++ #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT) ++ #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT) ++ #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT) ++#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */ ++#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */ ++#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */ ++#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */ ++#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */ ++#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ ++#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ ++#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ ++#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ ++#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ ++#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ ++#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ ++#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ ++ ++/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ ++ ++#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ ++#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) ++ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ ++ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ ++ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ ++ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ ++ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ ++ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ ++#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ ++#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) ++ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ ++ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ ++ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ ++ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ ++ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ ++ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ ++ ++/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ ++ ++#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ ++#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ ++#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ ++#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ ++#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) ++ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ ++#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) ++ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ ++#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ ++#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ ++#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ ++ ++/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ ++ ++#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ ++#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ ++#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) ++ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ ++ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ ++ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ ++ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ ++ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ ++#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ ++ ++/* AIC Controller FIFO Status Register (AIC_SR) */ ++ ++#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ ++#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) ++#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ ++#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) ++#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ ++#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ ++#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ ++#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ ++ ++/* AIC Controller AC-link Status Register (AIC_ACSR) */ ++ ++#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ ++#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ ++#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ ++#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ ++#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ ++#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ ++ ++/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ ++ ++#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ ++ ++/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ ++ ++#define AIC_ACCAR_CAR_BIT 0 ++#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) ++ ++/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ ++ ++#define AIC_ACCDR_CDR_BIT 0 ++#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) ++ ++/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ ++ ++#define AIC_ACSAR_SAR_BIT 0 ++#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) ++ ++/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ ++ ++#define AIC_ACSDR_SDR_BIT 0 ++#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) ++ ++/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ ++ ++#define AIC_I2SDIV_DIV_BIT 0 ++#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) ++ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ ++ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ ++ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ ++ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ ++ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ ++ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ ++ ++ ++/************************************************************************* ++ * ICDC (Internal CODEC) ++ *************************************************************************/ ++#define ICDC_CR (ICDC_BASE + 0x0400) /* ICDC Control Register */ ++#define ICDC_APWAIT (ICDC_BASE + 0x0404) /* Anti-Pop WAIT Stage Timing Control Register */ ++#define ICDC_APPRE (ICDC_BASE + 0x0408) /* Anti-Pop HPEN-PRE Stage Timing Control Register */ ++#define ICDC_APHPEN (ICDC_BASE + 0x040C) /* Anti-Pop HPEN Stage Timing Control Register */ ++#define ICDC_APSR (ICDC_BASE + 0x0410) /* Anti-Pop Status Register */ ++#define ICDC_CDCCR1 (ICDC_BASE + 0x0080) ++#define ICDC_CDCCR2 (ICDC_BASE + 0x0084) ++ ++#define REG_ICDC_CR REG32(ICDC_CR) ++#define REG_ICDC_APWAIT REG32(ICDC_APWAIT) ++#define REG_ICDC_APPRE REG32(ICDC_APPRE) ++#define REG_ICDC_APHPEN REG32(ICDC_APHPEN) ++#define REG_ICDC_APSR REG32(ICDC_APSR) ++#define REG_ICDC_CDCCR1 REG32(ICDC_CDCCR1) ++#define REG_ICDC_CDCCR2 REG32(ICDC_CDCCR2) ++ ++/* ICDC Control Register */ ++#define ICDC_CR_LINVOL_BIT 24 /* LINE Input Volume Gain: GAIN=LINVOL*1.5-34.5 */ ++#define ICDC_CR_LINVOL_MASK (0x1f << ICDC_CR_LINVOL_BIT) ++#define ICDC_CR_ASRATE_BIT 20 /* Audio Sample Rate */ ++#define ICDC_CR_ASRATE_MASK (0x0f << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_8000 (0x0 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_11025 (0x1 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_12000 (0x2 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_16000 (0x3 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_22050 (0x4 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_24000 (0x5 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_32000 (0x6 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_44100 (0x7 << ICDC_CR_ASRATE_BIT) ++ #define ICDC_CR_ASRATE_48000 (0x8 << ICDC_CR_ASRATE_BIT) ++#define ICDC_CR_MICBG_BIT 18 /* MIC Boost Gain */ ++#define ICDC_CR_MICBG_MASK (0x3 << ICDC_CR_MICBG_BIT) ++ #define ICDC_CR_MICBG_0DB (0x0 << ICDC_CR_MICBG_BIT) ++ #define ICDC_CR_MICBG_6DB (0x1 << ICDC_CR_MICBG_BIT) ++ #define ICDC_CR_MICBG_12DB (0x2 << ICDC_CR_MICBG_BIT) ++ #define ICDC_CR_MICBG_20DB (0x3 << ICDC_CR_MICBG_BIT) ++#define ICDC_CR_HPVOL_BIT 16 /* Headphone Volume Gain */ ++#define ICDC_CR_HPVOL_MASK (0x3 << ICDC_CR_HPVOL_BIT) ++ #define ICDC_CR_HPVOL_0DB (0x0 << ICDC_CR_HPVOL_BIT) ++ #define ICDC_CR_HPVOL_2DB (0x1 << ICDC_CR_HPVOL_BIT) ++ #define ICDC_CR_HPVOL_4DB (0x2 << ICDC_CR_HPVOL_BIT) ++ #define ICDC_CR_HPVOL_6DB (0x3 << ICDC_CR_HPVOL_BIT) ++#define ICDC_CR_ELINEIN (1 << 13) /* Enable LINE Input */ ++#define ICDC_CR_EMIC (1 << 12) /* Enable MIC Input */ ++#define ICDC_CR_SW1ON (1 << 11) /* Switch 1 in CODEC is on */ ++#define ICDC_CR_EADC (1 << 10) /* Enable ADC */ ++#define ICDC_CR_SW2ON (1 << 9) /* Switch 2 in CODEC is on */ ++#define ICDC_CR_EDAC (1 << 8) /* Enable DAC */ ++#define ICDC_CR_HPMUTE (1 << 5) /* Headphone Mute */ ++#define ICDC_CR_HPTON (1 << 4) /* Headphone Amplifier Trun On */ ++#define ICDC_CR_HPTOFF (1 << 3) /* Headphone Amplifier Trun Off */ ++#define ICDC_CR_TAAP (1 << 2) /* Turn Around of the Anti-Pop Procedure */ ++#define ICDC_CR_EAP (1 << 1) /* Enable Anti-Pop Procedure */ ++#define ICDC_CR_SUSPD (1 << 0) /* CODEC Suspend */ ++ ++/* Anti-Pop WAIT Stage Timing Control Register */ ++#define ICDC_APWAIT_WAITSN_BIT 0 ++#define ICDC_APWAIT_WAITSN_MASK (0x7ff << ICDC_APWAIT_WAITSN_BIT) ++ ++/* Anti-Pop HPEN-PRE Stage Timing Control Register */ ++#define ICDC_APPRE_PRESN_BIT 0 ++#define ICDC_APPRE_PRESN_MASK (0x1ff << ICDC_APPRE_PRESN_BIT) ++ ++/* Anti-Pop HPEN Stage Timing Control Register */ ++#define ICDC_APHPEN_HPENSN_BIT 0 ++#define ICDC_APHPEN_HPENSN_MASK (0x3fff << ICDC_APHPEN_HPENSN_BIT) ++ ++/* Anti-Pop Status Register */ ++#define ICDC_SR_HPST_BIT 14 /* Headphone Amplifier State */ ++#define ICDC_SR_HPST_MASK (0x7 << ICDC_SR_HPST_BIT) ++#define ICDC_SR_HPST_HP_OFF (0x0 << ICDC_SR_HPST_BIT) /* HP amplifier is off */ ++#define ICDC_SR_HPST_TON_WAIT (0x1 << ICDC_SR_HPST_BIT) /* wait state in turn-on */ ++ #define ICDC_SR_HPST_TON_PRE (0x2 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-on */ ++#define ICDC_SR_HPST_TON_HPEN (0x3 << ICDC_SR_HPST_BIT) /* HP enable state in turn-on */ ++ #define ICDC_SR_HPST_TOFF_HPEN (0x4 << ICDC_SR_HPST_BIT) /* HP enable state in turn-off */ ++ #define ICDC_SR_HPST_TOFF_PRE (0x5 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-off */ ++ #define ICDC_SR_HPST_TOFF_WAIT (0x6 << ICDC_SR_HPST_BIT) /* wait state in turn-off */ ++ #define ICDC_SR_HPST_HP_ON (0x7 << ICDC_SR_HPST_BIT) /* HP amplifier is on */ ++#define ICDC_SR_SNCNT_BIT 0 /* Sample Number Counter */ ++#define ICDC_SR_SNCNT_MASK (0x3fff << ICDC_SR_SNCNT_BIT) ++ ++ ++/************************************************************************* ++ * I2C ++ *************************************************************************/ ++#define I2C_DR (I2C_BASE + 0x000) ++#define I2C_CR (I2C_BASE + 0x004) ++#define I2C_SR (I2C_BASE + 0x008) ++#define I2C_GR (I2C_BASE + 0x00C) ++ ++#define REG_I2C_DR REG8(I2C_DR) ++#define REG_I2C_CR REG8(I2C_CR) ++#define REG_I2C_SR REG8(I2C_SR) ++#define REG_I2C_GR REG16(I2C_GR) ++ ++/* I2C Control Register (I2C_CR) */ ++ ++#define I2C_CR_IEN (1 << 4) ++#define I2C_CR_STA (1 << 3) ++#define I2C_CR_STO (1 << 2) ++#define I2C_CR_AC (1 << 1) ++#define I2C_CR_I2CE (1 << 0) ++ ++/* I2C Status Register (I2C_SR) */ ++ ++#define I2C_SR_STX (1 << 4) ++#define I2C_SR_BUSY (1 << 3) ++#define I2C_SR_TEND (1 << 2) ++#define I2C_SR_DRF (1 << 1) ++#define I2C_SR_ACKF (1 << 0) ++ ++ ++/************************************************************************* ++ * SSI ++ *************************************************************************/ ++#define SSI_DR (SSI_BASE + 0x000) ++#define SSI_CR0 (SSI_BASE + 0x004) ++#define SSI_CR1 (SSI_BASE + 0x008) ++#define SSI_SR (SSI_BASE + 0x00C) ++#define SSI_ITR (SSI_BASE + 0x010) ++#define SSI_ICR (SSI_BASE + 0x014) ++#define SSI_GR (SSI_BASE + 0x018) ++ ++#define REG_SSI_DR REG32(SSI_DR) ++#define REG_SSI_CR0 REG16(SSI_CR0) ++#define REG_SSI_CR1 REG32(SSI_CR1) ++#define REG_SSI_SR REG32(SSI_SR) ++#define REG_SSI_ITR REG16(SSI_ITR) ++#define REG_SSI_ICR REG8(SSI_ICR) ++#define REG_SSI_GR REG16(SSI_GR) ++ ++/* SSI Data Register (SSI_DR) */ ++ ++#define SSI_DR_GPC_BIT 0 ++#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) ++ ++/* SSI Control Register 0 (SSI_CR0) */ ++ ++#define SSI_CR0_SSIE (1 << 15) ++#define SSI_CR0_TIE (1 << 14) ++#define SSI_CR0_RIE (1 << 13) ++#define SSI_CR0_TEIE (1 << 12) ++#define SSI_CR0_REIE (1 << 11) ++#define SSI_CR0_LOOP (1 << 10) ++#define SSI_CR0_RFINE (1 << 9) ++#define SSI_CR0_RFINC (1 << 8) ++#define SSI_CR0_FSEL (1 << 6) ++#define SSI_CR0_TFLUSH (1 << 2) ++#define SSI_CR0_RFLUSH (1 << 1) ++#define SSI_CR0_DISREV (1 << 0) ++ ++/* SSI Control Register 1 (SSI_CR1) */ ++ ++#define SSI_CR1_FRMHL_BIT 30 ++#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) ++ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ ++#define SSI_CR1_TFVCK_BIT 28 ++#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) ++#define SSI_CR1_TCKFI_BIT 26 ++#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) ++#define SSI_CR1_LFST (1 << 25) ++#define SSI_CR1_ITFRM (1 << 24) ++#define SSI_CR1_UNFIN (1 << 23) ++#define SSI_CR1_MULTS (1 << 22) ++#define SSI_CR1_FMAT_BIT 20 ++#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) ++ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ ++ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ ++ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ ++ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ ++#define SSI_CR1_TTRG_BIT 16 ++#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_8 (1 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_16 (2 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_24 (3 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_32 (4 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_40 (5 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_48 (6 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_56 (7 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_64 (8 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_72 (9 << SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_80 (10<< SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_88 (11<< SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_96 (12<< SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_104 (13<< SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_112 (14<< SSI_CR1_TTRG_BIT) ++ #define SSI_CR1_TTRG_120 (15<< SSI_CR1_TTRG_BIT) ++#define SSI_CR1_MCOM_BIT 12 ++#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) ++ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ ++ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ ++ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ ++ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ ++ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ ++ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ ++ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ ++ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ ++ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ ++ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ ++ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ ++ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ ++ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ ++ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ ++ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ ++ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ ++#define SSI_CR1_RTRG_BIT 8 ++#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_8 (1 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_16 (2 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_24 (3 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_32 (4 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_40 (5 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_48 (6 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_56 (7 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_64 (8 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_72 (9 << SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_80 (10<< SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_88 (11<< SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_96 (12<< SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_104 (13<< SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_112 (14<< SSI_CR1_RTRG_BIT) ++ #define SSI_CR1_RTRG_120 (15<< SSI_CR1_RTRG_BIT) ++#define SSI_CR1_FLEN_BIT 4 ++#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) ++#define SSI_CR1_PHA (1 << 1) ++#define SSI_CR1_POL (1 << 0) ++ ++/* SSI Status Register (SSI_SR) */ ++ ++#define SSI_SR_TFIFONUM_BIT 16 ++#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) ++#define SSI_SR_RFIFONUM_BIT 8 ++#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) ++#define SSI_SR_END (1 << 7) ++#define SSI_SR_BUSY (1 << 6) ++#define SSI_SR_TFF (1 << 5) ++#define SSI_SR_RFE (1 << 4) ++#define SSI_SR_TFHE (1 << 3) ++#define SSI_SR_RFHF (1 << 2) ++#define SSI_SR_UNDR (1 << 1) ++#define SSI_SR_OVER (1 << 0) ++ ++/* SSI Interval Time Control Register (SSI_ITR) */ ++ ++#define SSI_ITR_CNTCLK (1 << 15) ++#define SSI_ITR_IVLTM_BIT 0 ++#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) ++ ++ ++/************************************************************************* ++ * MSC ++ *************************************************************************/ ++#define MSC_STRPCL (MSC_BASE + 0x000) ++#define MSC_STAT (MSC_BASE + 0x004) ++#define MSC_CLKRT (MSC_BASE + 0x008) ++#define MSC_CMDAT (MSC_BASE + 0x00C) ++#define MSC_RESTO (MSC_BASE + 0x010) ++#define MSC_RDTO (MSC_BASE + 0x014) ++#define MSC_BLKLEN (MSC_BASE + 0x018) ++#define MSC_NOB (MSC_BASE + 0x01C) ++#define MSC_SNOB (MSC_BASE + 0x020) ++#define MSC_IMASK (MSC_BASE + 0x024) ++#define MSC_IREG (MSC_BASE + 0x028) ++#define MSC_CMD (MSC_BASE + 0x02C) ++#define MSC_ARG (MSC_BASE + 0x030) ++#define MSC_RES (MSC_BASE + 0x034) ++#define MSC_RXFIFO (MSC_BASE + 0x038) ++#define MSC_TXFIFO (MSC_BASE + 0x03C) ++ ++#define REG_MSC_STRPCL REG16(MSC_STRPCL) ++#define REG_MSC_STAT REG32(MSC_STAT) ++#define REG_MSC_CLKRT REG16(MSC_CLKRT) ++#define REG_MSC_CMDAT REG32(MSC_CMDAT) ++#define REG_MSC_RESTO REG16(MSC_RESTO) ++#define REG_MSC_RDTO REG16(MSC_RDTO) ++#define REG_MSC_BLKLEN REG16(MSC_BLKLEN) ++#define REG_MSC_NOB REG16(MSC_NOB) ++#define REG_MSC_SNOB REG16(MSC_SNOB) ++#define REG_MSC_IMASK REG16(MSC_IMASK) ++#define REG_MSC_IREG REG16(MSC_IREG) ++#define REG_MSC_CMD REG8(MSC_CMD) ++#define REG_MSC_ARG REG32(MSC_ARG) ++#define REG_MSC_RES REG16(MSC_RES) ++#define REG_MSC_RXFIFO REG32(MSC_RXFIFO) ++#define REG_MSC_TXFIFO REG32(MSC_TXFIFO) ++ ++/* MSC Clock and Control Register (MSC_STRPCL) */ ++ ++#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) ++#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) ++#define MSC_STRPCL_START_READWAIT (1 << 5) ++#define MSC_STRPCL_STOP_READWAIT (1 << 4) ++#define MSC_STRPCL_RESET (1 << 3) ++#define MSC_STRPCL_START_OP (1 << 2) ++#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 ++#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) ++ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ ++ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ ++ ++/* MSC Status Register (MSC_STAT) */ ++ ++#define MSC_STAT_IS_RESETTING (1 << 15) ++#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) ++#define MSC_STAT_PRG_DONE (1 << 13) ++#define MSC_STAT_DATA_TRAN_DONE (1 << 12) ++#define MSC_STAT_END_CMD_RES (1 << 11) ++#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) ++#define MSC_STAT_IS_READWAIT (1 << 9) ++#define MSC_STAT_CLK_EN (1 << 8) ++#define MSC_STAT_DATA_FIFO_FULL (1 << 7) ++#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) ++#define MSC_STAT_CRC_RES_ERR (1 << 5) ++#define MSC_STAT_CRC_READ_ERROR (1 << 4) ++#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 ++#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) ++ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ ++#define MSC_STAT_TIME_OUT_RES (1 << 1) ++#define MSC_STAT_TIME_OUT_READ (1 << 0) ++ ++/* MSC Bus Clock Control Register (MSC_CLKRT) */ ++ ++#define MSC_CLKRT_CLK_RATE_BIT 0 ++#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) ++ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ ++ ++/* MSC Command Sequence Control Register (MSC_CMDAT) */ ++ ++#define MSC_CMDAT_IO_ABORT (1 << 11) ++#define MSC_CMDAT_BUS_WIDTH_BIT 9 ++#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) ++ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ ++ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ ++ #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) ++ #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) ++#define MSC_CMDAT_DMA_EN (1 << 8) ++#define MSC_CMDAT_INIT (1 << 7) ++#define MSC_CMDAT_BUSY (1 << 6) ++#define MSC_CMDAT_STREAM_BLOCK (1 << 5) ++#define MSC_CMDAT_WRITE (1 << 4) ++#define MSC_CMDAT_READ (0 << 4) ++#define MSC_CMDAT_DATA_EN (1 << 3) ++#define MSC_CMDAT_RESPONSE_BIT 0 ++#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) ++ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ ++ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ ++ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ ++ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ ++ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ ++ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ ++ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ ++ ++#define CMDAT_DMA_EN (1 << 8) ++#define CMDAT_INIT (1 << 7) ++#define CMDAT_BUSY (1 << 6) ++#define CMDAT_STREAM (1 << 5) ++#define CMDAT_WRITE (1 << 4) ++#define CMDAT_DATA_EN (1 << 3) ++ ++/* MSC Interrupts Mask Register (MSC_IMASK) */ ++ ++#define MSC_IMASK_SDIO (1 << 7) ++#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IMASK_END_CMD_RES (1 << 2) ++#define MSC_IMASK_PRG_DONE (1 << 1) ++#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) ++ ++ ++/* MSC Interrupts Status Register (MSC_IREG) */ ++ ++#define MSC_IREG_SDIO (1 << 7) ++#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IREG_END_CMD_RES (1 << 2) ++#define MSC_IREG_PRG_DONE (1 << 1) ++#define MSC_IREG_DATA_TRAN_DONE (1 << 0) ++ ++ ++/************************************************************************* ++ * EMC (External Memory Controller) ++ *************************************************************************/ ++#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ ++#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ ++#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ ++#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ ++#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ ++#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ ++#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ ++#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ ++#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ ++#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ ++ ++#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ ++#define EMC_NFECR (EMC_BASE + 0x100) /* NAND Flash ECC Control Register */ ++#define EMC_NFECC (EMC_BASE + 0x104) /* NAND Flash ECC Data Register */ ++#define EMC_NFPAR0 (EMC_BASE + 0x108) /* NAND Flash RS Parity 0 Register */ ++#define EMC_NFPAR1 (EMC_BASE + 0x10c) /* NAND Flash RS Parity 1 Register */ ++#define EMC_NFPAR2 (EMC_BASE + 0x110) /* NAND Flash RS Parity 2 Register */ ++#define EMC_NFINTS (EMC_BASE + 0x114) /* NAND Flash Interrupt Status Register */ ++#define EMC_NFINTE (EMC_BASE + 0x118) /* NAND Flash Interrupt Enable Register */ ++#define EMC_NFERR0 (EMC_BASE + 0x11c) /* NAND Flash RS Error Report 0 Register */ ++#define EMC_NFERR1 (EMC_BASE + 0x120) /* NAND Flash RS Error Report 1 Register */ ++#define EMC_NFERR2 (EMC_BASE + 0x124) /* NAND Flash RS Error Report 2 Register */ ++#define EMC_NFERR3 (EMC_BASE + 0x128) /* NAND Flash RS Error Report 3 Register */ ++ ++#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ ++#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ ++#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ ++#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ ++#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ ++#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ ++ ++ ++#define REG_EMC_SMCR0 REG32(EMC_SMCR0) ++#define REG_EMC_SMCR1 REG32(EMC_SMCR1) ++#define REG_EMC_SMCR2 REG32(EMC_SMCR2) ++#define REG_EMC_SMCR3 REG32(EMC_SMCR3) ++#define REG_EMC_SMCR4 REG32(EMC_SMCR4) ++#define REG_EMC_SACR0 REG32(EMC_SACR0) ++#define REG_EMC_SACR1 REG32(EMC_SACR1) ++#define REG_EMC_SACR2 REG32(EMC_SACR2) ++#define REG_EMC_SACR3 REG32(EMC_SACR3) ++#define REG_EMC_SACR4 REG32(EMC_SACR4) ++ ++#define REG_EMC_NFCSR REG32(EMC_NFCSR) ++#define REG_EMC_NFECR REG32(EMC_NFECR) ++#define REG_EMC_NFECC REG32(EMC_NFECC) ++#define REG_EMC_NFPAR0 REG32(EMC_NFPAR0) ++#define REG_EMC_NFPAR1 REG32(EMC_NFPAR1) ++#define REG_EMC_NFPAR2 REG32(EMC_NFPAR2) ++#define REG_EMC_NFINTS REG32(EMC_NFINTS) ++#define REG_EMC_NFINTE REG32(EMC_NFINTE) ++#define REG_EMC_NFERR0 REG32(EMC_NFERR0) ++#define REG_EMC_NFERR1 REG32(EMC_NFERR1) ++#define REG_EMC_NFERR2 REG32(EMC_NFERR2) ++#define REG_EMC_NFERR3 REG32(EMC_NFERR3) ++ ++#define REG_EMC_DMCR REG32(EMC_DMCR) ++#define REG_EMC_RTCSR REG16(EMC_RTCSR) ++#define REG_EMC_RTCNT REG16(EMC_RTCNT) ++#define REG_EMC_RTCOR REG16(EMC_RTCOR) ++#define REG_EMC_DMAR0 REG32(EMC_DMAR0) ++ ++/* Static Memory Control Register */ ++#define EMC_SMCR_STRV_BIT 24 ++#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) ++#define EMC_SMCR_TAW_BIT 20 ++#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) ++#define EMC_SMCR_TBP_BIT 16 ++#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) ++#define EMC_SMCR_TAH_BIT 12 ++#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) ++#define EMC_SMCR_TAS_BIT 8 ++#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) ++#define EMC_SMCR_BW_BIT 6 ++#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) ++#define EMC_SMCR_BCM (1 << 3) ++#define EMC_SMCR_BL_BIT 1 ++#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) ++#define EMC_SMCR_SMT (1 << 0) ++ ++/* Static Memory Bank Addr Config Reg */ ++#define EMC_SACR_BASE_BIT 8 ++#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) ++#define EMC_SACR_MASK_BIT 0 ++#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) ++ ++/* NAND Flash Control/Status Register */ ++#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ ++#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ ++#define EMC_NFCSR_NFCE3 (1 << 5) ++#define EMC_NFCSR_NFE3 (1 << 4) ++#define EMC_NFCSR_NFCE2 (1 << 3) ++#define EMC_NFCSR_NFE2 (1 << 2) ++#define EMC_NFCSR_NFCE1 (1 << 1) ++#define EMC_NFCSR_NFE1 (1 << 0) ++ ++/* NAND Flash ECC Control Register */ ++#define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */ ++#define EMC_NFECR_RS_DECODING (0 << 3) /* RS is in decoding phase */ ++#define EMC_NFECR_RS_ENCODING (1 << 3) /* RS is in encoding phase */ ++#define EMC_NFECR_HAMMING (0 << 2) /* Select HAMMING Correction Algorithm */ ++#define EMC_NFECR_RS (1 << 2) /* Select RS Correction Algorithm */ ++#define EMC_NFECR_ERST (1 << 1) /* ECC Reset */ ++#define EMC_NFECR_ECCE (1 << 0) /* ECC Enable */ ++ ++/* NAND Flash ECC Data Register */ ++#define EMC_NFECC_ECC2_BIT 16 ++#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT) ++#define EMC_NFECC_ECC1_BIT 8 ++#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT) ++#define EMC_NFECC_ECC0_BIT 0 ++#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT) ++ ++/* NAND Flash Interrupt Status Register */ ++#define EMC_NFINTS_ERRCNT_BIT 29 /* Error Count */ ++#define EMC_NFINTS_ERRCNT_MASK (0x7 << EMC_NFINTS_ERRCNT_BIT) ++#define EMC_NFINTS_PADF (1 << 4) /* Padding Finished */ ++#define EMC_NFINTS_DECF (1 << 3) /* Decoding Finished */ ++#define EMC_NFINTS_ENCF (1 << 2) /* Encoding Finished */ ++#define EMC_NFINTS_UNCOR (1 << 1) /* Uncorrectable Error Occurred */ ++#define EMC_NFINTS_ERR (1 << 0) /* Error Occurred */ ++ ++/* NAND Flash Interrupt Enable Register */ ++#define EMC_NFINTE_PADFE (1 << 4) /* Padding Finished Interrupt Enable */ ++#define EMC_NFINTE_DECFE (1 << 3) /* Decoding Finished Interrupt Enable */ ++#define EMC_NFINTE_ENCFE (1 << 2) /* Encoding Finished Interrupt Enable */ ++#define EMC_NFINTE_UNCORE (1 << 1) /* Uncorrectable Error Occurred Intr Enable */ ++#define EMC_NFINTE_ERRE (1 << 0) /* Error Occurred Interrupt */ ++ ++/* NAND Flash RS Error Report Register */ ++#define EMC_NFERR_INDEX_BIT 16 /* Error Symbol Index */ ++#define EMC_NFERR_INDEX_MASK (0x1ff << EMC_NFERR_INDEX_BIT) ++#define EMC_NFERR_MASK_BIT 0 /* Error Symbol Value */ ++#define EMC_NFERR_MASK_MASK (0x1ff << EMC_NFERR_MASK_BIT) ++ ++ ++/* DRAM Control Register */ ++#define EMC_DMCR_BW_BIT 31 ++#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) ++#define EMC_DMCR_CA_BIT 26 ++#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) ++#define EMC_DMCR_RMODE (1 << 25) ++#define EMC_DMCR_RFSH (1 << 24) ++#define EMC_DMCR_MRSET (1 << 23) ++#define EMC_DMCR_RA_BIT 20 ++#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) ++#define EMC_DMCR_BA_BIT 19 ++#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) ++#define EMC_DMCR_PDM (1 << 18) ++#define EMC_DMCR_EPIN (1 << 17) ++#define EMC_DMCR_TRAS_BIT 13 ++#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) ++#define EMC_DMCR_RCD_BIT 11 ++#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) ++#define EMC_DMCR_TPC_BIT 8 ++#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) ++#define EMC_DMCR_TRWL_BIT 5 ++#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) ++#define EMC_DMCR_TRC_BIT 2 ++#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) ++#define EMC_DMCR_TCL_BIT 0 ++#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) ++ ++/* Refresh Time Control/Status Register */ ++#define EMC_RTCSR_CMF (1 << 7) ++#define EMC_RTCSR_CKS_BIT 0 ++#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) ++ ++/* SDRAM Bank Address Configuration Register */ ++#define EMC_DMAR_BASE_BIT 8 ++#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) ++#define EMC_DMAR_MASK_BIT 0 ++#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) ++ ++/* Mode Register of SDRAM bank 0 */ ++#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ ++#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ ++#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) ++ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) ++#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ ++#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) ++#define EMC_SDMR_BT_BIT 3 /* Burst Type */ ++#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) ++ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ ++ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ ++#define EMC_SDMR_BL_BIT 0 /* Burst Length */ ++#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) ++ ++#define EMC_SDMR_CAS2_16BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS2_32BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++#define EMC_SDMR_CAS3_16BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS3_32BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++ ++ ++/************************************************************************* ++ * CIM ++ *************************************************************************/ ++#define CIM_CFG (CIM_BASE + 0x0000) ++#define CIM_CTRL (CIM_BASE + 0x0004) ++#define CIM_STATE (CIM_BASE + 0x0008) ++#define CIM_IID (CIM_BASE + 0x000C) ++#define CIM_RXFIFO (CIM_BASE + 0x0010) ++#define CIM_DA (CIM_BASE + 0x0020) ++#define CIM_FA (CIM_BASE + 0x0024) ++#define CIM_FID (CIM_BASE + 0x0028) ++#define CIM_CMD (CIM_BASE + 0x002C) ++ ++#define REG_CIM_CFG REG32(CIM_CFG) ++#define REG_CIM_CTRL REG32(CIM_CTRL) ++#define REG_CIM_STATE REG32(CIM_STATE) ++#define REG_CIM_IID REG32(CIM_IID) ++#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) ++#define REG_CIM_DA REG32(CIM_DA) ++#define REG_CIM_FA REG32(CIM_FA) ++#define REG_CIM_FID REG32(CIM_FID) ++#define REG_CIM_CMD REG32(CIM_CMD) ++ ++/* CIM Configuration Register (CIM_CFG) */ ++ ++#define CIM_CFG_INV_DAT (1 << 15) ++#define CIM_CFG_VSP (1 << 14) ++#define CIM_CFG_HSP (1 << 13) ++#define CIM_CFG_PCP (1 << 12) ++#define CIM_CFG_DUMMY_ZERO (1 << 9) ++#define CIM_CFG_EXT_VSYNC (1 << 8) ++#define CIM_CFG_PACK_BIT 4 ++#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) ++#define CIM_CFG_DSM_BIT 0 ++#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) ++ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ ++ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ ++ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ ++ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ ++ ++/* CIM Control Register (CIM_CTRL) */ ++ ++#define CIM_CTRL_MCLKDIV_BIT 24 ++#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) ++#define CIM_CTRL_FRC_BIT 16 ++#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) ++ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ ++ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ ++ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ ++ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ ++ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ ++ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ ++ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ ++ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ ++ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ ++ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ ++ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ ++ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ ++ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ ++ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ ++ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ ++ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ ++#define CIM_CTRL_VDDM (1 << 13) ++#define CIM_CTRL_DMA_SOFM (1 << 12) ++#define CIM_CTRL_DMA_EOFM (1 << 11) ++#define CIM_CTRL_DMA_STOPM (1 << 10) ++#define CIM_CTRL_RXF_TRIGM (1 << 9) ++#define CIM_CTRL_RXF_OFM (1 << 8) ++#define CIM_CTRL_RXF_TRIG_BIT 4 ++#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) ++ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ ++ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ ++ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ ++ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ ++ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ ++ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ ++ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ ++ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ ++#define CIM_CTRL_DMA_EN (1 << 2) ++#define CIM_CTRL_RXF_RST (1 << 1) ++#define CIM_CTRL_ENA (1 << 0) ++ ++/* CIM State Register (CIM_STATE) */ ++ ++#define CIM_STATE_DMA_SOF (1 << 6) ++#define CIM_STATE_DMA_EOF (1 << 5) ++#define CIM_STATE_DMA_STOP (1 << 4) ++#define CIM_STATE_RXF_OF (1 << 3) ++#define CIM_STATE_RXF_TRIG (1 << 2) ++#define CIM_STATE_RXF_EMPTY (1 << 1) ++#define CIM_STATE_VDD (1 << 0) ++ ++/* CIM DMA Command Register (CIM_CMD) */ ++ ++#define CIM_CMD_SOFINT (1 << 31) ++#define CIM_CMD_EOFINT (1 << 30) ++#define CIM_CMD_STOP (1 << 28) ++#define CIM_CMD_LEN_BIT 0 ++#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) ++ ++ ++/************************************************************************* ++ * SADC (Smart A/D Controller) ++ *************************************************************************/ ++ ++#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ ++#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ ++#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ ++#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ ++#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ ++#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ ++#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ ++#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ ++#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ ++ ++#define REG_SADC_ENA REG8(SADC_ENA) ++#define REG_SADC_CFG REG32(SADC_CFG) ++#define REG_SADC_CTRL REG8(SADC_CTRL) ++#define REG_SADC_STATE REG8(SADC_STATE) ++#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) ++#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) ++#define REG_SADC_TSDAT REG32(SADC_TSDAT) ++#define REG_SADC_BATDAT REG16(SADC_BATDAT) ++#define REG_SADC_SADDAT REG16(SADC_SADDAT) ++ ++/* ADC Enable Register */ ++#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ ++#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ ++#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ ++#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ ++ ++/* ADC Configure Register */ ++#define SADC_CFG_EXIN (1 << 30) ++#define SADC_CFG_CLKOUT_NUM_BIT 16 ++#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) ++#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ ++#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ ++#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) ++#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ ++#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ ++#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) ++#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ ++#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ ++#define SADC_CFG_CMD_BIT 0 /* ADC Command */ ++#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) ++ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ ++ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ ++ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ ++ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ ++ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ ++ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ ++ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ ++ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ ++ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ ++ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ ++ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ ++ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ ++ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ ++ ++/* ADC Control Register */ ++#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ ++#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ ++#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ ++#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ ++#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ ++ ++/* ADC Status Register */ ++#define SADC_STATE_TSBUSY (1 << 7) /* TS A/D is working */ ++#define SADC_STATE_PBATBUSY (1 << 6) /* PBAT A/D is working */ ++#define SADC_STATE_SBUSY (1 << 5) /* SADCIN A/D is working */ ++#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ ++#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ ++#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ ++#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ ++ ++/* ADC Touch Screen Data Register */ ++#define SADC_TSDAT_DATA0_BIT 0 ++#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) ++#define SADC_TSDAT_TYPE0 (1 << 15) ++#define SADC_TSDAT_DATA1_BIT 16 ++#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) ++#define SADC_TSDAT_TYPE1 (1 << 31) ++ ++ ++/************************************************************************* ++ * SLCD (Smart LCD Controller) ++ *************************************************************************/ ++ ++#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ ++#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ ++#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ ++#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ ++#define SLCD_FIFO (SLCD_BASE + 0xB0) /* SLCD FIFO Register */ ++ ++#define REG_SLCD_CFG REG32(SLCD_CFG) ++#define REG_SLCD_CTRL REG8(SLCD_CTRL) ++#define REG_SLCD_STATE REG8(SLCD_STATE) ++#define REG_SLCD_DATA REG32(SLCD_DATA) ++#define REG_SLCD_FIFO REG32(SLCD_FIFO) ++ ++/* SLCD Configure Register */ ++#define SLCD_CFG_BURST_BIT 14 ++#define SLCD_CFG_BURST_MASK (0x3 << SLCD_CFG_BURST_BIT) ++ #define SLCD_CFG_BURST_4_WORD (0 << SLCD_CFG_BURST_BIT) ++ #define SLCD_CFG_BURST_8_WORD (1 << SLCD_CFG_BURST_BIT) ++#define SLCD_CFG_DWIDTH_BIT 10 ++#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_18 (0 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_16 (1 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8_x3 (2 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8_x2 (3 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8_x1 (4 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_9_x2 (7 << SLCD_CFG_DWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_16BIT (0 << 8) ++#define SLCD_CFG_CWIDTH_8BIT (1 << 8) ++#define SLCD_CFG_CWIDTH_18BIT (2 << 8) ++#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) ++#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) ++#define SLCD_CFG_RS_CMD_LOW (0 << 3) ++#define SLCD_CFG_RS_CMD_HIGH (1 << 3) ++#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) ++#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) ++#define SLCD_CFG_TYPE_PARALLEL (0 << 0) ++#define SLCD_CFG_TYPE_SERIAL (1 << 0) ++ ++/* SLCD Control Register */ ++#define SLCD_CTRL_DMA_EN (1 << 0) ++ ++/* SLCD Status Register */ ++#define SLCD_STATE_BUSY (1 << 0) ++ ++/* SLCD Data Register */ ++#define SLCD_DATA_RS_DATA (0 << 31) ++#define SLCD_DATA_RS_COMMAND (1 << 31) ++ ++/* SLCD FIFO Register */ ++#define SLCD_FIFO_RS_DATA (0 << 31) ++#define SLCD_FIFO_RS_COMMAND (1 << 31) ++ ++ ++/************************************************************************* ++ * LCD (LCD Controller) ++ *************************************************************************/ ++#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ ++#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ ++#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ ++#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ ++#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ ++#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ ++#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ ++#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ ++#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ ++#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ ++#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ ++#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ ++#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ ++#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ ++#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ ++#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ ++#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ ++#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ ++#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ ++#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ ++#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ ++ ++#define REG_LCD_CFG REG32(LCD_CFG) ++#define REG_LCD_VSYNC REG32(LCD_VSYNC) ++#define REG_LCD_HSYNC REG32(LCD_HSYNC) ++#define REG_LCD_VAT REG32(LCD_VAT) ++#define REG_LCD_DAH REG32(LCD_DAH) ++#define REG_LCD_DAV REG32(LCD_DAV) ++#define REG_LCD_PS REG32(LCD_PS) ++#define REG_LCD_CLS REG32(LCD_CLS) ++#define REG_LCD_SPL REG32(LCD_SPL) ++#define REG_LCD_REV REG32(LCD_REV) ++#define REG_LCD_CTRL REG32(LCD_CTRL) ++#define REG_LCD_STATE REG32(LCD_STATE) ++#define REG_LCD_IID REG32(LCD_IID) ++#define REG_LCD_DA0 REG32(LCD_DA0) ++#define REG_LCD_SA0 REG32(LCD_SA0) ++#define REG_LCD_FID0 REG32(LCD_FID0) ++#define REG_LCD_CMD0 REG32(LCD_CMD0) ++#define REG_LCD_DA1 REG32(LCD_DA1) ++#define REG_LCD_SA1 REG32(LCD_SA1) ++#define REG_LCD_FID1 REG32(LCD_FID1) ++#define REG_LCD_CMD1 REG32(LCD_CMD1) ++ ++/* LCD Configure Register */ ++#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ ++#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) ++ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) ++ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) ++#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ ++#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ ++#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ ++#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ ++#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ ++#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ ++#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ ++#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ ++#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ ++#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ ++#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ ++#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ ++#define LCD_CFG_HSP (1 << 11) /* HSYNC pority:0-active high,1-active low */ ++#define LCD_CFG_PCP (1 << 10) /* PCLK pority:0-rising,1-falling */ ++#define LCD_CFG_DEP (1 << 9) /* DE pority:0-active high,1-active low */ ++#define LCD_CFG_VSP (1 << 8) /* VSYNC pority:0-rising,1-falling */ ++#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ ++#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) ++#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ ++ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ ++ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ ++ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ ++#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ ++#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ ++ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) ++ /* JZ47XX defines */ ++ #define LCD_CFG_MODE_SHARP_HR (1 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_CFG_MODE_BIT) ++ ++ ++ ++/* Vertical Synchronize Register */ ++#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */ ++#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT) ++#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */ ++#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT) ++ ++/* Horizontal Synchronize Register */ ++#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */ ++#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT) ++#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */ ++#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT) ++ ++/* Virtual Area Setting Register */ ++#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */ ++#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT) ++#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */ ++#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT) ++ ++/* Display Area Horizontal Start/End Point Register */ ++#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */ ++#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) ++#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */ ++#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) ++ ++/* Display Area Vertical Start/End Point Register */ ++#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */ ++#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) ++#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */ ++#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) ++ ++/* PS Signal Setting */ ++#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */ ++#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT) ++#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */ ++#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT) ++ ++/* CLS Signal Setting */ ++#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */ ++#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT) ++#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */ ++#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT) ++ ++/* SPL Signal Setting */ ++#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */ ++#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT) ++#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */ ++#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT) ++ ++/* REV Signal Setting */ ++#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */ ++#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT) ++ ++/* LCD Control Register */ ++#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ ++#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) ++ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ ++ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ ++ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ ++#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */ ++#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */ ++#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ ++#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ ++#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) ++ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ ++ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ ++ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ ++#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ ++#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) ++#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ ++#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ ++#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ ++#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ ++#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ ++#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ ++#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ ++#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ ++#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ ++#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ ++#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ ++#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ ++#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ ++ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ ++ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ ++ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ ++ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ ++ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ ++ ++/* LCD Status Register */ ++#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ ++#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ ++#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ ++#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ ++#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ ++#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ ++#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ ++ ++/* DMA Command Register */ ++#define LCD_CMD_SOFINT (1 << 31) ++#define LCD_CMD_EOFINT (1 << 30) ++#define LCD_CMD_PAL (1 << 28) ++#define LCD_CMD_LEN_BIT 0 ++#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) ++ ++ ++/************************************************************************* ++ * USB Device ++ *************************************************************************/ ++#define USB_BASE UDC_BASE ++ ++#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */ ++#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */ ++#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */ ++#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */ ++#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */ ++#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */ ++#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */ ++#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */ ++#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */ ++#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */ ++#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */ ++ ++#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */ ++#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */ ++#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */ ++#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */ ++#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */ ++#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */ ++#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */ ++#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */ ++ ++#define USB_FIFO_EP0 (USB_BASE + 0x20) ++#define USB_FIFO_EP1 (USB_BASE + 0x24) ++#define USB_FIFO_EP2 (USB_BASE + 0x28) ++ ++#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */ ++#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */ ++ ++#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */ ++#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */ ++#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */ ++#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */ ++#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */ ++#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */ ++#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */ ++ ++ ++/* Power register bit masks */ ++#define USB_POWER_SUSPENDM 0x01 ++#define USB_POWER_RESUME 0x04 ++#define USB_POWER_HSMODE 0x10 ++#define USB_POWER_HSENAB 0x20 ++#define USB_POWER_SOFTCONN 0x40 ++ ++/* Interrupt register bit masks */ ++#define USB_INTR_SUSPEND 0x01 ++#define USB_INTR_RESUME 0x02 ++#define USB_INTR_RESET 0x04 ++ ++#define USB_INTR_EP0 0x0001 ++#define USB_INTR_INEP1 0x0002 ++#define USB_INTR_INEP2 0x0004 ++#define USB_INTR_OUTEP1 0x0002 ++ ++/* CSR0 bit masks */ ++#define USB_CSR0_OUTPKTRDY 0x01 ++#define USB_CSR0_INPKTRDY 0x02 ++#define USB_CSR0_SENTSTALL 0x04 ++#define USB_CSR0_DATAEND 0x08 ++#define USB_CSR0_SETUPEND 0x10 ++#define USB_CSR0_SENDSTALL 0x20 ++#define USB_CSR0_SVDOUTPKTRDY 0x40 ++#define USB_CSR0_SVDSETUPEND 0x80 ++ ++/* Endpoint CSR register bits */ ++#define USB_INCSRH_AUTOSET 0x80 ++#define USB_INCSRH_ISO 0x40 ++#define USB_INCSRH_MODE 0x20 ++#define USB_INCSRH_DMAREQENAB 0x10 ++#define USB_INCSRH_DMAREQMODE 0x04 ++#define USB_INCSR_CDT 0x40 ++#define USB_INCSR_SENTSTALL 0x20 ++#define USB_INCSR_SENDSTALL 0x10 ++#define USB_INCSR_FF 0x08 ++#define USB_INCSR_UNDERRUN 0x04 ++#define USB_INCSR_FFNOTEMPT 0x02 ++#define USB_INCSR_INPKTRDY 0x01 ++#define USB_OUTCSRH_AUTOCLR 0x80 ++#define USB_OUTCSRH_ISO 0x40 ++#define USB_OUTCSRH_DMAREQENAB 0x20 ++#define USB_OUTCSRH_DNYT 0x10 ++#define USB_OUTCSRH_DMAREQMODE 0x08 ++#define USB_OUTCSR_CDT 0x80 ++#define USB_OUTCSR_SENTSTALL 0x40 ++#define USB_OUTCSR_SENDSTALL 0x20 ++#define USB_OUTCSR_FF 0x10 ++#define USB_OUTCSR_DATAERR 0x08 ++#define USB_OUTCSR_OVERRUN 0x04 ++#define USB_OUTCSR_FFFULL 0x02 ++#define USB_OUTCSR_OUTPKTRDY 0x01 ++ ++/* Testmode register bits */ ++#define USB_TEST_SE0NAK 0x01 ++#define USB_TEST_J 0x02 ++#define USB_TEST_K 0x04 ++#define USB_TEST_PACKET 0x08 ++ ++/* DMA control bits */ ++#define USB_CNTL_ENA 0x01 ++#define USB_CNTL_DIR_IN 0x02 ++#define USB_CNTL_MODE_1 0x04 ++#define USB_CNTL_INTR_EN 0x08 ++#define USB_CNTL_EP(n) ((n) << 4) ++#define USB_CNTL_BURST_0 (0 << 9) ++#define USB_CNTL_BURST_4 (1 << 9) ++#define USB_CNTL_BURST_8 (2 << 9) ++#define USB_CNTL_BURST_16 (3 << 9) ++ ++#endif /* __JZ4740_REGS_H__ */ +diff --git a/include/asm-mips/mach-jz4740/serial.h b/include/asm-mips/mach-jz4740/serial.h +new file mode 100644 +index 0000000..c4819b9 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/serial.h +@@ -0,0 +1,30 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/serial.h ++ * ++ * Ingenic's JZ4740 common include. ++ * ++ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_BOARD_SERIAL_H__ ++#define __ASM_BOARD_SERIAL_H__ ++ ++#ifndef CONFIG_SERIAL_MANY_PORTS ++#undef RS_TABLE_SIZE ++#define RS_TABLE_SIZE 1 ++#endif ++ ++#define JZ_BASE_BAUD (12000000/16) ++ ++#define JZ_SERIAL_PORT_DEFNS \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, ++ ++#endif /* __ASM_BORAD_SERIAL_H__ */ +diff --git a/include/asm-mips/mach-jz4740/war.h b/include/asm-mips/mach-jz4740/war.h +new file mode 100644 +index 0000000..3a5bc17 +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/war.h +@@ -0,0 +1,25 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H ++#define __ASM_MIPS_MACH_JZ4740_WAR_H ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 0 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ +diff --git a/include/asm-mips/mach-jz4750/board-apus.h b/include/asm-mips/mach-jz4750/board-apus.h +new file mode 100644 +index 0000000..18bba40 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/board-apus.h +@@ -0,0 +1,119 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/board-apus.h ++ * ++ * JZ4750-based APUS board ver 1.x definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_APUS_H__ ++#define __ASM_JZ4750_APUS_H__ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 24000000 /* Main extal freq: 24 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_DISP_OFF_N (32*4+25) /* GPE25 */ ++#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */ ++#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */ ++#define GPIO_SD0_WP (32*2+12) /* GPC12 */ ++#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */ ++#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */ ++#define GPIO_USB_DETE (32*2+11) /* GPC15 */ ++#define GPIO_DC_DETE_N (32*2+8) /* GPC8 */ ++#define GPIO_CHARG_STAT_N (32*2+9) /* GPC9 */ ++#define GPIO_LCD_VCC_EN_N (32*3+30) /* GPC10 */ ++#define GPIO_LCD_PWM (32*4+24) /* GPE24 */ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++ ++/*====================================================================== ++ * LCD backlight ++ */ ++#define LCD_PWM_CHN 4 /* pwm channel */ ++#define LCD_PWM_FULL 101 ++/* 100 level: 0,1,...,100 */ ++#define __lcd_set_backlight_level(n) \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_set_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++#define __lcd_close_backlight() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_clear_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC0_WP_PIN GPIO_SD0_WP ++#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N ++#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N) ++ ++#define MSC1_WP_PIN GPIO_SD1_WP ++#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N ++#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N) ++ ++#define __msc0_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD0_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD0_CD_N); \ ++} while (0) ++ ++#define __msc0_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD0_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#define __msc1_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD1_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD1_CD_N); \ ++} while (0) ++ ++#define __msc1_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_card_detected(s) \ ++({ \ ++ int detected = 0; \ ++ if (__gpio_get_pin(GPIO_SD1_CD_N)) \ ++ detected = 1; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4750_APUS_H__ */ +diff --git a/include/asm-mips/mach-jz4750/board-fuwa.h b/include/asm-mips/mach-jz4750/board-fuwa.h +new file mode 100644 +index 0000000..8b6a199 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/board-fuwa.h +@@ -0,0 +1,93 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/board-fuwa.h ++ * ++ * JZ4750-based FUWA board ver 1.x definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_FUWA_H__ ++#define __ASM_JZ4750_FUWA_H__ ++ ++#define CONFIG_FPGA /* fuwa is an FPGA board */ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ ++#define GPIO_SD_CD_N 110 /* GPD14 */ ++#define GPIO_SD_WP 112 /* GPD16 */ ++#define GPIO_USB_DETE 102 /* GPD6 */ ++#define GPIO_DC_DETE_N 103 /* GPD7 */ ++#define GPIO_CHARG_STAT_N 111 /* GPD15 */ ++#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */ ++#define GPIO_LED_EN 124 /* GPD28 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++/*====================================================================== ++ * LCD backlight ++ */ ++#define GPIO_LCD_PWM (32*4+20) /* GPE20 */ ++ ++#define LCD_PWM_CHN 0 /* pwm channel */ ++#define LCD_PWM_FULL 101 ++/* 100 level: 0,1,...,100 */ ++#define __lcd_set_backlight_level(n) \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_set_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++#define __lcd_close_backlight() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_clear_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC_WP_PIN GPIO_SD_WP ++#define MSC_HOTPLUG_PIN GPIO_SD_CD_N ++#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) ++ ++#define __msc_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD_CD_N); \ ++} while (0) ++ ++#define __msc_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ ++} while (0) ++ ++#define __msc_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4750_FUWA_H__ */ +diff --git a/include/asm-mips/mach-jz4750/clock.h b/include/asm-mips/mach-jz4750/clock.h +new file mode 100644 +index 0000000..5747e45 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/clock.h +@@ -0,0 +1,204 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/clock.h ++ * ++ * JZ4750 clocks definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_CLOCK_H__ ++#define __ASM_JZ4750_CLOCK_H__ ++ ++#ifndef JZ_EXTAL ++#define JZ_EXTAL 12000000 /* 3.6864 MHz */ ++#endif ++#ifndef JZ_EXTAL2 ++#define JZ_EXTAL2 32768 /* 32.768 KHz */ ++#endif ++ ++/* ++ * JZ4750 clocks structure ++ */ ++typedef struct { ++ unsigned int cclk; /* CPU clock */ ++ unsigned int hclk; /* System bus clock */ ++ unsigned int pclk; /* Peripheral bus clock */ ++ unsigned int mclk; /* Flash/SRAM/SDRAM clock */ ++ unsigned int lcdclk; /* LCDC module clock */ ++ unsigned int pixclk; /* LCD pixel clock */ ++ unsigned int i2sclk; /* AIC module clock */ ++ unsigned int usbclk; /* USB module clock */ ++ unsigned int mscclk; /* MSC module clock */ ++ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ ++ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ ++} jz_clocks_t; ++ ++extern jz_clocks_t jz_clocks; ++ ++ ++/* PLL output frequency */ ++static __inline__ unsigned int __cpm_get_pllout(void) ++{ ++ unsigned long m, n, no, pllout; ++ unsigned long cppcr = REG_CPM_CPPCR; ++ unsigned long od[4] = {1, 2, 2, 4}; ++ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { ++ m = __cpm_get_pllm() + 2; ++ n = __cpm_get_plln() + 2; ++ no = od[__cpm_get_pllod()]; ++ pllout = ((JZ_EXTAL) / (n * no)) * m; ++ } else ++ pllout = JZ_EXTAL; ++ return pllout; ++} ++ ++/* PLL output frequency for MSC/I2S/LCD/USB */ ++static __inline__ unsigned int __cpm_get_pllout2(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_PCS) ++ return __cpm_get_pllout(); ++ else ++ return __cpm_get_pllout()/2; ++} ++ ++/* CPU core clock */ ++static __inline__ unsigned int __cpm_get_cclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_cdiv()]; ++} ++ ++/* AHB system bus clock */ ++static __inline__ unsigned int __cpm_get_hclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_hdiv()]; ++} ++ ++/* Memory bus clock */ ++static __inline__ unsigned int __cpm_get_mclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_mdiv()]; ++} ++ ++/* APB peripheral bus clock */ ++static __inline__ unsigned int __cpm_get_pclk(void) ++{ ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_pdiv()]; ++} ++ ++/* LCDC module clock */ ++static __inline__ unsigned int __cpm_get_lcdclk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); ++} ++ ++/* LCD pixel clock */ ++static __inline__ unsigned int __cpm_get_pixclk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); ++} ++ ++/* I2S clock */ ++static __inline__ unsigned int __cpm_get_i2sclk(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { ++ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); ++ } ++ else { ++ return JZ_EXTAL; ++ } ++} ++ ++/* USB clock */ ++static __inline__ unsigned int __cpm_get_usbclk(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { ++ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); ++ } ++ else { ++ return JZ_EXTAL; ++ } ++} ++ ++/* ++ * MSC clock ++ * @n: the index of MMC/SD controller ++ */ ++static __inline__ unsigned int __cpm_get_mscclk(int n) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1); ++} ++ ++/* EXTAL clock */ ++static __inline__ unsigned int __cpm_get_extalclk0(void) ++{ ++ return JZ_EXTAL; ++} ++ ++/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ ++static __inline__ unsigned int __cpm_get_extalclk(void) ++{ ++#if defined(CONFIG_FPGA) ++ return JZ_EXTAL; ++#else ++ if (REG_CPM_CPCCR & CPM_CPCCR_ECS) ++ return __cpm_get_extalclk0()/2; ++ else ++ return __cpm_get_extalclk0(); ++#endif ++} ++ ++/* RTC clock for CPM,INTC,RTC,TCU,WDT */ ++static __inline__ unsigned int __cpm_get_rtcclk(void) ++{ ++ return JZ_EXTAL2; ++} ++ ++/* ++ * Output 24MHz for SD and 16MHz for MMC. ++ * @n: the index of MMC/SD controller ++ */ ++static inline void __cpm_select_msc_clk(int n, int sd) ++{ ++ unsigned int pllout2 = __cpm_get_pllout2(); ++ unsigned int div = 0; ++ ++ if (sd) { ++ div = pllout2 / 24000000; ++ } ++ else { ++ div = pllout2 / 16000000; ++ } ++ ++ REG_CPM_MSCCDR(n) = div - 1; ++ REG_CPM_CPCCR |= CPM_CPCCR_CE; ++} ++ ++/* ++ * Output 48MHz for high speed card. ++ */ ++static inline void __cpm_select_msc_clk_high(int n, int sd) ++{ ++ unsigned int pllout2 = __cpm_get_pllout2(); ++ unsigned int div = 0; ++ ++ div = pllout2 / 48000000; ++ ++ REG_CPM_MSCCDR(n) = div - 1; ++ REG_CPM_CPCCR |= CPM_CPCCR_CE; ++} ++ ++#endif /* __ASM_JZ4750_CLOCK_H__ */ +diff --git a/include/asm-mips/mach-jz4750/dma.h b/include/asm-mips/mach-jz4750/dma.h +new file mode 100644 +index 0000000..fc1f2c8 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/dma.h +@@ -0,0 +1,307 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/dma.h ++ * ++ * JZ4750 DMA definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_DMA_H__ ++#define __ASM_JZ4750_DMA_H__ ++ ++#include ++#include /* need byte IO */ ++#include /* And spinlocks */ ++#include ++#include ++ ++/* ++ * Descriptor structure for JZ4750 DMA engine ++ * Note: this structure must always be aligned to a 16-bytes boundary. ++ */ ++ ++/* old descriptor 4-word */ ++typedef struct { ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++ volatile u32 dsadr; /* DSAR value for the current transfer */ ++ volatile u32 dtadr; /* DTAR value for the current transfer */ ++ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ ++} jz_dma_desc; ++ ++/* new descriptor 8-word */ ++typedef struct { ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++ volatile u32 dsadr; /* DSAR value for the current transfer */ ++ volatile u32 dtadr; /* DTAR value for the current transfer */ ++ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ ++ volatile u32 dstrd; /* DMA source and target stride address */ ++ volatile u32 dreqt; /* DMA request type for current transfer */ ++ volatile u32 reserved0; /* Reserved */ ++ volatile u32 reserved1; /* Reserved */ ++} jz_dma_desc_8word; ++ ++/* DMA Device ID's follow */ ++enum { ++ DMA_ID_EXT = 0, /* External request with DREQn */ ++ DMA_ID_NAND, /* NAND DMA request */ ++ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */ ++ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */ ++ DMA_ID_AUTO, /* Auto-request */ ++// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */ ++ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */ ++ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */ ++ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */ ++ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */ ++ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */ ++ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */ ++ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */ ++ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */ ++ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */ ++ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */ ++ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */ ++ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */ ++ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */ ++ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */ ++ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */ ++ DMA_ID_SADC, /* SADC transfer request */ ++ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */ ++ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */ ++ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */ ++ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */ ++ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */ ++ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */ ++ DMA_ID_RAW_SET, ++ DMA_ID_MAX ++}; ++ ++/* DMA modes, simulated by sw */ ++#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ ++#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ ++#define DMA_AUTOINIT 0x2 ++#define DMA_MODE_MASK 0x3 ++ ++struct jz_dma_chan { ++ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ ++ unsigned int io; /* DMA channel number */ ++ const char *dev_str; /* string describes the DMA channel */ ++ int irq; /* DMA irq number */ ++ void *irq_dev; /* DMA private device structure */ ++ unsigned int fifo_addr; /* physical fifo address of the requested device */ ++ unsigned int cntl; /* DMA controll */ ++ unsigned int mode; /* DMA configuration */ ++ unsigned int source; /* DMA request source */ ++}; ++ ++extern struct jz_dma_chan jz_dma_table[]; ++ ++ ++#define DMA_8BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_8BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_32_32BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++#define DMA_AIC_32_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_32_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_TX_CMD_UC \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++extern int jz_request_dma(int dev_id, ++ const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id); ++extern void jz_free_dma(unsigned int dmanr); ++ ++extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data); ++extern void dump_jz_dma_channel(unsigned int dmanr); ++ ++extern void enable_dma(unsigned int dmanr); ++extern void disable_dma(unsigned int dmanr); ++extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); ++extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); ++extern void set_dma_mode(unsigned int dmanr, unsigned int mode); ++extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern void jz_set_dma_src_width(int dmanr, int nbit); ++extern void jz_set_dma_dest_width(int dmanr, int nbit); ++extern void jz_set_dma_block_size(int dmanr, int nbyte); ++extern unsigned int get_dma_residue(unsigned int dmanr); ++ ++extern spinlock_t dma_spin_lock; ++ ++static __inline__ unsigned long claim_dma_lock(void) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&dma_spin_lock, flags); ++ return flags; ++} ++ ++static __inline__ void release_dma_lock(unsigned long flags) ++{ ++ spin_unlock_irqrestore(&dma_spin_lock, flags); ++} ++ ++/* Clear the 'DMA Pointer Flip Flop'. ++ * Write 0 for LSB/MSB, 1 for MSB/LSB access. ++ */ ++#define clear_dma_ff(channel) ++ ++static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) ++{ ++ if (dmanr > MAX_DMA_NUM ++ || jz_dma_table[dmanr].dev_id < 0) ++ return NULL; ++ return &jz_dma_table[dmanr]; ++} ++ ++static __inline__ int dma_halted(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 1; ++ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; ++} ++ ++static __inline__ unsigned int get_dma_mode(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ return chan->mode; ++} ++ ++static __inline__ void clear_dma_done(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++} ++ ++static __inline__ void clear_dma_halt(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); ++ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT); ++} ++ ++static __inline__ void clear_dma_flag(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); ++} ++ ++static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) ++{ ++} ++ ++static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) ++{ ++ unsigned long dccsr; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ dccsr = REG_DMAC_DCCSR(chan->io); ++ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++} ++ ++static __inline__ int get_dma_done_irq(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return -1; ++ return chan->irq; ++} ++ ++#endif /* __ASM_JZ4750_DMA_H__ */ +diff --git a/include/asm-mips/mach-jz4750/jz4750.h b/include/asm-mips/mach-jz4750/jz4750.h +new file mode 100644 +index 0000000..9517780 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/jz4750.h +@@ -0,0 +1,44 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/jz4750.h ++ * ++ * JZ4750 common definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_H__ ++#define __ASM_JZ4750_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*------------------------------------------------------------------ ++ * Platform definitions ++ */ ++#ifdef CONFIG_JZ4750_FUWA ++#include ++#endif ++ ++#ifdef CONFIG_JZ4750_APUS ++#include ++#endif ++ ++/* Add other platform definition here ... */ ++ ++ ++/*------------------------------------------------------------------ ++ * Follows are related to platform definitions ++ */ ++ ++#include ++#include ++ ++#endif /* __ASM_JZ4750_H__ */ +diff --git a/include/asm-mips/mach-jz4750/misc.h b/include/asm-mips/mach-jz4750/misc.h +new file mode 100644 +index 0000000..f6c75c9 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/misc.h +@@ -0,0 +1,44 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/misc.h ++ * ++ * Ingenic's JZ4750 common include. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_MISC_H__ ++#define __ASM_JZ4750_MISC_H__ ++ ++/*========================================================== ++ * I2C ++ *===========================================================*/ ++ ++#define I2C_EEPROM_DEV 0xA /* b'1010 */ ++#define I2C_RTC_DEV 0xD /* b'1101 */ ++#define DIMM0_SPD_ADDR 0 ++#define DIMM1_SPD_ADDR 1 ++#define DIMM2_SPD_ADDR 2 ++#define DIMM3_SPD_ADDR 3 ++#define JZ_HCI_ADDR 7 ++ ++#define DIMM_SPD_LEN 128 ++#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ ++#define I2C_RTC_LEN 16 ++#define HCI_MAC_OFFSET 64 ++ ++extern void i2c_open(void); ++extern void i2c_close(void); ++extern void i2c_setclk(unsigned int i2cclk); ++ ++extern int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++extern int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++ ++#endif /* __ASM_JZ4750_MISC_H__ */ +diff --git a/include/asm-mips/mach-jz4750/ops.h b/include/asm-mips/mach-jz4750/ops.h +new file mode 100644 +index 0000000..c345ed2 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/ops.h +@@ -0,0 +1,3570 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750/ops.h ++ * ++ * JZ4750 register definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++#ifndef __JZ4750_OPS_H__ ++#define __JZ4750_OPS_H__ ++ ++/* ++ * Definition of Module Operations ++ */ ++ ++/*************************************************************************** ++ * EMC ++ ***************************************************************************/ ++#define is_share_mode() ((REG_EMC_BCR & EMC_BCR_BSR_MASK) == EMC_BCR_BSR_SHARE) ++#define is_normal_order() (!(REG_EMC_BCR & EMC_BCR_PK_SEL)) ++ ++/*************************************************************************** ++ * GPIO ++ ***************************************************************************/ ++ ++//------------------------------------------------------ ++// GPIO Pins Description ++// ++// PORT 0: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 D0 - ++// 1 D1 - ++// 2 D2 - ++// 3 D3 - ++// 4 D4 - ++// 5 D5 - ++// 6 D6 - ++// 7 D7 - ++// 8 D8 - ++// 9 D9 - ++// 10 D10 - ++// 11 D11 - ++// 12 D12 - ++// 13 D13 - ++// 14 D14 - ++// 15 D15 - ++// 16 D16 - ++// 17 D17 - ++// 18 D18 - ++// 19 D19 - ++// 20 D20 - ++// 21 D21 - ++// 22 D22 - ++// 23 D23 - ++// 24 D24 - ++// 25 D25 - ++// 26 D26 - ++// 27 D27 - ++// 28 D28 - ++// 29 D29 - ++// 30 D30 - ++// 31 D31 - ++// ++//------------------------------------------------------ ++// PORT 1: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 A0 - ++// 1 A1 - ++// 2 A2 - ++// 3 A3 - ++// 4 A4 - ++// 5 A5 - ++// 6 A6 - ++// 7 A7 - ++// 8 A8 - ++// 9 A9 - ++// 10 A10 - ++// 11 A11 - ++// 12 A12 - ++// 13 A13 - ++// 14 A14 - ++// 15 A15/CLE SA3 ++// 16 DCS0# - ++// 17 RAS# - ++// 18 CAS# - ++// 19 RDWE#/BUFD# - ++// 20 WE0# - ++// 21 WE1# - ++// 22 WE2# - ++// 23 WE3# - ++// 24 CKO - Note1 ++// 25 CKE - ++// 26 SSI0_CLK - ++// 27 SSI0_DT - ++// 28 SSI0_DR - ++// 29 SSI0_CE0# - ++// 30 SSI0_CE1#_GPC - ++// 31 SSI0_CE2# - ++// ++// Note1: BIT24: it is CKO when chip is reset ++// ++//------------------------------------------------------ ++// PORT 2: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 SD0 A20 ++// 1 SD1 A21 ++// 2 SD2 A22 ++// 3 SD3 A23 ++// 4 SD4 A24 ++// 5 SD5 A25 ++// 6 SD6 - ++// 7 SD7 - ++// 8 SD8 TSDI0 ++// 9 SD9 TSDI1 ++// 10 SD10 TSDI2 ++// 11 SD11 TSDI3 ++// 12 SD12 TSDI4 ++// 13 SD13 TSDI5 ++// 14 SD14 TSDI6 ++// 15 SD15 TSDI7 ++// 16 A16/ALE SA4 ++// 17 SA0 A17 ++// 18 SA1 A18 ++// 19 SA2 A19 ++// 20 WAIT# - Note2 ++// 21 CS1# - ++// 22 CS2# - ++// 23 CS3# - ++// 24 CS4# - ++// 25 RD# - ++// 26 WR# - ++// 27 FRB# - Note3 ++// 28 FRE# - ++// 29 FWE# - ++// 30 BOOT_SEL0 - Note4 ++// 31 BOOT_SEL1 - Note5 ++// ++// Note2: BIT20: it is WAIT# pin when chip is reset ++// ++// Note3: BIT27: when NAND is used, it should connect to NANF FRB#. ++// ++// Note4: BIT30: it is BOOT_SEL0 when chip is reset, it can used as output GPIO. ++// ++// Note5: BIT31: it is BOOT_SEL1 when chip is reset, it can used as general GPIO. ++// ++//------------------------------------------------------ ++// PORT 3: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 LCD_D0 - ++// 1 LCD_D1 - ++// 2 LCD_D2 - ++// 3 LCD_D3 - ++// 4 LCD_D4 - ++// 5 LCD_D5 - ++// 6 LCD_D6 - ++// 7 LCD_D7 - ++// 8 LCD_D8 - ++// 9 LCD_D9 - ++// 10 LCD_D10 - ++// 11 LCD_D11 - ++// 12 LCD_D12 - ++// 13 LCD_D13 - ++// 14 LCD_D14 - ++// 15 LCD_D15 - ++// 16 LCD_D16 - ++// 17 LCD_D17 - ++// 18 LCD_PCLK - ++// 19 LCD_HSYNC - ++// 20 LCD_VSYNC - ++// 21 LCD_DE - ++// 22 LCD_CLS - ++// 23 LCD_SPL - ++// 24 LCD_PS - ++// 25 LCD_REV - ++// 26 SSI1_CLK - ++// 27 SSI1_DT - ++// 28 SSI1_DR - ++// 29 SSI1_CE0# - ++// 30 SSI1_CE1# - ++// 31 - - ++// ++//------------------------------------------------------ ++// PORT 4: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 CIM_D0 - ++// 1 CIM_D1 - ++// 2 CIM_D2 - ++// 3 CIM_D3 - ++// 4 CIM_D4 - ++// 5 CIM_D5 - ++// 6 CIM_D6 - ++// 7 CIM_D7 - ++// 8 CIM_MCLK - ++// 9 CIM_PCLK - ++// 10 CIM_VSYNC - ++// 11 CIM_HSYNC - ++// 12 I2C_SDA - ++// 13 I2C_SCK - ++// 14 - - ++// 15 - - ++// 16 UART1_RxD - ++// 17 UART1_TxD - ++// 18 UART1_CTS PCM_DIN ++// 19 UART1_RTS PCM_DOUT ++// 20 PWM0 PCM_CLK ++// 21 PWM1 PCM_SYN ++// 22 PWM2 SCLK_RSTN ++// 23 PWM3 BCLK ++// 24 PWM4 SYNC ++// 25 PWM5 OWI ++// 26 SDATO UART2_TxD ++// 27 SDATI UART2_RxD ++// 28 DCS1# - ++// 29 - - ++// 30 WKUP - Note6 ++// 31 - - Note7 ++// ++// Note6: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down ++// ++// Note7: BIT31: it is used to select the function of UART or JTAG set by PESEL[31] ++// PESEL[31] = 0, select JTAG function ++// PESEL[31] = 1, select UART function ++// ++//------------------------------------------------------ ++// PORT 5: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 MSC0_D0 - ++// 1 MSC0_D1 - ++// 2 MSC0_D2 DREQ ++// 3 MSC0_D3 DACK ++// 4 MSC0_D4 UART0_RxD ++// 5 MSC0_D5 UART0_TxD ++// 6 MSC0_D6 UART0_CTS ++// 7 MSC0_D7 UART0_RTS ++// 8 MSC0_CLK - ++// 9 MSC0_CMD - ++// 10 MSC1_D0 - ++// 11 MSC1_D1 - ++// 12 MSC1_D2 - ++// 13 MSC1_D3 - ++// 14 MSC1_CLK - ++// 15 MSC1_CMD - ++// 16 UART3_RxD - ++// 17 UART3_TxD - ++// 18 UART3_CTS - ++// 19 UART3_RTS - ++// 20 TSCLK - ++// 21 TSSTR - ++// 22 TSFRM - ++// 23 TSFAIL - ++// 24 - - ++// 25 - - ++// 26 - - ++// 27 - - ++// 28 - - ++// 29 - - ++// 30 - - ++// 31 - - ++// ++////////////////////////////////////////////////////////// ++ ++/* ++ * p is the port number (0,1,2,3,4,5) ++ * o is the pin offset (0-31) inside the port ++ * n is the absolute number of a pin (0-191), regardless of the port ++ */ ++ ++//------------------------------------------- ++// Function Pins Mode ++ ++#define __gpio_as_func0(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXSELC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_func1(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++} while (0) ++ ++/* ++ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#, ++ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# ++ */ ++#define __gpio_as_sdram_32bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0xffffffff; \ ++ REG_GPIO_PXSELC(0) = 0xffffffff; \ ++ REG_GPIO_PXPES(0) = 0xffffffff; \ ++ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0x03ff7fff; \ ++} while (0) ++ ++/* ++ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#, ++ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# ++ */ ++#define __gpio_as_sdram_16bit() \ ++do { \ ++ if (is_normal_order()) { \ ++ /* 32/16-bit data normal order */ \ ++ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ ++ REG_GPIO_PXSELC(0) = 0x0000ffff; \ ++ REG_GPIO_PXPES(0) = 0x0000ffff; \ ++ } else { \ ++ /* 16-bit data special order */ \ ++ REG_GPIO_PXFUNS(0) = 0x00ffff00; \ ++ REG_GPIO_PXSELC(0) = 0x00ffff00; \ ++ REG_GPIO_PXPES(0) = 0x00ffff00; \ ++ } \ ++ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0x03ff7fff; \ ++} while (0) ++ ++/* ++ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nand_8bit(n) \ ++do { \ ++ if (!is_share_mode()) { \ ++ /* unshare mode */ \ ++ REG_GPIO_PXFUNS(2) = 0x000000ff; /* SD0~SD7 */ \ ++ REG_GPIO_PXSELS(2) = 0x000000ff; \ ++ REG_GPIO_PXPES(2) = 0x000000ff; \ ++ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(SA3) */ \ ++ REG_GPIO_PXSELS(1) = 0x00008000; \ ++ REG_GPIO_PXPES(1) = 0x00008000; \ ++ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(SA4) */ \ ++ REG_GPIO_PXSELS(2) = 0x00010000; \ ++ REG_GPIO_PXPES(2) = 0x00010000; \ ++ } else { \ ++ /* share mode */ \ ++ if (is_normal_order()) { \ ++ /* 32/16-bit data normal order */ \ ++ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \ ++ REG_GPIO_PXSELC(0) = 0x000000ff; \ ++ REG_GPIO_PXPES(0) = 0x000000ff; \ ++ } else { \ ++ /* 16-bit data special order */ \ ++ REG_GPIO_PXFUNS(0) = 0x0000ff00; /* D0~D7 */ \ ++ REG_GPIO_PXSELC(0) = 0x0000ff00; \ ++ REG_GPIO_PXPES(0) = 0x0000ff00; \ ++ } \ ++ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(A15) */ \ ++ REG_GPIO_PXSELC(1) = 0x00008000; \ ++ REG_GPIO_PXPES(1) = 0x00008000; \ ++ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(A16) */ \ ++ REG_GPIO_PXSELC(2) = 0x00010000; \ ++ REG_GPIO_PXPES(2) = 0x00010000; \ ++ } \ ++ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ ++ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ ++ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ ++ \ ++ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \ ++ REG_GPIO_PXSELC(1) = 0x00080000; \ ++ REG_GPIO_PXPES(1) = 0x00080000; \ ++ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \ ++ REG_GPIO_PXSELC(2) = 0x30000000; \ ++ REG_GPIO_PXPES(2) = 0x30000000; \ ++ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \ ++ REG_GPIO_PXSELC(2) = 0x08000000; \ ++ REG_GPIO_PXDIRC(2) = 0x08000000; \ ++ REG_GPIO_PXPES(2) = 0x08000000; \ ++} while (0) ++ ++ ++/* ++ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nor_8bit(n) \ ++do { \ ++ if (is_normal_order()) { \ ++ /* 32/16-bit data normal order */ \ ++ REG_GPIO_PXFUNS(0) = 0x000000ff; \ ++ REG_GPIO_PXSELC(0) = 0x000000ff; \ ++ REG_GPIO_PXPES(0) = 0x000000ff; \ ++ } else { \ ++ /* 16-bit data special order */ \ ++ REG_GPIO_PXFUNS(0) = 0x0000ff00; \ ++ REG_GPIO_PXSELC(0) = 0x0000ff00; \ ++ REG_GPIO_PXPES(0) = 0x0000ff00; \ ++ } \ ++ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ ++ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ ++ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ ++ \ ++ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ ++ REG_GPIO_PXSELC(1) = 0x0000ffff; \ ++ REG_GPIO_PXPES(1) = 0x0000ffff; \ ++ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ ++ REG_GPIO_PXSELC(2) = 0x06110007; \ ++ REG_GPIO_PXPES(2) = 0x06110007; \ ++ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ ++ REG_GPIO_PXSELS(2) = 0x000e0000; \ ++ REG_GPIO_PXPES(2) = 0x000e0000; \ ++} while (0) ++ ++/* ++ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nor_16bit(n) \ ++do { \ ++ if (is_normal_order()) { \ ++ /* 32/16-bit data normal order */ \ ++ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ ++ REG_GPIO_PXSELC(0) = 0x0000ffff; \ ++ REG_GPIO_PXPES(0) = 0x0000ffff; \ ++ } else { \ ++ /* 16-bit data special order */ \ ++ REG_GPIO_PXFUNS(0) = 0x00ffff00; \ ++ REG_GPIO_PXSELC(0) = 0x00ffff00; \ ++ REG_GPIO_PXPES(0) = 0x00ffff00; \ ++ } \ ++ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ ++ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ ++ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ ++ \ ++ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ ++ REG_GPIO_PXSELC(1) = 0x0000ffff; \ ++ REG_GPIO_PXPES(1) = 0x0000ffff; \ ++ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ ++ REG_GPIO_PXSELC(2) = 0x06110007; \ ++ REG_GPIO_PXPES(2) = 0x06110007; \ ++ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ ++ REG_GPIO_PXSELS(2) = 0x000e0000; \ ++ REG_GPIO_PXPES(2) = 0x000e0000; \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART0_RxD ++ */ ++#define __gpio_as_uart0() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x00000030; \ ++ REG_GPIO_PXSELS(5) = 0x00000030; \ ++ REG_GPIO_PXPES(5) = 0x00000030; \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS ++ */ ++#define __gpio_as_uart0_ctsrts() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x000000f0; \ ++ REG_GPIO_PXSELS(5) = 0x000000f0; \ ++ REG_GPIO_PXPES(5) = 0x000000f0; \ ++} while (0) ++ ++/* ++ * UART1_TxD, UART1_RxD ++ */ ++#define __gpio_as_uart1() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00030000; \ ++ REG_GPIO_PXSELC(4) = 0x00030000; \ ++ REG_GPIO_PXPES(4) = 0x00030000; \ ++} while (0) ++ ++/* ++ * UART1_TxD, UART1_RxD, UART1_CTS, UART1_RTS ++ */ ++#define __gpio_as_uart1_ctsrts() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x000f0000; \ ++ REG_GPIO_PXSELC(4) = 0x000f0000; \ ++ REG_GPIO_PXPES(4) = 0x000f0000; \ ++} while (0) ++ ++/* ++ * UART2_TxD, UART2_RxD ++ */ ++#define __gpio_as_uart2() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x0c000000; \ ++ REG_GPIO_PXSELS(4) = 0x0c000000; \ ++ REG_GPIO_PXPES(4) = 0x0c000000; \ ++} while (0) ++ ++/* ++ * UART3_TxD, UART3_RxD ++ */ ++#define __gpio_as_uart3() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x00030000; \ ++ REG_GPIO_PXSELC(5) = 0x00030000; \ ++ REG_GPIO_PXPES(5) = 0x00030000; \ ++} while (0) ++ ++/* ++ * UART3_TxD, UART3_RxD, UART3_CTS, UART3_RTS ++ */ ++#define __gpio_as_uart3_ctsrts() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x000f0000; \ ++ REG_GPIO_PXSELC(5) = 0x000f0000; \ ++ REG_GPIO_PXPES(5) = 0x000f0000; \ ++} while (0) ++ ++/* ++ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7 ++ */ ++#define __gpio_as_tssi() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x0000ff00; \ ++ REG_GPIO_PXSELS(2) = 0x0000ff00; \ ++ REG_GPIO_PXPES(2) = 0x0000ff00; \ ++ REG_GPIO_PXFUNS(5) = 0x00f00000; \ ++ REG_GPIO_PXSELC(5) = 0x00f00000; \ ++ REG_GPIO_PXPES(5) = 0x00f00000; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_8bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003c00ff; \ ++ REG_GPIO_PXSELC(3) = 0x003c00ff; \ ++ REG_GPIO_PXPES(3) = 0x003c00ff; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_16bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003cffff; \ ++ REG_GPIO_PXSELC(3) = 0x003cffff; \ ++ REG_GPIO_PXPES(3) = 0x003cffff; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_18bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003fffff; \ ++ REG_GPIO_PXSELC(3) = 0x003fffff; \ ++ REG_GPIO_PXPES(3) = 0x003fffff; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D17, LCD_D_R1, LCD_D_G0, LCD_D_G1, LCD_D_B1, ++ * LCD_D_R0, LCD_D_B0, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_24bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003fffff; \ ++ REG_GPIO_PXSELC(3) = 0x003fffff; \ ++ REG_GPIO_PXPES(3) = 0x003fffff; \ ++ REG_GPIO_PXFUNS(3) = 0x03c00000; \ ++ REG_GPIO_PXSELS(3) = 0x03c00000; \ ++ REG_GPIO_PXPES(3) = 0x03c00000; \ ++ REG_GPIO_PXFUNS(5) = 0x000c0000; \ ++ REG_GPIO_PXSELS(5) = 0x000c0000; \ ++ REG_GPIO_PXPES(5) = 0x000c0000; \ ++} while (0) ++ ++/* ++ * SLCD_DAT0~7, SLCD_CLK, SLCD_RS, SLCD_CS ++ */ ++#define __gpio_as_lcd_smart_pal_8bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x001c00ff; \ ++ REG_GPIO_PXSELC(3) = 0x001c00ff; \ ++ REG_GPIO_PXPES(3) = 0x001c00ff; \ ++} while (0) ++ ++/* ++ * SLCD_DAT0~15, SLCD_CLK, SLCD_RS, SLCD_CS ++ */ ++#define __gpio_as_lcd_smart_pal_15bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x001cffff; \ ++ REG_GPIO_PXSELC(3) = 0x001cffff; \ ++ REG_GPIO_PXPES(3) = 0x001cffff; \ ++} while (0) ++ ++/* ++ * SLCD_DAT0~17, SLCD_CLK, SLCD_RS, SLCD_CS ++ */ ++#define __gpio_as_lcd_smart_pal_17bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x001fffff; \ ++ REG_GPIO_PXSELC(3) = 0x001fffff; \ ++ REG_GPIO_PXPES(3) = 0x001fffff; \ ++} while (0) ++ ++/* ++ * SLCD_DAT15, SLCD_CLK, SLCD_RS, SLCD_CS ++ */ ++#define __gpio_as_lcd_smart_serial() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x001c8000; \ ++ REG_GPIO_PXSELC(3) = 0x001c8000; \ ++ REG_GPIO_PXPES(3) = 0x001c8000; \ ++} while (0) ++ ++/* ++ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV ++ */ ++#define __gpio_as_lcd_special() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x03C00000; \ ++ REG_GPIO_PXSELC(3) = 0x03C00000; \ ++ REG_GPIO_PXPES(3) = 0x03C00000; \ ++} while (0) ++ ++/* ++ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC ++ */ ++#define __gpio_as_cim() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00000fff; \ ++ REG_GPIO_PXSELC(4) = 0x00000fff; \ ++ REG_GPIO_PXPES(4) = 0x00000fff; \ ++} while (0) ++ ++/* ++ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or ++ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec) ++ */ ++#define __gpio_as_aic() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x0c000000; \ ++ REG_GPIO_PXSELS(4) = 0x0c000000; \ ++ REG_GPIO_PXPES(4) = 0x0c000000; \ ++ REG_GPIO_PXFUNS(4) = 0x00e00000; \ ++ REG_GPIO_PXSELC(4) = 0x00e00000; \ ++ REG_GPIO_PXPES(4) = 0x00e00000; \ ++} while (0) ++ ++/* ++ * PCM_DIN, PCM_DOUT, PCM_CLK, PCM_SYN ++*/ ++#define __gpio_as_pcm() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x003c0000; \ ++ REG_GPIO_PXSELS(4) = 0x003c0000; \ ++ REG_GPIO_PXPES(4) = 0x003c0000; \ ++} while (0) ++ ++/* ++ * OWI ++*/ ++#define __gpio_as_owi() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x02000000; \ ++ REG_GPIO_PXSELS(4) = 0x02000000; \ ++ REG_GPIO_PXPES(4) = 0x02000000; \ ++} while (0) ++ ++/* ++ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3 ++ */ ++#define __gpio_as_msc0_4bit() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x0000030f; \ ++ REG_GPIO_PXSELC(5) = 0x0000030f; \ ++ REG_GPIO_PXPES(5) = 0x0000030f; \ ++} while (0) ++ ++/* ++ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D7 ++ */ ++#define __gpio_as_msc0_8bit() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x000003ff; \ ++ REG_GPIO_PXSELC(5) = 0x000003ff; \ ++ REG_GPIO_PXPES(5) = 0x000003ff; \ ++} while (0) ++ ++/* ++ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3 ++ */ ++#define __gpio_as_msc1_4bit() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x0000fc00; \ ++ REG_GPIO_PXSELC(5) = 0x0000fc00; \ ++ REG_GPIO_PXPES(5) = 0x0000fc00; \ ++} while (0) ++ ++#define __gpio_as_msc __gpio_as_msc0_8bit /* default as msc0 8bit */ ++#define __gpio_as_msc0 __gpio_as_msc0_8bit /* msc0 default as 8bit */ ++#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */ ++ ++/* ++ * SSI0_CE0, SSI0_CE1#_GPC, SSI0_CE2, SSI0_CLK, SSI0_DT, SSI0_DR ++ */ ++#define __gpio_as_ssi0() \ ++do { \ ++ REG_GPIO_PXFUNS(1) = 0xfc000000; \ ++ REG_GPIO_PXSELC(1) = 0xfc000000; \ ++ REG_GPIO_PXPES(1) = 0xfc000000; \ ++} while (0) ++ ++/* ++ * SSI1_CE0, SSI1_CE1, SSI1_CLK, SSI1_DT, SSI1_DR ++ */ ++#define __gpio_as_ssi1() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x7c000000; \ ++ REG_GPIO_PXSELC(3) = 0x7c000000; \ ++ REG_GPIO_PXPES(3) = 0x7c000000; \ ++} while (0) ++ ++/* n = 0(SSI0), 1(SSI1) */ ++#define __gpio_as_ssi(n) __gpio_as_ssi##n() ++ ++/* ++ * I2C_SCK, I2C_SDA ++ */ ++#define __gpio_as_i2c() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00003000; \ ++ REG_GPIO_PXSELC(4) = 0x00003000; \ ++ REG_GPIO_PXPES(4) = 0x00003000; \ ++} while (0) ++ ++/* ++ * PWM0 ++ */ ++#define __gpio_as_pwm0() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00100000; \ ++ REG_GPIO_PXSELC(4) = 0x00100000; \ ++ REG_GPIO_PXPES(4) = 0x00100000; \ ++} while (0) ++ ++/* ++ * PWM1 ++ */ ++#define __gpio_as_pwm1() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00200000; \ ++ REG_GPIO_PXSELC(4) = 0x00200000; \ ++ REG_GPIO_PXPES(4) = 0x00200000; \ ++} while (0) ++ ++/* ++ * PWM2 ++ */ ++#define __gpio_as_pwm2() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00400000; \ ++ REG_GPIO_PXSELC(4) = 0x00400000; \ ++ REG_GPIO_PXPES(4) = 0x00400000; \ ++} while (0) ++ ++/* ++ * PWM3 ++ */ ++#define __gpio_as_pwm3() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00800000; \ ++ REG_GPIO_PXSELC(4) = 0x00800000; \ ++ REG_GPIO_PXPES(4) = 0x00800000; \ ++} while (0) ++ ++/* ++ * PWM4 ++ */ ++#define __gpio_as_pwm4() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x01000000; \ ++ REG_GPIO_PXSELC(4) = 0x01000000; \ ++ REG_GPIO_PXPES(4) = 0x01000000; \ ++} while (0) ++ ++/* ++ * PWM5 ++ */ ++#define __gpio_as_pwm5() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x02000000; \ ++ REG_GPIO_PXSELC(4) = 0x02000000; \ ++ REG_GPIO_PXPES(4) = 0x02000000; \ ++} while (0) ++ ++/* ++ * n = 0 ~ 5 ++ */ ++#define __gpio_as_pwm(n) __gpio_as_pwm##n() ++ ++/* ++ * DREQ ++ */ ++#define __gpio_as_dreq() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x00000004; \ ++ REG_GPIO_PXSELS(5) = 0x00000004; \ ++ REG_GPIO_PXPES(5) = 0x00000004; \ ++} while (0) ++ ++/* ++ * DACK ++ */ ++#define __gpio_as_dack() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x00000008; \ ++ REG_GPIO_PXSELS(5) = 0x00000008; \ ++ REG_GPIO_PXPES(5) = 0x00000008; \ ++} while (0) ++ ++/* ++ * GPIO or Interrupt Mode ++ */ ++#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) ++ ++#define __gpio_port_as_output(p, o) \ ++do { \ ++ REG_GPIO_PXFUNC(p) = (1 << (o)); \ ++ REG_GPIO_PXSELC(p) = (1 << (o)); \ ++ REG_GPIO_PXDIRS(p) = (1 << (o)); \ ++} while (0) ++ ++#define __gpio_port_as_input(p, o) \ ++do { \ ++ REG_GPIO_PXFUNC(p) = (1 << (o)); \ ++ REG_GPIO_PXSELC(p) = (1 << (o)); \ ++ REG_GPIO_PXDIRC(p) = (1 << (o)); \ ++} while (0) ++ ++#define __gpio_as_output(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_output(p, o); \ ++} while (0) ++ ++#define __gpio_as_input(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_input(p, o); \ ++} while (0) ++ ++#define __gpio_set_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXDATS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_clear_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXDATC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_get_pin(n) \ ++({ \ ++ unsigned int p, o, v; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ if (__gpio_get_port(p) & (1 << o)) \ ++ v = 1; \ ++ else \ ++ v = 0; \ ++ v; \ ++}) ++ ++#define __gpio_as_irq_high_level(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRS(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_low_level(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRC(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_rise_edge(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRS(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_fall_edge(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRC(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_mask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_unmask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_ack_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_get_irq() \ ++({ \ ++ unsigned int p, i, tmp, v = 0; \ ++ for (p = 3; p >= 0; p--) { \ ++ tmp = REG_GPIO_PXFLG(p); \ ++ for (i = 0; i < 32; i++) \ ++ if (tmp & (1 << i)) \ ++ v = (32*p + i); \ ++ } \ ++ v; \ ++}) ++ ++#define __gpio_group_irq(n) \ ++({ \ ++ register int tmp, i; \ ++ tmp = REG_GPIO_PXFLG((n)); \ ++ for (i=31;i>=0;i--) \ ++ if (tmp & (1 << i)) \ ++ break; \ ++ i; \ ++}) ++ ++#define __gpio_enable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXPEC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_disable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXPES(p) = (1 << o); \ ++} while (0) ++ ++ ++/*************************************************************************** ++ * CPM ++ ***************************************************************************/ ++#define __cpm_get_pllm() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) ++#define __cpm_get_plln() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) ++#define __cpm_get_pllod() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) ++ ++#define __cpm_get_cdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) ++#define __cpm_get_hdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) ++#define __cpm_get_pdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) ++#define __cpm_get_mdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) ++#define __cpm_get_ldiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) ++#define __cpm_get_udiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) ++#define __cpm_get_i2sdiv() \ ++ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) ++#define __cpm_get_pixdiv() \ ++ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) ++#define __cpm_get_mscdiv(n) \ ++ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) ++#define __cpm_get_uhcdiv() \ ++ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) ++#define __cpm_get_ssidiv() \ ++ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) ++#define __cpm_get_pcmdiv(v) \ ++ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT) ++ ++#define __cpm_set_cdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) ++#define __cpm_set_hdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) ++#define __cpm_set_pdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) ++#define __cpm_set_mdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) ++#define __cpm_set_ldiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) ++#define __cpm_set_udiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) ++#define __cpm_set_i2sdiv(v) \ ++ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) ++#define __cpm_set_pixdiv(v) \ ++ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) ++#define __cpm_set_mscdiv(n, v) \ ++ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) ++#define __cpm_set_uhcdiv(v) \ ++ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) ++#define __cpm_set_ssidiv(v) \ ++ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) ++#define __cpm_set_pcmdiv(v) \ ++ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT))) ++ ++#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS) ++#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS) ++#define __cpm_select_pixclk_ext() (REG_CPM_LPCDR |= CPM_LPCDR_LPCS) ++#define __cpm_select_pixclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LPCS) ++#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS) ++#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS) ++#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS) ++#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS) ++#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) ++#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) ++#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) ++#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) ++ ++#define __cpm_enable_cko() ++#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS) ++#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS) ++#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) ++#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) ++#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) ++#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) ++ ++#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF) ++#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON) ++#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP) ++ ++#define __cpm_get_cclk_doze_duty() \ ++ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) ++#define __cpm_set_cclk_doze_duty(v) \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) ++ ++#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) ++#define __cpm_idle_mode() \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) ++#define __cpm_sleep_mode() \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) ++ ++#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff) ++#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM) ++#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT) ++#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB) ++#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME) ++#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC) ++#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE) ++#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI) ++#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI) ++#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM) ++#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3) ++#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2) ++#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) ++#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) ++#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) ++#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) ++#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) ++#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) ++#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) ++#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) ++#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n) ++#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) ++#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) ++#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n) ++#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) ++#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) ++#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) ++#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) ++ ++#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) ++#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM) ++#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT) ++#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB) ++#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME) ++#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC) ++#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE) ++#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI) ++#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI) ++#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM) ++#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3) ++#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2) ++#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) ++#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) ++#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) ++#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) ++#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) ++#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) ++#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) ++#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) ++#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n) ++#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) ++#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) ++#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n) ++#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) ++#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) ++#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) ++#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) ++ ++#define __cpm_get_o1st() \ ++ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT) ++#define __cpm_set_o1st(v) \ ++ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT))) ++#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE) ++#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE) ++#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE) ++#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE) ++#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE) ++#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE) ++#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS) ++#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS) ++ ++ ++/*************************************************************************** ++ * TCU ++ ***************************************************************************/ ++// where 'n' is the TCU channel ++#define __tcu_select_extalclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) ++#define __tcu_select_rtcclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) ++#define __tcu_select_pclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) ++#define __tcu_disable_pclk(n) \ ++ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN); ++#define __tcu_select_clk_div1(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) ++#define __tcu_select_clk_div4(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) ++#define __tcu_select_clk_div16(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) ++#define __tcu_select_clk_div64(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) ++#define __tcu_select_clk_div256(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) ++#define __tcu_select_clk_div1024(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) ++ ++#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN) ++#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN) ++ ++#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH) ++#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH) ++ ++#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD) ++#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD) ++ ++#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ) ++ ++#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN) ++#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST) ++#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL) ++ ++#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n))) ++#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n))) ++#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n))) ++ ++#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16))) ++#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n))) ++#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16))) ++#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n))) ++#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16))) ++#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n))) ++#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16))) ++#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n))) ++#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16))) ++#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n))) ++ ++#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG) ++#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST) ++#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL) ++#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK) ++#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST) ++#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL) ++ ++#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC) ++#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST) ++#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n))) ++ ++#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC) ++#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC) ++#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n))) ++ ++#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC) ++#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS) ++#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n))) ++ ++#define __tcu_get_count(n) (REG_TCU_TCNT((n))) ++#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v)) ++#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v)) ++#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v)) ++ ++/* TCU2, counter 1, 2*/ ++#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) ++#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) ++#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n))) ++#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n))) ++ ++#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16))) ++#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16))) ++#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n))) ++#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n))) ++ ++/* ost counter */ ++#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD) ++#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD) ++#define __ostcu_select_clk_div1() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1) ++#define __ostcu_select_clk_div4() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4) ++#define __ostcu_select_clk_div16() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16) ++#define __ostcu_select_clk_div64() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64) ++#define __ostcu_select_clk_div256() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256) ++#define __ostcu_select_clk_div1024() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024) ++#define __ostcu_select_rtcclk() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN) ++#define __ostcu_select_extalclk() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN) ++#define __ostcu_select_pclk() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN) ++ ++ ++/*************************************************************************** ++ * WDT ++ ***************************************************************************/ ++#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) ++#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) ++#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) ++#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) ++ ++#define __wdt_select_extalclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) ++#define __wdt_select_rtcclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) ++#define __wdt_select_pclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) ++ ++#define __wdt_select_clk_div1() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) ++#define __wdt_select_clk_div4() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) ++#define __wdt_select_clk_div16() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) ++#define __wdt_select_clk_div64() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) ++#define __wdt_select_clk_div256() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) ++#define __wdt_select_clk_div1024() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) ++ ++ ++/*************************************************************************** ++ * UART ++ ***************************************************************************/ ++ ++#define __uart_enable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) ++#define __uart_disable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) ++ ++#define __uart_enable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) ++#define __uart_disable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) ++ ++#define __uart_enable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) ++#define __uart_disable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) ++ ++#define __uart_enable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) ++#define __uart_disable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) ++ ++#define __uart_set_8n1(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) ++ ++#define __uart_set_baud(n, devclk, baud) \ ++ do { \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ ++ } while (0) ++ ++#define __uart_parity_error(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) ++ ++#define __uart_clear_errors(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) ++ ++#define __uart_transmit_fifo_empty(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) ++ ++#define __uart_transmit_end(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) ++ ++#define __uart_transmit_char(n, ch) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) ++ ++#define __uart_receive_fifo_full(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_ready(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_char(n) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) ++ ++#define __uart_disable_irda() \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) ++#define __uart_enable_irda() \ ++ /* Tx high pulse as 0, Rx low pulse as 0 */ \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) ++ ++ ++/*************************************************************************** ++ * DMAC ++ ***************************************************************************/ ++ ++/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */ ++ ++#define __dmac_enable_module(m) \ ++ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 ) ++#define __dmac_disable_module(m) \ ++ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE ) ++ ++/* p=0,1,2,3 */ ++#define __dmac_set_priority(m,p) \ ++do { \ ++ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \ ++ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \ ++} while (0) ++ ++#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT ) ++#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR ) ++ ++#define __dmac_channel_enable_clk(n) \ ++ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM); ++ ++#define __dmac_enable_descriptor(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) ++#define __dmac_disable_descriptor(n) \ ++ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) ++ ++#define __dmac_enable_channel(n) \ ++do { \ ++ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \ ++} while (0) ++#define __dmac_disable_channel(n) \ ++do { \ ++ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \ ++} while (0) ++#define __dmac_channel_enabled(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) ++ ++#define __dmac_channel_enable_irq(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) ++#define __dmac_channel_disable_irq(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) ++ ++#define __dmac_channel_transmit_halt_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) ++#define __dmac_channel_transmit_end_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) ++#define __dmac_channel_address_error_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) ++#define __dmac_channel_count_terminated_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) ++#define __dmac_channel_descriptor_invalid_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) ++ ++#define __dmac_channel_clear_transmit_halt(n) \ ++ do { \ ++ /* clear both channel halt error and globle halt error */ \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \ ++ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \ ++ } while (0) ++#define __dmac_channel_clear_transmit_end(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) ++#define __dmac_channel_clear_address_error(n) \ ++ do { \ ++ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \ ++ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \ ++ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \ ++ /* clear both channel addr error and globle address error */ \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \ ++ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \ ++ } while (0) ++#define __dmac_channel_clear_count_terminated(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) ++#define __dmac_channel_clear_descriptor_invalid(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) ++ ++#define __dmac_channel_set_transfer_unit_32bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_8bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16byte(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_32byte(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_dest_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_src_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ ++} while (0) ++ ++/* v=0-15 */ ++#define __dmac_channel_set_rdil(n,v) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ ++ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ ++} while (0) ++ ++#define __dmac_channel_dest_addr_fixed(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) ++#define __dmac_channel_dest_addr_increment(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) ++ ++#define __dmac_channel_src_addr_fixed(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) ++#define __dmac_channel_src_addr_increment(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) ++ ++#define __dmac_channel_set_doorbell(n) \ ++ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) ++ ++#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) ++#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) ++ ++static __inline__ int __dmac_get_irq(void) ++{ ++ int i; ++ for (i = 0; i < MAX_DMA_NUM; i++) ++ if (__dmac_channel_irq_detected(i)) ++ return i; ++ return -1; ++} ++ ++ ++/*************************************************************************** ++ * AIC (AC'97 & I2S Controller) ++ ***************************************************************************/ ++ ++#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) ++#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) ++ ++#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) ++#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) ++ ++#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) ++#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) ++ ++#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) ++#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) ++#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) ++ ++#define __aic_reset() \ ++do { \ ++ REG_AIC_FR |= AIC_FR_RST; \ ++} while(0) ++ ++ ++#define __aic_set_transmit_trigger(n) \ ++do { \ ++ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ ++ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ ++} while(0) ++ ++#define __aic_set_receive_trigger(n) \ ++do { \ ++ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ ++ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ ++} while(0) ++ ++#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) ++#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) ++#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) ++#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) ++#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) ++#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) ++ ++#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) ++#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) ++ ++#define __aic_enable_transmit_intr() \ ++ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) ++#define __aic_disable_transmit_intr() \ ++ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) ++#define __aic_enable_receive_intr() \ ++ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) ++#define __aic_disable_receive_intr() \ ++ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) ++ ++#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) ++#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) ++#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) ++#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) ++ ++#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) ++#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) ++#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) ++#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) ++#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) ++#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) ++ ++#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 ++#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 ++#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 ++#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 ++#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 ++#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 ++ ++#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 ++#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 ++#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 ++#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 ++#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 ++#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 ++ ++#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) ++#define __ac97_set_xs_mono() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ ++} while(0) ++#define __ac97_set_xs_stereo() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ ++} while(0) ++ ++/* In fact, only stereo is support now. */ ++#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) ++#define __ac97_set_rs_mono() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ ++} while(0) ++#define __ac97_set_rs_stereo() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ ++} while(0) ++ ++#define __ac97_warm_reset_codec() \ ++ do { \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ ++ udelay(2); \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ ++ } while (0) ++ ++#define __ac97_cold_reset_codec() \ ++ do { \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ ++ udelay(2); \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ ++ } while (0) ++ ++/* n=8,16,18,20 */ ++#define __ac97_set_iass(n) \ ++ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) ++#define __ac97_set_oass(n) \ ++ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) ++ ++#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) ++#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) ++ ++/* n=8,16,18,20,24 */ ++/*#define __i2s_set_sample_size(n) \ ++ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ ++ ++#define __i2s_set_oss_sample_size(n) \ ++ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) ++#define __i2s_set_iss_sample_size(n) \ ++ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) ++ ++#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) ++#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) ++ ++#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) ++#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) ++#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) ++#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) ++ ++#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) ++ ++#define __aic_get_transmit_resident() \ ++ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) ++#define __aic_get_receive_count() \ ++ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) ++ ++#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) ++#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) ++#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) ++#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) ++#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) ++#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) ++#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) ++ ++#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) ++ ++#define CODEC_READ_CMD (1 << 19) ++#define CODEC_WRITE_CMD (0 << 19) ++#define CODEC_REG_INDEX_BIT 12 ++#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ ++#define CODEC_REG_DATA_BIT 4 ++#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ ++ ++#define __ac97_out_rcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_wcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_data(value) \ ++do { \ ++ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ ++} while (0) ++ ++#define __ac97_in_data() \ ++ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) ++ ++#define __ac97_in_status_addr() \ ++ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) ++ ++#define __i2s_set_sample_rate(i2sclk, sync) \ ++ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) ++ ++#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) ++#define __aic_read_rfifo() ( REG_AIC_DR ) ++ ++#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) ++#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) ++ ++// ++// Define next ops for AC97 compatible ++// ++ ++#define AC97_ACSR AIC_ACSR ++ ++#define __ac97_enable() __aic_enable(); __aic_select_ac97() ++#define __ac97_disable() __aic_disable() ++#define __ac97_reset() __aic_reset() ++ ++#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __ac97_enable_record() __aic_enable_record() ++#define __ac97_disable_record() __aic_disable_record() ++#define __ac97_enable_replay() __aic_enable_replay() ++#define __ac97_disable_replay() __aic_disable_replay() ++#define __ac97_enable_loopback() __aic_enable_loopback() ++#define __ac97_disable_loopback() __aic_disable_loopback() ++ ++#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __ac97_enable_receive_dma() __aic_enable_receive_dma() ++#define __ac97_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __ac97_transmit_request() __aic_transmit_request() ++#define __ac97_receive_request() __aic_receive_request() ++#define __ac97_transmit_underrun() __aic_transmit_underrun() ++#define __ac97_receive_overrun() __aic_receive_overrun() ++ ++#define __ac97_clear_errors() __aic_clear_errors() ++ ++#define __ac97_get_transmit_resident() __aic_get_transmit_resident() ++#define __ac97_get_receive_count() __aic_get_receive_count() ++ ++#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __ac97_enable_receive_intr() __aic_enable_receive_intr() ++#define __ac97_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __ac97_write_tfifo(v) __aic_write_tfifo(v) ++#define __ac97_read_rfifo() __aic_read_rfifo() ++ ++// ++// Define next ops for I2S compatible ++// ++ ++#define I2S_ACSR AIC_I2SSR ++ ++#define __i2s_enable() __aic_enable(); __aic_select_i2s() ++#define __i2s_disable() __aic_disable() ++#define __i2s_reset() __aic_reset() ++ ++#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __i2s_enable_record() __aic_enable_record() ++#define __i2s_disable_record() __aic_disable_record() ++#define __i2s_enable_replay() __aic_enable_replay() ++#define __i2s_disable_replay() __aic_disable_replay() ++#define __i2s_enable_loopback() __aic_enable_loopback() ++#define __i2s_disable_loopback() __aic_disable_loopback() ++ ++#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __i2s_enable_receive_dma() __aic_enable_receive_dma() ++#define __i2s_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __i2s_transmit_request() __aic_transmit_request() ++#define __i2s_receive_request() __aic_receive_request() ++#define __i2s_transmit_underrun() __aic_transmit_underrun() ++#define __i2s_receive_overrun() __aic_receive_overrun() ++ ++#define __i2s_clear_errors() __aic_clear_errors() ++ ++#define __i2s_get_transmit_resident() __aic_get_transmit_resident() ++#define __i2s_get_receive_count() __aic_get_receive_count() ++ ++#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __i2s_enable_receive_intr() __aic_enable_receive_intr() ++#define __i2s_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __i2s_write_tfifo(v) __aic_write_tfifo(v) ++#define __i2s_read_rfifo() __aic_read_rfifo() ++ ++#define __i2s_reset_codec() \ ++ do { \ ++ } while (0) ++ ++/************************************************************************* ++ * PCM Controller operation ++ *************************************************************************/ ++ ++#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN ) ++#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN ) ++ ++#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN ) ++#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN ) ++ ++#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST ) ++#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH ) ++ ++#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC ) ++#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC ) ++#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL ) ++#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL ) ++ ++#define __pcm_enable_rxfifo() __pcm_enable_record() ++#define __pcm_disable_rxfifo() __pcm_disable_record() ++#define __pcm_enable_txfifo() __pcm_enable_playback() ++#define __pcm_disable_txfifo() __pcm_disable_playback() ++ ++#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP ) ++#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP ) ++ ++#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA ) ++#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA ) ++#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA ) ++#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA ) ++ ++#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE ) ++#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE ) ++ ++#define __pcm_set_transmit_trigger(n) \ ++do { \ ++ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \ ++ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \ ++} while(0) ++ ++#define __pcm_set_receive_trigger(n) \ ++do { \ ++ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \ ++ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \ ++} while(0) ++ ++#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS ) ++#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS ) ++ ++#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS ) ++#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS ) ++ ++/* set input sample size 8 or 16*/ ++#define __pcm_set_iss(n) \ ++( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n ) ++/* set output sample size 8 or 16*/ ++#define __pcm_set_oss(n) \ ++( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n ) ++ ++#define __pcm_set_valid_slot(n) \ ++( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n ) ++ ++#define __pcm_write_data(v) ( REG_PCM_DP = (v) ) ++#define __pcm_read_data() ( REG_PCM_DP ) ++ ++#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS ) ++#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS ) ++ ++#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR ) ++#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR ) ++ ++#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS ) ++#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS ) ++ ++#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR ) ++#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR ) ++ ++#define __pcm_ints_valid_tx() \ ++( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) ) ++#define __pcm_ints_valid_rx() \ ++( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) ) ++ ++#define __pcm_set_clk_div(n) \ ++( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) ) ++ ++/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */ ++#define __pcm_set_clk_rate(sysclk, pcmclk) \ ++__pcm_set_clk_div(((sysclk) / (pcmclk) - 1)) ++ ++#define __pcm_set_sync_div(n) \ ++( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) ) ++ ++/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */ ++#define __pcm_set_sync_rate(pcmclk, sync) \ ++__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1)) ++ ++ /* set sync length in pcmclk n = 0 ... 63 */ ++#define __pcm_set_sync_len(n) \ ++( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) ) ++ ++ ++/*************************************************************************** ++ * ICDC ++ ***************************************************************************/ ++#define __i2s_internal_codec() __aic_internal_codec() ++#define __i2s_external_codec() __aic_external_codec() ++ ++#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY ) ++#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD ) ++#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD ) ++ ++#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR ) ++#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR ) ++#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR ) ++ ++#define __icdc_set_addr(n) \ ++do { \ ++ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \ ++ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \ ++} while(0) ++ ++#define __icdc_set_cmd(n) \ ++do { \ ++ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \ ++ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \ ++} while(0) ++ ++#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ ) ++#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK ) ++ ++/*************************************************************************** ++ * INTC ++ ***************************************************************************/ ++#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) ++#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) ++#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */ ++ ++ ++/*************************************************************************** ++ * I2C ++ ***************************************************************************/ ++ ++#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) ++#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) ++ ++#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) ++#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) ++#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) ++#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) ++ ++#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) ++#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) ++#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) ++ ++#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) ++#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) ++#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) ++ ++#define __i2c_set_clk(dev_clk, i2c_clk) \ ++ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) ++ ++#define __i2c_read() ( REG_I2C_DR ) ++#define __i2c_write(val) ( REG_I2C_DR = (val) ) ++ ++ ++/*************************************************************************** ++ * MSC ++ ***************************************************************************/ ++/* n = 0, 1 (MSC0, MSC1) */ ++ ++#define __msc_start_op(n) \ ++ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) ++ ++#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to ) ++#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to ) ++#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd ) ++#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg ) ++#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob ) ++#define __msc_get_nob(n) ( REG_MSC_NOB(n) ) ++#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len ) ++#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat ) ++#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT ) ++#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT ) ++ ++#define __msc_set_cmdat_bus_width1(n) \ ++do { \ ++ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_bus_width4(n) \ ++do { \ ++ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN ) ++#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT ) ++#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY ) ++#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN ) ++ ++/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ ++#define __msc_set_cmdat_res_format(n, r) \ ++do { \ ++ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ ++ REG_MSC_CMDAT(n) |= (r); \ ++} while(0) ++ ++#define __msc_clear_cmdat(n) \ ++ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ ++ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ ++ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) ++ ++#define __msc_get_imask(n) ( REG_MSC_IMASK(n) ) ++#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff ) ++#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 ) ++#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES ) ++#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES ) ++#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE ) ++#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE ) ++ ++/* m=0,1,2,3,4,5,6,7 */ ++#define __msc_set_clkrt(n, m) \ ++do { \ ++ REG_MSC_CLKRT(n) = m; \ ++} while(0) ++ ++#define __msc_get_ireg(n) ( REG_MSC_IREG(n) ) ++#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ ) ++#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ ) ++#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE ) ++#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE ) ++ ++#define __msc_get_stat(n) ( REG_MSC_STAT(n) ) ++#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0) ++#define __msc_stat_crc_err(n) \ ++ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) ++#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR ) ++#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR ) ++#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES ) ++#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES ) ++#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ ) ++ ++#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) ) ++#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) ) ++#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v ) ++ ++#define __msc_reset(n) \ ++do { \ ++ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \ ++ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \ ++} while (0) ++ ++#define __msc_start_clk(n) \ ++do { \ ++ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \ ++} while (0) ++ ++#define __msc_stop_clk(n) \ ++do { \ ++ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \ ++} while (0) ++ ++#define MMC_CLK 19169200 ++#define SD_CLK 24576000 ++ ++/* msc_clk should little than pclk and little than clk retrieve from card */ ++#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ ++do { \ ++ unsigned int rate, pclk, i; \ ++ pclk = dev_clk; \ ++ rate = type?SD_CLK:MMC_CLK; \ ++ if (msc_clk && msc_clk < pclk) \ ++ pclk = msc_clk; \ ++ i = 0; \ ++ while (pclk < rate) \ ++ { \ ++ i ++; \ ++ rate >>= 1; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++/* divide rate to little than or equal to 400kHz */ ++#define __msc_calc_slow_clk_divisor(type, lv) \ ++do { \ ++ unsigned int rate, i; \ ++ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ ++ i = 0; \ ++ while (rate > 0) \ ++ { \ ++ rate >>= 1; \ ++ i ++; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++ ++/*************************************************************************** ++ * SSI (Synchronous Serial Interface) ++ ***************************************************************************/ ++/* n = 0, 1 (SSI0, SSI1) */ ++#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE ) ++#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE ) ++#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL ) ++ ++#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK ) ++ ++#define __ssi_select_ce2(n) \ ++do { \ ++ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_select_gpc(n) \ ++do { \ ++ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \ ++ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_underrun_auto_clear(n) \ ++do { \ ++ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \ ++} while (0) ++ ++#define __ssi_underrun_clear_manually(n) \ ++do { \ ++ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \ ++} while (0) ++ ++#define __ssi_enable_tx_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE ) ++ ++#define __ssi_disable_tx_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) ++ ++#define __ssi_enable_rx_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE ) ++ ++#define __ssi_disable_rx_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) ++ ++#define __ssi_enable_txfifo_half_empty_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TIE ) ++#define __ssi_disable_txfifo_half_empty_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE ) ++#define __ssi_enable_tx_error_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE ) ++#define __ssi_disable_tx_error_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE ) ++#define __ssi_enable_rxfifo_half_full_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_RIE ) ++#define __ssi_disable_rxfifo_half_full_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE ) ++#define __ssi_enable_rx_error_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_REIE ) ++#define __ssi_disable_rx_error_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE ) ++ ++#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP ) ++#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP ) ++ ++#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV ) ++#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV ) ++ ++#define __ssi_finish_receive(n) \ ++ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_disable_recvfinish(n) \ ++ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH ) ++#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH ) ++ ++#define __ssi_flush_fifo(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) ++ ++#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN ) ++#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN ) ++#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n) ++#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n) ++ ++#define __ssi_spi_format(n) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \ ++ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ ++ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ ++ } while (0) ++ ++/* TI's SSP format, must clear SSI_CR1.UNFIN */ ++#define __ssi_ssp_format(n) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ ++ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \ ++ } while (0) ++ ++/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ ++#define __ssi_microwire_format(n) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \ ++ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ ++ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ ++ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \ ++ } while (0) ++ ++/* CE# level (FRMHL), CE# in interval time (ITFRM), ++ clock phase and polarity (PHA POL), ++ interval time (SSIITR), interval characters/frame (SSIICR) */ ++ ++/* frmhl,endian,mcom,flen,pha,pol MASK */ ++#define SSICR1_MISC_MASK \ ++ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ ++ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) ++ ++#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \ ++ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \ ++ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ ++ ((pha) << 1) | (pol); \ ++ } while(0) ++ ++/* Transfer with MSB or LSB first */ ++#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST ) ++#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST ) ++ ++#define __ssi_set_frame_length(n, m) \ ++ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4) ++ ++/* m = 1 - 16 */ ++#define __ssi_set_microwire_command_length(n,m) \ ++ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) ) ++ ++/* Set the clock phase for SPI */ ++#define __ssi_set_spi_clock_phase(n, m) \ ++ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1))) ++ ++/* Set the clock polarity for SPI */ ++#define __ssi_set_spi_clock_polarity(n, p) \ ++ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) ) ++ ++/* SSI tx trigger, m = i x 8 */ ++#define __ssi_set_tx_trigger(n, m) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \ ++ REG_SSI_CR1(n) |= ((m)/8)<> SSI_SR_TFIFONUM_BIT ) ++ ++#define __ssi_get_rxfifo_count(n) \ ++ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) ++ ++#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END ) ++#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY ) ++ ++#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF ) ++#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE ) ++#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF ) ++#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE ) ++#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR ) ++#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER ) ++#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR ) ++#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER ) ++#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) ++ ++#define __ssi_set_clk(n, dev_clk, ssi_clk) \ ++ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 ) ++ ++#define __ssi_receive_data(n) REG_SSI_DR(n) ++#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v)) ++ ++ ++/*************************************************************************** ++ * CIM ++ ***************************************************************************/ ++ ++#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) ++#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) ++ ++/* n = 0, 1, 2, 3 */ ++#define __cim_set_input_data_stream_order(n) \ ++ do { \ ++ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \ ++ REG_CIM_CFG |= ((n)<>CIM_SIZE_LPF_BIT) ++#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT) ++ ++#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<>CIM_OFFSET_V_BIT) ++#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT) ++ ++/************************************************************************* ++ * SLCD (Smart LCD Controller) ++ *************************************************************************/ ++#define __slcd_set_data_18bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT ) ++#define __slcd_set_data_16bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT ) ++#define __slcd_set_data_8bit_x3() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 ) ++#define __slcd_set_data_8bit_x2() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 ) ++#define __slcd_set_data_8bit_x1() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 ) ++#define __slcd_set_data_24bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT ) ++#define __slcd_set_data_9bit_x2() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 ) ++ ++#define __slcd_set_cmd_16bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT ) ++#define __slcd_set_cmd_8bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT ) ++#define __slcd_set_cmd_18bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT ) ++#define __slcd_set_cmd_24bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT ) ++ ++#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH ) ++#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH ) ++ ++#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH ) ++#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH ) ++ ++#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING ) ++#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING ) ++ ++#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL ) ++#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL ) ++ ++/* SLCD Control Register */ ++#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN ) ++#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN ) ++ ++/* SLCD Status Register */ ++#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY ) ++ ++/* SLCD Data Register */ ++#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND) ++#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND) ++ ++ ++/*************************************************************************** ++ * LCD ++ ***************************************************************************/ ++ ++/*************************************************************************** ++ * LCD ++ ***************************************************************************/ ++#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) ++#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) ++ ++#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH ) ++#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH ) ++ ++#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD ) ++#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD ) ++ ++#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES ) ++#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES ) ++ ++#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP ) ++#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP ) ++ ++#define __lcd_set_lcdpnl_term() ( REG_LCD_CTRL |= LCD_CFG_TVEN ) ++#define __lcd_set_tv_term() ( REG_LCD_CTRL &= ~LCD_CFG_TVEN ) ++ ++#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER ) ++#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER ) ++ ++#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER ) ++#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER ) ++ ++#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM ) ++#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM ) ++ ++#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM ) ++#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM ) ++ ++#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM ) ++#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM ) ++ ++#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM ) ++#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM ) ++ ++#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM ) ++#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM ) ++ ++#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM ) ++#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM ) ++ ++#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT ) ++#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT ) ++ ++#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN ) ++#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN ) ++ ++#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP ) ++#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP ) ++ ++#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP ) ++#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP ) ++ ++#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP ) ++#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP ) ++ ++#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP ) ++#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP ) ++ ++#define __lcd_set_16_tftpnl() \ ++ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT ) ++ ++#define __lcd_set_18_tftpnl() \ ++ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT ) ++ ++#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT ) ++ ++/* ++ * n=1,2,4,8 for single mono-STN ++ * n=4,8 for dual mono-STN ++ */ ++#define __lcd_set_panel_datawidth(n) \ ++do { \ ++ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \ ++ REG_LCD_CFG |= LCD_CFG_PDW_n##; \ ++} while (0) ++ ++/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */ ++#define __lcd_set_panel_mode(m) \ ++do { \ ++ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \ ++ REG_LCD_CFG |= (m); \ ++} while(0) ++ ++/* n=4,8,16 */ ++#define __lcd_set_burst_length(n) \ ++do { \ ++ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \ ++ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \ ++} while (0) ++ ++#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 ) ++#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 ) ++ ++#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP ) ++#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP ) ++ ++/* n=2,4,16 */ ++#define __lcd_set_stn_frc(n) \ ++do { \ ++ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \ ++ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \ ++} while (0) ++ ++#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM ) ++#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM ) ++ ++#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM ) ++#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM ) ++ ++#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM ) ++#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM ) ++ ++#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 ) ++#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 ) ++ ++#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 ) ++#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 ) ++ ++#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM ) ++#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM ) ++ ++#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM ) ++#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM ) ++ ++#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN ) ++#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN ) ++ ++#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN ) ++#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN ) ++ ++#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS ) ++#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS ) ++ ++#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA ) ++#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA ) ++ ++/* n=1,2,4,8,16 */ ++#define __lcd_set_bpp(n) \ ++ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n ) ++ ++/* LCD status register indication */ ++ ++#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD ) ++#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD ) ++#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 ) ++#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 ) ++#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU ) ++#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF ) ++#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF ) ++ ++#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU ) ++#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF ) ++#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF ) ++ ++/* OSD functions */ ++#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN) ++#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN) ++#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN) ++#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN) ++#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD) ++ ++#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN) ++#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN) ++#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN) ++#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN) ++#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD) ++ ++/* OSD Controll Register */ ++#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU) ++#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU) ++#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1() ++#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 ) ++#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 ) ++#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES ) ++#define __lcd_osd_bpp_15_16() \ ++ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 ) ++#define __lcd_osd_bpp_18_24() \ ++ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 ) ++ ++/* OSD State Register */ ++#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 ) ++#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 ) ++#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 ) ++#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 ) ++#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY ) ++ ++/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */ ++#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN) ++#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN) ++#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD) ++#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD) ++#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key)) ++#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key)) ++ ++#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN) ++#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN) ++#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD) ++#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD) ++ ++/* IPU Restart Register */ ++#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN) ++#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN) ++#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n)) ++ ++/* RGB Control Register */ ++#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM) ++#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM) ++ ++#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM) ++#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM) ++ ++#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC) ++#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC) ++ ++#define __lcd_odd_mode_rgb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB ) ++#define __lcd_odd_mode_rbg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG ) ++#define __lcd_odd_mode_grb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB) ++ ++#define __lcd_odd_mode_gbr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR) ++#define __lcd_odd_mode_brg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG) ++#define __lcd_odd_mode_bgr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR) ++ ++#define __lcd_even_mode_rgb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB ) ++#define __lcd_even_mode_rbg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG ) ++#define __lcd_even_mode_grb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB) ++ ++#define __lcd_even_mode_gbr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR) ++#define __lcd_even_mode_brg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG) ++#define __lcd_even_mode_bgr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR) ++ ++/* Vertical Synchronize Register */ ++#define __lcd_vsync_get_vps() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT ) ++ ++#define __lcd_vsync_get_vpe() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) ++#define __lcd_vsync_set_vpe(n) \ ++do { \ ++ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ ++ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hps() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) ++#define __lcd_hsync_set_hps(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hpe() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) ++#define __lcd_hsync_set_hpe(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_ht() \ ++ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) ++#define __lcd_vat_set_ht(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_vt() \ ++ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) ++#define __lcd_vat_set_vt(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hds() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) ++#define __lcd_dah_set_hds(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hde() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) ++#define __lcd_dah_set_hde(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vds() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) ++#define __lcd_dav_set_vds(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vde() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) ++#define __lcd_dav_set_vde(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ ++} while (0) ++ ++/* DMA Command Register */ ++#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) ++#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) ++ ++#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) ++#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) ++ ++#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) ++#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) ++ ++#define __lcd_cmd0_get_len() \ ++ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++#define __lcd_cmd1_get_len() \ ++ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++ ++/************************************************************************* ++ * TVE (TV Encoder Controller) ops ++ *************************************************************************/ ++/* TV Encoder Control register ops */ ++#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST) ++ ++#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR) ++#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR) ++ ++#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST) ++#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST) ++ ++#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK) ++#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK) ++ ++#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV) ++#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV) ++ ++#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL) ++#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL) ++ ++#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT) ++#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT) ++ ++/* n = 0 ~ 3 */ ++#define __tve_set_c_bandwidth(n) \ ++do {\ ++ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\ ++ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \ ++}while(0) ++ ++/* n = 0 ~ 3 */ ++#define __tve_set_c_gain(n) \ ++do {\ ++ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\ ++ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \ ++}while(0) ++ ++/* n = 0 ~ 7 */ ++#define __tve_set_yc_delay(n) \ ++do { \ ++ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \ ++ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \ ++} while(0) ++ ++#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD) ++#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1) ++#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1) ++#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2) ++#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2) ++#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3) ++#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3) ++ ++#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS) ++#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS) ++ ++/* TV Encoder Frame Configure register ops */ ++/* n = 0 ~ 255 */ ++#define __tve_set_first_video_line(n) \ ++do {\ ++ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\ ++ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_line_num_per_frm(n) \ ++do {\ ++ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\ ++ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\ ++} while(0) ++#define __tve_get_video_line_num()\ ++ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT)) ++ ++/* TV Encoder Signal Level Configure register ops */ ++/* n = 0 ~ 1023 */ ++#define __tve_set_white_level(n) \ ++do {\ ++ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\ ++ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_black_level(n) \ ++do {\ ++ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\ ++ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_blank_level(n) \ ++do {\ ++ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\ ++ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_vbi_blank_level(n) \ ++do {\ ++ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\ ++ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_sync_level(n) \ ++do {\ ++ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\ ++ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\ ++} while(0) ++ ++/* TV Encoder Signal Level Configure register ops */ ++/* n = 0 ~ 31 */ ++#define __tve_set_front_porch(n) \ ++do {\ ++ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\ ++ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \ ++} while(0) ++/* n = 0 ~ 127 */ ++#define __tve_set_hsync_width(n) \ ++do {\ ++ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\ ++ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \ ++} while(0) ++/* n = 0 ~ 127 */ ++#define __tve_set_back_porch(n) \ ++do {\ ++ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\ ++ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \ ++} while(0) ++/* n = 0 ~ 2047 */ ++#define __tve_set_active_linec(n) \ ++do {\ ++ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\ ++ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \ ++} while(0) ++/* n = 0 ~ 31 */ ++#define __tve_set_breezy_way(n) \ ++do {\ ++ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\ ++ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \ ++} while(0) ++ ++/* n = 0 ~ 127 */ ++#define __tve_set_burst_width(n) \ ++do {\ ++ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\ ++ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \ ++} while(0) ++ ++/* TV Encoder Chrominance filter and Modulation register ops */ ++/* n = 0 ~ (2^32-1) */ ++#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n) ++/* n = 0 ~ 255 */ ++#define __tve_set_c_sub_carrier_init_phase(n) \ ++do { \ ++ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \ ++ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_c_sub_carrier_act_phase(n) \ ++do { \ ++ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \ ++ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_c_phase_rst_period(n) \ ++do { \ ++ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \ ++ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cb_burst_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cr_burst_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cb_gain_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cr_gain_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \ ++} while(0) ++ ++/* TV Encoder Wide Screen Signal Control register ops */ ++/* n = 0 ~ 7 */ ++#define __tve_set_notch_freq(n) \ ++do { \ ++ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \ ++ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \ ++} while(0) ++/* n = 0 ~ 7 */ ++#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT) ++#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT) ++#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT) ++#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT) ++/* n = 0 ~ 7 */ ++#define __tve_set_wss_edge(n) \ ++do { \ ++ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \ ++ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \ ++} while(0) ++#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT) ++#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT) ++#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT) ++#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT) ++ ++/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */ ++/* n = 0 ~ 1023 */ ++#define __tve_set_wss_level(n) \ ++do { \ ++ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \ ++ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \ ++} while(0) ++/* n = 0 ~ 4095 */ ++#define __tve_set_wss_freq(n) \ ++do { \ ++ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \ ++ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \ ++} while(0) ++/* n = 0, 1; l = 0 ~ 255 */ ++#define __tve_set_wss_line(n,v) \ ++do { \ ++ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ ++ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ ++} while(0) ++/* n = 0, 1; d = 0 ~ (2^20-1) */ ++#define __tve_set_wss_data(n, v) \ ++do { \ ++ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ ++ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ ++} while(0) ++ ++/*************************************************************************** ++ * RTC ops ++ ***************************************************************************/ ++ ++#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) ++#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) ++#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) ++#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) ++#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) ++#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) ++#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) ++#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) ++#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) ++ ++#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) ++#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) ++#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) ++#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) ++ ++#define __rtc_get_second() ( REG_RTC_RSR ) ++#define __rtc_set_second(v) ( REG_RTC_RSR = v ) ++ ++#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) ++#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) ++ ++#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) ++#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) ++#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) ++#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) ++#define __rtc_set_adjc_val(v) \ ++ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) ++#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) ++#define __rtc_set_nc1Hz_val(v) \ ++ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) ++ ++#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) ++ ++#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) ++#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) ++#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) ++#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) ++ ++#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) ++#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) ++ ++#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) ++#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) ++#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) ++#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) ++#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) ++ ++#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) ++#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) ++ ++/************************************************************************* ++ * BCH ++ *************************************************************************/ ++#define __ecc_encoding_4bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \ ++ REG_BCH_CRC = BCH_CR_BSEL8; \ ++} while(0) ++#define __ecc_decoding_4bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \ ++ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \ ++} while(0) ++#define __ecc_encoding_8bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ ++} while(0) ++#define __ecc_decoding_8bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ ++ REG_BCH_CRC = BCH_CR_ENCE; \ ++} while(0) ++#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE ) ++#define __ecc_dma_disable() ( REG_BCH_CRC = BCH_CR_DMAE ) ++#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE ) ++#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF)) ++#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF)) ++#define __ecc_cnt_dec(n) \ ++do { \ ++ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \ ++ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \ ++} while(0) ++#define __ecc_cnt_enc(n) \ ++do { \ ++ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \ ++ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \ ++} while(0) ++ ++/*************************************************************************** ++ * OWI (one-wire bus) ops ++ ***************************************************************************/ ++ ++/* OW control register ops */ ++#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) ) ++#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 ) ++ ++#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE ) ++#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE ) ++#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT ) ++#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT ) ++#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST ) ++#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST ) ++ ++/* OW configure register ops */ ++#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE ) ++#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE ) ++ ++#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA ) ++#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA ) ++#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA ) ++ ++#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA ) ++#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA ) ++#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA ) ++ ++#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST ) ++ ++#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD ) ++#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD ) ++#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD ) ++ ++#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 ) ++#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 ) ++#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 ) ++ ++#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST ) ++#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST ) ++#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST ) ++ ++#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA ) ++#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA ) ++#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA ) ++ ++#define __owi_wait_ops_rdy() \ ++ do { \ ++ while(__owi_get_enable()); \ ++ udelay(1); \ ++ } while(0); ++ ++/* OW status register ops */ ++#define __owi_clr_sts() ( REG_OWI_STS = 0 ) ++#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST ) ++#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY ) ++#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY ) ++#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY ) ++ ++/************************************************************************* ++ * TSSI MPEG 2-TS slave interface operation ++ *************************************************************************/ ++#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA ) ++#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA ) ++#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST ) ++#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN ) ++#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN ) ++#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN ) ++#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN ) ++ ++/* n = 4, 8, 16 */ ++#define __tssi_set_tigger_num(n) \ ++ do { \ ++ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \ ++ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \ ++ } while (0) ++ ++#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD ) ++#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD ) ++ ++#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD ) ++#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD ) ++ ++#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H ) ++#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H ) ++ ++#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 ) ++#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 ) ++ ++#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH ) ++#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH ) ++ ++#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL ) ++#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL ) ++ ++#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P ) ++#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P ) ++ ++#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H ) ++#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H ) ++ ++#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H ) ++#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H ) ++ ++#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H ) ++#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H ) ++ ++#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM ) ++#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM ) ++ ++#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM ) ++#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM ) ++ ++#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN ) ++#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG ) ++#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */ ++#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN ) ++ ++#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 ) ++#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 ) ++ ++/* m = 0, ..., 15 */ ++#define __tssi_enable_pid_filter(m) \ ++ do { \ ++ int n = (m); \ ++ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ ++ if ( n >= TSSI_PID_MAX ) n += 8; \ ++ REG_TSSI_PEN |= ( 1 << n ); \ ++ } \ ++ } while (0) ++ ++/* m = 0, ..., 15 */ ++#define __tssi_disable_pid_filter(m) \ ++ do { \ ++ int n = (m); \ ++ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ ++ if ( n >= TSSI_PID_MAX ) n += 8; \ ++ REG_TSSI_PEN &= ~( 1 << n ); \ ++ } \ ++ } while (0) ++ ++/* n = 0, ..., 7 */ ++#define __tssi_set_pid0(n, pid0) \ ++ do { \ ++ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \ ++ REG_TSSI_PID(n) |= ((pid0)<=0 && n < TSSI_PID_MAX*2) { \ ++ if ( n < TSSI_PID_MAX ) \ ++ __tssi_set_pid0(n, pid); \ ++ else \ ++ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \ ++ } \ ++ }while (0) ++ ++ ++#if 0 ++/************************************************************************* ++ * IPU (Image Processing Unit) ++ *************************************************************************/ ++#define u32 volatile unsigned long ++ ++#define write_reg(reg, val) \ ++do { \ ++ *(u32 *)(reg) = (val); \ ++} while(0) ++ ++#define read_reg(reg, off) (*(u32 *)((reg)+(off))) ++ ++ ++#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \ ++({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)< Unsigned toggle enable */ ++#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ ++#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ ++#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ ++#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ ++#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ ++#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ ++#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ ++#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ ++ ++/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ ++ ++#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ ++#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) ++ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ ++ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ ++ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ ++ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ ++ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ ++ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ ++#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ ++#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) ++ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ ++ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ ++ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ ++ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ ++ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ ++ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ ++ ++/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ ++ ++#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ ++#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ ++#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ ++#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ ++#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) ++ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ ++#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) ++ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ ++#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ ++#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ ++#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ ++ ++/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ ++ ++#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ ++#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ ++#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) ++ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ ++ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ ++ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ ++ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ ++ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ ++#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ ++ ++/* AIC Controller FIFO Status Register (AIC_SR) */ ++ ++#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ ++#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) ++#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ ++#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) ++#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ ++#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ ++#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ ++#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ ++ ++/* AIC Controller AC-link Status Register (AIC_ACSR) */ ++ ++#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ ++#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ ++#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ ++#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ ++#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ ++#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ ++ ++/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ ++ ++#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ ++ ++/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ ++ ++#define AIC_ACCAR_CAR_BIT 0 ++#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) ++ ++/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ ++ ++#define AIC_ACCDR_CDR_BIT 0 ++#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) ++ ++/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ ++ ++#define AIC_ACSAR_SAR_BIT 0 ++#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) ++ ++/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ ++ ++#define AIC_ACSDR_SDR_BIT 0 ++#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) ++ ++/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ ++ ++#define AIC_I2SDIV_DIV_BIT 0 ++#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) ++ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ ++ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ ++ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ ++ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ ++ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ ++ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ ++ ++ ++/************************************************************************* ++ * ICDC (Internal CODEC) ++ *************************************************************************/ ++ ++#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */ ++#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */ ++#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */ ++ ++#define REG_ICDC_CKCFG REG32(ICDC_CKCFG) ++#define REG_ICDC_RGADW REG32(ICDC_RGADW) ++#define REG_ICDC_RGDATA REG32(ICDC_RGDATA) ++ ++/* ICDC Clock Configure Register */ ++#define ICDC_CKCFG_CKRDY (1 << 1) ++#define ICDC_CKCFG_SELAD (1 << 0) ++ ++/* ICDC internal register access control Register */ ++#define ICDC_RGADW_RGWR (1 << 16) ++#define ICDC_RGADW_RGADDR_BIT 8 ++#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT) ++#define ICDC_RGADW_RGDIN_BIT 0 ++#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT) ++ ++/* ICDC internal register data output Register */ ++#define ICDC_RGDATA_IRQ (1 << 8) ++#define ICDC_RGDATA_RGDOUT_BIT 0 ++#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT) ++ ++/************************************************************************* ++ * PCM Controller ++ *************************************************************************/ ++ ++#define PCM_CTL (PCM_BASE + 0x000) ++#define PCM_CFG (PCM_BASE + 0x004) ++#define PCM_DP (PCM_BASE + 0x008) ++#define PCM_INTC (PCM_BASE + 0x00c) ++#define PCM_INTS (PCM_BASE + 0x010) ++#define PCM_DIV (PCM_BASE + 0x014) ++ ++#define REG_PCM_CTL REG32(PCM_CTL) ++#define REG_PCM_CFG REG32(PCM_CFG) ++#define REG_PCM_DP REG32(PCM_DP) ++#define REG_PCM_INTC REG32(PCM_INTC) ++#define REG_PCM_INTS REG32(PCM_INTS) ++#define REG_PCM_DIV REG32(PCM_DIV) ++ ++/* PCM Controller control Register (PCM_CTL) */ ++ ++#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */ ++#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */ ++#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */ ++#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */ ++#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */ ++#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */ ++#define PCM_CTL_RST (1 << 3) /* Reset PCM */ ++#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */ ++#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */ ++ ++/* PCM Controller configure Register (PCM_CFG) */ ++ ++#define PCM_CFG_SLOT_BIT 13 ++#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT) ++ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */ ++ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */ ++ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */ ++ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */ ++#define PCM_CFG_ISS_BIT 12 ++#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT) ++ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT) ++ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT) ++#define PCM_CFG_OSS_BIT 11 ++#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT) ++ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT) ++ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT) ++#define PCM_CFG_IMSBPOS (1 << 10) ++#define PCM_CFG_OMSBPOS (1 << 9) ++#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */ ++#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT) ++#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */ ++#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT) ++#define PCM_CFG_MODE (0x0 << 0) ++ ++/* PCM Controller interrupt control Register (PCM_INTC) */ ++ ++#define PCM_INTC_ETFS (1 << 3) ++#define PCM_INTC_ETUR (1 << 2) ++#define PCM_INTC_ERFS (1 << 1) ++#define PCM_INTC_EROR (1 << 0) ++ ++/* PCM Controller interrupt status Register (PCM_INTS) */ ++ ++#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */ ++#define PCM_INTS_TFL_BIT 9 ++#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT) ++#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */ ++#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */ ++#define PCM_INTS_RFL_BIT 2 ++#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT) ++#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */ ++#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */ ++ ++/* PCM Controller clock division Register (PCM_DIV) */ ++#define PCM_DIV_SYNL_BIT 11 ++#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT) ++#define PCM_DIV_SYNDIV_BIT 6 ++#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT) ++#define PCM_DIV_CLKDIV_BIT 0 ++#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT) ++ ++ ++/************************************************************************* ++ * I2C ++ *************************************************************************/ ++#define I2C_DR (I2C_BASE + 0x000) ++#define I2C_CR (I2C_BASE + 0x004) ++#define I2C_SR (I2C_BASE + 0x008) ++#define I2C_GR (I2C_BASE + 0x00C) ++ ++#define REG_I2C_DR REG8(I2C_DR) ++#define REG_I2C_CR REG8(I2C_CR) ++#define REG_I2C_SR REG8(I2C_SR) ++#define REG_I2C_GR REG16(I2C_GR) ++ ++/* I2C Control Register (I2C_CR) */ ++ ++#define I2C_CR_IEN (1 << 4) ++#define I2C_CR_STA (1 << 3) ++#define I2C_CR_STO (1 << 2) ++#define I2C_CR_AC (1 << 1) ++#define I2C_CR_I2CE (1 << 0) ++ ++/* I2C Status Register (I2C_SR) */ ++ ++#define I2C_SR_STX (1 << 4) ++#define I2C_SR_BUSY (1 << 3) ++#define I2C_SR_TEND (1 << 2) ++#define I2C_SR_DRF (1 << 1) ++#define I2C_SR_ACKF (1 << 0) ++ ++ ++/************************************************************************* ++ * SSI (Synchronous Serial Interface) ++ *************************************************************************/ ++/* n = 0, 1 (SSI0, SSI1) */ ++#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000) ++#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000) ++#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000) ++#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000) ++#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000) ++#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000) ++#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000) ++ ++#define REG_SSI_DR(n) REG32(SSI_DR(n)) ++#define REG_SSI_CR0(n) REG16(SSI_CR0(n)) ++#define REG_SSI_CR1(n) REG32(SSI_CR1(n)) ++#define REG_SSI_SR(n) REG32(SSI_SR(n)) ++#define REG_SSI_ITR(n) REG16(SSI_ITR(n)) ++#define REG_SSI_ICR(n) REG8(SSI_ICR(n)) ++#define REG_SSI_GR(n) REG16(SSI_GR(n)) ++ ++/* SSI Data Register (SSI_DR) */ ++ ++#define SSI_DR_GPC_BIT 0 ++#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) ++ ++#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */ ++ ++/* SSI Control Register 0 (SSI_CR0) */ ++ ++#define SSI_CR0_SSIE (1 << 15) ++#define SSI_CR0_TIE (1 << 14) ++#define SSI_CR0_RIE (1 << 13) ++#define SSI_CR0_TEIE (1 << 12) ++#define SSI_CR0_REIE (1 << 11) ++#define SSI_CR0_LOOP (1 << 10) ++#define SSI_CR0_RFINE (1 << 9) ++#define SSI_CR0_RFINC (1 << 8) ++#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */ ++#define SSI_CR0_FSEL (1 << 6) ++#define SSI_CR0_TFLUSH (1 << 2) ++#define SSI_CR0_RFLUSH (1 << 1) ++#define SSI_CR0_DISREV (1 << 0) ++ ++/* SSI Control Register 1 (SSI_CR1) */ ++ ++#define SSI_CR1_FRMHL_BIT 30 ++#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) ++ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ ++#define SSI_CR1_TFVCK_BIT 28 ++#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) ++#define SSI_CR1_TCKFI_BIT 26 ++#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) ++#define SSI_CR1_LFST (1 << 25) ++#define SSI_CR1_ITFRM (1 << 24) ++#define SSI_CR1_UNFIN (1 << 23) ++#define SSI_CR1_MULTS (1 << 22) ++#define SSI_CR1_FMAT_BIT 20 ++#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) ++ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ ++ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ ++ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ ++ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ ++#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */ ++#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) ++#define SSI_CR1_MCOM_BIT 12 ++#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) ++ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ ++ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ ++ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ ++ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ ++ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ ++ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ ++ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ ++ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ ++ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ ++ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ ++ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ ++ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ ++ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ ++ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ ++ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ ++ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ ++#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */ ++#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) ++#define SSI_CR1_FLEN_BIT 4 ++#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) ++#define SSI_CR1_PHA (1 << 1) ++#define SSI_CR1_POL (1 << 0) ++ ++/* SSI Status Register (SSI_SR) */ ++ ++#define SSI_SR_TFIFONUM_BIT 16 ++#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) ++#define SSI_SR_RFIFONUM_BIT 8 ++#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) ++#define SSI_SR_END (1 << 7) ++#define SSI_SR_BUSY (1 << 6) ++#define SSI_SR_TFF (1 << 5) ++#define SSI_SR_RFE (1 << 4) ++#define SSI_SR_TFHE (1 << 3) ++#define SSI_SR_RFHF (1 << 2) ++#define SSI_SR_UNDR (1 << 1) ++#define SSI_SR_OVER (1 << 0) ++ ++/* SSI Interval Time Control Register (SSI_ITR) */ ++ ++#define SSI_ITR_CNTCLK (1 << 15) ++#define SSI_ITR_IVLTM_BIT 0 ++#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) ++ ++ ++/************************************************************************* ++ * MSC ++ ************************************************************************/ ++/* n = 0, 1 (MSC0, MSC1) */ ++#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000) ++#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004) ++#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008) ++#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C) ++#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010) ++#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014) ++#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018) ++#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C) ++#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020) ++#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024) ++#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028) ++#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C) ++#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030) ++#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034) ++#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038) ++#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C) ++#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040) ++ ++#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n)) ++#define REG_MSC_STAT(n) REG32(MSC_STAT(n)) ++#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n)) ++#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n)) ++#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n)) ++#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n)) ++#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n)) ++#define REG_MSC_NOB(n) REG16(MSC_NOB(n)) ++#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n)) ++#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n)) ++#define REG_MSC_IREG(n) REG16(MSC_IREG(n)) ++#define REG_MSC_CMD(n) REG8(MSC_CMD(n)) ++#define REG_MSC_ARG(n) REG32(MSC_ARG(n)) ++#define REG_MSC_RES(n) REG16(MSC_RES(n)) ++#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n)) ++#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n)) ++#define REG_MSC_LPM(n) REG32(MSC_LPM(n)) ++ ++/* MSC Clock and Control Register (MSC_STRPCL) */ ++#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */ ++#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */ ++#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) ++#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) ++#define MSC_STRPCL_START_READWAIT (1 << 5) ++#define MSC_STRPCL_STOP_READWAIT (1 << 4) ++#define MSC_STRPCL_RESET (1 << 3) ++#define MSC_STRPCL_START_OP (1 << 2) ++#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 ++#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) ++ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ ++ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ ++ ++/* MSC Status Register (MSC_STAT) */ ++#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */ ++#define MSC_STAT_IS_RESETTING (1 << 15) ++#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) ++#define MSC_STAT_PRG_DONE (1 << 13) ++#define MSC_STAT_DATA_TRAN_DONE (1 << 12) ++#define MSC_STAT_END_CMD_RES (1 << 11) ++#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) ++#define MSC_STAT_IS_READWAIT (1 << 9) ++#define MSC_STAT_CLK_EN (1 << 8) ++#define MSC_STAT_DATA_FIFO_FULL (1 << 7) ++#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) ++#define MSC_STAT_CRC_RES_ERR (1 << 5) ++#define MSC_STAT_CRC_READ_ERROR (1 << 4) ++#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 ++#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) ++ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ ++#define MSC_STAT_TIME_OUT_RES (1 << 1) ++#define MSC_STAT_TIME_OUT_READ (1 << 0) ++ ++/* MSC Bus Clock Control Register (MSC_CLKRT) */ ++#define MSC_CLKRT_CLK_RATE_BIT 0 ++#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) ++ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ ++ ++/* MSC Command Sequence Control Register (MSC_CMDAT) */ ++#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */ ++#define MSC_CMDAT_READ_CEATA (1 << 30) ++#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */ ++#define MSC_CMDAT_SEND_AS_STOP (1 << 16) ++#define MSC_CMDAT_RTRG_BIT 14 ++ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT) ++ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */ ++ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT) ++ ++#define MSC_CMDAT_TTRG_BIT 12 ++ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT) ++ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */ ++ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT) ++#define MSC_CMDAT_STOP_ABORT (1 << 11) ++#define MSC_CMDAT_BUS_WIDTH_BIT 9 ++#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) ++ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ ++ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ ++ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */ ++#define MSC_CMDAT_DMA_EN (1 << 8) ++#define MSC_CMDAT_INIT (1 << 7) ++#define MSC_CMDAT_BUSY (1 << 6) ++#define MSC_CMDAT_STREAM_BLOCK (1 << 5) ++#define MSC_CMDAT_WRITE (1 << 4) ++#define MSC_CMDAT_READ (0 << 4) ++#define MSC_CMDAT_DATA_EN (1 << 3) ++#define MSC_CMDAT_RESPONSE_BIT 0 ++#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) ++ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ ++ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ ++ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ ++ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ ++ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ ++ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ ++ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ ++ ++#define CMDAT_DMA_EN (1 << 8) ++#define CMDAT_INIT (1 << 7) ++#define CMDAT_BUSY (1 << 6) ++#define CMDAT_STREAM (1 << 5) ++#define CMDAT_WRITE (1 << 4) ++#define CMDAT_DATA_EN (1 << 3) ++ ++/* MSC Interrupts Mask Register (MSC_IMASK) */ ++#define MSC_IMASK_AUTO_CMD_DONE (1 << 8) ++#define MSC_IMASK_SDIO (1 << 7) ++#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IMASK_END_CMD_RES (1 << 2) ++#define MSC_IMASK_PRG_DONE (1 << 1) ++#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Interrupts Status Register (MSC_IREG) */ ++#define MSC_IREG_AUTO_CMD_DONE (1 << 8) ++#define MSC_IREG_SDIO (1 << 7) ++#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IREG_END_CMD_RES (1 << 2) ++#define MSC_IREG_PRG_DONE (1 << 1) ++#define MSC_IREG_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Low Power Mode Register (MSC_LPM) */ ++#define MSC_SET_LPM (1 << 0) ++ ++/************************************************************************* ++ * EMC (External Memory Controller) ++ *************************************************************************/ ++#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */ ++#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ ++#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ ++#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ ++#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ ++#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ ++#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ ++#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ ++#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ ++#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ ++#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ ++ ++#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ ++ ++#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ ++#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ ++#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ ++#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ ++#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ ++#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */ ++#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ ++ ++#define REG_EMC_BCR REG32(EMC_BCR) ++#define REG_EMC_SMCR0 REG32(EMC_SMCR0) ++#define REG_EMC_SMCR1 REG32(EMC_SMCR1) ++#define REG_EMC_SMCR2 REG32(EMC_SMCR2) ++#define REG_EMC_SMCR3 REG32(EMC_SMCR3) ++#define REG_EMC_SMCR4 REG32(EMC_SMCR4) ++#define REG_EMC_SACR0 REG32(EMC_SACR0) ++#define REG_EMC_SACR1 REG32(EMC_SACR1) ++#define REG_EMC_SACR2 REG32(EMC_SACR2) ++#define REG_EMC_SACR3 REG32(EMC_SACR3) ++#define REG_EMC_SACR4 REG32(EMC_SACR4) ++ ++#define REG_EMC_NFCSR REG32(EMC_NFCSR) ++ ++#define REG_EMC_DMCR REG32(EMC_DMCR) ++#define REG_EMC_RTCSR REG16(EMC_RTCSR) ++#define REG_EMC_RTCNT REG16(EMC_RTCNT) ++#define REG_EMC_RTCOR REG16(EMC_RTCOR) ++#define REG_EMC_DMAR0 REG32(EMC_DMAR0) ++#define REG_EMC_DMAR1 REG32(EMC_DMAR1) ++ ++/* Bus Control Register */ ++#define EMC_BCR_BT_SEL_BIT 30 ++#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT) ++#define EMC_BCR_PK_SEL (1 << 24) ++#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */ ++ #define EMC_BCR_BSR_SHARE (0 << 2) ++ #define EMC_BCR_BSR_UNSHARE (1 << 2) ++#define EMC_BCR_BRE (1 << 1) ++#define EMC_BCR_ENDIAN (1 << 0) ++ ++/* Static Memory Control Register */ ++#define EMC_SMCR_STRV_BIT 24 ++#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) ++#define EMC_SMCR_TAW_BIT 20 ++#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) ++#define EMC_SMCR_TBP_BIT 16 ++#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) ++#define EMC_SMCR_TAH_BIT 12 ++#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) ++#define EMC_SMCR_TAS_BIT 8 ++#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) ++#define EMC_SMCR_BW_BIT 6 ++#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) ++#define EMC_SMCR_BCM (1 << 3) ++#define EMC_SMCR_BL_BIT 1 ++#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) ++#define EMC_SMCR_SMT (1 << 0) ++ ++/* Static Memory Bank Addr Config Reg */ ++#define EMC_SACR_BASE_BIT 8 ++#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) ++#define EMC_SACR_MASK_BIT 0 ++#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) ++ ++/* NAND Flash Control/Status Register */ ++#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ ++#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ ++#define EMC_NFCSR_NFCE3 (1 << 5) ++#define EMC_NFCSR_NFE3 (1 << 4) ++#define EMC_NFCSR_NFCE2 (1 << 3) ++#define EMC_NFCSR_NFE2 (1 << 2) ++#define EMC_NFCSR_NFCE1 (1 << 1) ++#define EMC_NFCSR_NFE1 (1 << 0) ++ ++/* DRAM Control Register */ ++#define EMC_DMCR_BW_BIT 31 ++#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) ++#define EMC_DMCR_CA_BIT 26 ++#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) ++#define EMC_DMCR_RMODE (1 << 25) ++#define EMC_DMCR_RFSH (1 << 24) ++#define EMC_DMCR_MRSET (1 << 23) ++#define EMC_DMCR_RA_BIT 20 ++#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) ++#define EMC_DMCR_BA_BIT 19 ++#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) ++#define EMC_DMCR_PDM (1 << 18) ++#define EMC_DMCR_EPIN (1 << 17) ++#define EMC_DMCR_MBSEL (1 << 16) ++#define EMC_DMCR_TRAS_BIT 13 ++#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) ++#define EMC_DMCR_RCD_BIT 11 ++#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) ++#define EMC_DMCR_TPC_BIT 8 ++#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) ++#define EMC_DMCR_TRWL_BIT 5 ++#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) ++#define EMC_DMCR_TRC_BIT 2 ++#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) ++#define EMC_DMCR_TCL_BIT 0 ++#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) ++ ++/* Refresh Time Control/Status Register */ ++#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */ ++#define EMC_RTCSR_CMF (1 << 7) ++#define EMC_RTCSR_CKS_BIT 0 ++#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) ++ ++/* SDRAM Bank Address Configuration Register */ ++#define EMC_DMAR_BASE_BIT 8 ++#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) ++#define EMC_DMAR_MASK_BIT 0 ++#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) ++ ++/* Mode Register of SDRAM bank 0 */ ++#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ ++#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ ++#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) ++ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) ++#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ ++#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) ++#define EMC_SDMR_BT_BIT 3 /* Burst Type */ ++#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) ++ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ ++ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ ++#define EMC_SDMR_BL_BIT 0 /* Burst Length */ ++#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) ++ ++#define EMC_SDMR_CAS2_16BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS2_32BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++#define EMC_SDMR_CAS3_16BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS3_32BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++ ++ ++/************************************************************************* ++ * CIM ++ *************************************************************************/ ++#define CIM_CFG (CIM_BASE + 0x0000) ++#define CIM_CTRL (CIM_BASE + 0x0004) ++#define CIM_STATE (CIM_BASE + 0x0008) ++#define CIM_IID (CIM_BASE + 0x000C) ++#define CIM_RXFIFO (CIM_BASE + 0x0010) ++#define CIM_DA (CIM_BASE + 0x0020) ++#define CIM_FA (CIM_BASE + 0x0024) ++#define CIM_FID (CIM_BASE + 0x0028) ++#define CIM_CMD (CIM_BASE + 0x002C) ++#define CIM_SIZE (CIM_BASE + 0x0030) ++#define CIM_OFFSET (CIM_BASE + 0x0034) ++#define CIM_RAM_ADDR (CIM_BASE + 0x1000) ++ ++#define REG_CIM_CFG REG32(CIM_CFG) ++#define REG_CIM_CTRL REG32(CIM_CTRL) ++#define REG_CIM_STATE REG32(CIM_STATE) ++#define REG_CIM_IID REG32(CIM_IID) ++#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) ++#define REG_CIM_DA REG32(CIM_DA) ++#define REG_CIM_FA REG32(CIM_FA) ++#define REG_CIM_FID REG32(CIM_FID) ++#define REG_CIM_CMD REG32(CIM_CMD) ++#define REG_CIM_SIZE REG32(CIM_SIZE) ++#define REG_CIM_OFFSET REG32(CIM_OFFSET) ++ ++/* CIM Configuration Register (CIM_CFG) */ ++ ++#define CIM_CFG_ORDER_BIT 18 ++#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT) ++ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* RG-GB; YUYV; YUV */ ++ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) /* GR-BG; YVYU; YVU */ ++ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) /* BG-GR; UYVY; UVY */ ++ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) /* GB-RG; VYUY; VUY */ ++#define CIM_CFG_DF_BIT 16 ++#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT) ++ #define CIM_CFG_DF_RGB (0x0 << CIM_CFG_DF_BIT) ++ #define CIM_CFG_DF_RAWRGB CIM_CFG_DF_RGB ++ #define CIM_CFG_DF_BAYERRGB CIM_CFG_DF_RGB ++ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT) ++ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT) ++ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT) ++#define CIM_CFG_INV_DAT (1 << 15) ++#define CIM_CFG_VSP (1 << 14) /* VSYNC Polarity:0-rising edge active,1-falling edge active */ ++#define CIM_CFG_HSP (1 << 13) /* HSYNC Polarity:0-rising edge active,1-falling edge active */ ++#define CIM_CFG_PCP (1 << 12) /* PCLK working edge: 0-rising, 1-falling */ ++#define CIM_CFG_DMA_BURST_TYPE_BIT 10 ++#define CIM_CFG_DMA_BURST_TYPE_MASK (0x3 << CIM_CFG_DMA_BURST_TYPE_BIT) ++#define CIM_CFG_DMA_BURST_INCR (0 << CIM_CFG_DMA_BURST_TYPE_BIT) ++#define CIM_CFG_DMA_BURST_INCR4 (1 << CIM_CFG_DMA_BURST_TYPE_BIT) ++#define CIM_CFG_DMA_BURST_INCR8 (2 << CIM_CFG_DMA_BURST_TYPE_BIT) ++#define CIM_CFG_DUMMY_ZERO (1 << 9) ++#define CIM_CFG_EXT_VSYNC (1 << 8) ++#define CIM_CFG_PACK_BIT 4 ++#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 */ ++ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 */ ++ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 */ ++ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 */ ++ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 */ ++ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 */ ++ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 */ ++ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 */ ++#define CIM_CFG_BYPASS_BIT 2 ++#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT) ++ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT) ++#define CIM_CFG_DSM_BIT 0 ++#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) ++ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ ++ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ ++ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ ++ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ ++ ++/* CIM Control Register (CIM_CTRL) */ ++ ++#define CIM_CTRL_MCLKDIV_BIT 24 ++#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) ++#define CIM_CTRL_FRC_BIT 16 ++#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) ++ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ ++ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ ++ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ ++ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ ++ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ ++ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ ++ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ ++ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ ++ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ ++ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ ++ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ ++ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ ++ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ ++ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ ++ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ ++ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ ++#define CIM_CTRL_SIZEEN_BIT 14 ++#define CIM_CTRL_SIZEEN_MASK (0x1 << CIM_CTRL_SIZEEN_BIT) ++#define CIM_CTRL_SIZEEN (0x1 << CIM_CTRL_SIZEEN_BIT) ++#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */ ++#define CIM_CTRL_DMA_SOFM (1 << 12) ++#define CIM_CTRL_DMA_EOFM (1 << 11) ++#define CIM_CTRL_DMA_STOPM (1 << 10) ++#define CIM_CTRL_RXF_TRIGM (1 << 9) ++#define CIM_CTRL_RXF_OFM (1 << 8) ++#define CIM_CTRL_RXF_TRIG_BIT 4 ++#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) ++ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ ++ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ ++ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ ++ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ ++ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ ++ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ ++ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ ++ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ ++#define CIM_CTRL_FAST_MODE_MASK (1 << 3) /* CIM fast mode mask */ ++#define CIM_CTRL_FAST_MODE (1 << 3) /* CIM works in fast mode */ ++#define CIM_CTRL_NORMAL_MODE (0 << 3) /* CIM works in normal mode */ ++#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */ ++#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */ ++#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */ ++ ++/* CIM State Register (CIM_STATE) */ ++ ++#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */ ++#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */ ++#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */ ++#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */ ++#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */ ++#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */ ++#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */ ++ ++/* CIM DMA Command Register (CIM_CMD) */ ++ ++#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */ ++#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */ ++#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */ ++#define CIM_CMD_LEN_BIT 0 ++#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) ++ ++/* CIM Image Size Register (CIM_SIZE) */ ++#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */ ++#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT) ++#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */ ++#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT) ++ ++/* CIM Image Offset Register (CIM_OFFSET) */ ++#define CIM_OFFSET_V_BIT 16 /* Vertical offset */ ++#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT) ++#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */ ++#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/ ++ ++/************************************************************************* ++ * SADC (Smart A/D Controller) ++ *************************************************************************/ ++ ++#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ ++#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ ++#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ ++#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ ++#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ ++#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ ++#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ ++#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ ++#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ ++#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */ ++ ++#define REG_SADC_ENA REG8(SADC_ENA) ++#define REG_SADC_CFG REG32(SADC_CFG) ++#define REG_SADC_CTRL REG8(SADC_CTRL) ++#define REG_SADC_STATE REG8(SADC_STATE) ++#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) ++#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) ++#define REG_SADC_TSDAT REG32(SADC_TSDAT) ++#define REG_SADC_BATDAT REG16(SADC_BATDAT) ++#define REG_SADC_SADDAT REG16(SADC_SADDAT) ++#define REG_SADC_ADCLK REG32(SADC_ADCLK) ++ ++/* ADC Enable Register */ ++#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ ++#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */ ++#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */ ++#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ ++#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ ++#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ ++ ++/* ADC Configure Register */ ++#define SADC_CFG_EXIN (1 << 30) ++#define SADC_CFG_CLKOUT_NUM_BIT 16 ++#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) ++#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ ++#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ ++#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) ++#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ ++#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ ++#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) ++#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ ++#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ ++#define SADC_CFG_CMD_BIT 0 /* ADC Command */ ++#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) ++ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ ++ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ ++ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ ++ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ ++ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ ++ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ ++ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ ++ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ ++ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ ++ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ ++ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ ++ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ ++ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ ++ ++/* ADC Control Register */ ++#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */ ++#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ ++#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ ++#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ ++#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ ++#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ ++ ++/* ADC Status Register */ ++#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ ++#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ ++#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ ++#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ ++ ++/* ADC Touch Screen Data Register */ ++#define SADC_TSDAT_DATA0_BIT 0 ++#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) ++#define SADC_TSDAT_TYPE0 (1 << 15) ++#define SADC_TSDAT_DATA1_BIT 16 ++#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) ++#define SADC_TSDAT_TYPE1 (1 << 31) ++ ++/* ADC Clock Divide Register */ ++#define SADC_ADCLK_CLKDIV_10_BIT 16 ++#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT) ++#define SADC_ADCLK_CLKDIV_BIT 0 ++#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT) ++ ++/************************************************************************* ++ * SLCD (Smart LCD Controller) ++ *************************************************************************/ ++ ++#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ ++#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ ++#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ ++#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ ++ ++#define REG_SLCD_CFG REG32(SLCD_CFG) ++#define REG_SLCD_CTRL REG8(SLCD_CTRL) ++#define REG_SLCD_STATE REG8(SLCD_STATE) ++#define REG_SLCD_DATA REG32(SLCD_DATA) ++ ++/* SLCD Configure Register */ ++#define SLCD_CFG_DWIDTH_BIT 10 ++#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_BIT (8) ++#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) ++#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) ++#define SLCD_CFG_RS_CMD_LOW (0 << 3) ++#define SLCD_CFG_RS_CMD_HIGH (1 << 3) ++#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) ++#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) ++#define SLCD_CFG_TYPE_PARALLEL (0 << 0) ++#define SLCD_CFG_TYPE_SERIAL (1 << 0) ++ ++/* SLCD Control Register */ ++#define SLCD_CTRL_DMA_EN (1 << 0) ++ ++/* SLCD Status Register */ ++#define SLCD_STATE_BUSY (1 << 0) ++ ++/* SLCD Data Register */ ++#define SLCD_DATA_RS_DATA (0 << 31) ++#define SLCD_DATA_RS_COMMAND (1 << 31) ++ ++/************************************************************************* ++ * LCD (LCD Controller) ++ *************************************************************************/ ++#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ ++#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ ++#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ ++ ++#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */ ++#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */ ++#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */ ++#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */ ++#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */ ++#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */ ++#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */ ++#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */ ++ ++#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ ++#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ ++#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ ++ ++#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */ ++#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */ ++#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */ ++#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */ ++#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */ ++ ++#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ ++#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ ++#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ ++#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ ++#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ ++#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ ++#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ ++#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ ++#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ ++#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ ++#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ ++#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ ++#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ ++#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ ++#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ ++ ++#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */ ++#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */ ++#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */ ++#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/ ++#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */ ++#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */ ++#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */ ++#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/ ++ ++#define REG_LCD_CFG REG32(LCD_CFG) ++#define REG_LCD_CTRL REG32(LCD_CTRL) ++#define REG_LCD_STATE REG32(LCD_STATE) ++ ++#define REG_LCD_OSDC REG16(LCD_OSDC) ++#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL) ++#define REG_LCD_OSDS REG16(LCD_OSDS) ++#define REG_LCD_BGC REG32(LCD_BGC) ++#define REG_LCD_KEY0 REG32(LCD_KEY0) ++#define REG_LCD_KEY1 REG32(LCD_KEY1) ++#define REG_LCD_ALPHA REG8(LCD_ALPHA) ++#define REG_LCD_IPUR REG32(LCD_IPUR) ++ ++#define REG_LCD_VAT REG32(LCD_VAT) ++#define REG_LCD_DAH REG32(LCD_DAH) ++#define REG_LCD_DAV REG32(LCD_DAV) ++ ++#define REG_LCD_XYP0 REG32(LCD_XYP0) ++#define REG_LCD_XYP1 REG32(LCD_XYP1) ++#define REG_LCD_SIZE0 REG32(LCD_SIZE0) ++#define REG_LCD_SIZE1 REG32(LCD_SIZE1) ++#define REG_LCD_RGBC REG16(LCD_RGBC) ++ ++#define REG_LCD_VSYNC REG32(LCD_VSYNC) ++#define REG_LCD_HSYNC REG32(LCD_HSYNC) ++#define REG_LCD_PS REG32(LCD_PS) ++#define REG_LCD_CLS REG32(LCD_CLS) ++#define REG_LCD_SPL REG32(LCD_SPL) ++#define REG_LCD_REV REG32(LCD_REV) ++#define REG_LCD_IID REG32(LCD_IID) ++#define REG_LCD_DA0 REG32(LCD_DA0) ++#define REG_LCD_SA0 REG32(LCD_SA0) ++#define REG_LCD_FID0 REG32(LCD_FID0) ++#define REG_LCD_CMD0 REG32(LCD_CMD0) ++#define REG_LCD_DA1 REG32(LCD_DA1) ++#define REG_LCD_SA1 REG32(LCD_SA1) ++#define REG_LCD_FID1 REG32(LCD_FID1) ++#define REG_LCD_CMD1 REG32(LCD_CMD1) ++ ++#define REG_LCD_OFFS0 REG32(LCD_OFFS0) ++#define REG_LCD_PW0 REG32(LCD_PW0) ++#define REG_LCD_CNUM0 REG32(LCD_CNUM0) ++#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0) ++#define REG_LCD_OFFS1 REG32(LCD_OFFS1) ++#define REG_LCD_PW1 REG32(LCD_PW1) ++#define REG_LCD_CNUM1 REG32(LCD_CNUM1) ++#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1) ++ ++/* LCD Configure Register */ ++#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ ++#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) ++ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) ++ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) ++#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */ ++#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */ ++#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */ ++#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */ ++#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */ ++#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */ ++#define LCD_CFG_DITHER (1 << 24) /* Dither function */ ++#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ ++#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ ++#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ ++#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ ++#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ ++#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ ++#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ ++#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ ++#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ ++#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ ++#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ ++#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ ++#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */ ++#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */ ++#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */ ++#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */ ++#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */ ++#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */ ++#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */ ++#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ ++#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) ++#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ ++ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ ++ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ ++ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ ++#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ ++#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ ++ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM ++ ++/* LCD Control Register */ ++#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ ++#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) ++ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ ++ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ ++ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ ++ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */ ++#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */ ++#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */ ++#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ ++#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ ++#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) ++ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ ++ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ ++ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ ++#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ ++#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) ++#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ ++#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ ++#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ ++#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ ++#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ ++#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ ++#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ ++#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ ++#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ ++#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ ++#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ ++#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ ++#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ ++ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ ++ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ ++ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ ++ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ ++ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ ++ ++/* LCD Status Register */ ++#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ ++#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ ++#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ ++#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ ++#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ ++#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ ++#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ ++ ++/* OSD Configure Register */ ++#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */ ++#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */ ++#define LCD_OSDC_REM1 (1 << 13) /* Real end of frame mask for foreground 1 */ ++#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */ ++#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */ ++#define LCD_OSDC_REM0 (1 << 9) /* Real end of frame mask for foreground 0 */ ++#define LCD_OSDC_REMB (1 << 7) /* Real end of frame mask for background */ ++#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */ ++#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */ ++#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */ ++#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */ ++#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */ ++ ++/* OSD Controll Register */ ++#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */ ++#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */ ++#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */ ++#define LCD_OSDCTRL_OSDBPP_MASK (0x7< ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_BOARD_SERIAL_H__ ++#define __ASM_BOARD_SERIAL_H__ ++ ++#ifndef CONFIG_SERIAL_MANY_PORTS ++#undef RS_TABLE_SIZE ++#define RS_TABLE_SIZE 1 ++#endif ++ ++#define JZ_BASE_BAUD (12000000/16) ++ ++#define JZ_SERIAL_PORT_DEFNS \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, ++ ++#endif /* __ASM_BORAD_SERIAL_H__ */ +diff --git a/include/asm-mips/mach-jz4750/war.h b/include/asm-mips/mach-jz4750/war.h +new file mode 100644 +index 0000000..3a5bc17 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750/war.h +@@ -0,0 +1,25 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H ++#define __ASM_MIPS_MACH_JZ4740_WAR_H ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 0 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ +diff --git a/include/asm-mips/mach-jz4750d/board-cetus.h b/include/asm-mips/mach-jz4750d/board-cetus.h +new file mode 100644 +index 0000000..aea475d +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/board-cetus.h +@@ -0,0 +1,124 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/board-cetus.h ++ * ++ * JZ4750D-based CETUS board ver 1.x definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750D_CETUS_H__ ++#define __ASM_JZ4750D_CETUS_H__ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++#define JZ_EXTAL 24000000 ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++//#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++ ++#define GPIO_SD0_VCC_EN_N (32*4+0) /* CIM_D0 */ ++#define GPIO_SD0_CD_N (32*4+1) /* CIM_D1 */ ++#define GPIO_SD0_WP (32*4+2) /* CIM_D2 */ ++#define GPIO_SD1_VCC_EN_N (32*4+3) /* CIM_D3 */ ++#define GPIO_SD1_CD_N (32*4+4) /* CIM_D4 */ ++ ++#define GPIO_USB_DETE (32*4+6) /* CIM_D6 */ ++#define GPIO_DC_DETE_N (32*4+8) /* CIM_MCLK */ ++#define GPIO_CHARG_STAT_N (32*4+10) /* CIM_VSYNC */ ++#define GPIO_DISP_OFF_N (32*4+18) /* SDATO */ ++#define GPIO_LCD_VCC_EN_N (32*4+19) /* SDATI */ ++//#define GPIO_LED_EN 124 /* GPD28 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++/*====================================================================== ++ * LCD backlight ++ */ ++#define GPIO_LCD_PWM (32*4+22) /* GPE22 PWM2 */ ++#define LCD_PWM_CHN 2 /* pwm channel */ ++#define LCD_PWM_FULL 101 ++/* 100 level: 0,1,...,100 */ ++#define __lcd_set_backlight_level(n) \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_set_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++#define __lcd_close_backlight() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_clear_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC0_WP_PIN GPIO_SD0_WP ++#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N ++#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N) ++ ++#define MSC1_WP_PIN GPIO_SD1_WP ++#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N ++#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N) ++ ++#define __msc0_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD0_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD0_CD_N); \ ++} while (0) ++ ++#define __msc0_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD0_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#define __msc1_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD1_VCC_EN_N); \ ++ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \ ++} while (0) ++ ++#define __msc1_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_card_detected(s) \ ++({ \ ++ int detected = 0; \ ++ if (__gpio_get_pin(GPIO_SD1_CD_N)) \ ++ detected = 1; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4750d_CETUS_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/board-draco.h b/include/asm-mips/mach-jz4750d/board-draco.h +new file mode 100644 +index 0000000..fe04f79 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/board-draco.h +@@ -0,0 +1,126 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/board-draco.h ++ * ++ * JZ4750D-based DRACO board ver 1.x definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750D_DRACO_H__ ++#define __ASM_JZ4750D_DRACO_H__ ++ ++//#define CONFIG_FPGA /* fuwa is an FPGA board */ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++//#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL 24000000 ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++//#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */ ++#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */ ++#define GPIO_SD0_WP (32*2+12) /* GPC12 */ ++//#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */ ++#define GPIO_SD1_VCC_EN_N (32*4+4) /* GPE4 */ ++#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */ ++#define GPIO_USB_DETE (32*5+12) /* GPF12 */ ++#define GPIO_DC_DETE_N 103 /* GPD7 */ ++#define GPIO_CHARG_STAT_N 111 /* GPD15 */ ++#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */ ++//#define GPIO_LED_EN 124 /* GPD28 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++/*====================================================================== ++ * LCD backlight ++ */ ++#define GPIO_LCD_PWM (32*4+20) /* GPE20 */ ++ ++#define LCD_PWM_CHN 0 /* pwm channel */ ++#define LCD_PWM_FULL 101 ++/* 100 level: 0,1,...,100 */ ++#define __lcd_set_backlight_level(n) \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_set_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++#define __lcd_close_backlight() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_clear_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC0_WP_PIN GPIO_SD0_WP ++#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N ++#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N) ++ ++#define MSC1_WP_PIN GPIO_SD1_WP ++#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N ++#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N) ++ ++#define __msc0_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD0_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD0_CD_N); \ ++} while (0) ++ ++#define __msc0_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD0_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#define __msc1_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD1_VCC_EN_N); \ ++ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \ ++} while (0) ++ ++#define __msc1_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_card_detected(s) \ ++({ \ ++ int detected = 0; \ ++ if (__gpio_get_pin(GPIO_SD1_CD_N)) \ ++ detected = 1; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4750d_DRACO_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/board-fuwa1.h b/include/asm-mips/mach-jz4750d/board-fuwa1.h +new file mode 100644 +index 0000000..7b8c6c2 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/board-fuwa1.h +@@ -0,0 +1,126 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/board-fuwa1.h ++ * ++ * JZ4750D-based FUWA1 board ver 1.x definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750D_FUWA1_H__ ++#define __ASM_JZ4750D_FUWA1_H__ ++ ++//#define CONFIG_FPGA /* fuwa is an FPGA board */ ++ ++/*====================================================================== ++ * Frequencies of on-board oscillators ++ */ ++//#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */ ++#define JZ_EXTAL 24000000 ++#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ ++//#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */ ++ ++ ++/*====================================================================== ++ * GPIO ++ */ ++#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */ ++#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */ ++#define GPIO_SD0_WP (32*2+12) /* GPC12 */ ++//#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */ ++#define GPIO_SD1_VCC_EN_N (32*4+4) /* GPE4 */ ++#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */ ++#define GPIO_USB_DETE 102 /* GPD6 */ ++#define GPIO_DC_DETE_N 103 /* GPD7 */ ++#define GPIO_CHARG_STAT_N 111 /* GPD15 */ ++#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */ ++//#define GPIO_LED_EN 124 /* GPD28 */ ++ ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++/*====================================================================== ++ * LCD backlight ++ */ ++#define GPIO_LCD_PWM (32*4+20) /* GPE20 */ ++ ++#define LCD_PWM_CHN 0 /* pwm channel */ ++#define LCD_PWM_FULL 101 ++/* 100 level: 0,1,...,100 */ ++#define __lcd_set_backlight_level(n) \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_set_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++#define __lcd_close_backlight() \ ++do { \ ++ __gpio_as_output(GPIO_LCD_PWM); \ ++ __gpio_clear_pin(GPIO_LCD_PWM); \ ++} while (0) ++ ++/*====================================================================== ++ * MMC/SD ++ */ ++ ++#define MSC0_WP_PIN GPIO_SD0_WP ++#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N ++#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N) ++ ++#define MSC1_WP_PIN GPIO_SD1_WP ++#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N ++#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N) ++ ++#define __msc0_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD0_VCC_EN_N); \ ++ __gpio_as_input(GPIO_SD0_CD_N); \ ++} while (0) ++ ++#define __msc0_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \ ++} while (0) ++ ++#define __msc0_card_detected(s) \ ++({ \ ++ int detected = 1; \ ++ if (__gpio_get_pin(GPIO_SD0_CD_N)) \ ++ detected = 0; \ ++ detected; \ ++}) ++ ++#define __msc1_init_io() \ ++do { \ ++ __gpio_as_output(GPIO_SD1_VCC_EN_N); \ ++ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \ ++} while (0) ++ ++#define __msc1_enable_power() \ ++do { \ ++ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_disable_power() \ ++do { \ ++ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \ ++} while (0) ++ ++#define __msc1_card_detected(s) \ ++({ \ ++ int detected = 0; \ ++ if (__gpio_get_pin(GPIO_SD1_CD_N)) \ ++ detected = 1; \ ++ detected; \ ++}) ++ ++#endif /* __ASM_JZ4750d_FUWA1_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/clock.h b/include/asm-mips/mach-jz4750d/clock.h +new file mode 100644 +index 0000000..a2832d6 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/clock.h +@@ -0,0 +1,230 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/clock.h ++ * ++ * JZ4750D clocks definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750D_CLOCK_H__ ++#define __ASM_JZ4750D_CLOCK_H__ ++ ++#ifndef JZ_EXTAL ++#define JZ_EXTAL 12000000 /* 3.6864 MHz */ ++#endif ++#ifndef JZ_EXTAL2 ++#define JZ_EXTAL2 32768 /* 32.768 KHz */ ++#endif ++ ++/* ++ * JZ4750D clocks structure ++ */ ++typedef struct { ++ unsigned int cclk; /* CPU clock */ ++ unsigned int hclk; /* System bus clock */ ++ unsigned int pclk; /* Peripheral bus clock */ ++ unsigned int mclk; /* Flash/SRAM/SDRAM clock */ ++ unsigned int h1clk; /* AHB1 clock */ ++ unsigned int pixclk; /* LCD pixel clock */ ++ unsigned int i2sclk; /* AIC module clock */ ++ unsigned int usbclk; /* USB module clock */ ++ unsigned int mscclk; /* MSC module clock */ ++ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ ++ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ ++} jz_clocks_t; ++ ++extern jz_clocks_t jz_clocks; ++ ++ ++/* PLL output frequency */ ++static __inline__ unsigned int __cpm_get_pllout(void) ++{ ++#if defined(CONFIG_FPGA) ++ return JZ_EXTAL/CFG_DIV; ++#else ++ unsigned long m, n, no, pllout; ++ unsigned long cppcr = REG_CPM_CPPCR; ++ unsigned long od[4] = {1, 2, 2, 4}; ++ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { ++ m = __cpm_get_pllm() + 2; ++ n = __cpm_get_plln() + 2; ++ no = od[__cpm_get_pllod()]; ++ pllout = ((JZ_EXTAL) / (n * no)) * m; ++ } else ++ pllout = JZ_EXTAL; ++ return pllout; ++#endif ++} ++ ++/* PLL output frequency for MSC/I2S/LCD/USB */ ++static __inline__ unsigned int __cpm_get_pllout2(void) ++{ ++#if defined(CONFIG_FPGA) ++ return JZ_EXTAL/CFG_DIV; ++#else ++ if (REG_CPM_CPCCR & CPM_CPCCR_PCS) ++ return __cpm_get_pllout(); ++ else ++ return __cpm_get_pllout()/2; ++#endif ++} ++ ++/* CPU core clock */ ++static __inline__ unsigned int __cpm_get_cclk(void) ++{ ++ ++#if defined(CONFIG_FGPA) ++ return JZ_EXTAL; ++#else ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ return __cpm_get_pllout() / div[__cpm_get_cdiv()]; ++#endif ++} ++ ++/* AHB system bus clock */ ++static __inline__ unsigned int __cpm_get_hclk(void) ++{ ++#if defined(CONFIG_FPGA) ++ return JZ_EXTAL/CFG_DIV; ++#else ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_hdiv()]; ++#endif ++ ++} ++ ++/* Memory bus clock */ ++static __inline__ unsigned int __cpm_get_mclk(void) ++{ ++#if defined(CONFIG_FPGA) ++ return JZ_EXTAL/CFG_DIV; ++#else ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_mdiv()]; ++#endif ++} ++ ++/* APB peripheral bus clock */ ++static __inline__ unsigned int __cpm_get_pclk(void) ++{ ++#if defined(CONFIG_FPGA) ++ return JZ_EXTAL/CFG_DIV; ++#else ++ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; ++ ++ return __cpm_get_pllout() / div[__cpm_get_pdiv()]; ++#endif ++} ++ ++/* LCDC module clock */ ++static __inline__ unsigned int __cpm_get_h1clk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_h1div() + 1); ++} ++ ++/* LCD pixel clock */ ++static __inline__ unsigned int __cpm_get_pixclk(void) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); ++} ++ ++/* I2S clock */ ++static __inline__ unsigned int __cpm_get_i2sclk(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { ++ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); ++ } ++ else { ++ return JZ_EXTAL; ++ } ++} ++ ++/* USB clock */ ++static __inline__ unsigned int __cpm_get_usbclk(void) ++{ ++ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { ++ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); ++ } ++ else { ++ return JZ_EXTAL; ++ } ++} ++ ++/* ++ * MSC clock ++ * @n: the index of MMC/SD controller ++ */ ++static __inline__ unsigned int __cpm_get_mscclk(int n) ++{ ++ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1); ++} ++ ++/* EXTAL clock */ ++static __inline__ unsigned int __cpm_get_extalclk0(void) ++{ ++ return JZ_EXTAL; ++} ++ ++/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ ++static __inline__ unsigned int __cpm_get_extalclk(void) ++{ ++#if defined(CONFIG_FPGA) ++ return __cpm_get_pllout(); ++#else ++ if (REG_CPM_CPCCR & CPM_CPCCR_ECS) ++ return __cpm_get_extalclk0()/2; ++ else ++ return __cpm_get_extalclk0(); ++#endif ++ ++} ++ ++/* RTC clock for CPM,INTC,RTC,TCU,WDT */ ++static __inline__ unsigned int __cpm_get_rtcclk(void) ++{ ++ return JZ_EXTAL2; ++} ++ ++/* ++ * Output 24MHz for SD and 16MHz for MMC. ++ * @n: the index of MMC/SD controller ++ */ ++static inline void __cpm_select_msc_clk(int n, int sd) ++{ ++ unsigned int pllout2 = __cpm_get_pllout2(); ++ unsigned int div = 0; ++ ++ if (sd) { ++ div = pllout2 / 24000000; ++ } ++ else { ++ div = pllout2 / 16000000; ++ } ++ ++ REG_CPM_MSCCDR(n) = div - 1; ++ REG_CPM_CPCCR |= CPM_CPCCR_CE; ++} ++ ++/* ++ * Output 48MHz for high speed card. ++ */ ++static inline void __cpm_select_msc_clk_high(int n, int sd) ++{ ++ unsigned int pllout2 = __cpm_get_pllout2(); ++ unsigned int div = 0; ++ ++ div = pllout2 / 48000000; ++ ++ REG_CPM_MSCCDR(n) = div - 1; ++ REG_CPM_CPCCR |= CPM_CPCCR_CE; ++} ++ ++#endif /* __ASM_JZ4750D_CLOCK_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/dma.h b/include/asm-mips/mach-jz4750d/dma.h +new file mode 100644 +index 0000000..3cca844 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/dma.h +@@ -0,0 +1,307 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/dma.h ++ * ++ * JZ4750D DMA definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750D_DMA_H__ ++#define __ASM_JZ4750D_DMA_H__ ++ ++#include ++#include /* need byte IO */ ++#include /* And spinlocks */ ++#include ++#include ++ ++/* ++ * Descriptor structure for JZ4750D DMA engine ++ * Note: this structure must always be aligned to a 16-bytes boundary. ++ */ ++ ++/* old descriptor 4-word */ ++typedef struct { ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++ volatile u32 dsadr; /* DSAR value for the current transfer */ ++ volatile u32 dtadr; /* DTAR value for the current transfer */ ++ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ ++} jz_dma_desc; ++ ++/* new descriptor 8-word */ ++typedef struct { ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++ volatile u32 dsadr; /* DSAR value for the current transfer */ ++ volatile u32 dtadr; /* DTAR value for the current transfer */ ++ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ ++ volatile u32 dstrd; /* DMA source and target stride address */ ++ volatile u32 dreqt; /* DMA request type for current transfer */ ++ volatile u32 reserved0; /* Reserved */ ++ volatile u32 reserved1; /* Reserved */ ++} jz_dma_desc_8word; ++ ++/* DMA Device ID's follow */ ++enum { ++ DMA_ID_EXT = 0, /* External request with DREQn */ ++ DMA_ID_NAND, /* NAND DMA request */ ++ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */ ++ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */ ++ DMA_ID_AUTO, /* Auto-request */ ++// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */ ++ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */ ++ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */ ++ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */ ++ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */ ++ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */ ++ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */ ++ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */ ++ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */ ++ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */ ++ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */ ++ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */ ++ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */ ++ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */ ++ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */ ++ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */ ++ DMA_ID_SADC, /* SADC transfer request */ ++ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */ ++ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */ ++ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */ ++ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */ ++ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */ ++ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */ ++ DMA_ID_RAW_SET, ++ DMA_ID_MAX ++}; ++ ++/* DMA modes, simulated by sw */ ++#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ ++#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ ++#define DMA_AUTOINIT 0x2 ++#define DMA_MODE_MASK 0x3 ++ ++struct jz_dma_chan { ++ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ ++ unsigned int io; /* DMA channel number */ ++ const char *dev_str; /* string describes the DMA channel */ ++ int irq; /* DMA irq number */ ++ void *irq_dev; /* DMA private device structure */ ++ unsigned int fifo_addr; /* physical fifo address of the requested device */ ++ unsigned int cntl; /* DMA controll */ ++ unsigned int mode; /* DMA configuration */ ++ unsigned int source; /* DMA request source */ ++}; ++ ++extern struct jz_dma_chan jz_dma_table[]; ++ ++ ++#define DMA_8BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_8BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_32BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_32_32BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN ++#define DMA_AIC_32_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_32_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BIT_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BIT_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_RX_CMD \ ++ DMAC_DCMD_DAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_TX_CMD \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++#define DMA_AIC_16BYTE_TX_CMD_UC \ ++ DMAC_DCMD_SAI | \ ++ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ ++ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN ++ ++extern int jz_request_dma(int dev_id, ++ const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, ++ void *irq_dev_id); ++extern void jz_free_dma(unsigned int dmanr); ++ ++extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, ++ int length, int *eof, void *data); ++extern void dump_jz_dma_channel(unsigned int dmanr); ++ ++extern void enable_dma(unsigned int dmanr); ++extern void disable_dma(unsigned int dmanr); ++extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); ++extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); ++extern void set_dma_mode(unsigned int dmanr, unsigned int mode); ++extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); ++extern void jz_set_dma_src_width(int dmanr, int nbit); ++extern void jz_set_dma_dest_width(int dmanr, int nbit); ++extern void jz_set_dma_block_size(int dmanr, int nbyte); ++extern unsigned int get_dma_residue(unsigned int dmanr); ++ ++extern spinlock_t dma_spin_lock; ++ ++static __inline__ unsigned long claim_dma_lock(void) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&dma_spin_lock, flags); ++ return flags; ++} ++ ++static __inline__ void release_dma_lock(unsigned long flags) ++{ ++ spin_unlock_irqrestore(&dma_spin_lock, flags); ++} ++ ++/* Clear the 'DMA Pointer Flip Flop'. ++ * Write 0 for LSB/MSB, 1 for MSB/LSB access. ++ */ ++#define clear_dma_ff(channel) ++ ++static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) ++{ ++ if (dmanr > MAX_DMA_NUM ++ || jz_dma_table[dmanr].dev_id < 0) ++ return NULL; ++ return &jz_dma_table[dmanr]; ++} ++ ++static __inline__ int dma_halted(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 1; ++ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; ++} ++ ++static __inline__ unsigned int get_dma_mode(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ return chan->mode; ++} ++ ++static __inline__ void clear_dma_done(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++} ++ ++static __inline__ void clear_dma_halt(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); ++ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT); ++} ++ ++static __inline__ void clear_dma_flag(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return; ++ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); ++} ++ ++static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) ++{ ++} ++ ++static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) ++{ ++ unsigned long dccsr; ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return 0; ++ dccsr = REG_DMAC_DCCSR(chan->io); ++ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); ++} ++ ++static __inline__ int get_dma_done_irq(unsigned int dmanr) ++{ ++ struct jz_dma_chan *chan = get_dma_chan(dmanr); ++ if (!chan) ++ return -1; ++ return chan->irq; ++} ++ ++#endif /* __ASM_JZ4750D_DMA_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/jz4750d.h b/include/asm-mips/mach-jz4750d/jz4750d.h +new file mode 100644 +index 0000000..ac59226 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/jz4750d.h +@@ -0,0 +1,43 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/jz4750d.h ++ * ++ * JZ4750 common definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750_H__ ++#define __ASM_JZ4750_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*------------------------------------------------------------------ ++ * Platform definitions ++ */ ++#ifdef CONFIG_JZ4750D_FUWA1 ++#include ++#endif ++ ++#ifdef CONFIG_JZ4750D_CETUS ++#include ++#endif ++/* Add other platform definition here ... */ ++ ++ ++/*------------------------------------------------------------------ ++ * Follows are related to platform definitions ++ */ ++ ++#include ++#include ++ ++#endif /* __ASM_JZ4750_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/misc.h b/include/asm-mips/mach-jz4750d/misc.h +new file mode 100644 +index 0000000..cd0b13c +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/misc.h +@@ -0,0 +1,44 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/misc.h ++ * ++ * Ingenic's JZ4750D common include. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4750D_MISC_H__ ++#define __ASM_JZ4750D_MISC_H__ ++ ++/*========================================================== ++ * I2C ++ *===========================================================*/ ++ ++#define I2C_EEPROM_DEV 0xA /* b'1010 */ ++#define I2C_RTC_DEV 0xD /* b'1101 */ ++#define DIMM0_SPD_ADDR 0 ++#define DIMM1_SPD_ADDR 1 ++#define DIMM2_SPD_ADDR 2 ++#define DIMM3_SPD_ADDR 3 ++#define JZ_HCI_ADDR 7 ++ ++#define DIMM_SPD_LEN 128 ++#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ ++#define I2C_RTC_LEN 16 ++#define HCI_MAC_OFFSET 64 ++ ++extern void i2c_open(void); ++extern void i2c_close(void); ++extern void i2c_setclk(unsigned int i2cclk); ++ ++extern int i2c_read(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++extern int i2c_write(unsigned char device, unsigned char *buf, ++ unsigned char address, int count); ++ ++#endif /* __ASM_JZ4750D_MISC_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/ops.h b/include/asm-mips/mach-jz4750d/ops.h +new file mode 100644 +index 0000000..f28651f +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/ops.h +@@ -0,0 +1,3430 @@ ++/* ++ * linux/include/asm-mips/mach-jz4750d/ops.h ++ * ++ * JZ4750D register definition. ++ * ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++#ifndef __JZ4750D_OPS_H__ ++#define __JZ4750D_OPS_H__ ++ ++/* ++ * Definition of Module Operations ++ */ ++ ++/*************************************************************************** ++ * EMC ++ ***************************************************************************/ ++#define is_share_mode() (1) ++ ++/*************************************************************************** ++ * GPIO ++ ***************************************************************************/ ++ ++//------------------------------------------------------ ++// GPIO Pins Description ++// ++// PORT 0: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 D0 - ++// 1 D1 - ++// 2 D2 - ++// 3 D3 - ++// 4 D4 - ++// 5 D5 - ++// 6 D6 - ++// 7 D7 - ++// 8 D8 - ++// 9 D9 - ++// 10 D10 - ++// 11 D11 - ++// 12 D12 - ++// 13 D13 - ++// 14 D14 - ++// 15 D15 - ++// 16 D16 - ++// 17 D17 - ++// 18 D18 - ++// 19 D19 - ++// 20 D20 - ++// 21 D21 - ++// 22 D22 - ++// 23 D23 - ++// 24 D24 - ++// 25 D25 - ++// 26 D26 - ++// 27 D27 - ++// 28 D28 - ++// 29 D29 - ++// 30 D30 - ++// 31 D31 - ++// ++//------------------------------------------------------ ++// PORT 1: ++// ++// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE ++// 0 A0 - - ++// 1 A1 - - ++// 2 A2 - - ++// 3 A3 - - ++// 4 A4 - - ++// 5 A5 - - ++// 6 A6 - - ++// 7 A7 - - ++// 8 A8 - - ++// 9 A9 - - ++// 10 A10 - - ++// 11 A11 - - ++// 12 A12 - - ++// 13 A13 - - ++// 14 A14 - - ++// 15 A15/CLE CL(unshare) MSC0_CLK ++// 16 DCS0# - - ++// 17 RAS# - - ++// 18 CAS# - - ++// 19 SDWE#/BUFD# - - ++// 20 WE0# - - ++// 21 WE1# - - ++// 22 WE2# - - ++// 23 WE3# - - ++// 24 CKO - - Note1 ++// 25 CKE - - ++// 26 SSI_CLK MSC1_CLK - ++// 27 SSI_DT MSC1_D1 - ++// 28 SSI_DR MSC1_D0 - ++// 29 SSI_CE0# MSC1_CMD - ++// 30 SSI_GPC MSC1_D2 - ++// 31 SSI_CE1# MSC1_D3 - ++// ++// Note1: BIT24: it is CKO when chip is reset ++// ++//------------------------------------------------------ ++// PORT 2: ++// ++// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE ++// 0 SD0 A20 - ++// 1 SD1 A21 - ++// 2 SD2 A22 - ++// 3 SD3 A23 - ++// 4 SD4 A24 - ++// 5 SD5 A25 - ++// 6 SD6 - - ++// 7 SD7 - - ++// 8 SD8 TSDI0 - ++// 9 SD9 TSDI1 - ++// 10 SD10 TSDI2 - ++// 11 SD11 TSDI3 - ++// 12 SD12 TSDI4 - ++// 13 SD13 TSDI5 - ++// 14 SD14 TSDI6 - ++// 15 SD15 TSDI7 - ++// 16 A16/ALE AL(unshare) MSC0_CMD ++// 17 A17 MSC0_D3 - ++// 18 A18 DREQ - ++// 19 A19 DACK - ++// 20 WAIT# - - Note2 ++// 21 CS1# - - ++// 22 CS2# - - ++// 23 CS3# - - ++// 24 CS4# - - ++// 25 RD# - - ++// 26 WR# - - ++// 27 FRB# - - Note3 ++// 28 FRE# MSC0_D0 - ++// 29 FWE# MSC0_D1 - ++// 30 - - - Note4 ++// 31 - - - Note5 ++// ++// Note2: BIT20: it is WIAT# pin when chip is reset ++// ++// Note3: BIT27: when NAND is used, it should connect to NANF FRB#. ++// ++// Note4: BIT30: it is BOOT_SEL0 which would be set as input without pulling when chip is reset. ++// ++// Note5: BIT31: it is BOOT_SEL1 which would be set as input without pulling when chip is reset. ++// ++//------------------------------------------------------ ++// PORT 3: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 0 LCD_B2 - ++// 1 LCD_B3 - ++// 2 LCD_B4 - ++// 3 LCD_B5 - ++// 4 LCD_B6 - ++// 5 LCD_B7 - ++// 6 LCD_G2 - ++// 7 LCD_G3 - ++// 8 LCD_G4 - ++// 9 LCD_G5 - ++// 10 LCD_G6 - ++// 11 LCD_G7 - ++// 12 LCD_R2 - ++// 13 LCD_R3 - ++// 14 LCD_R4 - ++// 15 LCD_R5 - ++// 16 LCD_R6 - ++// 17 LCD_R7 - ++// 18 LCD_PCLK - ++// 19 LCD_HSYNC - ++// 20 LCD_VSYNC - ++// 21 LCD_DE - ++// 22 LCD_CLS LCD_R1 ++// 23 LCD_SPL LCD_G0 ++// 24 LCD_PS LCD_G1 ++// 25 LCD_REV LCD_B1 ++// 26 LCD_B0 - ++// 27 LCD_R0 - ++// 28 UART0_RXD TSCLK ++// 29 UART0_TXD TSSTR ++// 30 UART0_CTS TSFRM ++// 31 UART0_RTS TSFAIL ++// ++//------------------------------------------------------ ++// PORT 4: ++// ++// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE ++// 0 CIM_D0 TSDI0 - ++// 1 CIM_D1 TSDI1 - ++// 2 CIM_D2 TSDI2 - ++// 3 CIM_D3 TSDI3 - ++// 4 CIM_D4 TSDI4 - ++// 5 CIM_D5 TSDI5 - ++// 6 CIM_D6 TSDI6 - ++// 7 CIM_D7 TSDI7 - ++// 8 CIM_MCLK TSFAIL - ++// 9 CIM_PCLK TSCLK - ++// 10 CIM_VSYNC TSSTR - ++// 11 CIM_HSYNC TSFRM - ++// 12 I2C_SDA - - ++// 13 I2C_SCK - - ++// 18 SDATO - - ++// 19 SDATI - - ++// 20 PWM0 - - ++// 22 PWM2 SYNC - ++// 23 PWM3 UART1_RxD BCLK ++// 24 PWM4 - - ++// 25 PWM5 UART1_TxD SCLK_RSTN ++// 28 DCS1# - - ++// 29 - - - Note6 ++// 30 WKUP - - Note7 ++// 31 - - - Note8 ++// ++// Note6: BIT29: it is BOOT_SEL2 which would be set as input without pulling when chip is reset. ++// Note7: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down ++// Note8: BIT31: it is used to select the function of UART or JTAG set by PESEL[31] ++// PESEL[31] = 0, select JTAG function ++// PESEL[31] = 1, select UART function ++// ++//------------------------------------------------------ ++// PORT 5: ++// ++// PIN/BIT N FUNC0 FUNC1 NOTE ++// 10 SSI_CLK - ++// 11 SSI_DT PWM1 ++// 12 SSI_DR - ++// 13 SSI_CE0# - ++// 14 SSI_GPC - ++// 15 SSI_CE2# - ++// ++////////////////////////////////////////////////////////// ++ ++/*---------------------------------------------------------------- ++ * p is the port number (0,1,2,3,4,5) ++ * o is the pin offset (0-31) inside the port ++ * n is the absolute number of a pin (0-127), regardless of the port ++ */ ++ ++//------------------------------------------- ++// Function Pins Mode ++ ++#define __gpio_as_func0(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXSELC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_func1(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_func2(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFUNS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXSELC(p) = (1 << o); \ ++} while (0) ++ ++/* ++ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#, ++ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# ++ */ ++#define __gpio_as_sdram_32bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0xffffffff; \ ++ REG_GPIO_PXSELC(0) = 0xffffffff; \ ++ REG_GPIO_PXPES(0) = 0xffffffff; \ ++ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0x03ff7fff; \ ++} while (0) ++ ++ ++/* ++ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#, ++ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# ++ * !!!!DCS1# ++ */ ++#define __gpio_as_sdram_x2_32bit() \ ++do { \ ++ REG_GPIO_PXFUNS(0) = 0xffffffff; \ ++ REG_GPIO_PXSELC(0) = 0xffffffff; \ ++ REG_GPIO_PXPES(0) = 0xffffffff; \ ++ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0x03ff7fff; \ ++ REG_GPIO_PXFUNS(4) = 0x10000000; \ ++ REG_GPIO_PXSELC(4) = 0x10000000; \ ++ REG_GPIO_PXPES(4) = 0x10000000; \ ++} while (0) ++ ++/* ++ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#, ++ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# ++ */ ++#define __gpio_as_sdram_16bit() \ ++do { \ ++ /* 32/16-bit data normal order */ \ ++ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ ++ REG_GPIO_PXSELC(0) = 0x0000ffff; \ ++ REG_GPIO_PXPES(0) = 0x0000ffff; \ ++ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ ++ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ ++ REG_GPIO_PXPES(1) = 0x03ff7fff; \ ++} while (0) ++ ++/* ++ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nand_8bit(n) \ ++do { \ ++ /* 32/16-bit data bus */ \ ++ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \ ++ REG_GPIO_PXSELC(0) = 0x000000ff; \ ++ REG_GPIO_PXPES(0) = 0x000000ff; \ ++ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(A15) */ \ ++ REG_GPIO_PXSELC(1) = 0x00008000; \ ++ REG_GPIO_PXPES(1) = 0x00008000; \ ++ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(A16) */ \ ++ REG_GPIO_PXSELC(2) = 0x00010000; \ ++ REG_GPIO_PXPES(2) = 0x00010000; \ ++ \ ++ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ ++ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ ++ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ ++ \ ++ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \ ++ REG_GPIO_PXSELC(1) = 0x00080000; \ ++ REG_GPIO_PXPES(1) = 0x00080000; \ ++ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \ ++ REG_GPIO_PXSELC(2) = 0x30000000; \ ++ REG_GPIO_PXPES(2) = 0x30000000; \ ++ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \ ++ REG_GPIO_PXSELC(2) = 0x08000000; \ ++ REG_GPIO_PXDIRC(2) = 0x08000000; \ ++ REG_GPIO_PXPES(2) = 0x08000000; \ ++} while (0) ++ ++ ++/* ++ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nor_8bit(n) \ ++do { \ ++ /* 32/16-bit data bus */ \ ++ REG_GPIO_PXFUNS(0) = 0x000000ff; \ ++ REG_GPIO_PXSELC(0) = 0x000000ff; \ ++ REG_GPIO_PXPES(0) = 0x000000ff; \ ++ \ ++ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ ++ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ ++ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ ++ \ ++ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ ++ REG_GPIO_PXSELC(1) = 0x0000ffff; \ ++ REG_GPIO_PXPES(1) = 0x0000ffff; \ ++ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ ++ REG_GPIO_PXSELC(2) = 0x06110007; \ ++ REG_GPIO_PXPES(2) = 0x06110007; \ ++ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ ++ REG_GPIO_PXSELS(2) = 0x000e0000; \ ++ REG_GPIO_PXPES(2) = 0x000e0000; \ ++} while (0) ++ ++/* ++ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nor_16bit(n) \ ++do { \ ++ /* 32/16-bit data normal order */ \ ++ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ ++ REG_GPIO_PXSELC(0) = 0x0000ffff; \ ++ REG_GPIO_PXPES(0) = 0x0000ffff; \ ++ \ ++ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ ++ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ ++ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ ++ \ ++ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ ++ REG_GPIO_PXSELC(1) = 0x0000ffff; \ ++ REG_GPIO_PXPES(1) = 0x0000ffff; \ ++ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ ++ REG_GPIO_PXSELC(2) = 0x06110007; \ ++ REG_GPIO_PXPES(2) = 0x06110007; \ ++ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ ++ REG_GPIO_PXSELS(2) = 0x000e0000; \ ++ REG_GPIO_PXPES(2) = 0x000e0000; \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART0_RxD ++ */ ++#define __gpio_as_uart0() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x30000000; \ ++ REG_GPIO_PXSELC(3) = 0x30000000; \ ++ REG_GPIO_PXPES(3) = 0x30000000; \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS ++ */ ++#define __gpio_as_uart0_ctsrts() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0xf0000000; \ ++ REG_GPIO_PXSELC(3) = 0xf0000000; \ ++ REG_GPIO_PXPES(3) = 0xf0000000; \ ++} while (0) ++ ++/* ++ * UART1_TxD, UART1_RxD ++ */ ++#define __gpio_as_uart1() \ ++do { \ ++ REG_GPIO_PXTRGC(4) = 0x02800000; \ ++ REG_GPIO_PXFUNS(4) = 0x02800000; \ ++ REG_GPIO_PXSELS(4) = 0x02800000; \ ++ REG_GPIO_PXPES(4) = 0x02800000; \ ++} while (0) ++ ++/* ++ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7 ++ */ ++#define __gpio_as_tssi() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x0000ff00; \ ++ REG_GPIO_PXSELS(2) = 0x0000ff00; \ ++ REG_GPIO_PXPES(2) = 0x0000ff00; \ ++ REG_GPIO_PXFUNS(3) = 0xf0000000; \ ++ REG_GPIO_PXSELS(3) = 0xf0000000; \ ++ REG_GPIO_PXPES(3) = 0xf0000000; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_8bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003c00ff; \ ++ REG_GPIO_PXTRGC(3) = 0x003c00ff; \ ++ REG_GPIO_PXSELC(3) = 0x003c00ff; \ ++ REG_GPIO_PXPES(3) = 0x003c00ff; \ ++} while (0) ++ ++/* ++ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_16bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003cffff; \ ++ REG_GPIO_PXTRGC(3) = 0x003cffff; \ ++ REG_GPIO_PXSELC(3) = 0x003cffff; \ ++ REG_GPIO_PXPES(3) = 0x003cffff; \ ++} while (0) ++ ++/* ++ * LCD_R2~LCD_R7, LCD_G2~LCD_G7, LCD_B2~LCD_B7, ++ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_18bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x003fffff; \ ++ REG_GPIO_PXTRGC(3) = 0x003fffff; \ ++ REG_GPIO_PXSELC(3) = 0x003fffff; \ ++ REG_GPIO_PXPES(3) = 0x003fffff; \ ++} while (0) ++ ++/* ++ * LCD_R0~LCD_R7, LCD_G0~LCD_G7, LCD_B0~LCD_B7, ++ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE ++ */ ++#define __gpio_as_lcd_24bit() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x0fffffff; \ ++ REG_GPIO_PXTRGC(3) = 0x0fffffff; \ ++ REG_GPIO_PXSELC(3) = 0x0c3fffff; \ ++ REG_GPIO_PXSELS(3) = 0x03c00000; \ ++ REG_GPIO_PXPES(3) = 0x0fffffff; \ ++} while (0) ++ ++/* ++ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV ++ */ ++#define __gpio_as_lcd_special() \ ++do { \ ++ REG_GPIO_PXFUNS(3) = 0x03C00000; \ ++ REG_GPIO_PXSELC(3) = 0x03C00000; \ ++ REG_GPIO_PXPES(3) = 0x03C00000; \ ++} while (0) ++ ++/* ++ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC ++ */ ++#define __gpio_as_cim() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00000fff; \ ++ REG_GPIO_PXSELC(4) = 0x00000fff; \ ++ REG_GPIO_PXPES(4) = 0x00000fff; \ ++} while (0) ++ ++/* ++ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or ++ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec) ++ */ ++#define __gpio_as_aic() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x16c00000; \ ++ REG_GPIO_PXTRGC(4) = 0x02c00000; \ ++ REG_GPIO_PXTRGS(4) = 0x14000000; \ ++ REG_GPIO_PXSELC(4) = 0x14c00000; \ ++ REG_GPIO_PXSELS(4) = 0x02000000; \ ++ REG_GPIO_PXPES(4) = 0x16c00000; \ ++} while (0) ++ ++/* ++ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3 ++ */ ++#define __gpio_as_msc0_4bit() \ ++do { \ ++ REG_GPIO_PXFUNS(1) = 0x00008000; \ ++ REG_GPIO_PXTRGS(1) = 0x00008000; \ ++ REG_GPIO_PXSELC(1) = 0x00008000; \ ++ REG_GPIO_PXPES(1) = 0x00008000; \ ++ REG_GPIO_PXFUNS(2) = 0x38030000; \ ++ REG_GPIO_PXTRGS(2) = 0x00010000; \ ++ REG_GPIO_PXTRGC(2) = 0x38020000; \ ++ REG_GPIO_PXSELC(2) = 0x08010000; \ ++ REG_GPIO_PXSELS(2) = 0x30020000; \ ++ REG_GPIO_PXPES(2) = 0x38030000; \ ++} while (0) ++ ++ ++/* ++ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3 ++ */ ++#define __gpio_as_msc1_4bit() \ ++do { \ ++ REG_GPIO_PXFUNS(1) = 0xfc000000; \ ++ REG_GPIO_PXTRGC(1) = 0xfc000000; \ ++ REG_GPIO_PXSELS(1) = 0xfc000000; \ ++ REG_GPIO_PXPES(1) = 0xfc000000; \ ++} while (0) ++ ++#define __gpio_as_msc __gpio_as_msc0_4bit /* default as msc0 4bit */ ++#define __gpio_as_msc0 __gpio_as_msc0_4bit /* msc0 default as 4bit */ ++#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */ ++ ++/* ++ * SSI_CE0, SSI_CE1, SSI_GPC, SSI_CLK, SSI_DT, SSI_DR ++ */ ++#define __gpio_as_ssi() \ ++do { \ ++ REG_GPIO_PXFUNS(1) = 0xfc000000; \ ++ REG_GPIO_PXTRGC(1) = 0xfc000000; \ ++ REG_GPIO_PXSELC(1) = 0xfc000000; \ ++ REG_GPIO_PXPES(1) = 0xfc000000; \ ++} while (0) ++ ++/* ++ * SSI_CE0, SSI_CE2, SSI_GPC, SSI_CLK, SSI_DT, SSI1_DR ++ */ ++#define __gpio_as_ssi_1() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x0000fc00; \ ++ REG_GPIO_PXTRGC(5) = 0x0000fc00; \ ++ REG_GPIO_PXSELC(5) = 0x0000fc00; \ ++ REG_GPIO_PXPES(5) = 0x0000fc00; \ ++} while (0) ++ ++/* ++ * I2C_SCK, I2C_SDA ++ */ ++#define __gpio_as_i2c() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00003000; \ ++ REG_GPIO_PXSELC(4) = 0x00003000; \ ++ REG_GPIO_PXPES(4) = 0x00003000; \ ++} while (0) ++ ++/* ++ * PWM0 ++ */ ++#define __gpio_as_pwm0() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00100000; \ ++ REG_GPIO_PXSELC(4) = 0x00100000; \ ++ REG_GPIO_PXPES(4) = 0x00100000; \ ++} while (0) ++ ++/* ++ * PWM1 ++ */ ++#define __gpio_as_pwm1() \ ++do { \ ++ REG_GPIO_PXFUNS(5) = 0x00000800; \ ++ REG_GPIO_PXSELC(5) = 0x00000800; \ ++ REG_GPIO_PXPES(5) = 0x00000800; \ ++} while (0) ++ ++/* ++ * PWM2 ++ */ ++#define __gpio_as_pwm2() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00400000; \ ++ REG_GPIO_PXSELC(4) = 0x00400000; \ ++ REG_GPIO_PXPES(4) = 0x00400000; \ ++} while (0) ++ ++/* ++ * PWM3 ++ */ ++#define __gpio_as_pwm3() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x00800000; \ ++ REG_GPIO_PXSELC(4) = 0x00800000; \ ++ REG_GPIO_PXPES(4) = 0x00800000; \ ++} while (0) ++ ++/* ++ * PWM4 ++ */ ++#define __gpio_as_pwm4() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x01000000; \ ++ REG_GPIO_PXSELC(4) = 0x01000000; \ ++ REG_GPIO_PXPES(4) = 0x01000000; \ ++} while (0) ++ ++/* ++ * PWM5 ++ */ ++#define __gpio_as_pwm5() \ ++do { \ ++ REG_GPIO_PXFUNS(4) = 0x02000000; \ ++ REG_GPIO_PXSELC(4) = 0x02000000; \ ++ REG_GPIO_PXPES(4) = 0x02000000; \ ++} while (0) ++ ++/* ++ * n = 0 ~ 5 ++ */ ++#define __gpio_as_pwm(n) __gpio_as_pwm##n() ++ ++/* ++ * DREQ ++ */ ++#define __gpio_as_dreq() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x00040000; \ ++ REG_GPIO_PXSELS(2) = 0x00040000; \ ++ REG_GPIO_PXPES(2) = 0x00040000; \ ++} while (0) ++ ++/* ++ * DACK ++ */ ++#define __gpio_as_dack() \ ++do { \ ++ REG_GPIO_PXFUNS(2) = 0x00080000; \ ++ REG_GPIO_PXSELS(2) = 0x00080000; \ ++ REG_GPIO_PXPES(2) = 0x00080000; \ ++} while (0) ++ ++/* ++ * GPIO or Interrupt Mode ++ */ ++#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) ++ ++#define __gpio_port_as_output(p, o) \ ++do { \ ++ REG_GPIO_PXFUNC(p) = (1 << (o)); \ ++ REG_GPIO_PXSELC(p) = (1 << (o)); \ ++ REG_GPIO_PXDIRS(p) = (1 << (o)); \ ++} while (0) ++ ++#define __gpio_port_as_input(p, o) \ ++do { \ ++ REG_GPIO_PXFUNC(p) = (1 << (o)); \ ++ REG_GPIO_PXSELC(p) = (1 << (o)); \ ++ REG_GPIO_PXDIRC(p) = (1 << (o)); \ ++} while (0) ++ ++#define __gpio_as_output(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_output(p, o); \ ++} while (0) ++ ++#define __gpio_as_input(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ __gpio_port_as_input(p, o); \ ++} while (0) ++ ++#define __gpio_set_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXDATS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_clear_pin(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXDATC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_get_pin(n) \ ++({ \ ++ unsigned int p, o, v; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ if (__gpio_get_port(p) & (1 << o)) \ ++ v = 1; \ ++ else \ ++ v = 0; \ ++ v; \ ++}) ++ ++#define __gpio_as_irq_high_level(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRS(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_low_level(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGC(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRC(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_rise_edge(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRS(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_as_irq_fall_edge(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++ REG_GPIO_PXTRGS(p) = (1 << o); \ ++ REG_GPIO_PXFUNC(p) = (1 << o); \ ++ REG_GPIO_PXSELS(p) = (1 << o); \ ++ REG_GPIO_PXDIRC(p) = (1 << o); \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_mask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMS(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_unmask_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXIMC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_ack_irq(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXFLGC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_get_irq() \ ++({ \ ++ unsigned int p, i, tmp, v = 0; \ ++ for (p = 3; p >= 0; p--) { \ ++ tmp = REG_GPIO_PXFLG(p); \ ++ for (i = 0; i < 32; i++) \ ++ if (tmp & (1 << i)) \ ++ v = (32*p + i); \ ++ } \ ++ v; \ ++}) ++ ++#define __gpio_group_irq(n) \ ++({ \ ++ register int tmp, i; \ ++ tmp = REG_GPIO_PXFLG((n)); \ ++ for (i=31;i>=0;i--) \ ++ if (tmp & (1 << i)) \ ++ break; \ ++ i; \ ++}) ++ ++#define __gpio_enable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXPEC(p) = (1 << o); \ ++} while (0) ++ ++#define __gpio_disable_pull(n) \ ++do { \ ++ unsigned int p, o; \ ++ p = (n) / 32; \ ++ o = (n) % 32; \ ++ REG_GPIO_PXPES(p) = (1 << o); \ ++} while (0) ++ ++ ++/*************************************************************************** ++ * CPM ++ ***************************************************************************/ ++#define __cpm_get_pllm() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) ++#define __cpm_get_plln() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) ++#define __cpm_get_pllod() \ ++ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) ++ ++#define __cpm_get_cdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) ++#define __cpm_get_hdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) ++#define __cpm_get_pdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) ++#define __cpm_get_mdiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) ++#define __cpm_get_h1div() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_H1DIV_MASK) >> CPM_CPCCR_H1DIV_BIT) ++#define __cpm_get_udiv() \ ++ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) ++#define __cpm_get_i2sdiv() \ ++ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) ++#define __cpm_get_pixdiv() \ ++ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) ++#define __cpm_get_mscdiv(n) \ ++ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) ++#define __cpm_get_uhcdiv() \ ++ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) ++#define __cpm_get_ssidiv() \ ++ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) ++#define __cpm_get_pcmdiv(v) \ ++ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT) ++ ++#define __cpm_set_cdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) ++#define __cpm_set_hdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) ++#define __cpm_set_pdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) ++#define __cpm_set_mdiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) ++#define __cpm_set_h1div(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_H1DIV_MASK) | ((v) << (CPM_CPCCR_H1DIV_BIT))) ++#define __cpm_set_udiv(v) \ ++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) ++#define __cpm_set_i2sdiv(v) \ ++ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) ++#define __cpm_set_pixdiv(v) \ ++ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) ++#define __cpm_set_mscdiv(n, v) \ ++ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) ++#define __cpm_set_uhcdiv(v) \ ++ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) ++#define __cpm_set_ssidiv(v) \ ++ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) ++#define __cpm_set_pcmdiv(v) \ ++ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT))) ++ ++#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS) ++#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS) ++#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS) ++#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS) ++#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS) ++#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS) ++#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) ++#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) ++#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) ++#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) ++ ++#define __cpm_enable_cko() ++#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS) ++#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS) ++#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) ++#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) ++#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) ++#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) ++ ++#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF) ++#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON) ++#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP) ++ ++#define __cpm_get_cclk_doze_duty() \ ++ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) ++#define __cpm_set_cclk_doze_duty(v) \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) ++ ++#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) ++#define __cpm_idle_mode() \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) ++#define __cpm_sleep_mode() \ ++ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) ++ ++#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff) ++#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM) ++#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT) ++#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB) ++#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME) ++#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC) ++#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE) ++#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI) ++#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI) ++#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM) ++#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3) ++#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2) ++#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) ++#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) ++#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) ++#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) ++#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) ++#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) ++#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) ++#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) ++#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n) ++#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) ++#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) ++#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n) ++#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) ++#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) ++#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) ++#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) ++ ++#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) ++#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM) ++#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT) ++#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB) ++#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME) ++#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC) ++#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE) ++#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI) ++#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI) ++#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM) ++#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3) ++#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2) ++#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) ++#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) ++#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) ++#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) ++#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) ++#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) ++#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) ++#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) ++#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n) ++#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) ++#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) ++#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n) ++#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) ++#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) ++#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) ++#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) ++ ++#define __cpm_get_o1st() \ ++ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT) ++#define __cpm_set_o1st(v) \ ++ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT))) ++#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE) ++#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE) ++#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE) ++#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE) ++#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE) ++#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE) ++#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS) ++#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS) ++ ++ ++/*************************************************************************** ++ * TCU ++ ***************************************************************************/ ++// where 'n' is the TCU channel ++#define __tcu_select_extalclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) ++#define __tcu_select_rtcclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) ++#define __tcu_select_pclk(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) ++#define __tcu_disable_pclk(n) \ ++ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN); ++#define __tcu_select_clk_div1(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) ++#define __tcu_select_clk_div4(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) ++#define __tcu_select_clk_div16(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) ++#define __tcu_select_clk_div64(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) ++#define __tcu_select_clk_div256(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) ++#define __tcu_select_clk_div1024(n) \ ++ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) ++ ++#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN) ++#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN) ++ ++#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH) ++#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH) ++ ++#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD) ++#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD) ++ ++#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ) ++ ++#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN) ++#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST) ++#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL) ++ ++#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n))) ++#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n))) ++#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n))) ++ ++#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16))) ++#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n))) ++#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16))) ++#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n))) ++#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16))) ++#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n))) ++#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16))) ++#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n))) ++#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16))) ++#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n))) ++ ++#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG) ++#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST) ++#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL) ++#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK) ++#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST) ++#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL) ++ ++#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC) ++#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST) ++#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n))) ++ ++#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC) ++#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC) ++#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n))) ++ ++#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC) ++#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS) ++#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n))) ++ ++#define __tcu_get_count(n) (REG_TCU_TCNT((n))) ++#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v)) ++#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v)) ++#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v)) ++ ++/* TCU2, counter 1, 2*/ ++#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) ++#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) ++#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n))) ++#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n))) ++ ++#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16))) ++#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16))) ++#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n))) ++#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n))) ++ ++/* ost counter */ ++#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD) ++#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD) ++#define __ostcu_select_clk_div1() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1) ++#define __ostcu_select_clk_div4() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4) ++#define __ostcu_select_clk_div16() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16) ++#define __ostcu_select_clk_div64() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64) ++#define __ostcu_select_clk_div256() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256) ++#define __ostcu_select_clk_div1024() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024) ++#define __ostcu_select_rtcclk() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN) ++#define __ostcu_select_extalclk() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN) ++#define __ostcu_select_pclk() \ ++ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN) ++ ++ ++/*************************************************************************** ++ * WDT ++ ***************************************************************************/ ++#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) ++#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) ++#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) ++#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) ++ ++#define __wdt_select_extalclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) ++#define __wdt_select_rtcclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) ++#define __wdt_select_pclk() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) ++ ++#define __wdt_select_clk_div1() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) ++#define __wdt_select_clk_div4() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) ++#define __wdt_select_clk_div16() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) ++#define __wdt_select_clk_div64() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) ++#define __wdt_select_clk_div256() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) ++#define __wdt_select_clk_div1024() \ ++ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) ++ ++ ++/*************************************************************************** ++ * UART ++ ***************************************************************************/ ++ ++#define __uart_enable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) ++#define __uart_disable(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) ++ ++#define __uart_enable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) ++#define __uart_disable_transmit_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) ++ ++#define __uart_enable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) ++#define __uart_disable_receive_irq(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) ++ ++#define __uart_enable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) ++#define __uart_disable_loopback(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) ++ ++#define __uart_set_8n1(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) ++ ++#define __uart_set_baud(n, devclk, baud) \ ++ do { \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ ++ } while (0) ++ ++#define __uart_parity_error(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) ++ ++#define __uart_clear_errors(n) \ ++ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) ++ ++#define __uart_transmit_fifo_empty(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) ++ ++#define __uart_transmit_end(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) ++ ++#define __uart_transmit_char(n, ch) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) ++ ++#define __uart_receive_fifo_full(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_ready(n) \ ++ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) ++ ++#define __uart_receive_char(n) \ ++ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) ++ ++#define __uart_disable_irda() \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) ++#define __uart_enable_irda() \ ++ /* Tx high pulse as 0, Rx low pulse as 0 */ \ ++ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) ++ ++ ++/*************************************************************************** ++ * DMAC ++ ***************************************************************************/ ++ ++/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */ ++ ++#define __dmac_enable_module(m) \ ++ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 ) ++#define __dmac_disable_module(m) \ ++ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE ) ++ ++/* p=0,1,2,3 */ ++#define __dmac_set_priority(m,p) \ ++do { \ ++ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \ ++ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \ ++} while (0) ++ ++#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT ) ++#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR ) ++ ++#define __dmac_channel_enable_clk(n) \ ++ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM); ++ ++#define __dmac_enable_descriptor(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) ++#define __dmac_disable_descriptor(n) \ ++ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) ++ ++#define __dmac_enable_channel(n) \ ++do { \ ++ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \ ++} while (0) ++#define __dmac_disable_channel(n) \ ++do { \ ++ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \ ++} while (0) ++#define __dmac_channel_enabled(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) ++ ++#define __dmac_channel_enable_irq(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) ++#define __dmac_channel_disable_irq(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) ++ ++#define __dmac_channel_transmit_halt_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) ++#define __dmac_channel_transmit_end_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) ++#define __dmac_channel_address_error_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) ++#define __dmac_channel_count_terminated_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) ++#define __dmac_channel_descriptor_invalid_detected(n) \ ++ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) ++ ++#define __dmac_channel_clear_transmit_halt(n) \ ++ do { \ ++ /* clear both channel halt error and globle halt error */ \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \ ++ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \ ++ } while (0) ++#define __dmac_channel_clear_transmit_end(n) \ ++ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) ++#define __dmac_channel_clear_address_error(n) \ ++ do { \ ++ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \ ++ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \ ++ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \ ++ /* clear both channel addr error and globle address error */ \ ++ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \ ++ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \ ++ } while (0) ++#define __dmac_channel_clear_count_terminated(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) ++#define __dmac_channel_clear_descriptor_invalid(n) \ ++ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) ++ ++#define __dmac_channel_set_transfer_unit_32bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_8bit(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_16byte(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ ++} while (0) ++ ++#define __dmac_channel_set_transfer_unit_32byte(n) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_dest_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ ++} while (0) ++ ++/* w=8,16,32 */ ++#define __dmac_channel_set_src_port_width(n,w) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ ++ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ ++} while (0) ++ ++/* v=0-15 */ ++#define __dmac_channel_set_rdil(n,v) \ ++do { \ ++ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ ++ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ ++} while (0) ++ ++#define __dmac_channel_dest_addr_fixed(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) ++#define __dmac_channel_dest_addr_increment(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) ++ ++#define __dmac_channel_src_addr_fixed(n) \ ++ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) ++#define __dmac_channel_src_addr_increment(n) \ ++ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) ++ ++#define __dmac_channel_set_doorbell(n) \ ++ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) ++ ++#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) ++#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) ++ ++static __inline__ int __dmac_get_irq(void) ++{ ++ int i; ++ for (i = 0; i < MAX_DMA_NUM; i++) ++ if (__dmac_channel_irq_detected(i)) ++ return i; ++ return -1; ++} ++ ++ ++/*************************************************************************** ++ * AIC (AC'97 & I2S Controller) ++ ***************************************************************************/ ++ ++#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) ++#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) ++ ++#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) ++#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) ++ ++#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) ++#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) ++ ++#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) ++#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) ++#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) ++ ++#define __aic_reset() \ ++do { \ ++ REG_AIC_FR |= AIC_FR_RST; \ ++} while(0) ++ ++ ++#define __aic_set_transmit_trigger(n) \ ++do { \ ++ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ ++ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ ++} while(0) ++ ++#define __aic_set_receive_trigger(n) \ ++do { \ ++ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ ++ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ ++} while(0) ++ ++#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) ++#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) ++#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) ++#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) ++#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) ++#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) ++ ++#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) ++#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) ++ ++#define __aic_enable_transmit_intr() \ ++ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) ++#define __aic_disable_transmit_intr() \ ++ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) ++#define __aic_enable_receive_intr() \ ++ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) ++#define __aic_disable_receive_intr() \ ++ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) ++ ++#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) ++#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) ++#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) ++#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) ++ ++#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) ++#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) ++#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) ++#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) ++#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) ++#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) ++ ++#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 ++#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 ++#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 ++#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 ++#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 ++#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 ++ ++#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 ++#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 ++#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 ++#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 ++#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 ++#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 ++ ++#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) ++#define __ac97_set_xs_mono() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ ++} while(0) ++#define __ac97_set_xs_stereo() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ ++} while(0) ++ ++/* In fact, only stereo is support now. */ ++#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) ++#define __ac97_set_rs_mono() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ ++} while(0) ++#define __ac97_set_rs_stereo() \ ++do { \ ++ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ ++ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ ++} while(0) ++ ++#define __ac97_warm_reset_codec() \ ++ do { \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ ++ udelay(2); \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ ++ } while (0) ++ ++#define __ac97_cold_reset_codec() \ ++ do { \ ++ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ ++ udelay(2); \ ++ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ ++ } while (0) ++ ++/* n=8,16,18,20 */ ++#define __ac97_set_iass(n) \ ++ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) ++#define __ac97_set_oass(n) \ ++ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) ++ ++#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) ++#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) ++ ++/* n=8,16,18,20,24 */ ++/*#define __i2s_set_sample_size(n) \ ++ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ ++ ++#define __i2s_set_oss_sample_size(n) \ ++ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) ++#define __i2s_set_iss_sample_size(n) \ ++ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) ++ ++#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) ++#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) ++ ++#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) ++#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) ++#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) ++#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) ++ ++#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) ++ ++#define __aic_get_transmit_resident() \ ++ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) ++#define __aic_get_receive_count() \ ++ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) ++ ++#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) ++#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) ++#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) ++#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) ++#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) ++#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) ++#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) ++ ++#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) ++ ++#define CODEC_READ_CMD (1 << 19) ++#define CODEC_WRITE_CMD (0 << 19) ++#define CODEC_REG_INDEX_BIT 12 ++#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ ++#define CODEC_REG_DATA_BIT 4 ++#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ ++ ++#define __ac97_out_rcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_wcmd_addr(reg) \ ++do { \ ++ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ ++} while (0) ++ ++#define __ac97_out_data(value) \ ++do { \ ++ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ ++} while (0) ++ ++#define __ac97_in_data() \ ++ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) ++ ++#define __ac97_in_status_addr() \ ++ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) ++ ++#define __i2s_set_sample_rate(i2sclk, sync) \ ++ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) ++ ++#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) ++#define __aic_read_rfifo() ( REG_AIC_DR ) ++ ++#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) ++#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) ++ ++// ++// Define next ops for AC97 compatible ++// ++ ++#define AC97_ACSR AIC_ACSR ++ ++#define __ac97_enable() __aic_enable(); __aic_select_ac97() ++#define __ac97_disable() __aic_disable() ++#define __ac97_reset() __aic_reset() ++ ++#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __ac97_enable_record() __aic_enable_record() ++#define __ac97_disable_record() __aic_disable_record() ++#define __ac97_enable_replay() __aic_enable_replay() ++#define __ac97_disable_replay() __aic_disable_replay() ++#define __ac97_enable_loopback() __aic_enable_loopback() ++#define __ac97_disable_loopback() __aic_disable_loopback() ++ ++#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __ac97_enable_receive_dma() __aic_enable_receive_dma() ++#define __ac97_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __ac97_transmit_request() __aic_transmit_request() ++#define __ac97_receive_request() __aic_receive_request() ++#define __ac97_transmit_underrun() __aic_transmit_underrun() ++#define __ac97_receive_overrun() __aic_receive_overrun() ++ ++#define __ac97_clear_errors() __aic_clear_errors() ++ ++#define __ac97_get_transmit_resident() __aic_get_transmit_resident() ++#define __ac97_get_receive_count() __aic_get_receive_count() ++ ++#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __ac97_enable_receive_intr() __aic_enable_receive_intr() ++#define __ac97_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __ac97_write_tfifo(v) __aic_write_tfifo(v) ++#define __ac97_read_rfifo() __aic_read_rfifo() ++ ++// ++// Define next ops for I2S compatible ++// ++ ++#define I2S_ACSR AIC_I2SSR ++ ++#define __i2s_enable() __aic_enable(); __aic_select_i2s() ++#define __i2s_disable() __aic_disable() ++#define __i2s_reset() __aic_reset() ++ ++#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) ++#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) ++ ++#define __i2s_enable_record() __aic_enable_record() ++#define __i2s_disable_record() __aic_disable_record() ++#define __i2s_enable_replay() __aic_enable_replay() ++#define __i2s_disable_replay() __aic_disable_replay() ++#define __i2s_enable_loopback() __aic_enable_loopback() ++#define __i2s_disable_loopback() __aic_disable_loopback() ++ ++#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() ++#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() ++#define __i2s_enable_receive_dma() __aic_enable_receive_dma() ++#define __i2s_disable_receive_dma() __aic_disable_receive_dma() ++ ++#define __i2s_transmit_request() __aic_transmit_request() ++#define __i2s_receive_request() __aic_receive_request() ++#define __i2s_transmit_underrun() __aic_transmit_underrun() ++#define __i2s_receive_overrun() __aic_receive_overrun() ++ ++#define __i2s_clear_errors() __aic_clear_errors() ++ ++#define __i2s_get_transmit_resident() __aic_get_transmit_resident() ++#define __i2s_get_receive_count() __aic_get_receive_count() ++ ++#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() ++#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() ++#define __i2s_enable_receive_intr() __aic_enable_receive_intr() ++#define __i2s_disable_receive_intr() __aic_disable_receive_intr() ++ ++#define __i2s_write_tfifo(v) __aic_write_tfifo(v) ++#define __i2s_read_rfifo() __aic_read_rfifo() ++ ++#define __i2s_reset_codec() \ ++ do { \ ++ } while (0) ++ ++/************************************************************************* ++ * PCM Controller operation ++ *************************************************************************/ ++ ++#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN ) ++#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN ) ++ ++#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN ) ++#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN ) ++ ++#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST ) ++#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH ) ++ ++#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC ) ++#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC ) ++#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL ) ++#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL ) ++ ++#define __pcm_enable_rxfifo() __pcm_enable_record() ++#define __pcm_disable_rxfifo() __pcm_disable_record() ++#define __pcm_enable_txfifo() __pcm_enable_playback() ++#define __pcm_disable_txfifo() __pcm_disable_playback() ++ ++#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP ) ++#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP ) ++ ++#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA ) ++#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA ) ++#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA ) ++#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA ) ++ ++#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE ) ++#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE ) ++ ++#define __pcm_set_transmit_trigger(n) \ ++do { \ ++ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \ ++ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \ ++} while(0) ++ ++#define __pcm_set_receive_trigger(n) \ ++do { \ ++ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \ ++ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \ ++} while(0) ++ ++#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS ) ++#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS ) ++ ++#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS ) ++#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS ) ++ ++/* set input sample size 8 or 16*/ ++#define __pcm_set_iss(n) \ ++( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n ) ++/* set output sample size 8 or 16*/ ++#define __pcm_set_oss(n) \ ++( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n ) ++ ++#define __pcm_set_valid_slot(n) \ ++( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n ) ++ ++#define __pcm_write_data(v) ( REG_PCM_DP = (v) ) ++#define __pcm_read_data() ( REG_PCM_DP ) ++ ++#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS ) ++#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS ) ++ ++#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR ) ++#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR ) ++ ++#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS ) ++#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS ) ++ ++#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR ) ++#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR ) ++ ++#define __pcm_ints_valid_tx() \ ++( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) ) ++#define __pcm_ints_valid_rx() \ ++( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) ) ++ ++#define __pcm_set_clk_div(n) \ ++( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) ) ++ ++/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */ ++#define __pcm_set_clk_rate(sysclk, pcmclk) \ ++__pcm_set_clk_div(((sysclk) / (pcmclk) - 1)) ++ ++#define __pcm_set_sync_div(n) \ ++( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) ) ++ ++/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */ ++#define __pcm_set_sync_rate(pcmclk, sync) \ ++__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1)) ++ ++ /* set sync length in pcmclk n = 0 ... 63 */ ++#define __pcm_set_sync_len(n) \ ++( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) ) ++ ++ ++/*************************************************************************** ++ * ICDC ++ ***************************************************************************/ ++#define __i2s_internal_codec() __aic_internal_codec() ++#define __i2s_external_codec() __aic_external_codec() ++ ++#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY ) ++#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD ) ++#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD ) ++ ++#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR ) ++#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR ) ++#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR ) ++ ++#define __icdc_set_addr(n) \ ++do { \ ++ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \ ++ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \ ++} while(0) ++ ++#define __icdc_set_cmd(n) \ ++do { \ ++ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \ ++ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \ ++} while(0) ++ ++#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ ) ++#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK ) ++ ++/*************************************************************************** ++ * INTC ++ ***************************************************************************/ ++#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) ++#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) ++#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */ ++ ++ ++/*************************************************************************** ++ * I2C ++ ***************************************************************************/ ++ ++#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) ++#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) ++ ++#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) ++#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) ++#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) ++#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) ++ ++#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) ++#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) ++#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) ++ ++#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) ++#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) ++#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) ++ ++#define __i2c_set_clk(dev_clk, i2c_clk) \ ++ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) ++ ++#define __i2c_read() ( REG_I2C_DR ) ++#define __i2c_write(val) ( REG_I2C_DR = (val) ) ++ ++ ++/*************************************************************************** ++ * MSC ++ ***************************************************************************/ ++/* n = 0, 1 (MSC0, MSC1) */ ++ ++#define __msc_start_op(n) \ ++ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) ++ ++#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to ) ++#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to ) ++#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd ) ++#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg ) ++#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob ) ++#define __msc_get_nob(n) ( REG_MSC_NOB(n) ) ++#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len ) ++#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat ) ++#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT ) ++#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT ) ++ ++#define __msc_set_cmdat_bus_width1(n) \ ++do { \ ++ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_bus_width4(n) \ ++do { \ ++ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ ++ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \ ++} while(0) ++ ++#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN ) ++#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT ) ++#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY ) ++#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK ) ++#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ ) ++#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN ) ++ ++/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ ++#define __msc_set_cmdat_res_format(n, r) \ ++do { \ ++ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ ++ REG_MSC_CMDAT(n) |= (r); \ ++} while(0) ++ ++#define __msc_clear_cmdat(n) \ ++ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ ++ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ ++ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) ++ ++#define __msc_get_imask(n) ( REG_MSC_IMASK(n) ) ++#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff ) ++#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 ) ++#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ ) ++#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ ) ++#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES ) ++#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES ) ++#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE ) ++#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE ) ++#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE ) ++ ++/* m=0,1,2,3,4,5,6,7 */ ++#define __msc_set_clkrt(n, m) \ ++do { \ ++ REG_MSC_CLKRT(n) = m; \ ++} while(0) ++ ++#define __msc_get_ireg(n) ( REG_MSC_IREG(n) ) ++#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ ) ++#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ ) ++#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE ) ++#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES ) ++#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE ) ++#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE ) ++ ++#define __msc_get_stat(n) ( REG_MSC_STAT(n) ) ++#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0) ++#define __msc_stat_crc_err(n) \ ++ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) ++#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR ) ++#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR ) ++#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES ) ++#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES ) ++#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ ) ++ ++#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) ) ++#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) ) ++#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v ) ++ ++#define __msc_reset(n) \ ++do { \ ++ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \ ++ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \ ++} while (0) ++ ++#define __msc_start_clk(n) \ ++do { \ ++ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \ ++} while (0) ++ ++#define __msc_stop_clk(n) \ ++do { \ ++ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \ ++} while (0) ++ ++#define MMC_CLK 19169200 ++#define SD_CLK 24576000 ++ ++/* msc_clk should little than pclk and little than clk retrieve from card */ ++#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ ++do { \ ++ unsigned int rate, pclk, i; \ ++ pclk = dev_clk; \ ++ rate = type?SD_CLK:MMC_CLK; \ ++ if (msc_clk && msc_clk < pclk) \ ++ pclk = msc_clk; \ ++ i = 0; \ ++ while (pclk < rate) \ ++ { \ ++ i ++; \ ++ rate >>= 1; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++/* divide rate to little than or equal to 400kHz */ ++#define __msc_calc_slow_clk_divisor(type, lv) \ ++do { \ ++ unsigned int rate, i; \ ++ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ ++ i = 0; \ ++ while (rate > 0) \ ++ { \ ++ rate >>= 1; \ ++ i ++; \ ++ } \ ++ lv = i; \ ++} while(0) ++ ++ ++/*************************************************************************** ++ * SSI (Synchronous Serial Interface) ++ ***************************************************************************/ ++/* n = 0, 1 (SSI0, SSI1) */ ++#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE ) ++#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE ) ++#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL ) ++ ++#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK ) ++ ++#define __ssi_select_ce2(n) \ ++do { \ ++ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_select_gpc(n) \ ++do { \ ++ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \ ++ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \ ++} while (0) ++ ++#define __ssi_underrun_auto_clear(n) \ ++do { \ ++ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \ ++} while (0) ++ ++#define __ssi_underrun_clear_manually(n) \ ++do { \ ++ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \ ++} while (0) ++ ++#define __ssi_enable_tx_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE ) ++ ++#define __ssi_disable_tx_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) ++ ++#define __ssi_enable_rx_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE ) ++ ++#define __ssi_disable_rx_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) ++ ++#define __ssi_enable_txfifo_half_empty_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TIE ) ++#define __ssi_disable_txfifo_half_empty_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE ) ++#define __ssi_enable_tx_error_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE ) ++#define __ssi_disable_tx_error_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE ) ++#define __ssi_enable_rxfifo_half_full_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_RIE ) ++#define __ssi_disable_rxfifo_half_full_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE ) ++#define __ssi_enable_rx_error_intr(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_REIE ) ++#define __ssi_disable_rx_error_intr(n) \ ++ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE ) ++ ++#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP ) ++#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP ) ++ ++#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV ) ++#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV ) ++ ++#define __ssi_finish_receive(n) \ ++ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_disable_recvfinish(n) \ ++ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) ++ ++#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH ) ++#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH ) ++ ++#define __ssi_flush_fifo(n) \ ++ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) ++ ++#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN ) ++#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN ) ++#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n) ++#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n) ++ ++#define __ssi_spi_format(n) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \ ++ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ ++ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ ++ } while (0) ++ ++/* TI's SSP format, must clear SSI_CR1.UNFIN */ ++#define __ssi_ssp_format(n) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ ++ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \ ++ } while (0) ++ ++/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ ++#define __ssi_microwire_format(n) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ ++ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \ ++ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ ++ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ ++ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \ ++ } while (0) ++ ++/* CE# level (FRMHL), CE# in interval time (ITFRM), ++ clock phase and polarity (PHA POL), ++ interval time (SSIITR), interval characters/frame (SSIICR) */ ++ ++/* frmhl,endian,mcom,flen,pha,pol MASK */ ++#define SSICR1_MISC_MASK \ ++ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ ++ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) ++ ++#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \ ++ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \ ++ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ ++ ((pha) << 1) | (pol); \ ++ } while(0) ++ ++/* Transfer with MSB or LSB first */ ++#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST ) ++#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST ) ++ ++#define __ssi_set_frame_length(n, m) \ ++ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4) ++ ++/* m = 1 - 16 */ ++#define __ssi_set_microwire_command_length(n,m) \ ++ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) ) ++ ++/* Set the clock phase for SPI */ ++#define __ssi_set_spi_clock_phase(n, m) \ ++ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1))) ++ ++/* Set the clock polarity for SPI */ ++#define __ssi_set_spi_clock_polarity(n, p) \ ++ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) ) ++ ++/* SSI tx trigger, m = i x 8 */ ++#define __ssi_set_tx_trigger(n, m) \ ++ do { \ ++ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \ ++ REG_SSI_CR1(n) |= ((m)/8)<> SSI_SR_TFIFONUM_BIT ) ++ ++#define __ssi_get_rxfifo_count(n) \ ++ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) ++ ++#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END ) ++#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY ) ++ ++#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF ) ++#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE ) ++#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF ) ++#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE ) ++#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR ) ++#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER ) ++#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR ) ++#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER ) ++#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) ++ ++#define __ssi_set_clk(n, dev_clk, ssi_clk) \ ++ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 ) ++ ++#define __ssi_receive_data(n) REG_SSI_DR(n) ++#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v)) ++ ++ ++/*************************************************************************** ++ * CIM ++ ***************************************************************************/ ++ ++#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) ++#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) ++ ++/* n = 0, 1, 2, 3 */ ++#define __cim_set_input_data_stream_order(n) \ ++ do { \ ++ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \ ++ REG_CIM_CFG |= ((n)<>CIM_SIZE_LPF_BIT) ++#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT) ++ ++#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<>CIM_OFFSET_V_BIT) ++#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT) ++ ++/************************************************************************* ++ * SLCD (Smart LCD Controller) ++ *************************************************************************/ ++#define __slcd_set_data_18bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT ) ++#define __slcd_set_data_16bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT ) ++#define __slcd_set_data_8bit_x3() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 ) ++#define __slcd_set_data_8bit_x2() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 ) ++#define __slcd_set_data_8bit_x1() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 ) ++#define __slcd_set_data_24bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT ) ++#define __slcd_set_data_9bit_x2() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 ) ++ ++#define __slcd_set_cmd_16bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT ) ++#define __slcd_set_cmd_8bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT ) ++#define __slcd_set_cmd_18bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT ) ++#define __slcd_set_cmd_24bit() \ ++ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT ) ++ ++#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH ) ++#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH ) ++ ++#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH ) ++#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH ) ++ ++#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING ) ++#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING ) ++ ++#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL ) ++#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL ) ++ ++/* SLCD Control Register */ ++#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN ) ++#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN ) ++ ++/* SLCD Status Register */ ++#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY ) ++ ++/* SLCD Data Register */ ++#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND) ++#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND) ++ ++ ++/*************************************************************************** ++ * LCD ++ ***************************************************************************/ ++ ++/*************************************************************************** ++ * LCD ++ ***************************************************************************/ ++#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) ++#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) ++ ++#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH ) ++#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH ) ++ ++#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD ) ++#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD ) ++ ++#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES ) ++#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES ) ++ ++#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP ) ++#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP ) ++ ++#define __lcd_set_lcdpnl_term() ( REG_LCD_CFG |= LCD_CFG_TVEN ) ++#define __lcd_set_tv_term() ( REG_LCD_CFG &= ~LCD_CFG_TVEN ) ++ ++#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER ) ++#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER ) ++ ++#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER ) ++#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER ) ++ ++#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM ) ++#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM ) ++ ++#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM ) ++#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM ) ++ ++#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM ) ++#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM ) ++ ++#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM ) ++#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM ) ++ ++#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM ) ++#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM ) ++ ++#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM ) ++#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM ) ++ ++#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT ) ++#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT ) ++ ++#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN ) ++#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN ) ++ ++#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP ) ++#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP ) ++ ++#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP ) ++#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP ) ++ ++#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP ) ++#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP ) ++ ++#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP ) ++#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP ) ++ ++#define __lcd_set_16_tftpnl() \ ++ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT ) ++ ++#define __lcd_set_18_tftpnl() \ ++ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT ) ++ ++#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT ) ++ ++/* ++ * n=1,2,4,8 for single mono-STN ++ * n=4,8 for dual mono-STN ++ */ ++#define __lcd_set_panel_datawidth(n) \ ++do { \ ++ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \ ++ REG_LCD_CFG |= LCD_CFG_PDW_n##; \ ++} while (0) ++ ++/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */ ++#define __lcd_set_panel_mode(m) \ ++do { \ ++ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \ ++ REG_LCD_CFG |= (m); \ ++} while(0) ++ ++/* n=4,8,16 */ ++#define __lcd_set_burst_length(n) \ ++do { \ ++ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \ ++ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \ ++} while (0) ++ ++#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 ) ++#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 ) ++ ++#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP ) ++#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP ) ++ ++/* n=2,4,16 */ ++#define __lcd_set_stn_frc(n) \ ++do { \ ++ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \ ++ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \ ++} while (0) ++ ++#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM ) ++#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM ) ++ ++#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM ) ++#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM ) ++ ++#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM ) ++#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM ) ++ ++#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 ) ++#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 ) ++ ++#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 ) ++#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 ) ++ ++#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM ) ++#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM ) ++ ++#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM ) ++#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM ) ++ ++#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN ) ++#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN ) ++ ++#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN ) ++#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN ) ++ ++#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS ) ++#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS ) ++ ++#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA ) ++#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA ) ++ ++/* n=1,2,4,8,16 */ ++#define __lcd_set_bpp(n) \ ++ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n ) ++ ++/* LCD status register indication */ ++ ++#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD ) ++#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD ) ++#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 ) ++#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 ) ++#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU ) ++#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF ) ++#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF ) ++ ++#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU ) ++#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF ) ++#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF ) ++ ++/* OSD functions */ ++#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN) ++#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN) ++#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN) ++#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN) ++#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD) ++ ++#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN) ++#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN) ++#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN) ++#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN) ++#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD) ++ ++/* OSD Controll Register */ ++#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU) ++#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU) ++#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1() ++#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 ) ++#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 ) ++#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES ) ++#define __lcd_osd_bpp_15_16() \ ++ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 ) ++#define __lcd_osd_bpp_18_24() \ ++ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 ) ++ ++/* OSD State Register */ ++#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 ) ++#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 ) ++#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 ) ++#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 ) ++#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY ) ++ ++/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */ ++#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN) ++#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN) ++#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD) ++#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD) ++#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key)) ++#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key)) ++ ++#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN) ++#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN) ++#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD) ++#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD) ++ ++/* IPU Restart Register */ ++#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN) ++#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN) ++#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n)) ++ ++/* RGB Control Register */ ++#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM) ++#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM) ++ ++#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM) ++#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM) ++ ++#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC) ++#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC) ++ ++#define __lcd_odd_mode_rgb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB ) ++#define __lcd_odd_mode_rbg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG ) ++#define __lcd_odd_mode_grb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB) ++ ++#define __lcd_odd_mode_gbr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR) ++#define __lcd_odd_mode_brg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG) ++#define __lcd_odd_mode_bgr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR) ++ ++#define __lcd_even_mode_rgb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB ) ++#define __lcd_even_mode_rbg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG ) ++#define __lcd_even_mode_grb() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB) ++ ++#define __lcd_even_mode_gbr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR) ++#define __lcd_even_mode_brg() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG) ++#define __lcd_even_mode_bgr() \ ++ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR) ++ ++/* Vertical Synchronize Register */ ++#define __lcd_vsync_get_vps() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT ) ++ ++#define __lcd_vsync_get_vpe() \ ++ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) ++#define __lcd_vsync_set_vpe(n) \ ++do { \ ++ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ ++ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hps() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) ++#define __lcd_hsync_set_hps(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ ++} while (0) ++ ++#define __lcd_hsync_get_hpe() \ ++ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) ++#define __lcd_hsync_set_hpe(n) \ ++do { \ ++ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ ++ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_ht() \ ++ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) ++#define __lcd_vat_set_ht(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ ++} while (0) ++ ++#define __lcd_vat_get_vt() \ ++ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) ++#define __lcd_vat_set_vt(n) \ ++do { \ ++ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ ++ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hds() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) ++#define __lcd_dah_set_hds(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ ++} while (0) ++ ++#define __lcd_dah_get_hde() \ ++ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) ++#define __lcd_dah_set_hde(n) \ ++do { \ ++ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ ++ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vds() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) ++#define __lcd_dav_set_vds(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ ++} while (0) ++ ++#define __lcd_dav_get_vde() \ ++ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) ++#define __lcd_dav_set_vde(n) \ ++do { \ ++ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ ++ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ ++} while (0) ++ ++/* DMA Command Register */ ++#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) ++#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) ++#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) ++ ++#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) ++#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) ++#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) ++ ++#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) ++#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) ++ ++#define __lcd_cmd0_get_len() \ ++ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++#define __lcd_cmd1_get_len() \ ++ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) ++ ++/************************************************************************* ++ * TVE (TV Encoder Controller) ops ++ *************************************************************************/ ++/* TV Encoder Control register ops */ ++#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST) ++ ++#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR) ++#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR) ++ ++#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST) ++#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST) ++ ++#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK) ++#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK) ++ ++#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV) ++#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV) ++ ++#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL) ++#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL) ++ ++#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT) ++#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT) ++ ++/* n = 0 ~ 3 */ ++#define __tve_set_c_bandwidth(n) \ ++do {\ ++ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\ ++ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \ ++}while(0) ++ ++/* n = 0 ~ 3 */ ++#define __tve_set_c_gain(n) \ ++do {\ ++ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\ ++ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \ ++}while(0) ++ ++/* n = 0 ~ 7 */ ++#define __tve_set_yc_delay(n) \ ++do { \ ++ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \ ++ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \ ++} while(0) ++ ++#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD) ++#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1) ++#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1) ++#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2) ++#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2) ++#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3) ++#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3) ++ ++#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS) ++#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS) ++ ++/* TV Encoder Frame Configure register ops */ ++/* n = 0 ~ 255 */ ++#define __tve_set_first_video_line(n) \ ++do {\ ++ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\ ++ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_line_num_per_frm(n) \ ++do {\ ++ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\ ++ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\ ++} while(0) ++#define __tve_get_video_line_num()\ ++ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT)) ++ ++/* TV Encoder Signal Level Configure register ops */ ++/* n = 0 ~ 1023 */ ++#define __tve_set_white_level(n) \ ++do {\ ++ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\ ++ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_black_level(n) \ ++do {\ ++ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\ ++ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_blank_level(n) \ ++do {\ ++ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\ ++ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_vbi_blank_level(n) \ ++do {\ ++ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\ ++ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\ ++} while(0) ++/* n = 0 ~ 1023 */ ++#define __tve_set_sync_level(n) \ ++do {\ ++ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\ ++ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\ ++} while(0) ++ ++/* TV Encoder Signal Level Configure register ops */ ++/* n = 0 ~ 31 */ ++#define __tve_set_front_porch(n) \ ++do {\ ++ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\ ++ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \ ++} while(0) ++/* n = 0 ~ 127 */ ++#define __tve_set_hsync_width(n) \ ++do {\ ++ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\ ++ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \ ++} while(0) ++/* n = 0 ~ 127 */ ++#define __tve_set_back_porch(n) \ ++do {\ ++ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\ ++ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \ ++} while(0) ++/* n = 0 ~ 2047 */ ++#define __tve_set_active_linec(n) \ ++do {\ ++ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\ ++ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \ ++} while(0) ++/* n = 0 ~ 31 */ ++#define __tve_set_breezy_way(n) \ ++do {\ ++ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\ ++ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \ ++} while(0) ++ ++/* n = 0 ~ 127 */ ++#define __tve_set_burst_width(n) \ ++do {\ ++ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\ ++ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \ ++} while(0) ++ ++/* TV Encoder Chrominance filter and Modulation register ops */ ++/* n = 0 ~ (2^32-1) */ ++#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n) ++/* n = 0 ~ 255 */ ++#define __tve_set_c_sub_carrier_init_phase(n) \ ++do { \ ++ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \ ++ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_c_sub_carrier_act_phase(n) \ ++do { \ ++ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \ ++ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_c_phase_rst_period(n) \ ++do { \ ++ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \ ++ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cb_burst_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cr_burst_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cb_gain_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \ ++} while(0) ++/* n = 0 ~ 255 */ ++#define __tve_set_cr_gain_amp(n) \ ++do { \ ++ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \ ++ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \ ++} while(0) ++ ++/* TV Encoder Wide Screen Signal Control register ops */ ++/* n = 0 ~ 7 */ ++#define __tve_set_notch_freq(n) \ ++do { \ ++ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \ ++ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \ ++} while(0) ++/* n = 0 ~ 7 */ ++#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT) ++#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT) ++#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT) ++#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT) ++/* n = 0 ~ 7 */ ++#define __tve_set_wss_edge(n) \ ++do { \ ++ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \ ++ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \ ++} while(0) ++#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT) ++#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT) ++#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT) ++#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT) ++ ++/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */ ++/* n = 0 ~ 1023 */ ++#define __tve_set_wss_level(n) \ ++do { \ ++ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \ ++ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \ ++} while(0) ++/* n = 0 ~ 4095 */ ++#define __tve_set_wss_freq(n) \ ++do { \ ++ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \ ++ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \ ++} while(0) ++/* n = 0, 1; l = 0 ~ 255 */ ++#define __tve_set_wss_line(n,v) \ ++do { \ ++ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ ++ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ ++} while(0) ++/* n = 0, 1; d = 0 ~ (2^20-1) */ ++#define __tve_set_wss_data(n, v) \ ++do { \ ++ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ ++ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ ++} while(0) ++ ++/*************************************************************************** ++ * RTC ops ++ ***************************************************************************/ ++ ++#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) ++#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) ++#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) ++#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) ++#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) ++#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) ++#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) ++#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) ++#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) ++ ++#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) ++#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) ++#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) ++#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) ++ ++#define __rtc_get_second() ( REG_RTC_RSR ) ++#define __rtc_set_second(v) ( REG_RTC_RSR = v ) ++ ++#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) ++#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) ++ ++#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) ++#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) ++#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) ++#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) ++#define __rtc_set_adjc_val(v) \ ++ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) ++#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) ++#define __rtc_set_nc1Hz_val(v) \ ++ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) ++ ++#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) ++ ++#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) ++#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) ++#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) ++#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) ++ ++#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) ++#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) ++ ++#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) ++#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) ++#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) ++#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) ++#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) ++ ++#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) ++#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) ++ ++/************************************************************************* ++ * BCH ++ *************************************************************************/ ++#define __ecc_encoding_4bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \ ++ REG_BCH_CRC = BCH_CR_BSEL8; \ ++} while(0) ++#define __ecc_decoding_4bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \ ++ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \ ++} while(0) ++#define __ecc_encoding_8bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ ++} while(0) ++#define __ecc_decoding_8bit() \ ++do { \ ++ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ ++ REG_BCH_CRC = BCH_CR_ENCE; \ ++} while(0) ++#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE ) ++#define __ecc_dma_disable() ( REG_BCH_CRC = BCH_CR_DMAE ) ++#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE ) ++#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF)) ++#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF)) ++#define __ecc_cnt_dec(n) \ ++do { \ ++ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \ ++ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \ ++} while(0) ++#define __ecc_cnt_enc(n) \ ++do { \ ++ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \ ++ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \ ++} while(0) ++ ++/*************************************************************************** ++ * OWI (one-wire bus) ops ++ ***************************************************************************/ ++ ++/* OW control register ops */ ++#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) ) ++#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 ) ++ ++#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE ) ++#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE ) ++#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT ) ++#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT ) ++#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST ) ++#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST ) ++ ++/* OW configure register ops */ ++#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE ) ++#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE ) ++ ++#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA ) ++#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA ) ++#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA ) ++ ++#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA ) ++#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA ) ++#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA ) ++ ++#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST ) ++ ++#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD ) ++#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD ) ++#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD ) ++ ++#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 ) ++#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 ) ++#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 ) ++ ++#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST ) ++#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST ) ++#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST ) ++ ++#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA ) ++#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA ) ++#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA ) ++ ++#define __owi_wait_ops_rdy() \ ++ do { \ ++ while(__owi_get_enable()); \ ++ udelay(1); \ ++ } while(0); ++ ++/* OW status register ops */ ++#define __owi_clr_sts() ( REG_OWI_STS = 0 ) ++#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST ) ++#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY ) ++#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY ) ++#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY ) ++ ++/************************************************************************* ++ * TSSI MPEG 2-TS slave interface operation ++ *************************************************************************/ ++#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA ) ++#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA ) ++#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST ) ++#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN ) ++#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN ) ++#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN ) ++#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN ) ++ ++/* n = 4, 8, 16 */ ++#define __tssi_set_tigger_num(n) \ ++ do { \ ++ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \ ++ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \ ++ } while (0) ++ ++#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD ) ++#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD ) ++ ++#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD ) ++#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD ) ++ ++#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H ) ++#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H ) ++ ++#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 ) ++#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 ) ++ ++#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH ) ++#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH ) ++ ++#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL ) ++#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL ) ++ ++#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P ) ++#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P ) ++ ++#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H ) ++#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H ) ++ ++#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H ) ++#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H ) ++ ++#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H ) ++#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H ) ++ ++#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM ) ++#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM ) ++ ++#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM ) ++#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM ) ++ ++#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN ) ++#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG ) ++#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */ ++#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN ) ++ ++#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 ) ++#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 ) ++ ++/* m = 0, ..., 15 */ ++#define __tssi_enable_pid_filter(m) \ ++ do { \ ++ int n = (m); \ ++ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ ++ if ( n >= TSSI_PID_MAX ) n += 8; \ ++ REG_TSSI_PEN |= ( 1 << n ); \ ++ } \ ++ } while (0) ++ ++/* m = 0, ..., 15 */ ++#define __tssi_disable_pid_filter(m) \ ++ do { \ ++ int n = (m); \ ++ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ ++ if ( n >= TSSI_PID_MAX ) n += 8; \ ++ REG_TSSI_PEN &= ~( 1 << n ); \ ++ } \ ++ } while (0) ++ ++/* n = 0, ..., 7 */ ++#define __tssi_set_pid0(n, pid0) \ ++ do { \ ++ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \ ++ REG_TSSI_PID(n) |= ((pid0)<=0 && n < TSSI_PID_MAX*2) { \ ++ if ( n < TSSI_PID_MAX ) \ ++ __tssi_set_pid0(n, pid); \ ++ else \ ++ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \ ++ } \ ++ }while (0) ++ ++ ++#if 0 ++/************************************************************************* ++ * IPU (Image Processing Unit) ++ *************************************************************************/ ++#define u32 volatile unsigned long ++ ++#define write_reg(reg, val) \ ++do { \ ++ *(u32 *)(reg) = (val); \ ++} while(0) ++ ++#define read_reg(reg, off) (*(u32 *)((reg)+(off))) ++ ++ ++#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \ ++({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)< Unsigned toggle enable */ ++#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ ++#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ ++#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ ++#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ ++#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ ++#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ ++#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ ++#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ ++ ++/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ ++ ++#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ ++#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) ++ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ ++ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ ++ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ ++ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ ++ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ ++ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ ++#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ ++#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) ++ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ ++ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ ++ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ ++ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ ++ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ ++ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ ++ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ ++ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ ++ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ ++ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ ++ ++/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ ++ ++#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ ++#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ ++#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ ++#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ ++#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) ++ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ ++#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) ++ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ ++ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ ++ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ ++ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ ++#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ ++#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ ++#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ ++#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ ++ ++/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ ++ ++#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ ++#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ ++#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) ++ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ ++ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ ++ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ ++ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ ++ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ ++#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ ++ ++/* AIC Controller FIFO Status Register (AIC_SR) */ ++ ++#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ ++#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) ++#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ ++#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) ++#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ ++#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ ++#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ ++#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ ++ ++/* AIC Controller AC-link Status Register (AIC_ACSR) */ ++ ++#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ ++#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ ++#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ ++#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ ++#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ ++#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ ++ ++/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ ++ ++#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ ++ ++/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ ++ ++#define AIC_ACCAR_CAR_BIT 0 ++#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) ++ ++/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ ++ ++#define AIC_ACCDR_CDR_BIT 0 ++#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) ++ ++/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ ++ ++#define AIC_ACSAR_SAR_BIT 0 ++#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) ++ ++/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ ++ ++#define AIC_ACSDR_SDR_BIT 0 ++#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) ++ ++/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ ++ ++#define AIC_I2SDIV_DIV_BIT 0 ++#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) ++ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ ++ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ ++ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ ++ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ ++ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ ++ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ ++ ++ ++/************************************************************************* ++ * ICDC (Internal CODEC) ++ *************************************************************************/ ++ ++#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */ ++#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */ ++#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */ ++ ++#define REG_ICDC_CKCFG REG32(ICDC_CKCFG) ++#define REG_ICDC_RGADW REG32(ICDC_RGADW) ++#define REG_ICDC_RGDATA REG32(ICDC_RGDATA) ++ ++/* ICDC Clock Configure Register */ ++#define ICDC_CKCFG_CKRDY (1 << 1) ++#define ICDC_CKCFG_SELAD (1 << 0) ++ ++/* ICDC internal register access control Register */ ++#define ICDC_RGADW_RGWR (1 << 16) ++#define ICDC_RGADW_RGADDR_BIT 8 ++#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT) ++#define ICDC_RGADW_RGDIN_BIT 0 ++#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT) ++ ++/* ICDC internal register data output Register */ ++#define ICDC_RGDATA_IRQ (1 << 8) ++#define ICDC_RGDATA_RGDOUT_BIT 0 ++#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT) ++ ++/************************************************************************* ++ * PCM Controller ++ *************************************************************************/ ++ ++#define PCM_CTL (PCM_BASE + 0x000) ++#define PCM_CFG (PCM_BASE + 0x004) ++#define PCM_DP (PCM_BASE + 0x008) ++#define PCM_INTC (PCM_BASE + 0x00c) ++#define PCM_INTS (PCM_BASE + 0x010) ++#define PCM_DIV (PCM_BASE + 0x014) ++ ++#define REG_PCM_CTL REG32(PCM_CTL) ++#define REG_PCM_CFG REG32(PCM_CFG) ++#define REG_PCM_DP REG32(PCM_DP) ++#define REG_PCM_INTC REG32(PCM_INTC) ++#define REG_PCM_INTS REG32(PCM_INTS) ++#define REG_PCM_DIV REG32(PCM_DIV) ++ ++/* PCM Controller control Register (PCM_CTL) */ ++ ++#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */ ++#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */ ++#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */ ++#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */ ++#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */ ++#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */ ++#define PCM_CTL_RST (1 << 3) /* Reset PCM */ ++#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */ ++#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */ ++ ++/* PCM Controller configure Register (PCM_CFG) */ ++ ++#define PCM_CFG_SLOT_BIT 13 ++#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT) ++ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */ ++ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */ ++ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */ ++ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */ ++#define PCM_CFG_ISS_BIT 12 ++#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT) ++ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT) ++ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT) ++#define PCM_CFG_OSS_BIT 11 ++#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT) ++ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT) ++ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT) ++#define PCM_CFG_IMSBPOS (1 << 10) ++#define PCM_CFG_OMSBPOS (1 << 9) ++#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */ ++#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT) ++#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */ ++#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT) ++#define PCM_CFG_MODE (0x0 << 0) ++ ++/* PCM Controller interrupt control Register (PCM_INTC) */ ++ ++#define PCM_INTC_ETFS (1 << 3) ++#define PCM_INTC_ETUR (1 << 2) ++#define PCM_INTC_ERFS (1 << 1) ++#define PCM_INTC_EROR (1 << 0) ++ ++/* PCM Controller interrupt status Register (PCM_INTS) */ ++ ++#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */ ++#define PCM_INTS_TFL_BIT 9 ++#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT) ++#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */ ++#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */ ++#define PCM_INTS_RFL_BIT 2 ++#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT) ++#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */ ++#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */ ++ ++/* PCM Controller clock division Register (PCM_DIV) */ ++#define PCM_DIV_SYNL_BIT 11 ++#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT) ++#define PCM_DIV_SYNDIV_BIT 6 ++#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT) ++#define PCM_DIV_CLKDIV_BIT 0 ++#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT) ++ ++ ++/************************************************************************* ++ * I2C ++ *************************************************************************/ ++#define I2C_DR (I2C_BASE + 0x000) ++#define I2C_CR (I2C_BASE + 0x004) ++#define I2C_SR (I2C_BASE + 0x008) ++#define I2C_GR (I2C_BASE + 0x00C) ++ ++#define REG_I2C_DR REG8(I2C_DR) ++#define REG_I2C_CR REG8(I2C_CR) ++#define REG_I2C_SR REG8(I2C_SR) ++#define REG_I2C_GR REG16(I2C_GR) ++ ++/* I2C Control Register (I2C_CR) */ ++ ++#define I2C_CR_IEN (1 << 4) ++#define I2C_CR_STA (1 << 3) ++#define I2C_CR_STO (1 << 2) ++#define I2C_CR_AC (1 << 1) ++#define I2C_CR_I2CE (1 << 0) ++ ++/* I2C Status Register (I2C_SR) */ ++ ++#define I2C_SR_STX (1 << 4) ++#define I2C_SR_BUSY (1 << 3) ++#define I2C_SR_TEND (1 << 2) ++#define I2C_SR_DRF (1 << 1) ++#define I2C_SR_ACKF (1 << 0) ++ ++ ++/************************************************************************* ++ * SSI (Synchronous Serial Interface) ++ *************************************************************************/ ++/* n = 0, 1 (SSI0, SSI1) */ ++#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000) ++#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000) ++#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000) ++#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000) ++#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000) ++#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000) ++#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000) ++ ++#define REG_SSI_DR(n) REG32(SSI_DR(n)) ++#define REG_SSI_CR0(n) REG16(SSI_CR0(n)) ++#define REG_SSI_CR1(n) REG32(SSI_CR1(n)) ++#define REG_SSI_SR(n) REG32(SSI_SR(n)) ++#define REG_SSI_ITR(n) REG16(SSI_ITR(n)) ++#define REG_SSI_ICR(n) REG8(SSI_ICR(n)) ++#define REG_SSI_GR(n) REG16(SSI_GR(n)) ++ ++/* SSI Data Register (SSI_DR) */ ++ ++#define SSI_DR_GPC_BIT 0 ++#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) ++ ++#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */ ++ ++/* SSI Control Register 0 (SSI_CR0) */ ++ ++#define SSI_CR0_SSIE (1 << 15) ++#define SSI_CR0_TIE (1 << 14) ++#define SSI_CR0_RIE (1 << 13) ++#define SSI_CR0_TEIE (1 << 12) ++#define SSI_CR0_REIE (1 << 11) ++#define SSI_CR0_LOOP (1 << 10) ++#define SSI_CR0_RFINE (1 << 9) ++#define SSI_CR0_RFINC (1 << 8) ++#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */ ++#define SSI_CR0_FSEL (1 << 6) ++#define SSI_CR0_TFLUSH (1 << 2) ++#define SSI_CR0_RFLUSH (1 << 1) ++#define SSI_CR0_DISREV (1 << 0) ++ ++/* SSI Control Register 1 (SSI_CR1) */ ++ ++#define SSI_CR1_FRMHL_BIT 30 ++#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) ++ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ ++ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ ++ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ ++#define SSI_CR1_TFVCK_BIT 28 ++#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) ++ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) ++#define SSI_CR1_TCKFI_BIT 26 ++#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) ++ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) ++#define SSI_CR1_LFST (1 << 25) ++#define SSI_CR1_ITFRM (1 << 24) ++#define SSI_CR1_UNFIN (1 << 23) ++#define SSI_CR1_MULTS (1 << 22) ++#define SSI_CR1_FMAT_BIT 20 ++#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) ++ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ ++ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ ++ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ ++ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ ++#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */ ++#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) ++#define SSI_CR1_MCOM_BIT 12 ++#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) ++ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ ++ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ ++ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ ++ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ ++ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ ++ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ ++ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ ++ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ ++ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ ++ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ ++ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ ++ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ ++ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ ++ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ ++ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ ++ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ ++#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */ ++#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) ++#define SSI_CR1_FLEN_BIT 4 ++#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) ++ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) ++#define SSI_CR1_PHA (1 << 1) ++#define SSI_CR1_POL (1 << 0) ++ ++/* SSI Status Register (SSI_SR) */ ++ ++#define SSI_SR_TFIFONUM_BIT 16 ++#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) ++#define SSI_SR_RFIFONUM_BIT 8 ++#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) ++#define SSI_SR_END (1 << 7) ++#define SSI_SR_BUSY (1 << 6) ++#define SSI_SR_TFF (1 << 5) ++#define SSI_SR_RFE (1 << 4) ++#define SSI_SR_TFHE (1 << 3) ++#define SSI_SR_RFHF (1 << 2) ++#define SSI_SR_UNDR (1 << 1) ++#define SSI_SR_OVER (1 << 0) ++ ++/* SSI Interval Time Control Register (SSI_ITR) */ ++ ++#define SSI_ITR_CNTCLK (1 << 15) ++#define SSI_ITR_IVLTM_BIT 0 ++#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) ++ ++ ++/************************************************************************* ++ * MSC ++ ************************************************************************/ ++/* n = 0, 1 (MSC0, MSC1) */ ++#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000) ++#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004) ++#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008) ++#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C) ++#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010) ++#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014) ++#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018) ++#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C) ++#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020) ++#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024) ++#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028) ++#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C) ++#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030) ++#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034) ++#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038) ++#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C) ++#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040) ++ ++#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n)) ++#define REG_MSC_STAT(n) REG32(MSC_STAT(n)) ++#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n)) ++#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n)) ++#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n)) ++#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n)) ++#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n)) ++#define REG_MSC_NOB(n) REG16(MSC_NOB(n)) ++#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n)) ++#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n)) ++#define REG_MSC_IREG(n) REG16(MSC_IREG(n)) ++#define REG_MSC_CMD(n) REG8(MSC_CMD(n)) ++#define REG_MSC_ARG(n) REG32(MSC_ARG(n)) ++#define REG_MSC_RES(n) REG16(MSC_RES(n)) ++#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n)) ++#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n)) ++#define REG_MSC_LPM(n) REG32(MSC_LPM(n)) ++ ++/* MSC Clock and Control Register (MSC_STRPCL) */ ++#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */ ++#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */ ++#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) ++#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) ++#define MSC_STRPCL_START_READWAIT (1 << 5) ++#define MSC_STRPCL_STOP_READWAIT (1 << 4) ++#define MSC_STRPCL_RESET (1 << 3) ++#define MSC_STRPCL_START_OP (1 << 2) ++#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 ++#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) ++ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ ++ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ ++ ++/* MSC Status Register (MSC_STAT) */ ++#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */ ++#define MSC_STAT_IS_RESETTING (1 << 15) ++#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) ++#define MSC_STAT_PRG_DONE (1 << 13) ++#define MSC_STAT_DATA_TRAN_DONE (1 << 12) ++#define MSC_STAT_END_CMD_RES (1 << 11) ++#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) ++#define MSC_STAT_IS_READWAIT (1 << 9) ++#define MSC_STAT_CLK_EN (1 << 8) ++#define MSC_STAT_DATA_FIFO_FULL (1 << 7) ++#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) ++#define MSC_STAT_CRC_RES_ERR (1 << 5) ++#define MSC_STAT_CRC_READ_ERROR (1 << 4) ++#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 ++#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) ++ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ ++ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ ++#define MSC_STAT_TIME_OUT_RES (1 << 1) ++#define MSC_STAT_TIME_OUT_READ (1 << 0) ++ ++/* MSC Bus Clock Control Register (MSC_CLKRT) */ ++#define MSC_CLKRT_CLK_RATE_BIT 0 ++#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) ++ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ ++ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ ++ ++/* MSC Command Sequence Control Register (MSC_CMDAT) */ ++#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */ ++#define MSC_CMDAT_READ_CEATA (1 << 30) ++#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */ ++#define MSC_CMDAT_SEND_AS_STOP (1 << 16) ++#define MSC_CMDAT_RTRG_BIT 14 ++ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT) ++ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */ ++ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT) ++ ++#define MSC_CMDAT_TTRG_BIT 12 ++ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT) ++ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */ ++ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT) ++#define MSC_CMDAT_STOP_ABORT (1 << 11) ++#define MSC_CMDAT_BUS_WIDTH_BIT 9 ++#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) ++ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ ++ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ ++ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */ ++#define MSC_CMDAT_DMA_EN (1 << 8) ++#define MSC_CMDAT_INIT (1 << 7) ++#define MSC_CMDAT_BUSY (1 << 6) ++#define MSC_CMDAT_STREAM_BLOCK (1 << 5) ++#define MSC_CMDAT_WRITE (1 << 4) ++#define MSC_CMDAT_READ (0 << 4) ++#define MSC_CMDAT_DATA_EN (1 << 3) ++#define MSC_CMDAT_RESPONSE_BIT 0 ++#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) ++ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ ++ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ ++ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ ++ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ ++ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ ++ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ ++ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ ++ ++#define CMDAT_DMA_EN (1 << 8) ++#define CMDAT_INIT (1 << 7) ++#define CMDAT_BUSY (1 << 6) ++#define CMDAT_STREAM (1 << 5) ++#define CMDAT_WRITE (1 << 4) ++#define CMDAT_DATA_EN (1 << 3) ++ ++/* MSC Interrupts Mask Register (MSC_IMASK) */ ++#define MSC_IMASK_AUTO_CMD_DONE (1 << 8) ++#define MSC_IMASK_SDIO (1 << 7) ++#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IMASK_END_CMD_RES (1 << 2) ++#define MSC_IMASK_PRG_DONE (1 << 1) ++#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Interrupts Status Register (MSC_IREG) */ ++#define MSC_IREG_AUTO_CMD_DONE (1 << 8) ++#define MSC_IREG_SDIO (1 << 7) ++#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) ++#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) ++#define MSC_IREG_END_CMD_RES (1 << 2) ++#define MSC_IREG_PRG_DONE (1 << 1) ++#define MSC_IREG_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Low Power Mode Register (MSC_LPM) */ ++#define MSC_SET_LPM (1 << 0) ++ ++/************************************************************************* ++ * EMC (External Memory Controller) ++ *************************************************************************/ ++#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */ ++#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ ++#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ ++#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ ++#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ ++#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ ++#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ ++#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ ++#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ ++#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ ++#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ ++ ++#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ ++ ++#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ ++#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ ++#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ ++#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ ++#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ ++#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */ ++#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ ++ ++#define REG_EMC_BCR REG32(EMC_BCR) ++#define REG_EMC_SMCR0 REG32(EMC_SMCR0) ++#define REG_EMC_SMCR1 REG32(EMC_SMCR1) ++#define REG_EMC_SMCR2 REG32(EMC_SMCR2) ++#define REG_EMC_SMCR3 REG32(EMC_SMCR3) ++#define REG_EMC_SMCR4 REG32(EMC_SMCR4) ++#define REG_EMC_SACR0 REG32(EMC_SACR0) ++#define REG_EMC_SACR1 REG32(EMC_SACR1) ++#define REG_EMC_SACR2 REG32(EMC_SACR2) ++#define REG_EMC_SACR3 REG32(EMC_SACR3) ++#define REG_EMC_SACR4 REG32(EMC_SACR4) ++ ++#define REG_EMC_NFCSR REG32(EMC_NFCSR) ++ ++#define REG_EMC_DMCR REG32(EMC_DMCR) ++#define REG_EMC_RTCSR REG16(EMC_RTCSR) ++#define REG_EMC_RTCNT REG16(EMC_RTCNT) ++#define REG_EMC_RTCOR REG16(EMC_RTCOR) ++#define REG_EMC_DMAR0 REG32(EMC_DMAR0) ++#define REG_EMC_DMAR1 REG32(EMC_DMAR1) ++ ++/* Bus Control Register */ ++#define EMC_BCR_BT_SEL_BIT 30 ++#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT) ++#define EMC_BCR_PK_SEL (1 << 24) ++#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */ ++ #define EMC_BCR_BSR_SHARE (0 << 2) ++ #define EMC_BCR_BSR_UNSHARE (1 << 2) ++#define EMC_BCR_BRE (1 << 1) ++#define EMC_BCR_ENDIAN (1 << 0) ++ ++/* Static Memory Control Register */ ++#define EMC_SMCR_STRV_BIT 24 ++#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) ++#define EMC_SMCR_TAW_BIT 20 ++#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) ++#define EMC_SMCR_TBP_BIT 16 ++#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) ++#define EMC_SMCR_TAH_BIT 12 ++#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) ++#define EMC_SMCR_TAS_BIT 8 ++#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) ++#define EMC_SMCR_BW_BIT 6 ++#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) ++ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) ++#define EMC_SMCR_BCM (1 << 3) ++#define EMC_SMCR_BL_BIT 1 ++#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) ++ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) ++#define EMC_SMCR_SMT (1 << 0) ++ ++/* Static Memory Bank Addr Config Reg */ ++#define EMC_SACR_BASE_BIT 8 ++#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) ++#define EMC_SACR_MASK_BIT 0 ++#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) ++ ++/* NAND Flash Control/Status Register */ ++#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ ++#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ ++#define EMC_NFCSR_NFCE3 (1 << 5) ++#define EMC_NFCSR_NFE3 (1 << 4) ++#define EMC_NFCSR_NFCE2 (1 << 3) ++#define EMC_NFCSR_NFE2 (1 << 2) ++#define EMC_NFCSR_NFCE1 (1 << 1) ++#define EMC_NFCSR_NFE1 (1 << 0) ++ ++/* DRAM Control Register */ ++#define EMC_DMCR_BW_BIT 31 ++#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) ++#define EMC_DMCR_CA_BIT 26 ++#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) ++ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) ++#define EMC_DMCR_RMODE (1 << 25) ++#define EMC_DMCR_RFSH (1 << 24) ++#define EMC_DMCR_MRSET (1 << 23) ++#define EMC_DMCR_RA_BIT 20 ++#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) ++ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) ++#define EMC_DMCR_BA_BIT 19 ++#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) ++#define EMC_DMCR_PDM (1 << 18) ++#define EMC_DMCR_EPIN (1 << 17) ++#define EMC_DMCR_MBSEL (1 << 16) ++#define EMC_DMCR_TRAS_BIT 13 ++#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) ++#define EMC_DMCR_RCD_BIT 11 ++#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) ++#define EMC_DMCR_TPC_BIT 8 ++#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) ++#define EMC_DMCR_TRWL_BIT 5 ++#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) ++#define EMC_DMCR_TRC_BIT 2 ++#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) ++#define EMC_DMCR_TCL_BIT 0 ++#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) ++ ++/* Refresh Time Control/Status Register */ ++#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */ ++#define EMC_RTCSR_CMF (1 << 7) ++#define EMC_RTCSR_CKS_BIT 0 ++#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) ++ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) ++ ++/* SDRAM Bank Address Configuration Register */ ++#define EMC_DMAR_BASE_BIT 8 ++#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) ++#define EMC_DMAR_MASK_BIT 0 ++#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) ++ ++/* Mode Register of SDRAM bank 0 */ ++#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ ++#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ ++#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) ++ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) ++#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ ++#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) ++ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) ++#define EMC_SDMR_BT_BIT 3 /* Burst Type */ ++#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) ++ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ ++ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ ++#define EMC_SDMR_BL_BIT 0 /* Burst Length */ ++#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) ++ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) ++ ++#define EMC_SDMR_CAS2_16BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS2_32BIT \ ++ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++#define EMC_SDMR_CAS3_16BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) ++#define EMC_SDMR_CAS3_32BIT \ ++ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) ++ ++ ++/************************************************************************* ++ * CIM ++ *************************************************************************/ ++#define CIM_CFG (CIM_BASE + 0x0000) ++#define CIM_CTRL (CIM_BASE + 0x0004) ++#define CIM_STATE (CIM_BASE + 0x0008) ++#define CIM_IID (CIM_BASE + 0x000C) ++#define CIM_RXFIFO (CIM_BASE + 0x0010) ++#define CIM_DA (CIM_BASE + 0x0020) ++#define CIM_FA (CIM_BASE + 0x0024) ++#define CIM_FID (CIM_BASE + 0x0028) ++#define CIM_CMD (CIM_BASE + 0x002C) ++#define CIM_SIZE (CIM_BASE + 0x0030) ++#define CIM_OFFSET (CIM_BASE + 0x0034) ++#define CIM_RAM_ADDR (CIM_BASE + 0x1000) ++ ++#define REG_CIM_CFG REG32(CIM_CFG) ++#define REG_CIM_CTRL REG32(CIM_CTRL) ++#define REG_CIM_STATE REG32(CIM_STATE) ++#define REG_CIM_IID REG32(CIM_IID) ++#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) ++#define REG_CIM_DA REG32(CIM_DA) ++#define REG_CIM_FA REG32(CIM_FA) ++#define REG_CIM_FID REG32(CIM_FID) ++#define REG_CIM_CMD REG32(CIM_CMD) ++#define REG_CIM_SIZE REG32(CIM_SIZE) ++#define REG_CIM_OFFSET REG32(CIM_OFFSET) ++ ++#define CIM_CFG_ORDER_BIT 18 ++#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT) ++ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* Y0CbY1Cr; YCbCr */ ++ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) /* Y0CrY1Cb; YCrCb */ ++ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) /* CbY0CrY1; CbCrY */ ++ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) /* CrY0CbY1; CrCbY */ ++#define CIM_CFG_DF_BIT 16 ++#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT) ++ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT) /* YCbCr444 */ ++ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT) /* YCbCr422 */ ++ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT) /* ITU656 YCbCr422 */ ++#define CIM_CFG_INV_DAT (1 << 15) ++#define CIM_CFG_VSP (1 << 14) /* VSYNC Polarity:0-rising edge active,1-falling edge active */ ++#define CIM_CFG_HSP (1 << 13) /* HSYNC Polarity:0-rising edge active,1-falling edge active */ ++#define CIM_CFG_PCP (1 << 12) /* PCLK working edge: 0-rising, 1-falling */ ++#define CIM_CFG_DMA_BURST_TYPE_BIT 10 ++#define CIM_CFG_DMA_BURST_TYPE_MASK (0x3 << CIM_CFG_DMA_BURST_TYPE_BIT) ++ #define CIM_CFG_DMA_BURST_INCR4 (0 << CIM_CFG_DMA_BURST_TYPE_BIT) ++ #define CIM_CFG_DMA_BURST_INCR8 (1 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested */ ++ #define CIM_CFG_DMA_BURST_INCR16 (2 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested High speed AHB*/ ++#define CIM_CFG_DUMMY_ZERO (1 << 9) ++#define CIM_CFG_EXT_VSYNC (1 << 8) /* Only for ITU656 Progressive mode */ ++#define CIM_CFG_PACK_BIT 4 ++#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) ++ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 0xY0CbY1Cr */ ++ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 0xCbY1CrY0 */ ++ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 0xY1CrY0Cb */ ++ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 0xCrY0CbY1 */ ++ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 0xCrY1CbY0 */ ++ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 0xY1CbY0Cr */ ++ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 0xCbY0CrY1 */ ++ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 0xY0CrY1Cb */ ++#define CIM_CFG_BYPASS_BIT 2 ++#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT) ++ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT) ++#define CIM_CFG_DSM_BIT 0 ++#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) ++ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ ++ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ ++ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ ++ ++/* CIM Control Register (CIM_CTRL) */ ++#define CIM_CTRL_EEOF_LINE_BIT 20 ++#define CIM_CTRL_EEOF_LINE_MASK (0xfff << CIM_CTRL_EEOF_LINE_BIT) ++#define CIM_CTRL_FRC_BIT 16 ++#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) ++ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ ++ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ ++ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ ++ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ ++ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ ++ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ ++ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ ++ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ ++ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ ++ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ ++ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ ++ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ ++ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ ++ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ ++ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ ++ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ ++ ++#define CIM_CTRL_DMA_EEOF (1 << 15) /* Enable EEOF interrupt */ ++#define CIM_CTRL_WIN_EN (1 << 14) ++#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */ ++#define CIM_CTRL_DMA_SOFM (1 << 12) ++#define CIM_CTRL_DMA_EOFM (1 << 11) ++#define CIM_CTRL_DMA_STOPM (1 << 10) ++#define CIM_CTRL_RXF_TRIGM (1 << 9) ++#define CIM_CTRL_RXF_OFM (1 << 8) ++#define CIM_CTRL_DMA_SYNC (1 << 7) /*when change DA, do frame sync */ ++#define CIM_CTRL_RXF_TRIG_BIT 3 ++#define CIM_CTRL_RXF_TRIG_MASK (0xf << CIM_CTRL_RXF_TRIG_BIT) /* trigger value = (n+1)*burst_type */ ++ ++#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */ ++#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */ ++#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */ ++ ++/* CIM State Register (CIM_STATE) */ ++#define CIM_STATE_DMA_EEOF (1 << 7) /* DMA Line EEOf irq */ ++#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */ ++#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */ ++#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */ ++#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */ ++#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */ ++#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */ ++#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */ ++ ++/* CIM DMA Command Register (CIM_CMD) */ ++ ++#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */ ++#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */ ++#define CIM_CMD_EEOFINT (1 << 29) /* enable DMA EEOF irq */ ++#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */ ++#define CIM_CMD_OFRCV (1 << 27) /* enable recovery when TXFiFo overflow */ ++#define CIM_CMD_LEN_BIT 0 ++#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) ++ ++/* CIM Window-Image Size Register (CIM_SIZE) */ ++#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */ ++#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT) ++#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */ ++#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT) ++ ++/* CIM Image Offset Register (CIM_OFFSET) */ ++#define CIM_OFFSET_V_BIT 16 /* Vertical offset */ ++#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT) ++#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */ ++#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/ ++ ++/************************************************************************* ++ * SADC (Smart A/D Controller) ++ *************************************************************************/ ++ ++#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ ++#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ ++#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ ++#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ ++#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ ++#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ ++#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ ++#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ ++#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ ++#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */ ++ ++#define REG_SADC_ENA REG8(SADC_ENA) ++#define REG_SADC_CFG REG32(SADC_CFG) ++#define REG_SADC_CTRL REG8(SADC_CTRL) ++#define REG_SADC_STATE REG8(SADC_STATE) ++#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) ++#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) ++#define REG_SADC_TSDAT REG32(SADC_TSDAT) ++#define REG_SADC_BATDAT REG16(SADC_BATDAT) ++#define REG_SADC_SADDAT REG16(SADC_SADDAT) ++#define REG_SADC_ADCLK REG32(SADC_ADCLK) ++ ++/* ADC Enable Register */ ++#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ ++#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */ ++#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */ ++#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ ++#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ ++#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ ++ ++/* ADC Configure Register */ ++#define SADC_CFG_EXIN (1 << 30) ++#define SADC_CFG_CLKOUT_NUM_BIT 16 ++#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) ++#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ ++#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ ++#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) ++#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ ++#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ ++#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) ++#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ ++#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ ++#define SADC_CFG_CMD_BIT 0 /* ADC Command */ ++#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) ++ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ ++ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ ++ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ ++ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ ++ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ ++ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ ++ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ ++ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ ++ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ ++ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ ++ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ ++ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ ++ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ ++ ++/* ADC Control Register */ ++#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */ ++#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ ++#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ ++#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ ++#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ ++#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ ++ ++/* ADC Status Register */ ++#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ ++#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ ++#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ ++#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ ++ ++/* ADC Touch Screen Data Register */ ++#define SADC_TSDAT_DATA0_BIT 0 ++#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) ++#define SADC_TSDAT_TYPE0 (1 << 15) ++#define SADC_TSDAT_DATA1_BIT 16 ++#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) ++#define SADC_TSDAT_TYPE1 (1 << 31) ++ ++/* ADC Clock Divide Register */ ++#define SADC_ADCLK_CLKDIV_10_BIT 16 ++#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT) ++#define SADC_ADCLK_CLKDIV_BIT 0 ++#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT) ++ ++/************************************************************************* ++ * SLCD (Smart LCD Controller) ++ *************************************************************************/ ++ ++#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ ++#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ ++#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ ++#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ ++ ++#define REG_SLCD_CFG REG32(SLCD_CFG) ++#define REG_SLCD_CTRL REG8(SLCD_CTRL) ++#define REG_SLCD_STATE REG8(SLCD_STATE) ++#define REG_SLCD_DATA REG32(SLCD_DATA) ++ ++/* SLCD Configure Register */ ++#define SLCD_CFG_DWIDTH_BIT 10 ++#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT) ++ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_BIT (8) ++#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT) ++#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) ++#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) ++#define SLCD_CFG_RS_CMD_LOW (0 << 3) ++#define SLCD_CFG_RS_CMD_HIGH (1 << 3) ++#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) ++#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) ++#define SLCD_CFG_TYPE_PARALLEL (0 << 0) ++#define SLCD_CFG_TYPE_SERIAL (1 << 0) ++ ++/* SLCD Control Register */ ++#define SLCD_CTRL_DMA_MODE (1 << 2) ++#define SLCD_CTRL_DMA_START (1 << 1) ++#define SLCD_CTRL_DMA_EN (1 << 0) ++ ++/* SLCD Status Register */ ++#define SLCD_STATE_BUSY (1 << 0) ++ ++/* SLCD Data Register */ ++#define SLCD_DATA_RS_DATA (0 << 31) ++#define SLCD_DATA_RS_COMMAND (1 << 31) ++ ++/************************************************************************* ++ * LCD (LCD Controller) ++ *************************************************************************/ ++#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ ++#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ ++#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ ++ ++#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */ ++#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */ ++#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */ ++#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */ ++#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */ ++#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */ ++#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */ ++#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */ ++ ++#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ ++#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ ++#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ ++ ++#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */ ++#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */ ++#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */ ++#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */ ++#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */ ++ ++#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ ++#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ ++#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ ++#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ ++#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ ++#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ ++#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ ++#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ ++#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ ++#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ ++#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ ++#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ ++#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ ++#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ ++#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ ++ ++#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */ ++#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */ ++#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */ ++#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/ ++#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */ ++#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */ ++#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */ ++#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/ ++ ++#define REG_LCD_CFG REG32(LCD_CFG) ++#define REG_LCD_CTRL REG32(LCD_CTRL) ++#define REG_LCD_STATE REG32(LCD_STATE) ++ ++#define REG_LCD_OSDC REG16(LCD_OSDC) ++#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL) ++#define REG_LCD_OSDS REG16(LCD_OSDS) ++#define REG_LCD_BGC REG32(LCD_BGC) ++#define REG_LCD_KEY0 REG32(LCD_KEY0) ++#define REG_LCD_KEY1 REG32(LCD_KEY1) ++#define REG_LCD_ALPHA REG8(LCD_ALPHA) ++#define REG_LCD_IPUR REG32(LCD_IPUR) ++ ++#define REG_LCD_VAT REG32(LCD_VAT) ++#define REG_LCD_DAH REG32(LCD_DAH) ++#define REG_LCD_DAV REG32(LCD_DAV) ++ ++#define REG_LCD_XYP0 REG32(LCD_XYP0) ++#define REG_LCD_XYP1 REG32(LCD_XYP1) ++#define REG_LCD_SIZE0 REG32(LCD_SIZE0) ++#define REG_LCD_SIZE1 REG32(LCD_SIZE1) ++#define REG_LCD_RGBC REG16(LCD_RGBC) ++ ++#define REG_LCD_VSYNC REG32(LCD_VSYNC) ++#define REG_LCD_HSYNC REG32(LCD_HSYNC) ++#define REG_LCD_PS REG32(LCD_PS) ++#define REG_LCD_CLS REG32(LCD_CLS) ++#define REG_LCD_SPL REG32(LCD_SPL) ++#define REG_LCD_REV REG32(LCD_REV) ++#define REG_LCD_IID REG32(LCD_IID) ++#define REG_LCD_DA0 REG32(LCD_DA0) ++#define REG_LCD_SA0 REG32(LCD_SA0) ++#define REG_LCD_FID0 REG32(LCD_FID0) ++#define REG_LCD_CMD0 REG32(LCD_CMD0) ++#define REG_LCD_DA1 REG32(LCD_DA1) ++#define REG_LCD_SA1 REG32(LCD_SA1) ++#define REG_LCD_FID1 REG32(LCD_FID1) ++#define REG_LCD_CMD1 REG32(LCD_CMD1) ++ ++#define REG_LCD_OFFS0 REG32(LCD_OFFS0) ++#define REG_LCD_PW0 REG32(LCD_PW0) ++#define REG_LCD_CNUM0 REG32(LCD_CNUM0) ++#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0) ++#define REG_LCD_OFFS1 REG32(LCD_OFFS1) ++#define REG_LCD_PW1 REG32(LCD_PW1) ++#define REG_LCD_CNUM1 REG32(LCD_CNUM1) ++#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1) ++ ++/* LCD Configure Register */ ++#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ ++#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) ++ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) ++ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) ++#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */ ++#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */ ++#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */ ++#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */ ++#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */ ++#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */ ++#define LCD_CFG_DITHER (1 << 24) /* Dither function */ ++#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ ++#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ ++#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ ++#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ ++#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ ++#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ ++#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ ++#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ ++#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ ++#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ ++#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ ++#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ ++#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */ ++#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */ ++#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */ ++#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */ ++#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */ ++#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */ ++#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */ ++#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ ++#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) ++#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ ++ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ ++ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ ++ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ ++#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ ++#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ ++ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT) ++ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM ++ ++/* LCD Control Register */ ++#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ ++#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) ++ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ ++ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ ++ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ ++ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */ ++#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */ ++#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */ ++#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ ++#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ ++#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) ++ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ ++ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ ++ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ ++#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ ++#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) ++#define LCD_CTRL_VGA (1 << 15) /* VGA interface enable */ ++#define LCD_CTRL_DACTE (1 << 14) /* DAC loop back test */ ++#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ ++#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ ++#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ ++#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ ++#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ ++#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ ++#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ ++#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ ++#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ ++#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ ++#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ ++#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ ++#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) ++ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ ++ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ ++ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ ++ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ ++ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ ++ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ ++ #define LCD_CTRL_BPP_CMPS_24 (6 << LCD_CTRL_BPP_BIT) /* 24 compress bpp */ ++ ++/* LCD Status Register */ ++#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ ++#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ ++#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ ++#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ ++#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ ++#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ ++#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ ++ ++/* OSD Configure Register */ ++#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */ ++#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */ ++#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */ ++#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */ ++#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */ ++#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */ ++#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */ ++#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */ ++#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */ ++ ++/* OSD Controll Register */ ++#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */ ++#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ ++#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */ ++#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */ ++#define LCD_OSDCTRL_OSDBPP_MASK (0x7< ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_BOARD_SERIAL_H__ ++#define __ASM_BOARD_SERIAL_H__ ++ ++#ifndef CONFIG_SERIAL_MANY_PORTS ++#undef RS_TABLE_SIZE ++#define RS_TABLE_SIZE 1 ++#endif ++ ++#define JZ_BASE_BAUD (12000000/16) ++ ++#define JZ_SERIAL_PORT_DEFNS \ ++ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ ++ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ ++ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, ++ ++#endif /* __ASM_BORAD_SERIAL_H__ */ +diff --git a/include/asm-mips/mach-jz4750d/war.h b/include/asm-mips/mach-jz4750d/war.h +new file mode 100644 +index 0000000..3a5bc17 +--- /dev/null ++++ b/include/asm-mips/mach-jz4750d/war.h +@@ -0,0 +1,25 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H ++#define __ASM_MIPS_MACH_JZ4740_WAR_H ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 0 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ +diff --git a/include/asm-mips/sizes.h b/include/asm-mips/sizes.h +new file mode 100644 +index 0000000..503843d +--- /dev/null ++++ b/include/asm-mips/sizes.h +@@ -0,0 +1,56 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++/* DO NOT EDIT!! - this file automatically generated ++ * from .s file by awk -f s2h.awk ++ */ ++/* Size definitions ++ * Copyright (C) ARM Limited 1998. All rights reserved. ++ */ ++ ++#ifndef __sizes_h ++#define __sizes_h 1 ++ ++/* handy sizes */ ++#define SZ_16 0x00000010 ++#define SZ_256 0x00000100 ++#define SZ_512 0x00000200 ++ ++#define SZ_1K 0x00000400 ++#define SZ_4K 0x00001000 ++#define SZ_8K 0x00002000 ++#define SZ_16K 0x00004000 ++#define SZ_64K 0x00010000 ++#define SZ_128K 0x00020000 ++#define SZ_256K 0x00040000 ++#define SZ_512K 0x00080000 ++ ++#define SZ_1M 0x00100000 ++#define SZ_2M 0x00200000 ++#define SZ_4M 0x00400000 ++#define SZ_8M 0x00800000 ++#define SZ_16M 0x01000000 ++#define SZ_32M 0x02000000 ++#define SZ_64M 0x04000000 ++#define SZ_128M 0x08000000 ++#define SZ_256M 0x10000000 ++#define SZ_512M 0x20000000 ++ ++#define SZ_1G 0x40000000 ++#define SZ_2G 0x80000000 ++ ++#endif ++ ++/* END */ +diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h +index fd53bfd..b52bba3 100644 +--- a/include/linux/i2c-dev.h ++++ b/include/linux/i2c-dev.h +@@ -49,7 +49,8 @@ + + #define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ + #define I2C_SMBUS 0x0720 /* SMBus transfer */ +- ++#define I2C_SET_SUB_ADDRESS 0x0730 /* SMBus transfer */ ++#define I2C_SET_CLOCK 0x0731 /* SMBus transfer */ + + /* This is the structure as used in the I2C_SMBUS ioctl call */ + struct i2c_smbus_ioctl_data { +@@ -71,4 +72,5 @@ struct i2c_rdwr_ioctl_data { + #define I2C_MAJOR 89 /* Device major number */ + #endif + ++extern void i2c_jz_setclk(unsigned int i2cclk); + #endif /* _LINUX_I2C_DEV_H */ +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 4030eba..4af8f35 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -53,6 +53,10 @@ extern void nand_wait_ready(struct mtd_info *mtd); + * bits in one go. + */ + /* Select the chip by setting nCE to low */ ++#define NAND_NCE1 0x08 ++#define NAND_NCE2 0x10 ++#define NAND_NCE3 0x20 ++#define NAND_NCE4 0x40 + #define NAND_NCE 0x01 + /* Select the command latch by setting CLE to high */ + #define NAND_CLE 0x02 +diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h +index b70313d..4dbcf23 100644 +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -38,6 +38,17 @@ struct mtd_partition { + char *name; /* identifier string */ + uint64_t size; /* partition size */ + uint64_t offset; /* offset within the master MTD space */ ++ ++ char cpu_mode; ++ /* flag to specify whether the partition works with cpu mode, 0: ++ * dma mode, 1:cpu mode */ ++ char use_planes; ++ /* flag to specify whether multiple planes of NAND is used in ++ * the partition, 0:don't use planes, 1: use planes */ ++ uint32_t mtdblock_jz_invalid; ++ /* flag to specify whether the partition works over mtdblock-jz, ++ * 0: over mtdblock-jz, 1: not over mtdblock-jz */ ++ + uint32_t mask_flags; /* master MTD flags to mask out for this partition */ + struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ + }; +diff --git a/include/linux/vt.h b/include/linux/vt.h +index 02c1c02..edbb787 100644 +--- a/include/linux/vt.h ++++ b/include/linux/vt.h +@@ -18,10 +18,16 @@ extern int unregister_vt_notifier(struct notifier_block *nb); + * resizing). + */ + #define MIN_NR_CONSOLES 1 /* must be at least 1 */ +-#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ +-#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */ +- /* Note: the ioctl VT_GETSTATE does not work for +- consoles 16 and higher (since it returns a short) */ ++ ++#if defined(CONFIG_JZSOC) ++#define MAX_NR_CONSOLES 2 ++#define MAX_NR_USER_CONSOLES 2 ++#else ++#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ ++#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */ ++ /* Note: the ioctl VT_GETSTATE does not work for ++ consoles 16 and higher (since it returns a short) */ ++#endif + + /* 0x56 is 'V', to avoid collision with termios and kd */ + +diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h +index be51ae2..0d0b953 100644 +--- a/include/mtd/mtd-abi.h ++++ b/include/mtd/mtd-abi.h +@@ -30,6 +30,14 @@ struct mtd_oob_buf64 { + __u64 usr_ptr; + }; + ++struct mtd_page_buf { ++ uint32_t start; //page start address ++ uint32_t ooblength; ++ uint32_t datlength; ++ unsigned char __user *oobptr; ++ unsigned char __user *datptr; ++}; ++ + #define MTD_ABSENT 0 + #define MTD_RAM 1 + #define MTD_ROM 2 +@@ -42,6 +50,8 @@ struct mtd_oob_buf64 { + #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ + #define MTD_NO_ERASE 0x1000 /* No erase necessary */ + #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ ++#define MTD_MTDBLOCK_JZ_INVALID 0x4000 /* Device doesn't works over mtdblock-jz */ ++#define MTD_NAND_CPU_MODE 0x8000 /* Using cpu mode for NAND */ + + // Some common devices / combinations of capabilities + #define MTD_CAP_ROM 0 +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/oss/Kconfig b/sound/oss/Kconfig +index bcf2a06..558e4aa 100644 +--- a/sound/oss/Kconfig ++++ b/sound/oss/Kconfig +@@ -5,6 +5,91 @@ + # + # Prompt user for primary drivers. + ++config OSS_OBSOLETE ++ bool "Obsolete OSS drivers" ++ depends on SOUND_PRIME ++ help ++ This option enables support for obsolete OSS drivers that ++ are scheduled for removal in the near future. ++ ++ Please contact Adrian Bunk if you had to ++ say Y here because your hardware is not properly supported ++ by ALSA. ++ ++ If unsure, say N. ++ ++config SOUND_JZ_AC97 ++ bool "Jz On-Chip AC97 driver" ++ depends on OSS_OBSOLETE ++ help ++ Say Y here if you have want to select the on-chip AC97 driver ++ on Jz4730/Jz4740/Jz5730. ++ ++config SOUND_JZ_I2S ++ bool "Jz On-Chip I2S driver" ++ depends on OSS_OBSOLETE ++ help ++ Say Y here if you have want to select the on-chip I2S driver ++ on Jz4730/Jz4740/Jz5730. ++ ++config SOUND_JZ_PCM ++ bool "Jz On-Chip PCM driver" ++ depends on SOC_JZ4750 ++ help ++ Say Y here if you have want to select the on-chip PCM driver ++ on Jz4750. ++ ++choice ++ prompt "I2S codec type" ++ depends on SOUND_JZ_I2S ++ ++config I2S_AK4642EN ++ bool "AK4642EN" ++ depends on SOC_JZ4730 ++ help ++ Answer Y if you have an external AK4642EN codec. ++ ++config I2S_ICODEC ++ bool "Internal On-Chip codec" ++ depends on SOC_JZ4740 ++ help ++ Answer Y if you have an internal I2S codec. ++ ++config I2S_DLV ++ bool "Internal On-Chip codec on Jz4750 or Jz4750d" ++ depends on SOC_JZ4750 || SOC_JZ4750D ++ help ++ Answer Y if you have an internal I2S codec on Jz4750 or Jz4750d. ++ ++endchoice ++ ++choice ++ prompt "PCM codec type" ++ depends on SOUND_JZ_PCM ++ ++config PCM_TLV320AIC1106 ++ bool "TLV320AIC1106" ++ help ++ Answer Y if you have an TI tlv320aic 1106 codec. ++ ++endchoice ++ ++config SOUND_BT878 ++ tristate "BT878 audio dma" ++ depends on SOUND_PRIME && PCI && OSS_OBSOLETE ++ ---help--- ++ Audio DMA support for bt878 based grabber boards. As you might have ++ already noticed, bt878 is listed with two functions in /proc/pci. ++ Function 0 does the video stuff (bt848 compatible), function 1 does ++ the same for audio data. This is a driver for the audio part of ++ the chip. If you say 'Y' here you get a oss-compatible dsp device ++ where you can record from. If you want just watch TV you probably ++ don't need this driver as most TV cards handle sound with a short ++ cable from the TV card to your sound card's line-in. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called btaudio. ++ + config SOUND_BCM_CS4297A + tristate "Crystal Sound CS4297a (for Swarm)" + depends on SIBYTE_SWARM +@@ -15,6 +100,13 @@ config SOUND_BCM_CS4297A + note that CONFIG_KGDB should not be enabled at the same + time, since it also attempts to use this UART port. + ++config SOUND_ICH ++ tristate "Intel ICH (i8xx) audio support" ++ depends on SOUND_PRIME && PCI && OSS_OBSOLETE ++ help ++ Support for integral audio in Intel's I/O Controller Hub (ICH) ++ chipset, as used on the 810/820/840 motherboards. ++ + config SOUND_VWSND + tristate "SGI Visual Workstation Sound" + depends on X86_VISWS +@@ -24,6 +116,14 @@ config SOUND_VWSND + for more info on this driver's + capabilities. + ++config SOUND_VRC5477 ++ tristate "NEC Vrc5477 AC97 sound" ++ depends on SOUND_PRIME && DDB5477 ++ help ++ Say Y here to enable sound support for the NEC Vrc5477 chip, an ++ integrated, multi-function controller chip for MIPS CPUs. Works ++ with the AC97 codec. ++ + config SOUND_AU1550_AC97 + tristate "Au1550/Au1200 AC97 Sound" + depends on SOC_AU1550 || SOC_AU1200 +@@ -503,7 +603,7 @@ config SOUND_AEDSP16 + questions. + + Read the file and the head of +- as well as ++ as well as + to get more information + about this driver and its configuration. + +@@ -553,6 +653,13 @@ config SOUND_WAVEARTIST + Say Y here to include support for the Rockwell WaveArtist sound + system. This driver is mainly for the NetWinder. + ++config SOUND_TVMIXER ++ tristate "TV card (bt848) mixer support" ++ depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE ++ help ++ Support for audio mixer facilities on the BT848 TV frame-grabber ++ card. ++ + config SOUND_KAHLUA + tristate "XpressAudio Sound Blaster emulation" + depends on SOUND_SB +diff --git a/sound/oss/Makefile b/sound/oss/Makefile +index e0ae4d4..37d5233 100644 +--- a/sound/oss/Makefile ++++ b/sound/oss/Makefile +@@ -9,6 +9,12 @@ obj-$(CONFIG_SOUND_OSS) += sound.o + + # Please leave it as is, cause the link order is significant ! + ++obj-$(CONFIG_SOUND_JZ_AC97) += jz_ac97.o ac97_codec.o ++obj-$(CONFIG_I2S_AK4642EN) += ak4642en.o ++obj-$(CONFIG_I2S_ICODEC) += jzcodec.o jz_i2s.o ++obj-$(CONFIG_I2S_DLV) += jzdlv.o jz_i2s.o ++obj-$(CONFIG_SOUND_JZ_PCM) += jz_pcm_tlv320aic1106_dma.o ++ + obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o + obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o + obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o +diff --git a/sound/oss/ak4642en.c b/sound/oss/ak4642en.c +new file mode 100644 +index 0000000..b649a7e +--- /dev/null ++++ b/sound/oss/ak4642en.c +@@ -0,0 +1,712 @@ ++/* ++ * linux/sound/oss/ak4642en.c ++ * ++ * AKM ak4642en codec chip driver to I2S interface ++ * ++ * Copyright (c) 2005-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sound_config.h" ++ ++extern mixer_info info; ++extern _old_mixer_info old_info; ++extern int abnormal_data_count; ++ ++extern void (*clear_codec_mode)(void); ++extern void (*set_codec_gpio_pin)(void); ++extern void (*each_time_init_codec)(void); ++extern void (*set_codec_record)(void); ++extern void (*set_codec_replay)(void); ++extern void (*clear_codec_record)(void); ++extern void (*clear_codec_replay)(void); ++extern void (*set_codec_speed)(int range); ++extern void (*codec_mixer_old_info_id_name)(void); ++extern void (*codec_mixer_info_id_name)(void); ++extern void (*set_codec_volume)(int val); ++extern void (*set_codec_mic)(int val); ++extern void (*i2s_resume_codec)(void); ++extern void (*i2s_suspend_codec)(int wr,int rd); ++extern void (*set_replay_hp_or_speaker)(void); ++ ++#define I2S_PDN 68 ++#define JACK_PLUG_PIN 83 ++#define JACK_PLUG_IRQ (IRQ_GPIO_0 + JACK_PLUG_PIN) ++ ++static int jack_plug_level, old_level; ++static unsigned int i2c_addr = 0x26; //AK4642EN device address at I2C bus ++static unsigned int i2c_clk = 100000;//AK4642EN 400kHz max,but 100kHz here ++static unsigned int spk_hp = 0; ++static int codec_volume; ++ ++void set_ak4642en_gpio_pin(void); ++void each_time_init_ak4642en(void); ++void set_ak4642en_replay(void); ++void set_ak4642en_record(void); ++void turn_on_ak4642en(void); ++void turn_off_ak4642en(void); ++void set_ak4642en_speed(int rate); ++void reset_ak4642en(void); ++void ak4642en_mixer_old_info_id_name(void); ++void ak4642en_mixer_info_id_name(void); ++void set_ak4642en_bass(int val); ++void set_ak4642en_volume(int val); ++void set_ak4642en_mic(int val); ++void resume_ak4642en(void); ++void suspend_ak4642en(int wr,int rd); ++ ++static void write_reg(u8 reg, u8 val) ++{ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_write((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++} ++ ++#if 0 ++static u8 read_reg(u8 reg) ++{ ++ u8 val; ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_read((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++ return val; ++} ++ ++static u16 i2s_codec_read(u8 reg) ++{ ++ u16 value; ++ value = read_reg(reg); ++ return value; ++} ++#endif ++ ++static void i2s_codec_write(u8 reg, u16 data) ++{ ++ u8 val = data & 0xff; ++ write_reg(reg, val); ++} ++ ++void set_ak4642en_gpio_pin(void) ++{ ++ //set AIC pin to I2S slave mode,only GPIO70,71,77,78 ++ __gpio_as_output(68); ++ __gpio_clear_pin(68); ++ __gpio_as_output(69); ++ __gpio_clear_pin(69); ++ __gpio_as_output(70); ++ __gpio_clear_pin(70); ++ __gpio_as_input(71); ++ __gpio_clear_pin(71); ++ __gpio_as_input(77); ++ __gpio_clear_pin(77); ++ __gpio_as_input(78); ++ __gpio_clear_pin(78); ++ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; ++ REG_GPIO_GPALR(2) |= 0x14005000; ++ //set SCC clock initialization ++ REG_SCC1_CR(SCC1_BASE) = 0x00000000; ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; ++ udelay(2); ++ ++ __gpio_as_output(I2S_PDN); ++ __gpio_set_pin(I2S_PDN); ++ udelay(5); ++ __gpio_clear_pin(I2S_PDN); ++ ndelay(300);//>150ns ++ __gpio_set_pin(I2S_PDN); ++ mdelay(1); ++ //set PLL Master mode ++ i2s_codec_write(0x01, 0x0008);//master ++ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli ++ i2s_codec_write(0x05, 0x000b);//sync:48KHz; ++ i2s_codec_write(0x00, 0x0040);//PMVCM ++ i2s_codec_write(0x01, 0x0009);//master,PLL enable ++ mdelay(40); ++ jack_plug_level = 10; ++ old_level = 100; ++ spk_hp = 0; ++ __gpio_disable_pull(JACK_PLUG_PIN); ++ udelay(10); ++ __gpio_as_input(JACK_PLUG_PIN); ++ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); ++ //i suppose jack_plug_lvel is 1 indicate with HPO ++ if (jack_plug_level > 1 || jack_plug_level <0) ++ printk("Audio ak4642en codec Jack plug level is wrong!\n"); ++ if (jack_plug_level) ++ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); ++ else ++ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); ++} ++ ++void clear_ak4642en_mode(void) ++{ ++ spk_hp = 0; ++ i2s_codec_write(0x01, 0x0008);//master,PLL disable ++ //free_irq(JACK_PLUG_IRQ, i2s_controller); ++ __gpio_clear_pin(I2S_PDN); ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; ++ udelay(2); ++} ++ ++void set_ak4642en_replay(void) ++{ ++ //for poll ++ /*jack_plug_level is H for SPK,is L for HP*/ ++ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); ++ if(old_level == jack_plug_level) ++ return; ++ old_level = jack_plug_level; ++ if(spk_hp == 1) ++ { ++ if(jack_plug_level == 1) ++ { ++ //now HeadPhone output,so clear SPK ++ i2s_codec_write(0x02, 0x0020); ++ i2s_codec_write(0x02, 0x0000); ++ i2s_codec_write(0x00, 0x0040); ++ } ++ else ++ { ++ //now Speaker output,so clear HP ++ i2s_codec_write(0x01, 0x0039); ++ i2s_codec_write(0x01, 0x0009); ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x0e, 0x0000); ++ i2s_codec_write(0x0f, 0x0008); ++ } ++ } ++ spk_hp = 1; ++ if(jack_plug_level == 1) ++ { ++ //for HeadPhone output ++ i2s_codec_write(0x00, 0x0060); // ++ i2s_codec_write(0x0f, 0x0009); //5-10 ++ ++ i2s_codec_write(0x00, 0x0064); // ++ i2s_codec_write(0x09, 0x0091);// volume control 0dB ++ i2s_codec_write(0x0c, 0x0091);// 0dB(right) ++ //eq off ++ i2s_codec_write(0x11, 0x0000);//5-10 ++ i2s_codec_write(0x01, 0x0039); // ++ ++ i2s_codec_write(0x01, 0x0079); // ++ } ++ else ++ { ++ //for Speaker output ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x02, 0x0020); ++ ++ i2s_codec_write(0x03, 0x0018);//5-10 ++ i2s_codec_write(0x06, 0x003c); ++ ++ i2s_codec_write(0x08, 0x00A1);//5-10 ++ ++ i2s_codec_write(0x0b, 0x0040); //5-10 ++ ++ i2s_codec_write(0x07, 0x002d); //5-10 ++ i2s_codec_write(0x09, 0x0091); ++ i2s_codec_write(0x0c, 0x0091); ++ //HP volume output value ++ ++ i2s_codec_write(0x0a, codec_volume);//5-10 ++ i2s_codec_write(0x0d, codec_volume);//5-10 ++ ++ i2s_codec_write(0x00, 0x0074); ++ i2s_codec_write(0x02, 0x00a0); ++ } ++} ++ ++void set_ak4642en_record(void) ++{ ++ abnormal_data_count = 0; ++ i2s_codec_write(0x02, 0x0004); ++ i2s_codec_write(0x03, 0x0038);// recording volume add ++ i2s_codec_write(0x06, 0x0000);//for ALC short waiting time ++ i2s_codec_write(0x08, 0x00e1); ++ i2s_codec_write(0x0b, 0x0000); ++ i2s_codec_write(0x07, 0x0021); // ALC on ++ ++ i2s_codec_write(0x10, 0x0000);//0x0001 ++ //i2s_codec_write(0x10, 0x0001);//0x0001 ++ i2s_codec_write(0x01, 0x0039); //for open pop noise ++ i2s_codec_write(0x01, 0x0079); ++ i2s_codec_write(0x00, 0x0065); ++ mdelay(300); ++} ++ ++void clear_ak4642en_replay(void) ++{ ++ //for poll ++ old_level = 100; ++ spk_hp = 0; ++ if(jack_plug_level == 1) ++ { ++ //for HeadPhone output ++ i2s_codec_write(0x01, 0x0039); // for close pop noise ++ mdelay(300); ++ i2s_codec_write(0x01, 0x0009); //PLL on I2S ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x0f, 0x0008); // for open pop noise ++ } ++ else ++ { ++ //for Speaker output ++ i2s_codec_write(0x02, 0x0020); ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x02, 0x0000); ++ i2s_codec_write(0x00, 0x0040); // for close pop noise ++ } ++} ++ ++void clear_ak4642en_record(void) ++{ ++ //for Mic input(Stereo) ++ i2s_codec_write(0x02, 0x0001); ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++} ++ ++void each_time_init_ak4642en(void) ++{ ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __i2s_set_sample_size(16); ++} ++ ++void set_ak4642en_speed(int rate) ++{ ++ //codec work at frequency ++ unsigned short speed = 0; ++ unsigned short val = 0; ++ switch (rate) ++ { ++ case 8000: ++ speed = 0x00; ++ if(jack_plug_level == 1) //speaker ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x0027);//800hz ++ i2s_codec_write(0x1D, 0x0018); ++ i2s_codec_write(0x1E, 0x00b2); ++ i2s_codec_write(0x1F, 0x002f); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 12000: ++ speed = 0x01; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x0064); ++ i2s_codec_write(0x1D, 0x001a); ++ i2s_codec_write(0x1E, 0x0038); ++ i2s_codec_write(0x1F, 0x002b); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 16000: ++ speed = 0x02; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x00af); ++ i2s_codec_write(0x17, 0x0020); ++ i2s_codec_write(0x18, 0x0043); ++ i2s_codec_write(0x19, 0x001a); ++ i2s_codec_write(0x1A, 0x00af); ++ i2s_codec_write(0x1B, 0x0020); ++ i2s_codec_write(0x1C, 0x00a0); ++ i2s_codec_write(0x1D, 0x001b); ++ i2s_codec_write(0x1E, 0x00c0); ++ i2s_codec_write(0x1F, 0x0028); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 24000: ++ speed = 0x03; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0086); ++ i2s_codec_write(0x17, 0x0015); ++ i2s_codec_write(0x18, 0x005d); ++ i2s_codec_write(0x19, 0x0006); ++ i2s_codec_write(0x1A, 0x0086); ++ i2s_codec_write(0x1B, 0x0015); ++ i2s_codec_write(0x1C, 0x00f5); ++ i2s_codec_write(0x1D, 0x001c); ++ i2s_codec_write(0x1E, 0x0016); ++ i2s_codec_write(0x1F, 0x0026); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 7350: ++ speed = 0x04; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x0027); ++ i2s_codec_write(0x1D, 0x0018); ++ i2s_codec_write(0x1E, 0x00b2); ++ i2s_codec_write(0x1F, 0x002f); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 11025: ++ speed = 0x05; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0059); ++ i2s_codec_write(0x17, 0x000d); ++ i2s_codec_write(0x18, 0x00cb); ++ i2s_codec_write(0x19, 0x0037); ++ i2s_codec_write(0x1A, 0x0059); ++ i2s_codec_write(0x1B, 0x000d); ++ i2s_codec_write(0x1C, 0x0046); ++ i2s_codec_write(0x1D, 0x001e); ++ i2s_codec_write(0x1E, 0x0074); ++ i2s_codec_write(0x1F, 0x0023); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 14700: ++ speed = 0x06; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x004a); ++ i2s_codec_write(0x1D, 0x001b); ++ i2s_codec_write(0x1E, 0x006c); ++ i2s_codec_write(0x1F, 0x0029); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 22050: ++ speed = 0x07; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x002d); ++ i2s_codec_write(0x17, 0x0017); ++ i2s_codec_write(0x18, 0x0050); ++ i2s_codec_write(0x19, 0x0009); ++ i2s_codec_write(0x1A, 0x002d); ++ i2s_codec_write(0x1B, 0x0017); ++ i2s_codec_write(0x1C, 0x00d7); ++ i2s_codec_write(0x1D, 0x001c); ++ i2s_codec_write(0x1E, 0x0093); ++ i2s_codec_write(0x1F, 0x0026); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 32000: ++ speed = 0x0a; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0012); ++ i2s_codec_write(0x17, 0x0011); ++ i2s_codec_write(0x18, 0x006e); ++ i2s_codec_write(0x19, 0x003e); ++ i2s_codec_write(0x1A, 0x0012); ++ i2s_codec_write(0x1B, 0x0011); ++ i2s_codec_write(0x1C, 0x00aa); ++ i2s_codec_write(0x1D, 0x001d); ++ i2s_codec_write(0x1E, 0x00ab); ++ i2s_codec_write(0x1F, 0x0024); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 48000: ++ speed = 0x0b; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0082); ++ i2s_codec_write(0x17, 0x000c); ++ i2s_codec_write(0x18, 0x004b); ++ i2s_codec_write(0x19, 0x0036); ++ i2s_codec_write(0x1A, 0x0082); ++ i2s_codec_write(0x1B, 0x000c); ++ i2s_codec_write(0x1C, 0x0068); ++ i2s_codec_write(0x1D, 0x001e); ++ i2s_codec_write(0x1E, 0x0030); ++ i2s_codec_write(0x1F, 0x0023); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 29400: ++ speed = 0x0e; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x003d); ++ i2s_codec_write(0x17, 0x0012); ++ i2s_codec_write(0x18, 0x0083); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x003d); ++ i2s_codec_write(0x1B, 0x0012); ++ i2s_codec_write(0x1C, 0x0079); ++ i2s_codec_write(0x1D, 0x001d); ++ i2s_codec_write(0x1E, 0x000d); ++ i2s_codec_write(0x1F, 0x0025); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 44100: ++ speed = 0x0f; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0059); ++ i2s_codec_write(0x17, 0x000d); ++ i2s_codec_write(0x18, 0x00cb); ++ i2s_codec_write(0x19, 0x0037); ++ i2s_codec_write(0x1A, 0x0059); ++ i2s_codec_write(0x1B, 0x000d); ++ i2s_codec_write(0x1C, 0x0046); ++ i2s_codec_write(0x1D, 0x001e); ++ i2s_codec_write(0x1E, 0x0074); ++ i2s_codec_write(0x1F, 0x0023); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ default: ++ break; ++ } ++ val = speed & 0x08; ++ val = val << 2; ++ speed = speed & 0x07; ++ val = val | speed; ++ i2s_codec_write(0x05, val); ++} ++ ++void ak4642en_mixer_old_info_id_name(void) ++{ ++ strncpy(info.id, "AK4642EN", sizeof(info.id)); ++ strncpy(info.name,"AKM AK4642en codec", sizeof(info.name)); ++} ++ ++void ak4642en_mixer_info_id_name(void) ++{ ++ strncpy(old_info.id, "AK4642EN", sizeof(old_info.id)); ++ strncpy(old_info.name,"AKM AK4642en codec", sizeof(old_info.name)); ++} ++ ++void set_ak4642en_volume(int val) ++{ ++ if ( val == 0 ) ++ codec_volume = 255; ++ else if ( val > 1 && val <= 10) ++ codec_volume = 92; ++ else if ( val > 10 && val <= 20 ) ++ codec_volume = 67; ++ else if ( val > 20 && val <= 30 ) ++ codec_volume = 50; ++ else if ( val > 30 && val <= 40 ) ++ codec_volume = 40; ++ else if ( val > 40 && val <= 50 ) ++ codec_volume = 30; ++ else if ( val > 50 && val <= 60 ) ++ codec_volume = 22; ++ else if ( val > 60&& val <= 70 ) ++ codec_volume = 15; ++ else if ( val > 70 && val <= 80 ) ++ codec_volume = 8; ++ else if ( val > 80 && val <= 90 ) ++ codec_volume = 4; ++ else if ( val > 90 && val <= 100 ) ++ codec_volume = 2; ++ ++ i2s_codec_write(0x0a, codec_volume); ++ i2s_codec_write(0x0d, codec_volume); ++} ++ ++void set_ak4642en_mic(int val) ++{ ++ int mic_gain; ++ mic_gain = 241 * val /100; ++ i2s_codec_write(0x09, mic_gain); ++ i2s_codec_write(0x0c, mic_gain); ++} ++ ++void resume_ak4642en(void) ++{ ++ __gpio_as_output(17); ++ __gpio_set_pin(17); //enable ak4642 ++ __gpio_as_output(68); ++ __gpio_clear_pin(68); ++ __gpio_as_output(69); ++ __gpio_clear_pin(69); ++ __gpio_as_output(70); ++ __gpio_clear_pin(70); ++ __gpio_as_input(71); ++ __gpio_clear_pin(71); ++ __gpio_as_input(77); ++ __gpio_clear_pin(77); ++ __gpio_as_input(78); ++ __gpio_clear_pin(78); ++ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; ++ REG_GPIO_GPALR(2) |= 0x14005000; ++ //set SCC clock initialization ++ REG_SCC1_CR(SCC1_BASE) = 0x00000000; ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; ++ udelay(2); ++ __gpio_as_output(I2S_PDN); ++ __gpio_set_pin(I2S_PDN); ++ udelay(5); ++ __gpio_clear_pin(I2S_PDN); ++ ndelay(300);//>150ns ++ __gpio_set_pin(I2S_PDN); ++ mdelay(1); ++ //set PLL Master mode ++ i2s_codec_write(0x01, 0x0008);//master ++ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli ++ i2s_codec_write(0x05, 0x000b);//sync:48KHz; ++ i2s_codec_write(0x00, 0x0040);//PMVCM ++ i2s_codec_write(0x01, 0x0009);//master,PLL enable ++ jack_plug_level = 10; ++ old_level = 100; ++ spk_hp = 0; ++ __gpio_as_input(JACK_PLUG_PIN); ++ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); ++ //i suppose jack_plug_lvel is 1 indicate with HPO ++ if(jack_plug_level > 1 || jack_plug_level <0) ++ printk("Audio ak4642en codec Jack plug level is wrong!\n"); ++ if(jack_plug_level) ++ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); ++ else ++ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); ++ ++ i2s_codec_write(0x00, 0x0065); //for resume power ++ i2s_codec_write(0x01, 0x0039); //for open pop noise ++ i2s_codec_write(0x01, 0x0079); ++ i2s_codec_write(0x0a, codec_volume); ++ i2s_codec_write(0x0d, codec_volume); ++} ++ ++void suspend_ak4642en(int wr,int rd) ++{ ++ if(wr) //playing ++ { ++ if(jack_plug_level == 0) ++ { ++ i2s_codec_write(0x01, 0x0039); // for close pop noise ++ mdelay(500); ++ i2s_codec_write(0x01, 0x0009); //PLL on I2S ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x0f, 0x0008); // for open pop noise ++ ++ } ++ else ++ { ++ //for Speaker output ++ i2s_codec_write(0x02, 0x0020); ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x02, 0x0000); ++ i2s_codec_write(0x00, 0x0040); // for close pop noise ++ } ++ } ++ ++ if(rd) // recording ++ { ++ i2s_codec_write(0x02, 0x0001); // 5-11 a1 ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ mdelay(300); ++ } ++ __gpio_as_output(17); ++ __gpio_clear_pin(17);//disable ak4642 ++ __i2s_disable(); ++} ++ ++static int __init init_ak4642en(void) ++{ ++ set_codec_gpio_pin = set_ak4642en_gpio_pin; ++ each_time_init_codec = each_time_init_ak4642en; ++ clear_codec_mode = clear_ak4642en_mode; ++ ++ set_codec_record = set_ak4642en_record; ++ set_codec_replay = set_ak4642en_replay; ++ set_replay_hp_or_speaker = set_ak4642en_replay; ++ ++ set_codec_speed = set_ak4642en_speed; ++ clear_codec_record = clear_ak4642en_record; ++ clear_codec_replay = clear_ak4642en_replay; ++ ++ codec_mixer_old_info_id_name = ak4642en_mixer_old_info_id_name; ++ codec_mixer_info_id_name = ak4642en_mixer_info_id_name; ++ ++ set_codec_volume = set_ak4642en_volume; ++ ++ set_codec_mic = set_ak4642en_mic; ++ ++ i2s_resume_codec = resume_ak4642en; ++ i2s_suspend_codec = suspend_ak4642en; ++ printk("---> ak4642en initialization!\n"); ++ return 0; ++} ++ ++static void __exit cleanup_ak4642en(void) ++{ ++ spk_hp = 0; ++ i2s_codec_write(0x01, 0x0008);//master,PLL disable ++ //free_irq(JACK_PLUG_IRQ, i2s_controller); ++ __gpio_clear_pin(I2S_PDN); ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; ++ udelay(2); ++} ++ ++module_init(init_ak4642en); ++module_exit(cleanup_ak4642en); +diff --git a/sound/oss/jz_ac97.c b/sound/oss/jz_ac97.c +new file mode 100644 +index 0000000..698a003 +--- /dev/null ++++ b/sound/oss/jz_ac97.c +@@ -0,0 +1,2252 @@ ++/* ++ * linux/drivers/sound/jz_ac97.c ++ * ++ * Jz On-Chip AC97 audio driver. ++ * ++ * Copyright (C) 2005 - 2007, Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#define __NO_VERSION__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include "sound_config.h" ++ ++#define DMA_ID_AC97_TX DMA_ID_AIC_TX ++#define DMA_ID_AC97_RX DMA_ID_AIC_RX ++ ++/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ ++#define NR_AC97 2 ++ ++#define STANDARD_SPEED 48000 ++#define MAX_RETRY 100 ++ ++static unsigned int k_8000[] = { ++ 0, 42, 85, 128, 170, 213, ++}; ++ ++static unsigned int reload_8000[] = { ++ 1, 0, 0, 0, 0, 0, ++}; ++ ++static unsigned int k_11025[] = { ++ 0, 58, 117, 176, 234, 37, 96, 154, ++ 213, 16, 74, 133, 192, 250, 53, 112, ++ 170, 229, 32, 90, 149, 208, 10, 69, ++ 128, 186, 245, 48, 106, 165, 224, 26, ++ 85, 144, 202, 5, 64, 122, 181, 240, ++ 42, 101, 160, 218, 21, 80, 138, 197, ++}; ++ ++static unsigned int reload_11025[] = { ++ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ++ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, ++ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, ++}; ++ ++static unsigned int k_16000[] = { ++ 0, 85, 170, ++}; ++ ++static unsigned int reload_16000[] = { ++ 1, 0, 0, ++}; ++ ++static unsigned int k_22050[] = { ++ 0, 117, 234, 96, 213, 74, 192, 53, ++ 170, 32, 149, 10, 128, 245, 106, 224, ++ 85, 202, 64, 181, 42, 160, 21, 138, ++}; ++ ++static unsigned int reload_22050[] = { ++ 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, ++ 1, 0, 1, 0, 1, 0, 1, 0, ++}; ++ ++static unsigned int k_24000[] = { ++ 0, 128, ++}; ++ ++static unsigned int reload_24000[] = { ++ 1, 0, ++}; ++ ++static unsigned int k_32000[] = { ++ 0, 170, 85, ++}; ++ ++static unsigned int reload_32000[] = { ++ 1, 0, 1, ++}; ++ ++static unsigned int k_44100[] = { ++ 0, 234, 213, 192, 170, 149, 128, 106, ++ 85, 64, 42, 21, ++}; ++ ++static unsigned int reload_44100[] = { ++ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++}; ++ ++static unsigned int k_48000[] = { ++ 0, ++}; ++ ++static unsigned int reload_48000[] = { ++ 1, ++}; ++ ++ ++static unsigned int f_scale_counts[8] = { ++ 6, 48, 3, 24, 2, 3, 12, 1, ++}; ++ ++static int jz_audio_rate; ++static char jz_audio_format; ++static char jz_audio_channels; ++static int jz_audio_k; /* rate expand multiple */ ++static int jz_audio_q; /* rate expand compensate */ ++static int jz_audio_count; /* total count of voice data */ ++static int last_jz_audio_count; ++ ++static int jz_audio_fragments;//unused fragment amount ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_dma_tran_count;//bytes count of one DMA transfer ++ ++static unsigned int f_scale_count; ++static unsigned int *f_scale_array; ++static unsigned int *f_scale_reload; ++static unsigned int f_scale_idx; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++extern void jz_set_dma_block_size(int dmanr, int nbyte); ++extern void jz_set_dma_dest_width(int dmanr, int nbit); ++extern void jz_set_dma_src_width(int dmanr, int nbit); ++ ++static void jz_update_filler(int bits, int channels); ++ ++static void Init_In_Out_queue(int fragstotal,int fragsize); ++static void Free_In_Out_queue(int fragstotal,int fragsize); ++ ++static irqreturn_t ++jz_ac97_replay_dma_irq(int irqnr, void *dev_id); ++static irqreturn_t ++jz_ac97_record_dma_irq(int irqnr, void *dev_id); ++ ++static void ++(*replay_filler)(unsigned long src_start, int count, int id); ++static int ++(*record_filler)(unsigned long dst_start, int count, int id); ++ ++static struct file_operations jz_ac97_audio_fops; ++ ++DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++ ++struct jz_ac97_controller_info ++{ ++ int io_base; ++ int dma1; /* play */ ++ int dma2; /* record */ ++ ++ char *name; ++ ++ int dev_audio; ++ struct ac97_codec *ac97_codec[NR_AC97]; ++ ++ unsigned short ac97_features; ++ ++ int opened1; ++ int opened2; ++ ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ ++ int nextIn; // byte index to next-in to DMA buffer ++ int nextOut; // byte index to next-out from DMA buffer ++ int count; // current byte count in DMA buffer ++ int finish; // current transfered byte count in DMA buffer ++ unsigned total_bytes; // total bytes written or read ++ unsigned blocks; ++ unsigned error; // over/underrun ++ ++ /* We use two devices, because we can do simultaneous play and record. ++ This keeps track of which device is being used for what purpose; ++ these are the actual device numbers. */ ++ int dev_for_play; ++ int dev_for_record; ++ ++ int playing; ++ int recording; ++ int patched; ++ unsigned long rec_buf_size; ++ unsigned long playback_buf_size; ++ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++static struct jz_ac97_controller_info *ac97_controller = NULL; ++ ++static int jz_readAC97Reg(struct ac97_codec *dev, u8 reg); ++static int jz_writeAC97Reg(struct ac97_codec *dev, u8 reg, u16 data); ++static u16 ac97_codec_read(struct ac97_codec *codec, u8 reg); ++static void ac97_codec_write(struct ac97_codec *codec, u8 reg, u16 data); ++ ++#define QUEUE_MAX 2 ++ ++typedef struct buffer_queue_s { ++ int count; ++ int *id; ++ spinlock_t lock; ++} buffer_queue_t; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++ ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++ ++static int first_record_call = 0; ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r, i; ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ return r; ++} ++ ++/**************************************************************************** ++ * Architecture related routines ++ ****************************************************************************/ ++static inline ++void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_ac97_controller_info * controller = ++ (struct jz_ac97_controller_info *) dev_id; ++ //for DSP_GETOPTR ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ set_dma_mode(chan, mode); ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk(KERN_DEBUG "%s: JzSOC DMA controller can't set dma count zero!\n", ++ __FUNCTION__); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t ++jz_ac97_record_dma_irq (int irq, void *dev_id) ++{ ++ struct jz_ac97_controller_info * controller = ++ (struct jz_ac97_controller_info *) dev_id; ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ //for DSP_GETIPTR ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else { ++ in_busy_queue.count = 0; ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ++jz_ac97_replay_dma_irq (int irq, void *dev_id) ++{ ++ struct jz_ac97_controller_info * controller = ++ (struct jz_ac97_controller_info *) dev_id; ++ int dma = controller->dma1, id; ++ unsigned long flags; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ //for DSP_GETOPTR ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) { ++ printk(KERN_DEBUG "Strange DMA finish interrupt for AC97 module\n"); ++ } ++ ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ } ++ } else { ++ out_busy_queue.count = 0; ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Initialize the onchip AC97 controller ++ */ ++static void jz_ac97_initHw(struct jz_ac97_controller_info *controller) ++{ ++ __ac97_disable(); ++ __ac97_reset(); ++ __ac97_enable(); ++ ++ __ac97_cold_reset_codec(); ++ /* wait for a long time to let ac97 controller reset completely, ++ * otherwise, registers except ACFR will be clear by reset, can't be ++ * set correctly. ++ */ ++ udelay(160); ++ ++ __ac97_disable_record(); ++ __ac97_disable_replay(); ++ __ac97_disable_loopback(); ++ ++ /* Check the trigger threshold reset value to detect version */ ++ if (((REG_AIC_FR & AIC_FR_TFTH_MASK) >> AIC_FR_TFTH_BIT) == 8) { ++ printk("JzAC97: patched controller detected.\n"); ++ controller->patched = 1; ++ } else { ++ printk("JzAC97: standard controller detected.\n"); ++ controller->patched = 0; ++ } ++ ++ /* Set FIFO data size. Which shows valid data bits. ++ * ++ */ ++ __ac97_set_oass(8); ++ __ac97_set_iass(8); ++ ++ __ac97_set_xs_stereo(); ++ __ac97_set_rs_stereo(); ++} ++ ++/* ++ * Initialize all of in(out)_empty_queue value ++ */ ++static void Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ if(out_dma_buf || in_dma_buf) ++ return; ++ in_empty_queue.count = fragstotal; ++ out_empty_queue.count = fragstotal; ++ ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) { ++ *(in_empty_queue.id + i) = i; ++ *(out_empty_queue.id + i) = i; ++ } ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /*alloc DMA buffer*/ ++ for (i = 0; i < jz_audio_fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ for (i = 0; i < jz_audio_fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(IN) buffers.\n"); ++ goto mem_failed_in; ++ } ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), 4096*8);//fragsize ++ *(in_dma_buf + i) = KSEG1ADDR(*(in_dma_buf + i)); ++ } ++ return ; ++ ++ all_mem_err: ++ printk("error:allocate memory occur error!\n"); ++ return ; ++ ++mem_failed_out: ++ ++ for (i = 0; i < jz_audio_fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ return ; ++ ++mem_failed_in: ++ ++ for (i = 0; i < jz_audio_fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return ; ++ ++} ++static void Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ if(out_dma_buf != NULL) ++ { ++ for (i = 0; i < jz_audio_fragstotal; i++) ++ { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) ++ { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) ++ { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(in_dma_buf) ++ { ++ for (i = 0; i < jz_audio_fragstotal; i++) ++ { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) ++ { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) ++ { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) ++ { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) ++ { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) ++ { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ if(out_empty_queue.id) ++ { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) ++ { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) ++ { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ out_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ return ; ++} ++ ++/* ++ * Reset everything ++ */ ++static void ++jz_ac97_full_reset(struct jz_ac97_controller_info *controller) ++{ ++ jz_ac97_initHw(controller); ++} ++ ++ ++static void ++jz_ac97_mksound(unsigned int hz, unsigned int ticks) ++{ ++// printk("BEEP - %d %d!\n", hz, ticks); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ u32 dacp; ++ struct ac97_codec *codec=ac97_controller->ac97_codec[0]; ++ ++ if (rate > 48000) ++ rate = 48000; ++ if (rate < 8000) ++ rate = 8000; ++ ++ ++ /* Power down the DAC */ ++ dacp=ac97_codec_read(codec, AC97_POWER_CONTROL); ++ ac97_codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200); ++ /* Load the rate; only 48Khz playback available, read always zero */ ++ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1)) ++ ac97_codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate); ++ else ++ ac97_codec_write(codec, AC97_PCM_FRONT_DAC_RATE, 48000); ++ ++ /* Power it back up */ ++ ac97_codec_write(codec, AC97_POWER_CONTROL, dacp); ++ ++ jz_audio_rate = rate; ++ jz_audio_k = STANDARD_SPEED / rate; ++ if (rate * jz_audio_k != STANDARD_SPEED) ++ jz_audio_q = rate / ((STANDARD_SPEED / jz_audio_k) - rate ); ++ else ++ jz_audio_q = 0x1fffffff; /* a very big value, don't compensate */ ++ ++ switch (rate) { ++ case 8000: ++ f_scale_count = f_scale_counts[0]; ++ f_scale_array = k_8000; ++ f_scale_reload = reload_8000; ++ break; ++ case 11025: ++ f_scale_count = f_scale_counts[1]; ++ f_scale_array = k_11025; ++ f_scale_reload = reload_11025; ++ break; ++ case 16000: ++ f_scale_count = f_scale_counts[2]; ++ f_scale_array = k_16000; ++ f_scale_reload = reload_16000; ++ break; ++ case 22050: ++ f_scale_count = f_scale_counts[3]; ++ f_scale_array = k_22050; ++ f_scale_reload = reload_22050; ++ break; ++ case 24000: ++ f_scale_count = f_scale_counts[4]; ++ f_scale_array = k_24000; ++ f_scale_reload = reload_24000; ++ break; ++ case 32000: ++ f_scale_count = f_scale_counts[5]; ++ f_scale_array = k_32000; ++ f_scale_reload = reload_32000; ++ break; ++ case 44100: ++ f_scale_count = f_scale_counts[6]; ++ f_scale_array = k_44100; ++ f_scale_reload = reload_44100; ++ break; ++ case 48000: ++ f_scale_count = f_scale_counts[7]; ++ f_scale_array = k_48000; ++ f_scale_reload = reload_48000; ++ break; ++ } ++ f_scale_idx = 0; ++ ++ return jz_audio_rate; ++} ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ volatile unsigned char *s = (unsigned char *)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ if ((jz_audio_count++ % jz_audio_k) == 0) { ++ cnt++; ++ data = *(s++); ++ *(dp ++) = data + 0x80; ++ s++; /* skip the other channel */ ++ } else { ++ s += 2; /* skip the redundancy */ ++ } ++ if (jz_audio_count - last_jz_audio_count >= jz_audio_q) { ++ jz_audio_count++; ++ last_jz_audio_count = jz_audio_count; ++ count -= 2; ++ s += 2; ++ } ++ } ++ return cnt; ++} ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1, d2; ++ volatile unsigned char *s = (unsigned char *)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ if ((jz_audio_count++ % jz_audio_k) == 0) { ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = d1 + 0x80; ++ d2 = *(s++); ++ *(dp ++) = d2 + 0x80; ++ } else { ++ s += 2; /* skip the redundancy */ ++ } ++ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { ++ jz_audio_count += 2; ++ last_jz_audio_count = jz_audio_count; ++ count -= 2; ++ s += 2; ++ } ++ } ++ return cnt; ++} ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned short d1; ++ unsigned short *s = (unsigned short *)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ if ((jz_audio_count++ % jz_audio_k) == 0) { ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = d1; ++ s++; /* skip the other channel */ ++ } else { ++ s += 2; /* skip the redundancy */ ++ } ++ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { ++ jz_audio_count += 2; ++ last_jz_audio_count = jz_audio_count; ++ count -= 2; ++ s += 2; ++ } ++ } ++ return cnt; ++} ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned short d1, d2; ++ unsigned short *s = (unsigned short *)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ if ((jz_audio_count++ % jz_audio_k) == 0) { ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = d1; ++ d2 = *(s++); ++ *(dp ++) = d2; ++ } else ++ s += 2; /* skip the redundancy */ ++ ++ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 4) { ++ jz_audio_count += 4; ++ last_jz_audio_count = jz_audio_count; ++ count -= 2; ++ s += 2; ++ } ++ } ++ return cnt; ++} ++ ++ ++static void replay_fill_1x8_u(unsigned long src_start, int count, int id) ++{ ++ int i, cnt = 0; ++ unsigned char data; ++ unsigned char *s = (unsigned char *)src_start; ++ unsigned char *dp = (unsigned char *)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ jz_audio_count++; ++ cnt += jz_audio_k; ++ data = *(s++) - 0x80; ++ for (i=0;i 0) { ++ count -= 2; ++ jz_audio_count += 2; ++ cnt += 2 * jz_audio_k; ++ d1 = *(s++) - 0x80; ++ d2 = *(s++) - 0x80; ++ for (i=0;i= jz_audio_q * 2) { ++ cnt += 2 * jz_audio_k; ++ last_jz_audio_count = jz_audio_count; ++ for (i=0;i= 0) { ++ if (f_scale_reload[f_scale_idx]) { ++ d1 = d2; ++ d2 = *s++; ++ if (!count) ++ break; ++ count -= 2; ++ } ++ d = d1 + (((d2 - d1) * f_scale_array[f_scale_idx]) >> 8); ++ *dp++ = d; ++ *dp++ = d; ++ cnt += 4; ++ f_scale_idx ++; ++ if (f_scale_idx >= f_scale_count) ++ f_scale_idx = 0; ++ } ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x16_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ static short d11, d12, d21, d22, d1, d2; ++ short *s = (short *)src_start; ++ short *dp = (short *)(*(out_dma_buf + id)); ++ ++ d12 = *s++; ++ d22 = *s++; ++ count -= 4; ++ while (count >= 0) { ++ register unsigned int kvalue; ++ kvalue = f_scale_array[f_scale_idx]; ++ if (f_scale_reload[f_scale_idx]) { ++ d11 = d12; ++ d12 = *s++; ++ d21 = d22; ++ d22 = *s++; ++ if (!count) ++ break; ++ count -= 4; ++ } ++ d1 = d11 + (((d12 - d11)*kvalue) >> 8); ++ d2 = d21 + (((d22 - d21)*kvalue) >> 8); ++ *dp++ = d1; ++ *dp++ = d2; ++ cnt += 4; ++ f_scale_idx ++; ++ if (f_scale_idx >= f_scale_count) ++ f_scale_idx = 0; ++ } ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ case AFMT_S16_LE: ++ jz_audio_format = fmt; ++ jz_update_filler(fmt, jz_audio_channels); ++ case AFMT_QUERY: ++ break; ++ } ++ return jz_audio_format; ++} ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ __ac97_set_xs_stereo(); // always stereo when recording ++ __ac97_set_rs_stereo(); // always stereo when recording ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case 2: ++ __ac97_set_xs_stereo(); ++ __ac97_set_rs_stereo(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case 0: ++ break; ++ } ++ return jz_audio_channels; ++} ++ ++ ++static void jz_audio_reset(void) ++{ ++ __ac97_disable_replay(); ++ __ac97_disable_receive_dma(); ++ __ac97_disable_record(); ++ __ac97_disable_transmit_dma(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file, ++ struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer, ++ size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_ac97_audio_fops */ ++static struct file_operations jz_ac97_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++/* Read / Write AC97 codec registers */ ++static inline int jz_out_command_ready(void) ++{ ++ int t2 = 1000; ++ int done = 0; ++ ++ while (! done && t2-- > 0) { ++ if (REG32(AC97_ACSR) & AIC_ACSR_CADT) { ++ REG32(AC97_ACSR) &= ~AIC_ACSR_CADT; ++ done = 1; ++ } ++ else ++ udelay (1); ++ } ++ return done; ++} ++ ++static inline int jz_in_status_ready(void) ++{ ++ int t2 = 1000; ++ int done = 0; ++ ++ while (! done && t2-- > 0) { ++ if (REG32(AC97_ACSR) & AIC_ACSR_SADR) { ++ REG32(AC97_ACSR) &= ~AIC_ACSR_SADR; ++ done = 1; ++ } ++ else { ++ if (REG32(AC97_ACSR) & AIC_ACSR_RSTO) { ++ REG32(AC97_ACSR) &= ~AIC_ACSR_RSTO; ++ printk(KERN_DEBUG "%s: RSTO receive status timeout.\n", ++ __FUNCTION__); ++ done = 0; ++ break; ++ } ++ udelay (1); ++ } ++ } ++ return done; ++} ++ ++static int jz_readAC97Reg (struct ac97_codec *dev, u8 reg) ++{ ++ u16 value; ++ ++ if (reg < 128) { ++ u8 ret_reg; ++ __ac97_out_rcmd_addr(reg);//output read addr ++ if (jz_out_command_ready())//judge if send completely? ++ while (jz_in_status_ready()) {//judge if receive completely? ++ ret_reg = __ac97_in_status_addr();//slot1:send addr ++ value = __ac97_in_data(); ++ if (ret_reg == reg) ++ return value; ++ else { ++// printk(KERN_DEBUG "%s: index (0x%02x)->(0x%02x) 0x%x\n", __FUNCTION__, reg, ret_reg, value); ++ return -EINVAL; ++ } ++ } ++ } ++ value = __ac97_in_data(); ++ printk (KERN_DEBUG "timeout while reading AC97 codec (0x%x)\n", reg); ++ return -EINVAL; ++} ++ ++static u16 ac97_codec_read(struct ac97_codec *codec, u8 reg) ++{ ++ int res = jz_readAC97Reg(codec, reg); ++ int count = 0; ++ while (res == -EINVAL) { ++ udelay(1000); ++ __ac97_warm_reset_codec(); ++ udelay(1000); ++ res = jz_readAC97Reg(codec, reg); ++ count ++; ++ if (count > MAX_RETRY){ ++ printk(KERN_WARNING"After try %d when read AC97 codec 0x%x, can't success, give up operate!!\n", ++ MAX_RETRY, reg); ++ break; ++ } ++ } ++ return (u16)res; ++} ++ ++static int jz_writeAC97Reg (struct ac97_codec *dev, u8 reg, u16 value) ++{ ++ //unsigned long flags; ++ int done = 0; ++ ++ //save_and_cli(flags); ++ ++ __ac97_out_wcmd_addr(reg); ++ __ac97_out_data(value); ++ if (jz_out_command_ready()) ++ done = 1; ++ else ++ printk (KERN_DEBUG "Tiemout AC97 codec write (0x%X<==0x%X)\n", reg, value); ++ //restore_flags(flags); ++ return done; ++} ++static void ac97_codec_write(struct ac97_codec *codec, u8 reg, u16 data) ++{ ++ int done = jz_writeAC97Reg(codec, reg, data); ++ int count = 0; ++ while (done == 0) { ++ count ++; ++ udelay (2000); ++ __ac97_warm_reset_codec(); ++ udelay(2000); ++ done = jz_writeAC97Reg(codec, reg, data); ++ if ( count > MAX_RETRY ){ ++ printk (KERN_DEBUG " After try %d when write AC97 codec (0x%x), can't sucess, give up!! \n", ++ MAX_RETRY, reg); ++ break; ++ } ++ } ++} ++ ++/* OSS /dev/mixer file operation methods */ ++ ++static int jz_ac97_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_ac97_controller_info *controller = ac97_controller; ++ ++ for (i = 0; i < NR_AC97; i++) ++ if (controller->ac97_codec[i] != NULL && ++ controller->ac97_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++ ++ match: ++ file->private_data = controller->ac97_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_ac97_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)file->private_data; ++ ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_ac97_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static /*const*/ struct file_operations jz_ac97_mixer_fops = { ++ owner: THIS_MODULE, ++ llseek: jz_ac97_llseek, ++ ioctl: jz_ac97_ioctl_mixdev, ++ open: jz_ac97_open_mixdev, ++}; ++ ++/* AC97 codec initialisation. */ ++static int __init jz_ac97_codec_init(struct jz_ac97_controller_info *controller) ++{ ++ int num_ac97 = 0; ++ int ready_2nd = 0; ++ struct ac97_codec *codec; ++ unsigned short eid; ++ int i = 0; ++ ++ if (__ac97_codec_is_low_power_mode()) { ++ printk(KERN_DEBUG "AC97 codec is low power mode, warm reset ...\n"); ++ __ac97_warm_reset_codec(); ++ udelay(10); ++ } ++ i = 0; ++ while (!__ac97_codec_is_ready()) { ++ i++; ++ if ( i > 100 ) { ++ printk(KERN_WARNING "AC97 codec not ready, failed init ..\n"); ++ return -ENODEV; ++ } ++ udelay(10); ++ } ++ i = 0; ++ ++ /* Reset the mixer. */ ++ for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { ++ if ((codec = kmalloc(sizeof(struct ac97_codec), ++ GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct ac97_codec)); ++ ++ /* initialize some basic codec information, ++ other fields will be filled ++ in ac97_probe_codec */ ++ codec->private_data = controller; ++ codec->id = num_ac97; ++ ++ codec->codec_read = ac97_codec_read; ++ codec->codec_write = ac97_codec_write; ++ ++ if (ac97_probe_codec(codec) == 0) ++ break; ++ ++ eid = ac97_codec_read(codec, AC97_EXTENDED_ID); ++ if (eid == 0xFFFF) { ++ printk(KERN_WARNING "Jz AC97: no codec attached?\n"); ++ kfree(codec); ++ break; ++ } ++ ++ controller->ac97_features = eid; ++ ++ if (!(eid & 0x0001)) ++ printk(KERN_WARNING "AC97 codec: only 48Khz playback available.\n"); ++ else { ++ printk(KERN_WARNING "AC97 codec: supports variable sample rate.\n"); ++ /* Enable HPEN: UCB1400 only */ ++ ac97_codec_write(codec, 0x6a, ++ ac97_codec_read(codec, 0x6a) | 0x40); ++ ++ /* Enable variable rate mode */ ++ ac97_codec_write(codec, AC97_EXTENDED_STATUS, 9); ++ ac97_codec_write(codec, ++ AC97_EXTENDED_STATUS, ++ ac97_codec_read(codec, AC97_EXTENDED_STATUS) | 0xE800); ++ /* power up everything, modify this ++ when implementing power saving */ ++ ac97_codec_write(codec, ++ AC97_POWER_CONTROL, ++ ac97_codec_read(codec, AC97_POWER_CONTROL) & ~0x7f00); ++ /* wait for analog ready */ ++ for (i=10; i && ((ac97_codec_read(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) { ++// current->state = TASK_UNINTERRUPTIBLE; ++// schedule_timeout(HZ/20); ++ } ++ ++ if (!(ac97_codec_read(codec, AC97_EXTENDED_STATUS) & 1)) { ++ printk(KERN_WARNING "Jz AC97: Codec refused to allow VRA, using 48Khz only.\n"); ++ controller->ac97_features &= ~1; ++ } ++ } ++ ++ if ((codec->dev_mixer = ++ register_sound_mixer(&jz_ac97_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz AC97: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ ++ controller->ac97_codec[num_ac97] = codec; ++ ++ /* if there is no secondary codec at all, don't probe any more */ ++ if (!ready_2nd) ++ return num_ac97+1; ++ } ++ return num_ac97; ++} ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<3) | ((ch)&7)) /* up to 8 chans supported. */ ++ ++ ++ switch (TYPE(format, channels)) { ++ default: ++ ++ case TYPE(AFMT_U8, 1): ++ if ((ac97_controller->patched) && ++ (ac97_controller->ac97_features & 1)) { ++ __aic_enable_mono2stereo(); ++ __aic_enable_unsignadj(); ++ jz_set_dma_block_size(ac97_controller->dma1, 16); ++ jz_set_dma_block_size(ac97_controller->dma2, 16); ++ } else { ++ __aic_disable_mono2stereo(); ++ __aic_disable_unsignadj(); ++ jz_set_dma_block_size(ac97_controller->dma1, 4); ++ jz_set_dma_block_size(ac97_controller->dma2, 4); ++ } ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ __ac97_set_oass(8); ++ __ac97_set_iass(8); ++ jz_set_dma_dest_width(ac97_controller->dma1, 8); ++ jz_set_dma_src_width(ac97_controller->dma2, 8); ++ break; ++ case TYPE(AFMT_U8, 2): ++ if ((ac97_controller->patched) && ++ (ac97_controller->ac97_features & 1)) { ++ __aic_enable_mono2stereo(); ++ __aic_enable_unsignadj(); ++ jz_set_dma_block_size(ac97_controller->dma1, 16); ++ jz_set_dma_block_size(ac97_controller->dma2, 16); ++ } else { ++ __aic_disable_mono2stereo(); ++ __aic_disable_unsignadj(); ++ jz_set_dma_block_size(ac97_controller->dma1, 4); ++ jz_set_dma_block_size(ac97_controller->dma2, 4); ++ } ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ __ac97_set_oass(8); ++ __ac97_set_iass(8); ++ jz_set_dma_dest_width(ac97_controller->dma1, 8); ++ jz_set_dma_src_width(ac97_controller->dma2, 8); ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ if ((ac97_controller->patched) && ++ (ac97_controller->ac97_features & 1)) { ++ __aic_enable_mono2stereo(); ++ jz_set_dma_block_size(ac97_controller->dma1, 16); ++ jz_set_dma_block_size(ac97_controller->dma2, 16); ++ } else { ++ __aic_disable_mono2stereo(); ++ jz_set_dma_block_size(ac97_controller->dma1, 4); ++ jz_set_dma_block_size(ac97_controller->dma2, 4); ++ } ++ __aic_disable_unsignadj(); ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ __ac97_set_oass(16); ++ __ac97_set_iass(16); ++ ++ jz_set_dma_dest_width(ac97_controller->dma1, 16); ++ jz_set_dma_src_width(ac97_controller->dma2, 16); ++ ++ break; ++ ++ case TYPE(AFMT_S16_LE, 2): ++ if ((ac97_controller->patched) && ++ (ac97_controller->ac97_features & 1)) { ++ jz_set_dma_block_size(ac97_controller->dma1, 16); ++ jz_set_dma_block_size(ac97_controller->dma2, 16); ++ } else { ++ jz_set_dma_block_size(ac97_controller->dma1, 4); ++ jz_set_dma_block_size(ac97_controller->dma2, 4); ++ } ++ __aic_disable_mono2stereo(); ++ __aic_disable_unsignadj(); ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ __ac97_set_oass(16); ++ __ac97_set_iass(16); ++ jz_set_dma_dest_width(ac97_controller->dma1, 16); ++ jz_set_dma_src_width(ac97_controller->dma2, 16); ++ break; ++ } ++} ++ ++#ifdef CONFIG_PROC_FS ++ ++extern struct proc_dir_entry *proc_jz_root; ++ ++static int jz_ac97_init_proc(struct jz_ac97_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("ac97", 0, proc_jz_root, ++ ac97_read_proc, controller->ac97_codec[0])) ++ return -EIO; ++ ++ return 0; ++} ++ ++static void jz_ac97_cleanup_proc(struct jz_ac97_controller_info *controller) ++{ ++} ++ ++#endif ++ ++static void __init attach_jz_ac97(struct jz_ac97_controller_info *controller) ++{ ++ char *name; ++ int adev; ++ ++ name = controller->name; ++ jz_ac97_initHw(controller); ++ ++ /* register /dev/audio ? */ ++ adev = register_sound_dsp(&jz_ac97_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ ++ /* initialize AC97 codec and register /dev/mixer */ ++ if (jz_ac97_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_ac97_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create AC97 proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);//4 ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);//4 ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ ++ if ((controller->dma1 = jz_request_dma(DMA_ID_AC97_TX, "audio dac", ++ jz_ac97_replay_dma_irq, ++ IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_AC97_RX, "audio adc", ++ jz_ac97_record_dma_irq, ++ IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ ++ printk("Jz On-Chip AC97 controller registered (DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d)\n", ++ controller->dma1, get_dma_done_irq(controller->dma1), ++ controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ old_mksound = kd_mksound; /* see vt.c */ ++ kd_mksound = jz_ac97_mksound; ++ controller->dev_audio = adev; ++ return; ++ ++ dma2_failed: ++ jz_free_dma(controller->dma1); ++ dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8);//4 ++ tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8);//4 ++ tmp1_failed: ++#ifdef CONFIG_PROC_FS ++ jz_ac97_cleanup_proc(controller); ++#endif ++ proc_failed: ++ /* unregister mixer dev */ ++ mixer_failed: ++ unregister_sound_dsp(adev); ++ audio_failed: ++ return; ++} ++ ++static int __init probe_jz_ac97(struct jz_ac97_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_ac97_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz AC97 Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ memset( *controller, 0, sizeof(struct jz_ac97_controller_info) ); ++ (*controller)->name = "Jz AC97 controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_ac97(struct jz_ac97_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_ac97_full_reset (controller); ++ ++ controller->dev_audio = -1; ++ ++ if (old_mksound) ++ kd_mksound = old_mksound; /* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_ac97_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ ++ free_pages((unsigned long)controller->tmp1, 8);//4 ++ free_pages((unsigned long)controller->tmp2, 8);//4 ++ ++ if (adev >= 0) { ++ //unregister_sound_mixer(audio_devs[adev]->mixer_dev); ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++ ++static int reserve_mastervol, reserve_micvol; ++static int reserve_power1, reserve_power2; ++static int reserve_power3, reserve_power4; ++static int reserve_power5, reserve_power6; ++ ++static int jz_ac97_suspend(struct jz_ac97_controller_info *controller, int state) ++{ ++ struct ac97_codec *codec = controller->ac97_codec[0]; ++ ++ /* save codec states */ ++ reserve_mastervol = ac97_codec_read(codec, 0x0002); ++ reserve_micvol = ac97_codec_read(codec, 0x000e); ++ ++ reserve_power1 = ac97_codec_read(codec, 0x0026); ++ reserve_power2 = ac97_codec_read(codec, 0x006c); ++ reserve_power3 = ac97_codec_read(codec, 0x005c); ++ reserve_power4 = ac97_codec_read(codec, 0x0064); ++ reserve_power5 = ac97_codec_read(codec, 0x0066); ++ reserve_power6 = ac97_codec_read(codec, 0x006a); ++ ++ /* put codec into power-saving mode */ ++ ac97_codec_write(codec, 0x5c, 0xffff); ++ ac97_codec_write(codec, 0x64, 0x0000); ++ ac97_codec_write(codec, 0x66, 0x0000); ++ ac97_codec_write(codec, 0x6a, 0x0000); ++ ++ ac97_codec_write(codec, 0x6c, 0x0030); ++ ac97_codec_write(codec, 0x26, 0x3b00); ++ ++ ac97_save_state(codec); ++ __ac97_disable(); ++ ++ return 0; ++} ++ ++static int jz_ac97_resume(struct jz_ac97_controller_info *controller) ++{ ++ struct ac97_codec *codec = controller->ac97_codec[0]; ++ ++ jz_ac97_full_reset(controller); ++ ac97_probe_codec(codec); ++ ac97_restore_state(codec); ++ ++ ac97_codec_write(codec, 0x0026, reserve_power1); ++ ac97_codec_write(codec, 0x006c, reserve_power2); ++ ac97_codec_write(codec, 0x005c, reserve_power3); ++ ac97_codec_write(codec, 0x0064, reserve_power4); ++ ac97_codec_write(codec, 0x0066, reserve_power5); ++ ac97_codec_write(codec, 0x006a, reserve_power6); ++ ++ ac97_codec_write(codec, 0x0002, reserve_mastervol); ++ ac97_codec_write(codec, 0x000e, reserve_micvol); ++ ++ /* Enable variable rate mode */ ++ ac97_codec_write(codec, AC97_EXTENDED_STATUS, 9); ++ ac97_codec_write(codec, ++ AC97_EXTENDED_STATUS, ++ ac97_codec_read(codec, AC97_EXTENDED_STATUS) | 0xE800); ++ ++ return 0; ++} ++ ++static int jz_ac97_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_ac97_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_ac97_suspend(controller, (int)data); ++ break; ++ ++ case PM_RESUME: ++ ret = jz_ac97_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++ ++static int __init init_jz_ac97(void) ++{ ++ int errno; ++ ++ if ((errno = probe_jz_ac97(&ac97_controller)) < 0) ++ return errno; ++ attach_jz_ac97(ac97_controller); ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++#ifdef CONFIG_PM ++ ac97_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_ac97_pm_callback); ++ if (ac97_controller->pm) ++ ac97_controller->pm->data = ac97_controller; ++#endif ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_ac97(void) ++{ ++ unload_jz_ac97(ac97_controller); ++} ++ ++module_init(init_jz_ac97); ++module_exit(cleanup_jz_ac97); ++ ++ ++static int drain_adc(struct jz_ac97_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ unsigned tmo; ++ ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ ++ if (signal_pending(current)) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ tmo = (PAGE_SIZE * HZ) / STANDARD_SPEED; ++ tmo *= jz_audio_k * (jz_audio_format == AFMT_S16_LE) ? 2 : 4; ++ tmo /= jz_audio_channels; ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ return 0; ++} ++ ++static int drain_dac(struct jz_ac97_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ unsigned tmo; ++ ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0 && elements_in_queue(&out_full_queue) <= 0) ++ break; ++ if (signal_pending(current)) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ tmo = (PAGE_SIZE * HZ) / STANDARD_SPEED; ++ tmo *= jz_audio_k * (jz_audio_format == AFMT_S16_LE) ? 2 : 4; ++ tmo /= jz_audio_channels; ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ return 0; ++} ++ ++/* ++ * Audio operation routines implementation ++ */ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ struct jz_ac97_controller_info *controller = ++ (struct jz_ac97_controller_info *) file->private_data; ++ unsigned long flags; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ controller->opened1 = 0; ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __ac97_disable_transmit_dma(); ++ __ac97_disable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ } ++ if (file->f_mode & FMODE_READ) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __ac97_disable_receive_dma(); ++ __ac97_disable_record(); ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ } ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ struct jz_ac97_controller_info *controller= ac97_controller; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ controller->opened1 = 1; ++ //for ioctl ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ jz_audio_set_channels(controller->dev_audio, 1); ++ jz_audio_set_format(controller->dev_audio, AFMT_U8); ++ jz_audio_set_speed(controller->dev_audio, 8000); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ controller->opened2 = 1; ++ first_record_call = 1; ++ printk(KERN_DEBUG "You'd better apply 48000Hz 16-bit Stereo for record.\n"); ++ //for ioctl ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ jz_audio_set_channels(controller->dev_audio, 2); ++ jz_audio_set_format(controller->dev_audio, AFMT_S16_LE); ++ jz_audio_set_speed(controller->dev_audio, 48000); ++ } ++ ++ last_jz_audio_count = jz_audio_count = 0; ++ file->private_data = controller; ++ ++ jz_audio_fragsize = 8 * PAGE_SIZE; ++ jz_audio_fragstotal = 4; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ return 0; ++} ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct jz_ac97_controller_info *controller = ++ (struct jz_ac97_controller_info *) file->private_data; ++ int val=0,fullc,busyc,unfinish; ++ unsigned int flags; ++ count_info cinfo; ++ ++ switch (cmd) ++ { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ ++ case SNDCTL_DSP_RESET: ++ jz_audio_reset(); ++ return 0; ++ ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ ++ case SNDCTL_DSP_SPEED: /* set smaple rate */ ++ { ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ return put_user(val, (int *)arg); ++ } ++ ++ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ return 0; ++ ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(4*PAGE_SIZE, (int *)arg); ++ return put_user(jz_audio_fragsize , (int *)arg); ++ ++ case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ ++ case SNDCTL_DSP_SETFMT: /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ ++ if (val != AFMT_QUERY) { ++ jz_audio_set_format(controller->dev_audio,val); ++ } else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? ++ AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? ++ AFMT_S16_LE : AFMT_U8; ++ } ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ ++ case SNDCTL_DSP_SETFRAGMENT: ++ if(out_dma_buf || in_dma_buf) ++ return -EBUSY; ++ get_user(val, (long *) arg); ++ jz_audio_fragsize = 1 << (val & 0xFFFF);//16 least bits ++ ++ if (jz_audio_fragsize < 4 * PAGE_SIZE) ++ jz_audio_fragsize = 4 * PAGE_SIZE; ++ if (jz_audio_fragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE ++ jz_audio_fragsize = 16 * PAGE_SIZE; ++ jz_audio_fragstotal = (val >> 16) & 0x7FFF; ++ if (jz_audio_fragstotal < 2) ++ jz_audio_fragstotal = 2; ++ if (jz_audio_fragstotal > 32) ++ jz_audio_fragstotal = 32; ++ ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ return 0; ++ ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ audio_buf_info abinfo; ++ int i, bytes = 0; ++ ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ //unused fragment amount ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ bytes /= jz_audio_k; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ //bytes /= jz_audio_b; ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ abinfo.fragsize = jz_audio_fragsize; ++ abinfo.bytes = bytes; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ ++ case SNDCTL_DSP_GETISPACE: ++ { ++ audio_buf_info abinfo; ++ int i, bytes = 0; ++ ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ //unused fragment amount ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ abinfo.fragsize = jz_audio_fragsize; ++ abinfo.bytes = bytes; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) //record is at working ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) //playback is at working ++ val |= PCM_ENABLE_OUTPUT; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ /*if (file->f_mode & FMODE_READ) { ++ if (val & PCM_ENABLE_INPUT) { ++ if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) ++ return ret; ++ start_adc(state); ++ } else ++ stop_adc(state); ++ } ++ if (file->f_mode & FMODE_WRITE) { ++ if (val & PCM_ENABLE_OUTPUT) { ++ if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) ++ return ret; ++ start_dac(state); ++ } else ++ stop_dac(state); ++ }*/ ++ return 0; ++ ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ //controller->total_bytes += get_dma_residue(controller->dma2); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ //controller->total_bytes += get_dma_residue(controller->dma1); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ ++ case SNDCTL_DSP_GETODELAY: ++ { ++ int id, i; ++ ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ ++ for(i = 0;i < fullc ;i ++) ++ { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) ++ { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ unfinish /= jz_audio_k;//jz_audio_k is jz_audio_b ++ return put_user(val, (int *)arg); ++ } ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++static unsigned int jz_audio_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct jz_ac97_controller_info *controller = ++ (struct jz_ac97_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } ++ else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct jz_ac97_controller_info *controller = ++ (struct jz_ac97_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++ if (count < 2*PAGE_SIZE / jz_audio_k) { ++ copy_count = count * 16 / (jz_audio_channels * jz_audio_format); ++ } else ++ copy_count = ((2*PAGE_SIZE / jz_audio_k + 3) / 4) * 4; ++ left_count = count; ++ ++ if (first_record_call) { ++ first_record_call = 0; ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ *(in_dma_buf_data_count + id) = copy_count * (jz_audio_format/8); ++ __ac97_enable_receive_dma(); ++ __ac97_enable_record(); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ interruptible_sleep_on(&rx_wait_queue); ++ } else ++ BUG(); ++ } ++ ++ while (left_count > 0) { ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ interruptible_sleep_on(&rx_wait_queue); ++ } ++ if (signal_pending(current)) ++ return ret ? ret: -ERESTARTSYS; ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ BUG(); ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ *(in_dma_buf_data_count + id) = copy_count * (jz_audio_format/8); ++ __ac97_enable_receive_dma(); ++ __ac97_enable_record(); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ ++ if (ret + cnt > count) ++ cnt = count - ret; ++ ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ ret += cnt; ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ left_count -= cnt; ++ } ++ if (ret != count) ++ printk(KERN_DEBUG "%s: count=%d ret=%d jz_audio_count=%d\n", ++ __FUNCTION__, count, ret, jz_audio_count); ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct jz_ac97_controller_info *controller = ++ (struct jz_ac97_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count; ++ unsigned int flags; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++ /* The data buffer size of the user space is always a PAGE_SIZE ++ * scale, so the process can be simplified. ++ */ ++ ++ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1)) ++ copy_count = count; ++ else { ++ if (count < 2*PAGE_SIZE / jz_audio_k) ++ copy_count = count; ++ else ++ copy_count = ((2*PAGE_SIZE / jz_audio_k + 3) / 4) * 4; ++ } ++ left_count = count; ++ ++ if (!(ac97_controller->patched) || !(ac97_controller->ac97_features & 1)) { ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk(KERN_DEBUG "%s: copy_from_user failed.\n", __FUNCTION__); ++ return ret ? ret : -EFAULT; ++ } ++ } ++ ++ while (left_count > 0) { ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ interruptible_sleep_on(&tx_wait_queue); ++ } ++ ++ if (signal_pending(current)) ++ return ret ? ret : -ERESTARTSYS; ++ ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ if ((ac97_controller->patched) && ++ (ac97_controller->ac97_features & 1)) { ++ if (copy_from_user((char *)(*(out_dma_buf + id)), buffer+ret, copy_count)) { ++ printk(KERN_DEBUG "%s: copy_from_user failed.\n", __FUNCTION__); ++ return ret ? ret : -EFAULT; ++ } ++ *(out_dma_buf_data_count + id) = copy_count; ++ } else ++ replay_filler( ++ (unsigned long)controller->tmp1 + ret, ++ copy_count, id); ++ //when 0,kernel will panic ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); ++ } else {//when 0,i need refill in empty queue ++ put_buffer_id(&out_empty_queue, id); ++ } ++ } else ++ BUG(); ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ ++ __ac97_enable_transmit_dma(); ++ __ac97_enable_replay(); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1,file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ } ++ } ++ } ++ } ++ ++ if (ret != count) ++ printk(KERN_DEBUG "%s: count=%d ret=%d jz_audio_count=%d\n", ++ __FUNCTION__, count, ret, jz_audio_count); ++ return ret; ++} ++ ++/* this function for the other codec function */ ++struct ac97_codec * find_ac97_codec(void) ++{ ++ if ( ac97_controller ) ++ return ac97_controller->ac97_codec[0]; ++ return 0; ++ ++} ++ +diff --git a/sound/oss/jz_i2s.c b/sound/oss/jz_i2s.c +new file mode 100644 +index 0000000..ab67cae +--- /dev/null ++++ b/sound/oss/jz_i2s.c +@@ -0,0 +1,2894 @@ ++/* ++ * linux/drivers/sound/Jz_i2s.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#if defined(CONFIG_I2S_DLV) ++#include "jzdlv.h" ++#endif ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++#define NR_I2S 2 ++#define JZCODEC_RW_BUFFER_SIZE 5 ++#define JZCODEC_RW_BUFFER_TOTAL 4 ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++mixer_info info; ++_old_mixer_info old_info; ++int codec_volue_shift; ++hpvol_shift_t hpvol_shift_table[72]; ++int abnormal_data_count; ++unsigned long i2s_clk; ++ ++void (*set_codec_mode)(void) = NULL; ++void (*clear_codec_mode)(void) = NULL; ++void (*set_codec_gpio_pin)(void) = NULL; ++void (*each_time_init_codec)(void) = NULL; ++int (*set_codec_startup_param)(void) = NULL; ++void (*set_codec_volume_table)(void) = NULL; ++void (*set_codec_record)(int mode) = NULL; ++void (*set_codec_replay)(void) = NULL; ++void (*set_codec_replay_record)(int mode) = NULL; ++void (*turn_on_codec)(void) = NULL; ++void (*turn_off_codec)(void) = NULL; ++void (*set_codec_speed)(int rate) = NULL; ++void (*reset_codec)(void) = NULL; ++void (*codec_mixer_old_info_id_name)(void) = NULL; ++void (*codec_mixer_info_id_name)(void) = NULL; ++void (*set_codec_bass)(int val) = NULL; ++void (*set_codec_volume)(int val) = NULL; ++void (*set_codec_mic)(int val) = NULL; ++void (*set_codec_line)(int val) = NULL; ++void (*i2s_resume_codec)(void) = NULL; ++void (*i2s_suspend_codec)(int wr,int rd) = NULL; ++void (*init_codec_pin)(void) = NULL; ++void (*set_codec_some_func)(void) = NULL; ++void (*clear_codec_record)(void) = NULL; ++void (*clear_codec_replay)(void) = NULL; ++void (*set_replay_hp_or_speaker)(void) = NULL; ++void (*set_codec_direct_mode)(void) = NULL; ++void (*clear_codec_direct_mode)(void) = NULL; ++void (*set_codec_linein2hp)(void) = NULL; ++void (*clear_codec_linein2hp)(void) = NULL; ++ ++static int jz_audio_rate; ++static int jz_audio_format; ++static int jz_audio_volume; ++static int jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments; /* unused fragment amount */ ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++ ++static int codec_bass_gain; ++static int audio_mix_modcnt; ++static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ ++#if defined(CONFIG_I2S_DLV) ++int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++#endif ++ ++static int codec_mic_gain; ++static int pop_dma_flag; ++static int last_dma_buffer_id; ++static int drain_flag; ++static int use_mic_line_flag; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++static void jz_update_filler(int bits, int channels); ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); ++#endif ++static void jz_audio_reset(void); ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* for play */ ++ int dma2; /* for record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; /* byte index to next-in to DMA buffer */ ++ int nextOut; /* byte index to next-out from DMA buffer */ ++ int count; /* current byte count in DMA buffer */ ++ int finish; /* current transfered byte count in DMA buffer */ ++ unsigned total_bytes; /* total bytes written or read */ ++ unsigned blocks; ++ unsigned error; /* over/underrun */ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++static unsigned long pop_turn_onoff_buf; ++static unsigned long pop_turn_onoff_pbuf; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static left_right_sample_t save_last_samples[64]; ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count / jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++#if 1 ++ jz_set_oss_dma(chan, mode, jz_audio_format); ++#else ++ set_dma_mode(chan, mode); ++#endif ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(drain_flag == 1) ++ wake_up(&drain_wait_queue); ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(pop_dma_flag == 1) { ++ pop_dma_flag = 0; ++ wake_up(&pop_wait_queue); ++ } else { ++ if(drain_flag == 1) { ++ /* Is replay dma buffer over ? */ ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ drain_flag = 0; ++ wake_up(&drain_wait_queue); ++ } ++ } ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++#if defined(CONFIG_MIPS_JZ_URANUS) ++ i2s_clk = 48000000; ++#else ++ i2s_clk = __cpm_get_i2sclk(); ++#endif ++ __i2s_disable(); ++ if(set) ++ __i2s_reset(); ++ schedule_timeout(5); ++ if(each_time_init_codec) ++ each_time_init_codec(); ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ ++ /* recording */ ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ /* playing */ ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* alloc DMA buffer */ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ /* playing */ ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ /* recording */ ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ jz_audio_speed = rate; ++#if defined(CONFIG_I2S_DLV) ++ if (rate > 96000) ++ rate = 96000; ++#else ++ if (rate > 48000) ++ rate = 48000; ++#endif ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ if(set_codec_speed) ++ set_codec_speed(rate); ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ d2 = *(s++); ++ if(abnormal_data_count > 0) { ++ d1 = d2 = 0; ++ abnormal_data_count --; ++ } ++ *(dp ++) = (d1 << 16) >> 16; ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = ddata; ++ save_last_samples[id].right = ddata; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_2x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ /* save last left */ ++ if(count == 2) ++ save_last_samples[id].left = dd1; ++ /* save last right */ ++ if(count == 1) ++ save_last_samples[id].right = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++#if defined(CONFIG_I2S_ICODEC) ++ l1 >>= codec_volue_shift; ++#endif ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = l1; ++ save_last_samples[id].right = l1; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++#if defined(CONFIG_I2S_ICODEC) ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ volatile signed long *before_dp; ++ int sam_rate = jz_audio_rate / 20; ++ ++ tmp1 = tmp2 = 0; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ l1 >>= codec_volue_shift; ++ ++ if(l1 == 0) { ++ mute_cnt ++; ++ if(mute_cnt >= sam_rate) { ++ before_dp = dp - 10; ++ *(before_dp) = (signed long)1; ++ before_dp = dp - 11; ++ *(before_dp) = (signed long)1; ++ mute_cnt = 0; ++ } ++ } else ++ mute_cnt = 0; ++ ++ *(dp ++) = l1; ++ ++ tmp1 = tmp2; ++ tmp2 = l1; ++ } ++ ++ /* save last left */ ++ save_last_samples[id].left = tmp1; ++ /* save last right */ ++ save_last_samples[id].right = tmp2; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++#endif ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x18_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed long d1; ++ signed long l1; ++ volatile signed long *s = (signed long *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 4; ++ cnt += 4; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ } ++ ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++#if defined(CONFIG_I2S_DLV) ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++#endif ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ case 18: ++ __i2s_set_oss_sample_size(18); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ break; ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ if(set_codec_some_func) ++ set_codec_some_func(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++#endif ++ break; ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++#endif ++ break; ++ case 0: ++ break; ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ /* inititalize internal I2S codec */ ++ if(init_codec_pin) ++ init_codec_pin(); ++ ++#if defined(CONFIG_I2S_ICDC) ++ /* initialize AIC but not reset it */ ++ jz_i2s_initHw(0); ++#endif ++ if(reset_codec) ++ reset_codec(); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#if defined(CONFIG_I2S_DLV) ++ REG_AIC_I2SCR = 0x10; ++#endif ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ ++ if(codec_mixer_info_id_name) ++ codec_mixer_info_id_name(); ++ info.modify_counter = audio_mix_modcnt; ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ case SOUND_OLD_MIXER_INFO: ++ ++ if(codec_mixer_old_info_id_name) ++ codec_mixer_old_info_id_name(); ++ ++ return copy_to_user((void *)arg, &old_info, sizeof(info)); ++ case SOUND_MIXER_READ_STEREODEVS: ++ ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ switch(val) { ++ case 100: ++ if(set_codec_direct_mode) ++ set_codec_direct_mode(); ++ break; ++ case 0: ++ if(clear_codec_direct_mode) ++ clear_codec_direct_mode(); ++ break; ++ } ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_bass_gain = val; ++ if(set_codec_bass) ++ set_codec_bass(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_BASS: ++ ++ val = codec_bass_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ ++ jz_audio_volume = val; ++ if(set_codec_volume) ++ set_codec_volume(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ ++ case SOUND_MIXER_WRITE_MIC: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_mic_gain = val; ++ use_mic_line_flag = USE_MIC; ++ if(set_codec_mic) ++ set_codec_mic(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_MIC: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ ++ case SOUND_MIXER_WRITE_LINE: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ use_mic_line_flag = USE_LINEIN; ++ codec_mic_gain = val; ++ if(set_codec_line) ++ set_codec_line(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_LINE: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ return 0; ++} ++ ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ case TYPE(18, 2): ++ jz_audio_b = 1; ++ replay_filler = replay_fill_2x18_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ default: ++ ; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev; /* No of Audio device. */ ++ ++ name = controller->name; ++ /* initialize AIC controller and reset it */ ++ jz_i2s_initHw(1); ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); ++ if(!pop_turn_onoff_buf) ++ printk("pop_turn_onoff_buf alloc is wrong!\n"); ++ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma1); ++dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8); ++tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8); ++tmp1_failed: ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ init_waitqueue_head(&drain_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_i2s_full_reset(controller); ++ controller->dev_audio = -1; ++ if (old_mksound) ++ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, 8); ++ free_pages((unsigned long)controller->tmp2, 8); ++ free_pages((unsigned long)pop_turn_onoff_buf, 8); ++ ++ if (adev >= 0) { ++ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ if(i2s_suspend_codec) ++ i2s_suspend_codec(controller->opened1,controller->opened2); ++ printk("Aic and codec are suspended!\n"); ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ if(i2s_resume_codec) ++ i2s_resume_codec(); ++ ++#if defined(CONFIG_I2S_AK4642EN) ++ jz_i2s_initHw(0); ++ jz_audio_reset(); ++ __i2s_enable(); ++ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); ++ /* playing */ ++ if(controller->opened1) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ int dma = controller->dma1; ++ int id; ++ unsigned long flags; ++ disable_dma(dma); ++ if(__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if(__dmac_channel_transmit_end_detected(dma)) ++ __dmac_channel_clear_transmit_end(dma); ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ while((id = get_buffer_id(&out_busy_queue)) >= 0) ++ put_buffer_id(&out_empty_queue, id); ++ ++ out_busy_queue.count=0; ++ if((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_empty_queue, id); ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } else ++ printk("pm out_empty_queue empty"); ++ } ++ ++ /* recording */ ++ if(controller->opened2) { ++ if(set_codec_record) ++ set_codec_record(use_mic_line_flag); ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ } ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_full_queue, id2); ++ } ++ in_busy_queue.count = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++ ++#if defined(CONFIG_I2S_DLV) ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno; ++#if defined(CONFIG_I2S_DLV) ++ int retval; ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++#endif ++ use_mic_line_flag = USE_NONE; ++ abnormal_data_count = 0; ++ if(set_codec_mode) ++ set_codec_mode(); ++ ++ drain_flag = 0; ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ if(set_codec_gpio_pin) ++ set_codec_gpio_pin(); ++ ++ attach_jz_i2s(i2s_controller); ++ if(set_codec_startup_param) ++ set_codec_startup_param(); ++ if(set_codec_volume_table) ++ set_codec_volume_table(); ++ ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++#endif ++ printk("JZ I2S OSS audio driver initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++#ifdef CONFIG_PM ++ /* pm_unregister(i2s_controller->pm); */ ++#endif ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ unload_jz_i2s(i2s_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ if(clear_codec_mode) ++ clear_codec_mode(); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++#if defined(CONFIG_SOC_JZ4730) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,con; ++ ++ if(elements_in_queue(&in_busy_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (con = 0; con < 1000; con ++) { ++ udelay(1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ return 0; ++} ++ ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ ++ if(elements_in_queue(&out_full_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if(count <= 0) ++ break; ++ } ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4740) ++#define MAXDELAY 50000 ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,ele,i=0; ++ int tfl; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ /* wait for TX fifo */ ++ while (1) { ++ tfl = __aic_get_transmit_resident(); ++ if (tfl == 0) ++ break; ++ udelay(2); ++ } ++ ++ return 0; ++} ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) ++ { ++ udelay(10); ++ i++; ++ } ++ else ++ break; ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++#define MAXDELAY 50000 ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ //mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ //mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++#if defined(CONFIG_I2S_DLV) ++ unsigned long tfl; ++#endif ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++#endif ++ if (controller == NULL) ++ return -ENODEV; ++ ++ pop_dma_flag = 0; ++ ++ if (controller->opened1 == 1 && controller->opened2 == 1) { ++ controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++#if defined(CONFIG_I2S_DLV) ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ /*while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ }*/ ++ mdelay(100); ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_replay) ++ clear_codec_replay(); ++#endif ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_record) ++ clear_codec_record(); ++#endif ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ if (use_mic_line_flag == USE_LINEIN) { ++ unset_record_line_input_audio_with_audio_data_replay(); ++ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag); ++ } ++ if (use_mic_line_flag == USE_MIC) { ++ unset_record_mic_input_audio_with_audio_data_replay(); ++ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag); ++ } ++ ++#if 0 ++ unset_record_playing_audio_mixed_with_mic_input_audio(); ++#endif ++#endif ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ abnormal_data_count = 0; ++ } else if (controller->opened1 == 1) { ++ //controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* add some mute to anti-pop */ ++#if defined(CONFIG_I2S_ICODEC) ++ //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right); ++#endif ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_replay) ++ clear_codec_replay(); ++#endif ++ __aic_flush_fifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(turn_off_codec) ++ turn_off_codec(); ++#endif ++ } else if (controller->opened2 == 1) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_record) ++ clear_codec_record(); ++#endif ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++#if defined(CONFIG_I2S_DLV) ++#if 0 ++ /* unset Record MIC input audio with direct playback */ ++ unset_record_mic_input_audio_with_direct_playback(); ++#endif ++#if 1 ++ /* unset Record MIC input audio without playback */ ++ unset_record_mic_input_audio_without_playback(); ++#endif ++#if 0 ++ /* tested */ ++ /* unset Record LINE input audio without playback */ ++ unset_record_line_input_audio_without_playback(); ++#endif ++#endif ++ __i2s_disable(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(turn_off_codec) ++ turn_off_codec(); ++#endif ++ abnormal_data_count = 0; ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++/* __cpm_stop_idct(); ++ __cpm_stop_db(); ++ __cpm_stop_me(); ++ __cpm_stop_mc(); ++ __cpm_stop_ipu();*/ ++#endif ++ ++ if (controller->opened1 == 1 && controller->opened2 == 1) { ++ controller->opened1 = 0; ++ controller->opened2 = 0; ++ //print_pop_duration(); ++ //__dmac_disable_module(0); ++ } else if ( controller->opened1 == 1 ) { ++ controller->opened1 = 0; ++ //print_pop_duration(); ++ } else if ( controller->opened2 == 1 ) { ++ controller->opened2 = 0; ++ } ++ ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++#endif ++ if (controller == NULL) ++ return -ENODEV; ++ ++ mdelay(2); ++#if defined(CONFIG_I2S_DLV) ++ REG_DMAC_DMACKE(0) = 0x3f; ++#endif ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } else if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ } else if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ REG_AIC_FR |= (1 << 6); ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++#if defined(CONFIG_I2S_ICODEC) ++ if (set_codec_replay_record) ++ set_codec_replay_record(use_mic_line_flag); ++#endif ++#if defined(CONFIG_I2S_DLV) ++ if (use_mic_line_flag == USE_NONE) { ++ printk("you select mic or line recording please.or use mic recording!\n"); ++ use_mic_line_flag = USE_MIC; ++ } ++ if (use_mic_line_flag == USE_LINEIN) { ++ /* Record LINE input audio with Audio data replay (full duplex for linein) */ ++ /* codec_test_line */ ++ set_record_line_input_audio_with_audio_data_replay(); ++ ++ } ++ if (use_mic_line_flag == USE_MIC) { ++ /* Record MIC input audio with Audio data replay (full duplex) */ ++ /* codec_test_mic */ ++ set_record_mic_input_audio_with_audio_data_replay(); ++ } ++#if 0 ++ /* Record playing audio mixed with MIC input audio */ ++ set_record_playing_audio_mixed_with_mic_input_audio(); ++#endif ++ ++#endif ++ } else if (file->f_mode & FMODE_WRITE) { ++#if defined(CONFIG_I2S_ICODEC) ++ if(set_codec_replay) ++ set_codec_replay(); ++#endif ++#if defined(CONFIG_I2S_DLV) ++ //mdelay(10); ++ /* Audio data replay */ ++ set_audio_data_replay(); ++#endif ++ } else if (file->f_mode & FMODE_READ) { ++#if defined(CONFIG_I2S_ICODEC) ++ abnormal_data_count = 0; ++ if(set_codec_record) ++ set_codec_record(use_mic_line_flag); ++#endif ++#if defined(CONFIG_I2S_DLV) ++#if 0 ++ /* Record MIC input audio with direct playback */ ++ set_record_mic_input_audio_with_direct_playback(); ++#endif ++ ++#if 1 ++ /* set Record MIC input audio without playback */ ++ set_record_mic_input_audio_without_playback(); ++#endif ++#if 0 ++ /* tested */ ++ /* set Record LINE input audio without playback */ ++ set_record_line_input_audio_without_playback(); ++#endif ++ mdelay(1); ++#endif ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++#endif ++ ++ __i2s_enable(); ++ ++#if defined(CONFIG_I2S_DLV) ++ ndelay(100); ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++#if defined(CONFIG_I2S_DLV) ++ //set SB_ADC or SB_DAC ++ __dmac_enable_module(0); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++#endif ++ } else if (file->f_mode & FMODE_WRITE) { ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++#endif ++ } else if (file->f_mode & FMODE_READ) { ++#if defined(CONFIG_I2S_DLV) ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++#endif ++ } ++#endif ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ count_info cinfo; ++ audio_buf_info abinfo; ++ int id, i; ++ ++ val = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++#if 0 ++ jz_audio_reset(); ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#endif ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ ++ return 0; ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); ++ return put_user(jz_audio_fragsize, (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ } ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF); ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ int i; ++ unsigned long bytes = 0; ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ /* unused fragment amount */ ++ abinfo.fragments = jz_audio_fragments; ++ /* amount of fragments */ ++ abinfo.fragstotal = jz_audio_fragstotal; ++ /* fragment size in bytes */ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); ++ ++ /* write size count without blocking in bytes */ ++ abinfo.bytes = (int)bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ { ++ int i; ++ unsigned long bytes = 0; ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); ++ ++ abinfo.bytes = (int)bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (jz_audio_channels == 2) ++ unfinish /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ unfinish /= 4; ++ else ++ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); ++ ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ if(set_replay_hp_or_speaker) ++ set_replay_hp_or_speaker(); ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ if (file->f_flags & O_NONBLOCK) ++ udelay(2); ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++#if defined(CONFIG_I2S_DLV) ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++#endif ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) ++{ ++ int i,step_len; ++ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; ++ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ unsigned long l_sample_count,r_sample_count,sample_count; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ signed int left_sam=0,right_sam=0,l_val,r_val; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ left_sam = (signed int)l_sample; ++ right_sam = (signed int)r_sample; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++ ++ if(left_sam == 0 && right_sam == 0) ++ return; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ step_len = jz_audio_speed / 10 * 3; ++ step_len = step_len / 2; ++ step_len = 0x7fff / step_len + 1; ++ ++ l_sample_count = 0; ++ l_val = left_sam; ++ ++ while(1) { ++ if(l_val > 0) { ++ if(l_val >= step_len) { ++ l_val -= step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val < 0) { ++ if(l_val <= -step_len) { ++ l_val += step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val == 0) ++ break; ++ } ++ ++ r_sample_count = 0; ++ r_val = right_sam; ++ while(1) { ++ if(r_val > 0) { ++ if(r_val >= step_len) { ++ r_val -= step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val < 0) { ++ if(r_val <= -step_len) { ++ r_val += step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val == 0) ++ break; ++ } ++ /* fill up */ ++ if(l_sample_count > r_sample_count) ++ sample_count = l_sample_count; ++ else ++ sample_count = r_sample_count; ++ ++ l_val = left_sam; ++ r_val = right_sam; ++ for(i=0;i <= sample_count;i++) { ++ ++ *pop_buf = (unsigned long)l_val; ++ pop_buf ++; ++ ++ if(l_val > step_len) ++ l_val -= step_len; ++ else if(l_val < -step_len) ++ l_val += step_len; ++ else if(l_val >= -step_len && l_val <= step_len) ++ l_val = 0; ++ ++ *pop_buf = (unsigned long)r_val; ++ pop_buf ++; ++ if(r_val > step_len) ++ r_val -= step_len; ++ else if(r_val < -step_len) ++ r_val += step_len; ++ else if(r_val >= -step_len && r_val <= step_len) ++ r_val = 0; ++ } ++ ++ *pop_buf = 0; ++ pop_buf ++; ++ *pop_buf = 0; ++ ++ pop_buf ++; ++ sample_count += 2; ++ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); ++ ++ pop_dma_flag = 1; ++ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); ++ sleep_on(&pop_wait_queue); ++ pop_dma_flag = 0; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++} ++#endif +diff --git a/sound/oss/jz_i2s_4750.c b/sound/oss/jz_i2s_4750.c +new file mode 100644 +index 0000000..d99fa8d +--- /dev/null ++++ b/sound/oss/jz_i2s_4750.c +@@ -0,0 +1,3010 @@ ++/* ++ * linux/drivers/sound/Jz_i2s.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++#define NR_I2S 2 ++#define MAXDELAY 50000 ++#define JZCODEC_RW_BUFFER_SIZE 2 ++#define JZCODEC_RW_BUFFER_TOTAL 6 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++mixer_info info; ++_old_mixer_info old_info; ++int codec_volue_shift; ++hpvol_shift_t hpvol_shift_table[72]; ++int abnormal_data_count; ++unsigned long i2s_clk; ++ ++void (*set_codec_mode)(void) = NULL; ++void (*clear_codec_mode)(void) = NULL; ++void (*set_codec_gpio_pin)(void) = NULL; ++void (*each_time_init_codec)(void) = NULL; ++int (*set_codec_startup_param)(void) = NULL; ++void (*set_codec_volume_table)(void) = NULL; ++void (*set_codec_record)(void) = NULL; ++void (*set_codec_replay)(void) = NULL; ++void (*set_codec_replay_record)(void); ++void (*turn_on_codec)(void) = NULL; ++void (*turn_off_codec)(void) = NULL; ++void (*set_codec_speed)(int rate) = NULL; ++void (*reset_codec)(void) = NULL; ++void (*codec_mixer_old_info_id_name)(void) = NULL; ++void (*codec_mixer_info_id_name)(void) = NULL; ++void (*set_codec_bass)(int val) = NULL; ++void (*set_codec_volume)(int val) = NULL; ++void (*set_codec_mic)(int val) = NULL; ++void (*i2s_resume_codec)(void) = NULL; ++void (*i2s_suspend_codec)(int wr,int rd) = NULL; ++void (*init_codec_pin)(void) = NULL; ++void (*set_codec_some_func)(void) = NULL; ++void (*clear_codec_record)(void) = NULL; ++void (*clear_codec_replay)(void) = NULL; ++void (*set_replay_hp_or_speaker)(void) = NULL; ++void (*set_codec_direct_mode)(void) = NULL; ++void (*clear_codec_direct_mode)(void) = NULL; ++ ++static int jz_audio_rate; ++static int jz_audio_format; ++static int jz_audio_volume; ++static int jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments; /* unused fragment amount */ ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++ ++static int codec_bass_gain; ++static int audio_mix_modcnt; ++static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ ++static int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++ ++static int codec_mic_gain; ++static int pop_dma_flag; ++static int last_dma_buffer_id; ++static int drain_flag; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++static void jz_update_filler(int bits, int channels); ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); ++#endif ++static void jz_audio_reset(void); ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* for play */ ++ int dma2; /* for record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; /* byte index to next-in to DMA buffer */ ++ int nextOut; /* byte index to next-out from DMA buffer */ ++ int count; /* current byte count in DMA buffer */ ++ int finish; /* current transfered byte count in DMA buffer */ ++ unsigned total_bytes; /* total bytes written or read */ ++ unsigned blocks; ++ unsigned error; /* over/underrun */ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++static unsigned long pop_turn_onoff_buf; ++static unsigned long pop_turn_onoff_pbuf; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static left_right_sample_t save_last_samples[64]; ++static int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++#if 0 /* mask warning */ ++static void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++#endif ++ ++static void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++static int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++ ++#if 0 /* mask warning */ ++/* set Audio data replay */ ++static void set_audio_data_replay(void) ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++#endif ++ ++/* unset Audio data replay */ ++static void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio without playback */ ++static void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio without playback */ ++static void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record LINE input audio without playback */ ++static void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record LINE input audio without playback */ ++static void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Playback LINE input audio direct only */ ++static void set_playback_line_input_audio_direct_only(void) ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Playback LINE input audio direct only */ ++static void unset_playback_line_input_audio_direct_only(void) ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio with direct playback */ ++static void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio with direct playback */ ++static void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record playing audio mixed with MIC input audio */ ++static void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record playing audio mixed with MIC input audio */ ++static void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++static void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++static void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count / jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ //set_dma_mode(chan, mode); ++ jz_set_oss_dma(chan, mode, jz_audio_format); ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(drain_flag == 1) ++ wake_up(&drain_wait_queue); ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(pop_dma_flag == 1) { ++ pop_dma_flag = 0; ++ wake_up(&pop_wait_queue); ++ } else { ++ if(drain_flag == 1) { ++ /* Is replay dma buffer over ? */ ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ drain_flag = 0; ++ wake_up(&drain_wait_queue); ++ } ++ } ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++#if defined(CONFIG_MIPS_JZ_URANUS) ++ i2s_clk = 48000000; ++#else ++ i2s_clk = __cpm_get_i2sclk(); ++#endif ++ __i2s_disable(); ++ if(set) ++ __i2s_reset(); ++ schedule_timeout(5); ++ if(each_time_init_codec) ++ each_time_init_codec(); ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ ++ /* recording */ ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ /* playing */ ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* alloc DMA buffer */ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ /* playing */ ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ /* recording */ ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ jz_audio_speed = rate; ++ if (rate > 48000) ++ rate = 48000; ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ if(set_codec_speed) ++ set_codec_speed(rate); ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ d2 = *(s++); ++ if(abnormal_data_count > 0) { ++ d1 = d2 = 0; ++ abnormal_data_count --; ++ } ++ *(dp ++) = (d1 << 16) >> 16; ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = ddata; ++ save_last_samples[id].right = ddata; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_2x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ /* save last left */ ++ if(count == 2) ++ save_last_samples[id].left = dd1; ++ /* save last right */ ++ if(count == 1) ++ save_last_samples[id].right = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = l1; ++ save_last_samples[id].right = l1; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++#if 0 ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++#if defined(CONFIG_I2S_ICDC) ++ volatile signed long *before_dp; ++ int sam_rate = jz_audio_rate / 20; ++ ++ tmp1 = tmp2 = 0; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ l1 >>= codec_volue_shift; ++ ++ if(l1 == 0) { ++ mute_cnt ++; ++ if(mute_cnt >= sam_rate) { ++ before_dp = dp - 10; ++ *(before_dp) = (signed long)1; ++ before_dp = dp - 11; ++ *(before_dp) = (signed long)1; ++ mute_cnt = 0; ++ } ++ } else ++ mute_cnt = 0; ++ ++ *(dp ++) = l1; ++ ++ tmp1 = tmp2; ++ tmp2 = l1; ++ } ++ ++ /* save last left */ ++ save_last_samples[id].left = tmp1; ++ /* save last right */ ++ save_last_samples[id].right = tmp2; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++#endif ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++#else ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ ++#if 0 ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); ++ memcpy((char*)dp, (char*)s, count); ++ *(out_dma_buf_data_count + id) = count; ++#else ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++#endif ++} ++#endif ++ ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++#if defined(CONFIG_I2S_DLV) ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++#endif ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ /* print all files */ ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ if(set_codec_some_func) ++ set_codec_some_func(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++#endif ++ break; ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++#endif ++ break; ++ case 0: ++ break; ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ /* inititalize internal I2S codec */ ++ if(init_codec_pin) ++ init_codec_pin(); ++ ++#if defined(CONFIG_I2S_ICDC) ++ /* initialize AIC but not reset it */ ++ jz_i2s_initHw(0); ++#endif ++ if(reset_codec) ++ reset_codec(); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#if defined(CONFIG_I2S_DLV) ++ REG_AIC_I2SCR = 0x10; ++#endif ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ ++ if(codec_mixer_info_id_name) ++ codec_mixer_info_id_name(); ++ info.modify_counter = audio_mix_modcnt; ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ case SOUND_OLD_MIXER_INFO: ++ ++ if(codec_mixer_old_info_id_name) ++ codec_mixer_old_info_id_name(); ++ ++ return copy_to_user((void *)arg, &old_info, sizeof(info)); ++ case SOUND_MIXER_READ_STEREODEVS: ++ ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ switch(val) { ++ case 100: ++ if(set_codec_direct_mode) ++ set_codec_direct_mode(); ++ break; ++ case 0: ++ if(clear_codec_direct_mode) ++ clear_codec_direct_mode(); ++ break; ++ } ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_bass_gain = val; ++ if(set_codec_bass) ++ set_codec_bass(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_BASS: ++ ++ val = codec_bass_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ if (val > 31) ++ val = 31; ++ jz_audio_volume = val; ++ ++ if(set_codec_volume) ++ set_codec_volume(val); ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_MIC: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_mic_gain = val; ++ if(set_codec_mic) ++ set_codec_mic(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_MIC: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ return 0; ++} ++ ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ default: ++ ; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev; /* No of Audio device. */ ++ ++ name = controller->name; ++ /* initialize AIC controller and reset it */ ++ jz_i2s_initHw(1); ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); ++ if(!pop_turn_onoff_buf) ++ printk("pop_turn_onoff_buf alloc is wrong!\n"); ++ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma1); ++dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8); ++tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8); ++tmp1_failed: ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ init_waitqueue_head(&drain_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_i2s_full_reset(controller); ++ controller->dev_audio = -1; ++ if (old_mksound) ++ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, 8); ++ free_pages((unsigned long)controller->tmp2, 8); ++ free_pages((unsigned long)pop_turn_onoff_buf, 8); ++ ++ if (adev >= 0) { ++ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ if(i2s_suspend_codec) ++ i2s_suspend_codec(controller->opened1,controller->opened2); ++ printk("Aic and codec are suspended!\n"); ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ if(i2s_resume_codec) ++ i2s_resume_codec(); ++ ++#if defined(CONFIG_I2S_AK4642EN) ++ jz_i2s_initHw(0); ++ jz_audio_reset(); ++ __i2s_enable(); ++ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); ++ /* playing */ ++ if(controller->opened1) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ int dma = controller->dma1; ++ int id; ++ unsigned long flags; ++ disable_dma(dma); ++ if(__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if(__dmac_channel_transmit_end_detected(dma)) ++ __dmac_channel_clear_transmit_end(dma); ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ while((id = get_buffer_id(&out_busy_queue)) >= 0) ++ put_buffer_id(&out_empty_queue, id); ++ ++ out_busy_queue.count=0; ++ if((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_empty_queue, id); ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } else ++ printk("pm out_empty_queue empty"); ++ } ++ ++ /* recording */ ++ if(controller->opened2) { ++ if(set_codec_record) ++ set_codec_record(); ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ } ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_full_queue, id2); ++ } ++ in_busy_queue.count = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno, retval; ++#if defined(CONFIG_I2S_DLV) ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++#endif ++ ++ abnormal_data_count = 0; ++ if(set_codec_mode) ++ set_codec_mode(); ++ ++ drain_flag = 0; ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ if(set_codec_gpio_pin) ++ set_codec_gpio_pin(); ++ ++ attach_jz_i2s(i2s_controller); ++ if(set_codec_startup_param) ++ set_codec_startup_param(); ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ if(set_codec_volume_table) ++ set_codec_volume_table(); ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++ ++#if defined(CONFIG_I2S_DLV) ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++#endif ++ ++ printk("JZ I2S OSS audio driver initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++#ifdef CONFIG_PM ++ /* pm_unregister(i2s_controller->pm); */ ++#endif ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ unload_jz_i2s(i2s_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ if(clear_codec_mode) ++ clear_codec_mode(); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++#if defined(CONFIG_SOC_JZ4730) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,con; ++ ++ if(elements_in_queue(&in_busy_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (con = 0; con < 1000; con ++) { ++ udelay(1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ return 0; ++} ++ ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ ++ if(elements_in_queue(&out_full_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if(count <= 0) ++ break; ++ } ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ //mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ //mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4740) ++#define MAXDELAY 50000 ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,ele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) ++ { ++ udelay(10); ++ i++; ++ } ++ else ++ break; ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long tfl; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1) { ++ controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* add some mute to anti-pop */ ++#if defined(CONFIG_I2S_DLV) ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ __aic_flush_fifo(); ++ if(clear_codec_replay) ++ clear_codec_replay(); ++ __aic_flush_fifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ } ++ ++ if (controller->opened2 == 1) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ ++ if(clear_codec_record) ++ clear_codec_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ abnormal_data_count = 0; ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++#endif ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ mdelay(2); ++ REG_DMAC_DMACKE(0) = 0x3f; ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ jz_codec_config = 0; ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++ if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ REG_AIC_FR |= (1 << 6); ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ abnormal_data_count = 0; ++ if(set_codec_record) ++ set_codec_record(); ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++#endif ++ ++ __i2s_enable(); ++ ++#if defined(CONFIG_I2S_DLV) ++ if (file->f_mode & FMODE_WRITE) { ++ ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ } else if (file->f_mode & FMODE_READ) { ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++ } ++ ++#endif ++ ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ count_info cinfo; ++ audio_buf_info abinfo; ++ int id, i; ++ ++ val = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++#if 0 ++ jz_audio_reset(); ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#endif ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ ++ return 0; ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); ++ return put_user(jz_audio_fragsize, (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ } ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF); ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); ++ ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ /* unused fragment amount */ ++ abinfo.fragments = jz_audio_fragments; ++ /* amount of fragments */ ++ abinfo.fragstotal = jz_audio_fragstotal; ++ /* fragment size in bytes */ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); ++ ++ /* write size count without blocking in bytes */ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); ++ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (jz_audio_channels == 2) ++ unfinish /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ unfinish /= 4; ++ else ++ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); ++ ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ if(set_replay_hp_or_speaker) ++ set_replay_hp_or_speaker(); ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ /*if (file->f_flags & O_NONBLOCK) ++ udelay(2);*/ ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), ++ *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) ++{ ++ int i,step_len; ++ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; ++ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ unsigned long l_sample_count,r_sample_count,sample_count; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ signed int left_sam=0,right_sam=0,l_val,r_val; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ left_sam = (signed int)l_sample; ++ right_sam = (signed int)r_sample; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++ ++ if(left_sam == 0 && right_sam == 0) ++ return; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ step_len = jz_audio_speed / 10 * 3; ++ step_len = step_len / 2; ++ step_len = 0x7fff / step_len + 1; ++ ++ l_sample_count = 0; ++ l_val = left_sam; ++ ++ while(1) { ++ if(l_val > 0) { ++ if(l_val >= step_len) { ++ l_val -= step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val < 0) { ++ if(l_val <= -step_len) { ++ l_val += step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val == 0) ++ break; ++ } ++ ++ r_sample_count = 0; ++ r_val = right_sam; ++ while(1) { ++ if(r_val > 0) { ++ if(r_val >= step_len) { ++ r_val -= step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val < 0) { ++ if(r_val <= -step_len) { ++ r_val += step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val == 0) ++ break; ++ } ++ /* fill up */ ++ if(l_sample_count > r_sample_count) ++ sample_count = l_sample_count; ++ else ++ sample_count = r_sample_count; ++ ++ l_val = left_sam; ++ r_val = right_sam; ++ for(i=0;i <= sample_count;i++) { ++ ++ *pop_buf = (unsigned long)l_val; ++ pop_buf ++; ++ ++ if(l_val > step_len) ++ l_val -= step_len; ++ else if(l_val < -step_len) ++ l_val += step_len; ++ else if(l_val >= -step_len && l_val <= step_len) ++ l_val = 0; ++ ++ *pop_buf = (unsigned long)r_val; ++ pop_buf ++; ++ if(r_val > step_len) ++ r_val -= step_len; ++ else if(r_val < -step_len) ++ r_val += step_len; ++ else if(r_val >= -step_len && r_val <= step_len) ++ r_val = 0; ++ } ++ ++ *pop_buf = 0; ++ pop_buf ++; ++ *pop_buf = 0; ++ ++ pop_buf ++; ++ sample_count += 2; ++ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); ++ ++ pop_dma_flag = 1; ++ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); ++ sleep_on(&pop_wait_queue); ++ pop_dma_flag = 0; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++} ++#endif +diff --git a/sound/oss/jz_i2s_dlv_dma_test.c b/sound/oss/jz_i2s_dlv_dma_test.c +new file mode 100644 +index 0000000..49a64a2 +--- /dev/null ++++ b/sound/oss/jz_i2s_dlv_dma_test.c +@@ -0,0 +1,2808 @@ ++/* ++ * linux/drivers/sound/jz_i2s_dlv.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++ ++#define NR_I2S 2 ++#define MAXDELAY 50000 ++#define JZCODEC_RW_BUFFER_SIZE 3 ++#define JZCODEC_RW_BUFFER_TOTAL 3 ++#define JZCODEC_USER_BUFFER 6 ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++static int jz_audio_rate; ++static char jz_audio_format; ++static char jz_audio_volume; ++static char jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments;//unused fragment amount ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++static int audio_mix_modcnt; ++static int codec_volue_shift; ++static int jz_audio_dma_tran_count;//bytes count of one DMA transfer ++static int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static int use_mic_line_flag; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++ ++ ++static void jz_update_filler(int bits, int channels); ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++static void jz_audio_reset(void); ++ ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* play */ ++ int dma2; /* record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; // byte index to next-in to DMA buffer ++ int nextOut; // byte index to next-out from DMA buffer ++ int count; // current byte count in DMA buffer ++ int finish; // current transfered byte count in DMA buffer ++ unsigned total_bytes; // total bytes written or read ++ unsigned blocks; ++ unsigned error; // over/underrun ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg);//the function accessing Codec REGs fcj add ++ void (*codec_write) (u8 reg, u16 val);//to AK4642EN,val is 8bit ++ /* Wait for codec-ready. Ok to sleep here. */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++static void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++ ++static void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++static int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++ ++/* set Audio data replay */ ++static void set_audio_data_replay() ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++ ++/* unset Audio data replay */ ++static void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio without playback */ ++static void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio without playback */ ++static void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record LINE input audio without playback */ ++static void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record LINE input audio without playback */ ++static void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Playback LINE input audio direct only */ ++static void set_playback_line_input_audio_direct_only() ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++ ++/* unset Playback LINE input audio direct only */ ++static void unset_playback_line_input_audio_direct_only() ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio with direct playback */ ++static void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio with direct playback */ ++static void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record playing audio mixed with MIC input audio */ ++static void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record playing audio mixed with MIC input audio */ ++static void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++static void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++static void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++///////// ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++///////// ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ spin_lock_irqsave(&q->lock, flags); ++ //spin_lock(&q->lock); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ //spin_unlock(&q->lock); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ //spin_unlock(&q->lock); ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ //spin_lock(&q->lock); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++ //spin_unlock(&q->lock); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ //spin_lock(&q->lock); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ //spin_unlock(&q->lock); ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ //for DSP_GETOPTR ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ jz_audio_dma_tran_count = count; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ flags = claim_dma_lock(); ++ //__dmac_disable_module(0); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ ++ set_dma_mode(chan, mode); ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) ++ { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ //__dmac_enable_module(0); ++ release_dma_lock(flags); ++ //dump_jz_dma_channel(chan); ++ ++ //printk_codec_files(); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ //for DSP_GETIPTR ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ //write back ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } ++ else ++ in_busy_queue.count = 0; ++ } ++ return IRQ_HANDLED; ++ ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ disable_dma(dma); ++ ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ ++ //for DSP_GETOPTR ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ //spin_lock(&controller->ioctllock); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ //spin_unlock(&controller->ioctllock); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); //very busy ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++ __i2s_disable(); ++ //schedule_timeout(5); ++ ++#if defined(CONFIG_I2S_DLV) ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __aic_internal_codec(); ++ //__i2s_set_oss_sample_size(16); ++ //__i2s_set_iss_sample_size(16); ++ ++#endif ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(7); ++ __i2s_set_receive_trigger(8); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ // recording ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ //playing ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /*alloc DMA buffer*/ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ //playing ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; //release page error ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ // recording ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; //release page error ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ int speed = 0, val; ++ ++ jz_audio_speed = rate; ++ if (rate > 96000) ++ rate = 96000; ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++#if defined(CONFIG_I2S_DLV) ++ speed = 0; ++ switch (rate) { ++ case 8000: ++ speed = 10; ++ break; ++ case 9600: ++ speed = 9; ++ break; ++ case 11025: ++ speed = 8; ++ break; ++ case 12000: ++ speed = 7; ++ break; ++ case 16000: ++ speed = 6; ++ break; ++ case 22050: ++ speed = 5; ++ break; ++ case 24000: ++ speed = 4; ++ break; ++ case 32000: ++ speed = 3; ++ break; ++ case 44100: ++ speed = 2; ++ break; ++ case 48000: ++ speed = 1; ++ break; ++ case 96000: ++ speed = 0; ++ break; ++ default: ++ break; ++ } ++ ++ val = read_codec_file(4); ++ val = (speed << 4) | speed; ++ write_codec_file(4, val); ++ ++#if 0 ++ for (i = 0; i <= 27 ; i++) { ++ printk(" ( CCC %d : 0x%x ) ",i ,read_codec_file(i)); ++ } ++#endif ++ ++#endif ++ return jz_audio_rate; ++} ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ return cnt; ++} ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ return cnt; ++} ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ d2 = *(s++); ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ return cnt; ++} ++ ++static int record_fill_2x24_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 4; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 24) >> 24; ++ d2 = *(s++); ++ *(dp ++) = (d2 << 24) >> 24; ++ } ++ //printk("--- rec 24 ---\n"); ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x8_u(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (unsigned long)d1; ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++ ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++ ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ ++ /* print all files */ ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ case 18: ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x28); ++ //write_codec_file(2, 0x60); ++ __i2s_set_oss_sample_size(18); ++ __i2s_set_iss_sample_size(16); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ break; ++ case 24: ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x78); ++ //write_codec_file(2, 0x60); ++ __i2s_set_oss_sample_size(24); ++ __i2s_set_iss_sample_size(24); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ break; ++ case AFMT_QUERY: ++ break; ++ } ++ return jz_audio_format; ++} ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ /* print all files */ ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++ break; ++ case 2: ++ /* print all files */ ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++ break; ++ case 0: ++ break; ++ } ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++#if defined(CONFIG_I2S_DLV) ++ /* reset DLV codec. from hibernate mode to sleep mode */ ++ write_codec_file(0, 0xf); ++ write_codec_file_bit(6, 0, 0); ++ write_codec_file_bit(6, 0, 1); ++ mdelay(200); ++ //write_codec_file(0, 0xf); ++ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 ++ mdelay(10);//wait for stability ++#endif ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++ REG_AIC_I2SCR = 0x10; ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ u8 cur_vol; ++ long val = 0; ++ ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ { ++ mixer_info info; ++#if defined(CONFIG_I2S_DLV) ++ strncpy(info.id, "DLV", sizeof(info.id)); ++ strncpy(info.name,"Jz4750 internal codec", sizeof(info.name)); ++#endif ++ ++ info.modify_counter = audio_mix_modcnt; ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ } ++ case SOUND_OLD_MIXER_INFO: ++ { ++ _old_mixer_info info; ++#if defined(CONFIG_I2S_DLV) ++ strncpy(info.id, "DLV", sizeof(info.id)); ++ strncpy(info.name,"Jz4750 internal codec", sizeof(info.name)); ++#endif ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ } ++ case SOUND_MIXER_READ_STEREODEVS: ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ ++ REG_CPM_I2SCDR = val; ++ printk_codec_files(); ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++#if defined(CONFIG_I2S_DLV) ++#endif ++ return 0; ++ ++ case SOUND_MIXER_READ_BASS: ++#if defined(CONFIG_I2S_DLV) ++#endif ++ return put_user(val, (long *) arg); ++ ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val == 100) { ++ //REG_CPM_CLKGR |= 0x60; ++ printk("gate clock : 0x%08x\n", REG_CPM_CLKGR); ++ return 100; ++ } ++ if(val == 99) { ++ REG_CPM_CLKGR &= ~0x60; ++ return 99; ++ } ++ if(val == 98) { ++ REG_CPM_CPCCR |= 0x80400000; ++ return 98; ++ } ++ if(val == 97) { ++ REG_CPM_CPCCR &= ~0x8000000; ++ REG_CPM_CPCCR |= 0x0040000; ++ return 97; ++ } ++ if(val > 31) ++ val = 31; ++ ++ jz_audio_volume = val; ++ //printk("\njz_audio_volume=%d\n",jz_audio_volume); ++#if defined(CONFIG_I2S_DLV) ++ cur_vol = val; ++ write_codec_file(17, cur_vol | 0xc0); ++ write_codec_file(18, cur_vol); ++#endif ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++#if defined(CONFIG_I2S_DLV) ++ val = jz_audio_volume | jz_audio_volume << 8; ++#endif ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_LINE: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if (val == 100) { ++ printk("Playback LINE input audio direct only is starting...\n"); ++ printk_codec_files(); ++ set_playback_line_input_audio_direct_only(); ++ printk_codec_files(); ++ return 100; ++ } ++ if (val == 99) { ++ printk("Playback LINE input audio direct only is end\n"); ++ unset_playback_line_input_audio_direct_only(); ++ printk_codec_files(); ++ return 99; ++ } ++ ++ if(val > 31) ++ val = 31; ++#if defined(CONFIG_I2S_DLV) ++ use_mic_line_flag = USE_LINEIN; ++ /* set gain */ ++ cur_vol = val; ++ cur_vol &= 0x1f; ++ write_codec_file(11, cur_vol);//GO1L ++ write_codec_file(12, cur_vol);//GO1R ++#endif ++ return 0; ++ break; ++ case SOUND_MIXER_WRITE_MIC: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ ++ if(val > 0xf) ++ val = 0xf; ++#if defined(CONFIG_I2S_DLV) ++ use_mic_line_flag = USE_MIC; ++ /* set gain */ ++ //write_codec_file_bit(6, 1, 3);//GIM ++ cur_vol = val; ++ cur_vol |= cur_vol << 4; ++ write_codec_file(19, cur_vol);//GIL,GIR ++#endif ++ return 0; ++ ++ case SOUND_MIXER_READ_MIC: ++#if defined(CONFIG_I2S_DLV) ++#endif ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ ++ return 0; ++} ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++static void replay_fill_2x18_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed long d1; ++ signed long l1; ++ volatile signed long *s = (signed long *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 4; ++ cnt += 4; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ } ++ ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x24_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed long d1; ++ signed long l1; ++ volatile signed long *s = (signed long *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 4; ++ cnt += 4; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ } ++ ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++ //printk("--- play 24 ---\n"); ++} ++ ++static void jz_update_filler(int format, int channels) ++{ ++ #define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ default: ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4;//4bytes * 8bits =32bits ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ //2bytes * 16bits =32bits ++ jz_audio_b = 2; ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ case TYPE(18, 2): ++ jz_audio_b = 1; ++ replay_filler = replay_fill_2x18_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ case TYPE(24, 2): ++ jz_audio_b = 1; ++ replay_filler = replay_fill_2x24_s; ++ record_filler = record_fill_2x24_s; ++ //printk("--- 24 ---\n"); ++ break; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++ ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++ ; ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev;//No of Audio device. ++ name = controller->name; ++ jz_i2s_initHw(1);//initialize AIC controller and reset it ++ /* register /dev/audio */ ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma2); ++dma1_failed: ++ jz_free_dma(controller->dma1); ++ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER); ++tmp2_failed: ++tmp1_failed: ++ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ jz_i2s_full_reset (controller); ++ controller->dev_audio = -1; ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); ++ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER); ++ if (adev >= 0) { ++ //unregister_sound_mixer(audio_devs[adev]->mixer_dev); ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++ ++ ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno, retval; ++ ++#if defined(CONFIG_I2S_DLV) ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++ ++ //REG_CPM_CPCCR &= ~(1 << 31); ++ //REG_CPM_CPCCR &= ~(1 << 30); ++ use_mic_line_flag = USE_NONE; ++ write_codec_file(0, 0xf); ++ ++ REG_AIC_I2SCR = 0x10; ++ __i2s_internal_codec(); ++ __i2s_as_slave(); ++ __i2s_select_i2s(); ++ __aic_select_i2s(); ++ __aic_reset(); ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ ++ /* power on DLV */ ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++#endif ++ ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ attach_jz_i2s(i2s_controller); ++#if defined(CONFIG_I2S_DLV) ++ __i2s_disable_transmit_intr(); ++ __i2s_disable_receive_intr(); ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++ ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++ ++ return 0; ++} ++ ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++ unload_jz_i2s(i2s_controller); ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static void print_pop_duration(void) ++{ ++ long diff; ++#if 0 ++ printk(" ramp_up_start=0x%x\n",ramp_up_start); ++ printk(" ramp_up_end =0x%x\n",ramp_up_end); ++ printk(" gain_up_start=0x%x\n",gain_up_start); ++ printk(" gain_up_end =0x%x\n",gain_up_end); ++ ++ printk("ramp_down_start=0x%x\n",ramp_down_start); ++ printk("ramp_down_end =0x%x\n",ramp_down_end); ++ printk("gain_down_start=0x%x\n",gain_down_start); ++ printk("gain_down_end =0x%x\n",gain_down_end); ++#endif ++ ++ diff = (long)ramp_up_end - (long)ramp_up_start; ++ printk("ramp up duration: %d ms\n",diff * 1000 / HZ); ++ diff = (long)gain_up_end - (long)gain_up_start; ++ printk("gain up duration: %d ms\n",diff * 1000 / HZ); ++ diff = (long)gain_down_end - (long)gain_down_start; ++ printk("gain down duration: %d ms\n",diff); ++ diff = (long)ramp_down_end - (long)ramp_down_start; ++ printk("ramp down duration: %d ms\n",diff * 1000 / HZ); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long tfl; ++ ++ jz_codec_config = 0; ++ if (controller == NULL) ++ return -ENODEV; ++ ++ if (controller->opened1 == 1 && controller->opened2 == 1) { ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ /*while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ }*/ ++ mdelay(100); ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ ++ ///////////////////////// ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ //__aic_flush_fifo(); ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ if (use_mic_line_flag == USE_LINEIN) { ++ unset_record_line_input_audio_with_audio_data_replay(); ++ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag); ++ } ++ if (use_mic_line_flag == USE_MIC) { ++ unset_record_mic_input_audio_with_audio_data_replay(); ++ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag); ++ } ++ ++#if 0 ++ unset_record_playing_audio_mixed_with_mic_input_audio(); ++#endif ++ __i2s_disable(); ++#endif ++ } else if ( controller->opened1 == 1 ) { ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ ++ __aic_flush_fifo(); ++ ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++ } else if ( controller->opened2 == 1 ) { ++ //controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++#if defined(CONFIG_I2S_DLV) ++#if 0 ++ /* unset Record MIC input audio with direct playback */ ++ unset_record_mic_input_audio_with_direct_playback(); ++#endif ++#if 1 ++ /* unset Record MIC input audio without playback */ ++ unset_record_mic_input_audio_without_playback(); ++#endif ++#if 0 ++ /* tested */ ++ /* unset Record LINE input audio without playback */ ++ unset_record_line_input_audio_without_playback(); ++#endif ++#endif ++ __i2s_disable(); ++ } ++ ++ if (controller->opened1 == 1 && controller->opened2 == 1) { ++ controller->opened1 = 0; ++ controller->opened2 = 0; ++ print_pop_duration(); ++ //__dmac_disable_module(0); ++ } else if ( controller->opened1 == 1 ) { ++ controller->opened1 = 0; ++ print_pop_duration(); ++ } else if ( controller->opened2 == 1 ) { ++ controller->opened2 = 0; ++ } ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ ++/* __cpm_stop_idct(); ++ __cpm_stop_db(); ++ __cpm_stop_me(); ++ __cpm_stop_mc(); ++ __cpm_stop_ipu();*/ ++ printk("close audio and clear ipu gate : 0x%08x\n", REG_CPM_CLKGR); ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ if (controller == NULL) ++ return -ENODEV; ++ mdelay(2); ++ REG_DMAC_DMACKE(0) = 0x3f; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ jz_codec_config = 0; ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } else if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ controller->opened1 = 1; ++ //for ioctl ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ } else if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ //for ioctl ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset();//11.2 ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++#if defined(CONFIG_I2S_DLV) ++ ++ if (use_mic_line_flag == USE_LINEIN) { ++ /* Record LINE input audio with Audio data replay (full duplex for linein) */ ++ /* codec_test_line */ ++ set_record_line_input_audio_with_audio_data_replay(); ++ ++ } ++ if (use_mic_line_flag == USE_MIC) { ++ /* Record MIC input audio with Audio data replay (full duplex) */ ++ /* codec_test_mic */ ++ set_record_mic_input_audio_with_audio_data_replay(); ++ } ++#if 0 ++ /* Record playing audio mixed with MIC input audio */ ++ set_record_playing_audio_mixed_with_mic_input_audio(); ++#endif ++ ++#endif ++ } else if (file->f_mode & FMODE_WRITE) { ++#if defined(CONFIG_I2S_DLV) ++ //mdelay(10); ++ /* Audio data replay */ ++ set_audio_data_replay(); ++#endif ++ } else if (file->f_mode & FMODE_READ) { ++#if defined(CONFIG_I2S_DLV) ++#if 0 ++ /* Record MIC input audio with direct playback */ ++ set_record_mic_input_audio_with_direct_playback(); ++#endif ++ ++#if 1 ++ /* set Record MIC input audio without playback */ ++ set_record_mic_input_audio_without_playback(); ++#endif ++#if 0 ++ /* tested */ ++ /* set Record LINE input audio without playback */ ++ set_record_line_input_audio_without_playback(); ++#endif ++ mdelay(1); ++#endif ++ } ++ ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++ __i2s_enable(); ++ ndelay(100); ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++#if defined(CONFIG_I2S_DLV) ++ //set SB_ADC or SB_DAC ++ __dmac_enable_module(0); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++#endif ++ } else if (file->f_mode & FMODE_WRITE) { ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++#endif ++ } else if (file->f_mode & FMODE_READ) { ++#if defined(CONFIG_I2S_DLV) ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++#endif ++ } ++ ++ ++ printk("open audio and set ipu gate : 0x%08x\n", REG_CPM_CLKGR); ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ audio_buf_info abinfo; ++ int i, bytes, id; ++ count_info cinfo; ++ val = 0; ++ bytes = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ { ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ return put_user(val, (int *)arg); ++ } ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ return 0; ++ ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(4*PAGE_SIZE, (int *)arg); ++ return put_user(jz_audio_fragsize , (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ { ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) { ++ jz_audio_set_format(controller->dev_audio,val); ++ } else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ ++ } ++ return put_user(val, (int *)arg); ++ } ++ ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF);//16 least bits ++ ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ //unused fragment amount ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ bytes /= jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ abinfo.fragsize = jz_audio_fragsize; ++ abinfo.bytes = bytes; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ bytes = 0; ++ //unused fragment amount ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ bytes /= jz_audio_b; ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ abinfo.fragsize = jz_audio_fragsize; ++ abinfo.bytes = bytes; ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ //controller->total_bytes += get_dma_residue(controller->dma2); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ //controller->total_bytes += get_dma_residue(controller->dma1); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ unfinish /= jz_audio_b; ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, ++ (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->nextIn = 0; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ ++ spin_lock(&controller->lock); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ spin_unlock(&controller->lock); ++ ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ //write back ++ dma_cache_wback_inv(*(in_dma_buf + id), ++ *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ //interruptible_sleep_on(&rx_wait_queue); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ /*if (signal_pending(current)) ++ return ret ? ret: -ERESTARTSYS; */ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, ++ copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ //write back ++ dma_cache_wback_inv(*(in_dma_buf + id), ++ *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->nextIn += ret; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ }//while (left_count > 0) ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0, val; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ //spin_lock(&controller->ioctllock); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ //spin_unlock(&controller->ioctllock); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ if (file->f_flags & O_NONBLOCK) ++ udelay(2); ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ // all are full ++ if (file->f_flags & O_NONBLOCK) ++ return ret;//no waiting,no block ++ else { ++ sleep_on(&tx_wait_queue);//blocked ++ } ++ } ++ /*if (signal_pending(current)) ++ return ret ? ret : -ERESTARTSYS;*/ ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ //replay_filler((unsigned long)controller->tmp1 + ret, copy_count, id); ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); //busy in ++ dma_cache_wback_inv(*(out_dma_buf + id), ++ *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); //spare ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ controller->nextOut += ret; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); //first once,next spare ++ ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++ } ++ } ++ } ++ } ++ return ret; ++} +diff --git a/sound/oss/jz_i2s_for_4750.c b/sound/oss/jz_i2s_for_4750.c +new file mode 100644 +index 0000000..2ca3342 +--- /dev/null ++++ b/sound/oss/jz_i2s_for_4750.c +@@ -0,0 +1,2981 @@ ++/* ++ * linux/drivers/sound/Jz_i2s.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++#define NR_I2S 2 ++#define MAXDELAY 50000 ++#define JZCODEC_RW_BUFFER_SIZE 2 ++#define JZCODEC_RW_BUFFER_TOTAL 6 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++mixer_info info; ++_old_mixer_info old_info; ++int codec_volue_shift; ++hpvol_shift_t hpvol_shift_table[72]; ++int abnormal_data_count; ++unsigned long i2s_clk; ++ ++void (*set_codec_mode)(void) = NULL; ++void (*clear_codec_mode)(void) = NULL; ++void (*set_codec_gpio_pin)(void) = NULL; ++void (*each_time_init_codec)(void) = NULL; ++int (*set_codec_startup_param)(void) = NULL; ++void (*set_codec_volume_table)(void) = NULL; ++void (*set_codec_record)(void) = NULL; ++void (*set_codec_replay)(void) = NULL; ++void (*set_codec_replay_record)(void); ++void (*turn_on_codec)(void) = NULL; ++void (*turn_off_codec)(void) = NULL; ++void (*set_codec_speed)(int rate) = NULL; ++void (*reset_codec)(void) = NULL; ++void (*codec_mixer_old_info_id_name)(void) = NULL; ++void (*codec_mixer_info_id_name)(void) = NULL; ++void (*set_codec_bass)(int val) = NULL; ++void (*set_codec_volume)(int val) = NULL; ++void (*set_codec_mic)(int val) = NULL; ++void (*i2s_resume_codec)(void) = NULL; ++void (*i2s_suspend_codec)(int wr,int rd) = NULL; ++void (*init_codec_pin)(void) = NULL; ++void (*set_codec_some_func)(void) = NULL; ++void (*clear_codec_record)(void) = NULL; ++void (*clear_codec_replay)(void) = NULL; ++void (*set_replay_hp_or_speaker)(void) = NULL; ++void (*set_codec_direct_mode)(void) = NULL; ++void (*clear_codec_direct_mode)(void) = NULL; ++ ++static int jz_audio_rate; ++static int jz_audio_format; ++static int jz_audio_volume; ++static int jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments; /* unused fragment amount */ ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++ ++static int codec_bass_gain; ++static int audio_mix_modcnt; ++static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ ++static int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++ ++static int codec_mic_gain; ++static int pop_dma_flag; ++static int last_dma_buffer_id; ++static int drain_flag; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++static void jz_update_filler(int bits, int channels); ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); ++#endif ++static void jz_audio_reset(void); ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* for play */ ++ int dma2; /* for record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; /* byte index to next-in to DMA buffer */ ++ int nextOut; /* byte index to next-out from DMA buffer */ ++ int count; /* current byte count in DMA buffer */ ++ int finish; /* current transfered byte count in DMA buffer */ ++ unsigned total_bytes; /* total bytes written or read */ ++ unsigned blocks; ++ unsigned error; /* over/underrun */ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++static unsigned long pop_turn_onoff_buf; ++static unsigned long pop_turn_onoff_pbuf; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static left_right_sample_t save_last_samples[64]; ++static int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++static void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++ ++static void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++static int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++ ++/* set Audio data replay */ ++static void set_audio_data_replay() ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++ ++/* unset Audio data replay */ ++static void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio without playback */ ++static void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio without playback */ ++static void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record LINE input audio without playback */ ++static void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record LINE input audio without playback */ ++static void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Playback LINE input audio direct only */ ++static void set_playback_line_input_audio_direct_only() ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++ ++/* unset Playback LINE input audio direct only */ ++static void unset_playback_line_input_audio_direct_only() ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio with direct playback */ ++static void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio with direct playback */ ++static void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record playing audio mixed with MIC input audio */ ++static void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record playing audio mixed with MIC input audio */ ++static void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++static void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++static void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++///////// ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++///////// ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count / jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ //set_dma_mode(chan, mode); ++ jz_set_oss_dma(chan, mode, jz_audio_format); ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(drain_flag == 1) ++ wake_up(&drain_wait_queue); ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(pop_dma_flag == 1) { ++ pop_dma_flag = 0; ++ wake_up(&pop_wait_queue); ++ } else { ++ if(drain_flag == 1) { ++ /* Is replay dma buffer over ? */ ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ drain_flag = 0; ++ wake_up(&drain_wait_queue); ++ } ++ } ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++#if defined(CONFIG_MIPS_JZ_URANUS) ++ i2s_clk = 48000000; ++#else ++ i2s_clk = __cpm_get_i2sclk(); ++#endif ++ __i2s_disable(); ++ if(set) ++ __i2s_reset(); ++ schedule_timeout(5); ++ if(each_time_init_codec) ++ each_time_init_codec(); ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ ++ /* recording */ ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ /* playing */ ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* alloc DMA buffer */ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ /* playing */ ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ /* recording */ ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ jz_audio_speed = rate; ++ if (rate > 48000) ++ rate = 48000; ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ if(set_codec_speed) ++ set_codec_speed(rate); ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ d2 = *(s++); ++ if(abnormal_data_count > 0) { ++ d1 = d2 = 0; ++ abnormal_data_count --; ++ } ++ *(dp ++) = (d1 << 16) >> 16; ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = ddata; ++ save_last_samples[id].right = ddata; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_2x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ /* save last left */ ++ if(count == 2) ++ save_last_samples[id].left = dd1; ++ /* save last right */ ++ if(count == 1) ++ save_last_samples[id].right = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = l1; ++ save_last_samples[id].right = l1; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++#if 0 ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++#if defined(CONFIG_I2S_ICDC) ++ volatile signed long *before_dp; ++ int sam_rate = jz_audio_rate / 20; ++ ++ tmp1 = tmp2 = 0; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ l1 >>= codec_volue_shift; ++ ++ if(l1 == 0) { ++ mute_cnt ++; ++ if(mute_cnt >= sam_rate) { ++ before_dp = dp - 10; ++ *(before_dp) = (signed long)1; ++ before_dp = dp - 11; ++ *(before_dp) = (signed long)1; ++ mute_cnt = 0; ++ } ++ } else ++ mute_cnt = 0; ++ ++ *(dp ++) = l1; ++ ++ tmp1 = tmp2; ++ tmp2 = l1; ++ } ++ ++ /* save last left */ ++ save_last_samples[id].left = tmp1; ++ /* save last right */ ++ save_last_samples[id].right = tmp2; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++#endif ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++#else ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ ++#if 0 ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); ++ memcpy((char*)dp, (char*)s, count); ++ *(out_dma_buf_data_count + id) = count; ++#else ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++#endif ++} ++#endif ++ ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++#if defined(CONFIG_I2S_DLV) ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++#endif ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ /* print all files */ ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ if(set_codec_some_func) ++ set_codec_some_func(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++#endif ++ break; ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++#endif ++ break; ++ case 0: ++ break; ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ /* inititalize internal I2S codec */ ++ if(init_codec_pin) ++ init_codec_pin(); ++ ++#if defined(CONFIG_I2S_ICDC) ++ /* initialize AIC but not reset it */ ++ jz_i2s_initHw(0); ++#endif ++ if(reset_codec) ++ reset_codec(); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#if defined(CONFIG_I2S_DLV) ++ REG_AIC_I2SCR = 0x10; ++#endif ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ ++ if(codec_mixer_info_id_name) ++ codec_mixer_info_id_name(); ++ info.modify_counter = audio_mix_modcnt; ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ case SOUND_OLD_MIXER_INFO: ++ ++ if(codec_mixer_old_info_id_name) ++ codec_mixer_old_info_id_name(); ++ ++ return copy_to_user((void *)arg, &old_info, sizeof(info)); ++ case SOUND_MIXER_READ_STEREODEVS: ++ ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ switch(val) { ++ case 100: ++ if(set_codec_direct_mode) ++ set_codec_direct_mode(); ++ break; ++ case 0: ++ if(clear_codec_direct_mode) ++ clear_codec_direct_mode(); ++ break; ++ } ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_bass_gain = val; ++ if(set_codec_bass) ++ set_codec_bass(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_BASS: ++ ++ val = codec_bass_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ if (val > 31) ++ val = 31; ++ jz_audio_volume = val; ++ ++ if(set_codec_volume) ++ set_codec_volume(val); ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_MIC: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_mic_gain = val; ++ if(set_codec_mic) ++ set_codec_mic(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_MIC: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ return 0; ++} ++ ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ default: ++ ; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev; /* No of Audio device. */ ++ ++ name = controller->name; ++ /* initialize AIC controller and reset it */ ++ jz_i2s_initHw(1); ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); ++ if(!pop_turn_onoff_buf) ++ printk("pop_turn_onoff_buf alloc is wrong!\n"); ++ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma1); ++dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8); ++tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8); ++tmp1_failed: ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ init_waitqueue_head(&drain_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_i2s_full_reset(controller); ++ controller->dev_audio = -1; ++ if (old_mksound) ++ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, 8); ++ free_pages((unsigned long)controller->tmp2, 8); ++ free_pages((unsigned long)pop_turn_onoff_buf, 8); ++ ++ if (adev >= 0) { ++ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ if(i2s_suspend_codec) ++ i2s_suspend_codec(controller->opened1,controller->opened2); ++ printk("Aic and codec are suspended!\n"); ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ if(i2s_resume_codec) ++ i2s_resume_codec(); ++ ++#if defined(CONFIG_I2S_AK4642EN) ++ jz_i2s_initHw(0); ++ jz_audio_reset(); ++ __i2s_enable(); ++ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); ++ /* playing */ ++ if(controller->opened1) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ int dma = controller->dma1; ++ int id; ++ unsigned long flags; ++ disable_dma(dma); ++ if(__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if(__dmac_channel_transmit_end_detected(dma)) ++ __dmac_channel_clear_transmit_end(dma); ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ while((id = get_buffer_id(&out_busy_queue)) >= 0) ++ put_buffer_id(&out_empty_queue, id); ++ ++ out_busy_queue.count=0; ++ if((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_empty_queue, id); ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } else ++ printk("pm out_empty_queue empty"); ++ } ++ ++ /* recording */ ++ if(controller->opened2) { ++ if(set_codec_record) ++ set_codec_record(); ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ } ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_full_queue, id2); ++ } ++ in_busy_queue.count = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno, retval; ++#if defined(CONFIG_I2S_DLV) ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++#endif ++ ++ abnormal_data_count = 0; ++ if(set_codec_mode) ++ set_codec_mode(); ++ ++ drain_flag = 0; ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ if(set_codec_gpio_pin) ++ set_codec_gpio_pin(); ++ ++ attach_jz_i2s(i2s_controller); ++ if(set_codec_startup_param) ++ set_codec_startup_param(); ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ if(set_codec_volume_table) ++ set_codec_volume_table(); ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++ ++#if defined(CONFIG_I2S_DLV) ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++#endif ++ ++ printk("JZ I2S OSS audio driver initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++#ifdef CONFIG_PM ++ /* pm_unregister(i2s_controller->pm); */ ++#endif ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ unload_jz_i2s(i2s_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ if(clear_codec_mode) ++ clear_codec_mode(); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++#if defined(CONFIG_SOC_JZ4730) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,con; ++ ++ if(elements_in_queue(&in_busy_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (con = 0; con < 1000; con ++) { ++ udelay(1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ return 0; ++} ++ ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ ++ if(elements_in_queue(&out_full_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if(count <= 0) ++ break; ++ } ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4750) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ //mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ //mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4740) ++#define MAXDELAY 50000 ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,ele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) ++ { ++ udelay(10); ++ i++; ++ } ++ else ++ break; ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long tfl; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1) { ++ controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* add some mute to anti-pop */ ++#if defined(CONFIG_I2S_DLV) ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ __aic_flush_fifo(); ++ if(clear_codec_replay) ++ clear_codec_replay(); ++ __aic_flush_fifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ } ++ ++ if (controller->opened2 == 1) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ ++ if(clear_codec_record) ++ clear_codec_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ abnormal_data_count = 0; ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++#endif ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ mdelay(2); ++ REG_DMAC_DMACKE(0) = 0x3f; ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ jz_codec_config = 0; ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++ if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ REG_AIC_FR |= (1 << 6); ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ abnormal_data_count = 0; ++ if(set_codec_record) ++ set_codec_record(); ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++#endif ++ ++ __i2s_enable(); ++ ++#if defined(CONFIG_I2S_DLV) ++ if (file->f_mode & FMODE_WRITE) { ++ ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ } else if (file->f_mode & FMODE_READ) { ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++ } ++ ++#endif ++ ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ count_info cinfo; ++ audio_buf_info abinfo; ++ int id, i; ++ ++ val = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++#if 0 ++ jz_audio_reset(); ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#endif ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ ++ return 0; ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); ++ return put_user(jz_audio_fragsize, (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ } ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF); ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); ++ ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ /* unused fragment amount */ ++ abinfo.fragments = jz_audio_fragments; ++ /* amount of fragments */ ++ abinfo.fragstotal = jz_audio_fragstotal; ++ /* fragment size in bytes */ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); ++ ++ /* write size count without blocking in bytes */ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); ++ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (jz_audio_channels == 2) ++ unfinish /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ unfinish /= 4; ++ else ++ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); ++ ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ if(set_replay_hp_or_speaker) ++ set_replay_hp_or_speaker(); ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ /*if (file->f_flags & O_NONBLOCK) ++ udelay(2);*/ ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), ++ *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) ++{ ++ int i,step_len; ++ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; ++ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ unsigned long l_sample_count,r_sample_count,sample_count; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ signed int left_sam=0,right_sam=0,l_val,r_val; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ left_sam = (signed int)l_sample; ++ right_sam = (signed int)r_sample; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++ ++ if(left_sam == 0 && right_sam == 0) ++ return; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ step_len = jz_audio_speed / 10 * 3; ++ step_len = step_len / 2; ++ step_len = 0x7fff / step_len + 1; ++ ++ l_sample_count = 0; ++ l_val = left_sam; ++ ++ while(1) { ++ if(l_val > 0) { ++ if(l_val >= step_len) { ++ l_val -= step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val < 0) { ++ if(l_val <= -step_len) { ++ l_val += step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val == 0) ++ break; ++ } ++ ++ r_sample_count = 0; ++ r_val = right_sam; ++ while(1) { ++ if(r_val > 0) { ++ if(r_val >= step_len) { ++ r_val -= step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val < 0) { ++ if(r_val <= -step_len) { ++ r_val += step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val == 0) ++ break; ++ } ++ /* fill up */ ++ if(l_sample_count > r_sample_count) ++ sample_count = l_sample_count; ++ else ++ sample_count = r_sample_count; ++ ++ l_val = left_sam; ++ r_val = right_sam; ++ for(i=0;i <= sample_count;i++) { ++ ++ *pop_buf = (unsigned long)l_val; ++ pop_buf ++; ++ ++ if(l_val > step_len) ++ l_val -= step_len; ++ else if(l_val < -step_len) ++ l_val += step_len; ++ else if(l_val >= -step_len && l_val <= step_len) ++ l_val = 0; ++ ++ *pop_buf = (unsigned long)r_val; ++ pop_buf ++; ++ if(r_val > step_len) ++ r_val -= step_len; ++ else if(r_val < -step_len) ++ r_val += step_len; ++ else if(r_val >= -step_len && r_val <= step_len) ++ r_val = 0; ++ } ++ ++ *pop_buf = 0; ++ pop_buf ++; ++ *pop_buf = 0; ++ ++ pop_buf ++; ++ sample_count += 2; ++ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); ++ ++ pop_dma_flag = 1; ++ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); ++ sleep_on(&pop_wait_queue); ++ pop_dma_flag = 0; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++} ++#endif +diff --git a/sound/oss/jz_pcm_tlv320aic1106_dma.c b/sound/oss/jz_pcm_tlv320aic1106_dma.c +new file mode 100644 +index 0000000..1a1f4cf +--- /dev/null ++++ b/sound/oss/jz_pcm_tlv320aic1106_dma.c +@@ -0,0 +1,1839 @@ ++/* ++ * linux/drivers/sound/jz_pcm_tlv320aic1106.c ++ * ++ * JzSOC On-Chip PCM audio driver. ++ * ++ * Copyright (C) 2005 by Ingenic Corp. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#define NR_PCM 2 ++#define MAXDELAY 50000 ++#define JZCODEC_RW_BUFFER_SIZE 4 ++#define JZCODEC_RW_BUFFER_TOTAL 3 ++#define JZCODEC_USER_BUFFER 6 ++ ++#define MODE_is_8 0 // 1 is 8 bits, and 0 is 16 bits ++ ++static int jz_audio_rate; ++static char jz_audio_format; ++static char jz_audio_volume; ++static char jz_audio_channels; ++static int jz_audio_fragments;//unused fragment amount ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++static int jz_audio_dma_tran_count;//bytes count of one DMA transfer ++ ++static void jz_update_filler(int bits, int channels); ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_pcm_irq(int irqnr, void *ref); ++static irqreturn_t jz_pcm_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_pcm_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(unsigned long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++static void dump_pcmc_reg(void); ++ ++static struct file_operations jz_pcm_audio_fops; ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++ ++struct jz_pcm_controller_info { ++ int io_base; ++ int dma1; /* play */ ++ int dma2; /* record */ ++ char *name; ++ int dev_audio; ++ struct pcm_codec *pcm_codec[NR_PCM]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; // byte index to next-in to DMA buffer ++ int nextOut; // byte index to next-out from DMA buffer ++ int count; // current byte count in DMA buffer ++ int finish; // current transfered byte count in DMA buffer ++ unsigned long total_bytes; // total bytes written or read ++ unsigned long blocks; ++ unsigned long error; // over/underrun ++}; ++static struct jz_pcm_controller_info *pcm_controller = NULL; ++ ++struct pcm_codec { ++ /* PCM controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl pcm accessing routines */ ++ u16 (*codec_read) (u8 reg);//the function accessing Codec REGs ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready. Ok to sleep here. */ ++ void (*codec_wait) (struct pcm_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct pcm_codec *codec, int oss_channel); ++ void (*write_mixer)(struct pcm_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct pcm_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct pcm_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++typedef struct buffer_queue_s { ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r, i; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; ++ ++ //for DSP_GETOPTR ++ //spin_lock_irqsave(&controller->ioctllock, flags); ++ spin_lock(&controller->ioctllock); ++ jz_audio_dma_tran_count = count; ++ //spin_unlock_irqrestore(&controller->ioctllock, flags); ++ spin_unlock(&controller->ioctllock); ++ flags = claim_dma_lock(); ++ __dmac_disable_module(0);//!!!!!!!!! ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ set_dma_mode(chan, mode); ++#if MODE_is_8 ++ __dmac_channel_set_src_port_width(chan, 8); ++ __dmac_channel_set_dest_port_width(chan, 8); ++ __dmac_channel_set_transfer_unit_8bit(chan); ++#else ++ __dmac_channel_set_src_port_width(chan, 16); ++ __dmac_channel_set_dest_port_width(chan, 16); ++ __dmac_channel_set_transfer_unit_16bit(chan); ++#endif ++ ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ __dmac_enable_module(0); ++ release_dma_lock(flags); ++#if 0 ++ //for DSP_GETOPTR on FPGA ++ struct jz_dma_chan *tmpchan = &jz_dma_table[1]; ++ ++ spin_lock(&controller->ioctllock); ++ jz_audio_dma_tran_count = count; ++ spin_unlock(&controller->ioctllock); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ set_dma_mode(chan, mode); ++#if MODE_is_8 ++ __dmac_channel_set_src_port_width(chan, 8); ++ __dmac_channel_set_dest_port_width(chan, 8); ++ __dmac_channel_set_transfer_unit_8bit(chan); ++#else ++ __dmac_channel_set_src_port_width(chan, 16); ++ __dmac_channel_set_dest_port_width(chan, 16); ++ __dmac_channel_set_transfer_unit_16bit(chan); ++#endif ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++#if 0 ++ __pcm_enable_tfs_intr(); ++ __pcm_enable_tur_intr(); ++ __pcm_enable_rfs_intr(); ++ __pcm_enable_ror_intr(); ++#endif ++#endif ++} ++ ++static irqreturn_t jz_pcm_record_dma_irq(int irq, void *dev_id) ++{ ++ int id1, id2; ++ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ //for DSP_GETIPTR ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock(&controller->ioctllock); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_pcm_irq(int irq, void *dev_id) ++{ ++ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; ++ printk("pcm interrupt REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_pcm_replay_dma_irq(int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ //for DSP_GETOPTR ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for PCM module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); //very busy ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ // recording ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ //playing ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /*alloc DMA buffer*/ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ //playing ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; //release page error ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ // recording ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; //release page error ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 */ ++ long codec_speed; ++ long speed = 0; ++ ++ jz_audio_speed = rate; ++ if (rate > 48000) ++ rate = 48000; ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ /*switch (rate) { ++ case 8000: ++ speed = 0; ++ break; ++ case 11025: ++ speed = 1; ++ break; ++ case 12000: ++ speed = 2; ++ break; ++ case 16000: ++ speed = 3; ++ break; ++ case 22050: ++ speed = 4; ++ break; ++ case 24000: ++ speed = 5; ++ break; ++ case 32000: ++ speed = 6; ++ break; ++ case 44100: ++ speed = 7; ++ break; ++ case 48000: ++ speed = 8; ++ break; ++ default: ++ break; ++ } ++ printk("set PCMIN or PCMOUT speed.\n"); ++ __pcm_set_clk_rate(speed); ++ __pcm_set_sync_rate(256);*/ ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ volatile unsigned char *s = (unsigned char*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ *dp = *s; ++ dp ++; ++ s++; ++ count --; ++ cnt ++; ++ } ++ ++ return cnt; ++} ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ volatile unsigned char *s = (unsigned char*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++#if 1 ++ while (count > 0) { ++ *dp = *s; ++ s ++; ++ dp ++; ++ count --; ++ cnt ++; ++ } ++#else ++ while (count > 0) { ++ *dp = *s; ++ s += 2; //skip right sample ++ dp ++; ++ count -= 2; ++ cnt ++; ++ } ++#endif ++ return cnt; ++} ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned short d1; ++ unsigned short *s = (unsigned short*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ *dp = *s; ++ s ++; ++ dp ++; ++ count -= 2; ++ cnt += 2; ++ } ++ ++ return cnt; ++} ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned short *s = (unsigned short*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++#if 1 ++ while (count > 0) { ++ *dp = *s; ++ s ++; ++ dp ++; ++ count -= 2; ++ cnt += 2; ++ } ++#else ++ while (count > 0) { ++ *dp = *s; ++ s += 2; //skip right sample ++ dp ++; ++ count -= 4; ++ cnt += 2;/* count in byte */ ++ } ++#endif ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(unsigned long src_start, int count, int id) ++{ ++#if 0 ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned char *dp = (unsigned char *)(*(out_dma_buf + id)); ++ ++ *(out_dma_buf_data_count + id) = count; ++ while (count > 0) { ++ *dp = *s; ++ dp ++; ++ s ++; ++ count --; ++ } ++#else ++ volatile u8 *s = (u8 *)src_start; ++ volatile u8 *dp = (u8 *)(*(out_dma_buf + id)); ++ ++ *(out_dma_buf_data_count + id) = count; ++ while (count > 0) { ++ *dp = *s; ++ dp ++; ++ s ++; ++ count --; ++ } ++#endif ++} ++ ++static void replay_fill_2x8_u(unsigned long src_start, int count, int id) ++{ ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned char *dp = (unsigned char *)(*(out_dma_buf + id)); ++ ++#if 1 ++ *(out_dma_buf_data_count + id) = count; ++ while (count > 0) { ++ *dp = *s; ++ dp ++; ++ s ++; ++ count --; ++ } ++#else ++ while (count > 0) { ++ *dp = *s; ++ s += 2; //skip right sample ++ dp ++; ++ count -= 2; ++ cnt ++; ++ } ++ *(out_dma_buf_data_count + id) = cnt; ++#endif ++} ++ ++ ++static void replay_fill_1x16_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned short d1, l1; ++ signed short sam_to; ++ volatile unsigned short *s = (unsigned short *)src_start; ++ volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ d1 = *s; ++ ++ sam_to = (signed short)d1; ++ if (sam_to >= 0) { ++ sam_to = 0xfff * sam_to / 0x7fff; ++ } else { ++ sam_to = 0 - sam_to; ++ sam_to = 0xfff * sam_to / 0x7fff; ++ sam_to = 0 - sam_to; ++ } ++ d1 = (unsigned short)sam_to; ++ d1 = d1 << 3; ++ l1 = d1 | jz_audio_volume; ++ ++ *dp = l1; ++ s ++; ++ dp ++; ++ count -= 2; ++ cnt += 2 ; ++ } ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x16_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned short d1, l1; ++ volatile unsigned short *s = (unsigned short *)src_start; ++ volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id)); ++ ++#if 1 ++ while (count > 0) { ++ d1 = *s; ++ l1 = (d1 & 0xfff8) | jz_audio_volume; ++ *dp = l1; ++ s ++; ++ dp ++; ++ count -= 2; ++ cnt += 2 ; ++ } ++ *(out_dma_buf_data_count + id) = cnt; ++#else ++ while (count > 0) { ++ d1 = *s; ++ l1 = (d1 & 0xfff8) | jz_audio_volume; ++ *dp = l1; ++ s += 2; //skip right sample ++ dp ++; ++ count -= 4; ++ cnt += 2; ++ } ++ *(out_dma_buf_data_count + id) = cnt; ++#endif ++} ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ case AFMT_S16_LE: ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ default: ++ printk("channel number is wrong. %d\n",__LINE__); ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ printk("set PCM codec RESET pin on LOW, while MCLK occur.\n"); ++ printk("set LINSEL on LOW(8bits) or HIGH(13bits+3bits for PCMOUT gain).\n"); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __pcm_flush_fifo(); ++ __pcm_disable_txfifo(); ++ __pcm_disable_rxfifo(); ++ __pcm_set_transmit_trigger(7); ++ __pcm_set_receive_trigger(7); ++ __pcm_omsb_next_sync(); ++ __pcm_imsb_next_sync(); ++#if MODE_is_8 ++ __pcm_set_iss(8);//8bits decided by LINSEL ++ __pcm_set_oss(8);//8bits decided by LINSEL ++#else ++ __pcm_set_iss(16);//16bits decided by LINSEL ++ __pcm_set_oss(16); ++#endif ++ __pcm_disable_tfs_intr(); ++ __pcm_disable_tur_intr(); ++ __pcm_disable_rfs_intr(); ++ __pcm_disable_ror_intr(); ++ ++ __pcm_disable_receive_dma(); ++ __pcm_disable_transmit_dma(); ++ ++ //init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_pcm_audio_fops */ ++static struct file_operations jz_pcm_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_pcm_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_pcm_controller_info *controller = pcm_controller; ++ ++ for (i = 0; i < NR_PCM; i++) ++ if (controller->pcm_codec[i] != NULL && controller->pcm_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->pcm_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_pcm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct pcm_codec *codec = (struct pcm_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_pcm_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_pcm_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_pcm_llseek, ++ ioctl: jz_pcm_ioctl_mixdev, ++ open: jz_pcm_open_mixdev, ++}; ++ ++static int pcm_mixer_ioctl(struct pcm_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ ++ switch (cmd) { ++ case SOUND_MIXER_READ_STEREODEVS: ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ if (val == 100) { ++ dump_pcmc_reg(); ++ return 100; ++ } ++ val = val / 10; ++ switch (val) { ++ case 0: ++ case 1: ++ jz_audio_volume = 7; ++ break; ++ case 2: ++ jz_audio_volume = 6; ++ break; ++ case 3: ++ jz_audio_volume = 5; ++ break; ++ case 4: ++ jz_audio_volume = 4; ++ break; ++ case 5: ++ jz_audio_volume = 3; ++ break; ++ case 6: ++ jz_audio_volume = 2; ++ break; ++ case 7: ++ case 8: ++ jz_audio_volume = 1; ++ break; ++ case 9: ++ case 10: ++ jz_audio_volume = 0; ++ break; ++ } ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_MIC: ++ printk("Can not justify Mic gain to the PCM codec.!\n"); ++ return -ENOSYS; ++ ++ case SOUND_MIXER_READ_MIC: ++ printk("Can not justify Mic gain to the PCM codec.!\n"); ++ return -ENOSYS; ++ default: ++ return -ENOSYS; ++ } ++ ++ return 0; ++} ++ ++ ++int pcm_probe_codec(struct pcm_codec *codec) ++{ ++ /* generic OSS to PCM wrapper */ ++ codec->mixer_ioctl = pcm_mixer_ioctl; ++ return 1; ++} ++ ++/* PCM codec initialisation. */ ++static int __init jz_pcm_codec_init(struct jz_pcm_controller_info *controller) ++{ ++ int num_pcm = 0; ++ struct pcm_codec *codec; ++ ++ for (num_pcm = 0; num_pcm < NR_PCM; num_pcm++) { ++ if ((codec = kmalloc(sizeof(struct pcm_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct pcm_codec)); ++ codec->private_data = controller; ++ codec->id = num_pcm; ++ ++ if (pcm_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_pcm_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz PCM: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->pcm_codec[num_pcm] = codec; ++ } ++ ++ return num_pcm; ++} ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) { ++ default: ++ case TYPE(AFMT_U8, 1): ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ /*replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u;*/ ++ printk("channel is 2. Line:%d\n",__LINE__); ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ /*replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s;*/ ++ printk("channel is 2. Line:%d\n",__LINE__); ++ break; ++ } ++} ++ ++static void __init attach_jz_pcm(struct jz_pcm_controller_info *controller) ++{ ++ char *name; ++ int adev;//No of Audio device. ++ int err; ++ ++ name = controller->name; ++ /* register /dev/audio */ ++ adev = register_sound_dsp(&jz_pcm_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize PCM codec and register /dev/mixer */ ++ if (jz_pcm_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ printk("DMA_ID_PCM_TX=0x%08x DMA_ID_PCM_RX=0x%08x\n",DMA_ID_PCM_TX ,DMA_ID_PCM_RX); ++ if ((controller->dma1 = jz_request_dma(DMA_ID_PCM_TX, "audio dac", jz_pcm_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_PCM_RX, "audio adc", jz_pcm_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ printk("JzSOC On-Chip PCM controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ err = request_irq(IRQ_PCM, jz_pcm_irq, IRQF_DISABLED, "pcm irq", controller); ++ if (err < 0) ++ printk("can't allocate pcm irq.\n"); ++ controller->dev_audio = adev; ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma2); ++dma1_failed: ++ jz_free_dma(controller->dma1); ++tmp1_failed: ++ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); ++ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++ ++static int __init probe_jz_pcm(struct jz_pcm_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_pcm_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz PCM Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ ++ (*controller)->name = "Jz PCM controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_pcm(struct jz_pcm_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ __pcm_reset(); ++ schedule_timeout(5); ++ __pcm_disable(); ++ __pcm_clk_disable(); ++ __pcm_flush_fifo(); ++ ++ controller->dev_audio = -1; ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); ++ ++ if (adev >= 0) ++ unregister_sound_dsp(controller->dev_audio); ++} ++ ++static int __init init_jz_pcm(void) ++{ ++ int errno; ++ /* 24M OSC ---> CPCCR.ECS ---> PCMCDR.PCMS ---> cpm_pcm_sysclk(X) */ ++ long X = 12000000; //in Hz /* 6.144 MHz <= X <= 264.192 MHz */ ++ ++#if 0 ++ /* pcm_sys_clk is from PLL divsion */ ++ REG_CPM_PCMCDR = 0x8000001b; ++ REG_CPM_CPCCR |= 0x00400000; ++#endif ++ /* pcm_sys_clk is from external clock */ ++ /* reset codec GPF4 */ ++ __gpio_as_output(32 * 5 + 4); ++ __gpio_set_pin(32 * 5 + 4); ++ mdelay(1); ++ ++ __pcm_reset(); ++ schedule_timeout(5); ++ __pcm_clk_disable(); ++ ++ /* set CPM to output cpm-pcm-sysclk ,assume cpm-pcm-sysclk is X Hz */ ++ /* PCMCLK must be 2048000 Hz, it is 256 mutil of PCMSYNC */ ++ //__pcm_set_clk_rate(X, 2048000); ++ __pcm_set_clk_rate(X, 2000000); ++ /* PCMSYNC must be 8000 Hz. 2048000 / 256 = 8000 */ ++ __pcm_set_sync_rate(2048000, 8000); ++ //__pcm_set_sync_rate(2000000, 8000); ++ __pcm_set_sync_len(0); ++ ++ __pcm_flush_fifo(); ++ __pcm_disable_txfifo(); ++ __pcm_disable_rxfifo(); ++ __pcm_set_transmit_trigger(7); ++ __pcm_set_receive_trigger(7); ++ __pcm_omsb_next_sync(); ++ __pcm_imsb_next_sync(); ++ ++#if MODE_is_8 ++ __pcm_set_iss(8);//8bits decided by LINSEL ++ __pcm_set_oss(8); ++#else ++ __pcm_set_iss(16);//16bits decided by LINSEL ++ __pcm_set_oss(16); ++#endif ++ __pcm_set_valid_slot(1); ++ ++ __pcm_disable_tfs_intr(); ++ __pcm_disable_tur_intr(); ++ __pcm_disable_rfs_intr(); ++ __pcm_disable_ror_intr(); ++ ++ __pcm_disable_receive_dma(); ++ __pcm_disable_transmit_dma(); ++ ++ __pcm_last_sample(); ++ __pcm_as_master(); ++ ++ __pcm_enable(); ++ __pcm_clk_enable(); ++ ++ if ((errno = probe_jz_pcm(&pcm_controller)) < 0) ++ return errno; ++ attach_jz_pcm(pcm_controller); ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++ __gpio_clear_pin(32 * 5 + 4); ++ udelay(100); ++ ++ __gpio_set_pin(32 * 5 + 4); ++ dump_pcmc_reg(); ++ ++ return 0; ++} ++ ++ ++static void __exit cleanup_jz_pcm(void) ++{ ++ unload_jz_pcm(pcm_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++} ++ ++module_init(init_jz_pcm); ++module_exit(cleanup_jz_pcm); ++ ++static int drain_adc(struct jz_pcm_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count, i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++static int drain_dac(struct jz_pcm_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count, ele, i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ if ( controller->opened1 == 1 ) { ++ __pcm_enable_transmit_dma(); ++ __pcm_enable_txfifo(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ ++ __pcm_disable_transmit_dma(); ++ __pcm_disable_txfifo(); ++ ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock(&controller->ioctllock); ++ //__pcm_disable(); ++ controller->opened1 = 0; ++ } ++ ++ if ( controller->opened2 == 1 ) { ++ first_record_call = 1; ++ __pcm_enable_receive_dma(); ++ __pcm_enable_rxfifo(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __pcm_disable_receive_dma(); ++ __pcm_disable_rxfifo(); ++ ++ spin_lock(&controller->ioctllock); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock(&controller->ioctllock); ++ //__pcm_disable(); ++ controller->opened2 = 0; ++ } ++ __pcm_disable_tfs_intr(); ++ __pcm_disable_tur_intr(); ++ __pcm_disable_rfs_intr(); ++ __pcm_disable_ror_intr(); ++ ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_pcm_controller_info *controller = pcm_controller; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ REG_DMAC_DMACKE(0) = 0x3f; ++ REG_DMAC_DMACKE(1) = 0x3f; ++ if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ controller->opened1 = 1; ++ //for ioctl ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* set PCMOUT params */ ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ controller->opened2 = 1; ++ first_record_call = 1; ++ //for ioctl ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ /* set PCMIN params */ ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ __pcm_enable(); ++ ++ return 0; ++} ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ audio_buf_info abinfo; ++ int i, bytes, id; ++ count_info cinfo; ++ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; ++ ++ val = 0; ++ bytes = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ { ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ /* set smaple rate */ ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ return put_user(val, (int *)arg); ++ } ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ return 0; ++ ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(4*PAGE_SIZE, (int *)arg); ++ return put_user(jz_audio_fragsize , (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ ++ case SNDCTL_DSP_SETFMT: ++ { ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ /* Select sample format */ ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ return put_user(val, (int *)arg); ++ } ++ ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__); ++ jz_audio_set_channels(controller->dev_audio, val); ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF);//16 least bits ++ ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ //unused fragment amount ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ abinfo.fragsize = jz_audio_fragsize; ++ abinfo.bytes = bytes; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ bytes = 0; ++ //unused fragment amount ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ abinfo.fragsize = jz_audio_fragsize; ++ abinfo.bytes = bytes; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ unsigned long flags; ++ unsigned int mask = 0; ++ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __pcm_enable_receive_dma(); ++ __pcm_enable_rxfifo(); ++ ++ spin_lock(&controller->ioctllock); ++ controller->nextIn = 0; ++ spin_unlock(&controller->ioctllock); ++ ++ spin_lock(&controller->lock); ++ ++#if 0 ++ if (count < 2 * PAGE_SIZE ) ++ copy_count = count * 16 / (jz_audio_channels * jz_audio_format); ++ else ++ copy_count = 2 * PAGE_SIZE ; ++#else ++ if (count <= jz_audio_fragsize) ++ copy_count = count; ++ else ++ copy_count = jz_audio_fragsize; ++#endif ++ ++ left_count = count; ++ spin_unlock(&controller->lock); ++ ++ if (first_record_call) { ++ first_record_call = 0; ++audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp1+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp1+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock(&controller->ioctllock); ++ controller->nextIn += ret; ++ spin_unlock(&controller->ioctllock); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret, left_count, copy_count; ++ unsigned int flags; ++ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ __pcm_enable_transmit_dma(); ++ __pcm_enable_txfifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++#if 0 ++ if (count < 2 * PAGE_SIZE ) ++ copy_count = count; ++ else ++ copy_count = 2 * PAGE_SIZE; ++#else ++ if (count <= jz_audio_fragsize) ++ copy_count = count; ++ else ++ copy_count = jz_audio_fragsize; ++#endif ++ ++ left_count = count; ++ ret = 0; ++ ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++audio_write_back: ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ // all are full ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((unsigned long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); //busy in ++ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); //spare ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count;//all is in byte ++ ++ spin_lock(&controller->ioctllock); ++ controller->nextOut += ret; ++ spin_unlock(&controller->ioctllock); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++static void dump_pcmc_reg(void) ++{ ++ printk("REG_DMAC_DMACKE(0) : 0x%08x\n",REG_DMAC_DMACKE(0)); ++ printk("REG_DMAC_DMACKE(1) : 0x%08x\n",REG_DMAC_DMACKE(1)); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR : 0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_CPM_PCMCDR : 0x%08x\n",REG_CPM_PCMCDR); ++ printk("REG_PCM_CLT : 0x%08x\n",REG_PCM_CTL); ++ printk("REG_PCM_CFG : 0x%08x\n",REG_PCM_CFG); ++ printk("REG_PCM_INTC : 0x%08x\n",REG_PCM_INTC); ++ printk("REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS); ++ printk("REG_PCM_DIV : 0x%08x\n",REG_PCM_DIV); ++} +diff --git a/sound/oss/jzcodec.c b/sound/oss/jzcodec.c +new file mode 100644 +index 0000000..680b1d2 +--- /dev/null ++++ b/sound/oss/jzcodec.c +@@ -0,0 +1,443 @@ ++/* ++ * linux/drivers/sound/jzcodec.c ++ * ++ * JzSOC internal audio driver. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sound_config.h" ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++extern mixer_info info; ++extern _old_mixer_info old_info; ++extern int codec_volue_shift; ++extern hpvol_shift_t hpvol_shift_table[72]; ++extern int abnormal_data_count; ++ ++extern void (*set_codec_mode)(void); ++extern void (*each_time_init_codec)(void); ++extern int (*set_codec_startup_param)(void); ++extern void (*set_codec_volume_table)(void); ++extern void (*set_codec_record)(int mode); ++extern void (*set_codec_replay)(void); ++extern void (*set_codec_replay_record)(int mode); ++extern void (*turn_on_codec)(void); ++extern void (*turn_off_codec)(void); ++extern void (*set_codec_speed)(int rate); ++extern void (*reset_codec)(void); ++extern void (*codec_mixer_old_info_id_name)(void); ++extern void (*codec_mixer_info_id_name)(void); ++extern void (*set_codec_bass)(int val); ++extern void (*set_codec_volume)(int val); ++extern void (*set_codec_mic)(int val); ++extern void (*set_codec_line)(int val); ++extern void (*i2s_resume_codec)(void); ++extern void (*i2s_suspend_codec)(void); ++extern void (*set_codec_direct_mode)(void); ++extern void (*clear_codec_direct_mode)(void); ++ ++static int jzcodec_reg[2]; ++ ++void set_jzcodec_mode(void); ++void each_time_init_jzcodec(void); ++int set_jzcodec_startup_param(void); ++void set_jzcodec_volume_table(void); ++void set_jzcodec_replay(void); ++void set_jzcodec_record(int mode); ++void turn_on_jzcodec(void); ++void turn_off_jzcodec(void); ++void set_jzcodec_speed(int rate); ++void reset_jzcodec(void); ++void jzcodec_mixer_old_info_id_name(void); ++void jzcodec_mixer_info_id_name(void); ++void set_jzcodec_bass(int val); ++void set_jzcodec_volume(int val); ++void set_jzcodec_mic(int val); ++void set_jzcodec_line(int val); ++void in_codec_app1(void); ++void in_codec_app12(void); ++void HP_turn_on(void); ++void HP_turn_off(void); ++void resume_jzcodec(void); ++void suspend_jzcodec(void); ++void set_jzcodec_replay_record(int mode); ++ ++void set_jzcodec_mode(void) ++{ ++ __i2s_internal_codec(); ++ __i2s_as_slave(); ++ __i2s_select_i2s(); ++ __aic_select_i2s(); ++ ++ REG_ICDC_CDCCR1 = 0x001b2303; ++ schedule_timeout(1); ++ REG_ICDC_CDCCR1 = 0x001b2302; ++} ++ ++void each_time_init_jzcodec(void) ++{ ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++} ++ ++int set_jzcodec_startup_param(void) ++{ ++ REG_ICDC_CDCCR1 = 0x001b2300; ++ schedule_timeout(50); ++ REG_ICDC_CDCCR1 = 0x00033300; ++ schedule_timeout(5); ++ REG_ICDC_CDCCR1 = 0x17026300; ++ ++ return 1; ++} ++void set_jzcodec_volume_table(void) ++{ ++ int errno,hpvol_step,sample_shift; ++ ++ codec_volue_shift = 0; ++ hpvol_step = 3; ++ sample_shift = 0; ++ for(errno = 0;errno < 72;errno++) { ++ hpvol_shift_table[errno].hpvol = hpvol_step; ++ hpvol_shift_table[errno].shift = sample_shift; ++ hpvol_step --; ++ if(hpvol_step <= 0) { ++ hpvol_step = 3; ++ sample_shift ++; ++ } ++ } ++} ++ ++void set_jzcodec_replay(void) ++{ ++ in_codec_app1(); ++} ++ ++void set_jzcodec_record(int mode) ++{ ++ switch (mode) { ++ case USE_NONE: ++ case USE_MIC: ++ in_codec_app12(); ++ abnormal_data_count = 0; ++ break; ++ case USE_LINEIN: ++ REG_ICDC_CDCCR1 = 0x27022000;//for linein ++ mdelay(300); ++ break; ++ } ++} ++ ++void set_jzcodec_replay_record(int mode) ++{ ++ long val = 0; ++ REG_ICDC_CDCCR1 = 0x00037302; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x03006000; ++ mdelay(2); ++ ++ switch (mode) { ++ case USE_NONE: ++ case USE_MIC: ++ REG_ICDC_CDCCR1 = 0x17022000;//for mic ++ break; ++ case USE_LINEIN: ++ REG_ICDC_CDCCR1 = 0x27022000;//for linein ++ break; ++ } ++ ++ val = REG_ICDC_CDCCR2; ++ val &= 0x0000ff00; ++ val |= 0x00170030; ++ REG_ICDC_CDCCR2 = val; ++} ++ ++void turn_on_jzcodec(void) ++{ ++ HP_turn_on(); ++} ++ ++void set_jzcodec_direct_mode(void) ++{ ++ long val = 0; ++ REG_ICDC_CDCCR1 = 0x14000000; ++ val &= 0x0000ff00; ++ val |= 0x001f0033; ++ REG_ICDC_CDCCR2 = val; ++ mdelay(300); ++} ++ ++void clear_jzcodec_direct_mode(void) ++{ ++ HP_turn_off(); ++} ++ ++void turn_off_jzcodec(void) ++{ ++ HP_turn_off(); ++} ++ ++void set_jzcodec_speed(int rate) ++{ ++ long codec_speed,speed = 0; ++ switch (rate) { ++ case 8000: ++ speed = 0; ++ break; ++ case 11025: ++ speed = 1; ++ break; ++ case 12000: ++ speed = 2; ++ break; ++ case 16000: ++ speed = 3; ++ break; ++ case 22050: ++ speed = 4; ++ break; ++ case 24000: ++ speed = 5; ++ break; ++ case 32000: ++ speed = 6; ++ break; ++ case 44100: ++ speed = 7; ++ break; ++ case 48000: ++ speed = 8; ++ break; ++ default: ++ break; ++ } ++ ++ codec_speed = REG_ICDC_CDCCR2; ++ codec_speed |= 0x00000f00; ++ ++ speed = speed << 8; ++ speed |= 0xfffff0ff; ++ codec_speed &= speed; ++ REG_ICDC_CDCCR2 = codec_speed; ++} ++ ++void reset_jzcodec(void) ++{ ++ REG_ICDC_CDCCR1 |= 1; ++ mdelay(1); ++ REG_ICDC_CDCCR1 &= 0xfffffffe; ++} ++ ++void jzcodec_mixer_old_info_id_name(void) ++{ ++ strncpy(info.id, "JZCODEC", sizeof(info.id)); ++ strncpy(info.name,"Jz internal codec", sizeof(info.name)); ++} ++ ++void jzcodec_mixer_info_id_name(void) ++{ ++ strncpy(old_info.id, "JZCODEC", sizeof(old_info.id)); ++ strncpy(old_info.name,"Jz internal codec", sizeof(old_info.name)); ++} ++ ++void set_jzcodec_bass(int val) ++{ ++ int bass_gain = 0; ++ if(val < 25) ++ bass_gain = 0; ++ if(val >= 25 && val < 50) ++ bass_gain = 1; ++ if(val >= 50 && val < 75) ++ bass_gain = 2; ++ if(val >= 75 && val <= 100 ) ++ bass_gain = 3; ++ ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (bass_gain << 4)); ++} ++ ++void set_jzcodec_volume(int val) ++{ ++ unsigned int sample_oss; ++ int index,shift_max,vol_scale,vol_step,codec_volume; ++ shift_max = 0; ++ sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ ++ switch(sample_oss) ++ { ++ case 0x0: ++ shift_max = 4; /* 8 bits */ ++ break; ++ case 0x1: ++ shift_max = 10; /* 16 bits */ ++ break; ++ case 0x2: ++ shift_max = 12; /* 18 bits */ ++ break; ++ case 0x3: ++ shift_max = 15; /* 20 bits */ ++ break; ++ case 0x4: ++ shift_max = 19; /* 24 bits */ ++ break; ++ } ++ ++ vol_scale = 3 * (shift_max + 1); ++ vol_step = 100 / vol_scale; ++ ++ for(index = 0;index <= 100;index += vol_step) ++ if( val <= index ) ++ break; ++ ++ if(index == 0) ++ index = vol_step; ++ index = index / vol_step; ++ if(index > vol_scale) ++ index = vol_scale; ++ ++ index = vol_scale - index; ++ codec_volume = hpvol_shift_table[index].hpvol; ++ codec_volue_shift = hpvol_shift_table[index].shift; ++ codec_volume = 3; ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume); ++} ++ ++void set_jzcodec_mic(int val) ++{ ++ long mic_gain; ++ ++ mic_gain = 31 * val /100; ++ REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 | (0x3 << 4)); ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (mic_gain << 16)); ++} ++ ++void set_jzcodec_line(int val) ++{ ++ long line_gain; ++ ++ line_gain = 31 * val /100; ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (line_gain << 16)); ++} ++ ++void HP_turn_on(void) ++{ ++ long val = 0; ++ /* simple and slow anti-pop */ ++ REG_ICDC_CDCCR1 = 0x00037302; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x03006000; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x03002000; ++ ++ val = REG_ICDC_CDCCR2; ++ val &= 0x0000ff00; ++ val |= 0x001f0033; ++ REG_ICDC_CDCCR2 = val; ++} ++ ++void HP_turn_off(void) ++{ ++ mdelay(20); ++ REG_ICDC_CDCCR1 = 0x00033300; ++} ++ ++void in_codec_app1(void) ++{ ++ /* test is OK */ ++ HP_turn_on(); ++} ++ ++void in_codec_app12(void) ++{ ++ REG_ICDC_CDCCR1 = 0x14024300; ++ mdelay(300); ++} ++ ++void resume_jzcodec(void) ++{ ++ REG_ICDC_CDCCR2 = 0x00170800; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x001f2102; ++ mdelay(5); ++ REG_ICDC_CDCCR1 = 0x00033302; ++ mdelay(550); ++ REG_ICDC_CDCCR1 = 0x00033300; ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ REG_ICDC_CDCCR2 = jzcodec_reg[1]; ++} ++ ++void suspend_jzcodec(void) ++{ ++ ++ jzcodec_reg[0] = REG_ICDC_CDCCR1; ++ jzcodec_reg[1] = REG_ICDC_CDCCR2; ++ ++ REG_ICDC_CDCCR1 = 0x001b2302; ++ mdelay(1); ++ REG_ICDC_CDCCR1 = 0x001b2102; ++} ++ ++static int __init init_jzcodec(void) ++{ ++ set_codec_mode = set_jzcodec_mode; ++ each_time_init_codec = each_time_init_jzcodec; ++ ++ set_codec_startup_param = set_jzcodec_startup_param; ++ set_codec_volume_table = set_jzcodec_volume_table; ++ set_codec_record = set_jzcodec_record; ++ set_codec_replay = set_jzcodec_replay; ++ set_codec_replay_record = set_jzcodec_replay_record; ++ turn_on_codec = turn_on_jzcodec; ++ turn_off_codec = turn_off_jzcodec; ++ set_codec_speed = set_jzcodec_speed; ++ reset_codec = reset_jzcodec; ++ codec_mixer_old_info_id_name = jzcodec_mixer_old_info_id_name; ++ codec_mixer_info_id_name = jzcodec_mixer_info_id_name; ++ set_codec_bass = set_jzcodec_bass; ++ set_codec_volume = set_jzcodec_volume; ++ set_codec_mic = set_jzcodec_mic; ++ set_codec_line = set_jzcodec_line; ++ i2s_resume_codec = resume_jzcodec; ++ i2s_suspend_codec = suspend_jzcodec; ++ set_codec_direct_mode = set_jzcodec_direct_mode; ++ clear_codec_direct_mode = clear_jzcodec_direct_mode; ++ ++ return 0; ++} ++ ++ ++static void __exit cleanup_jzcodec(void) ++{ ++ REG_ICDC_CDCCR1 = 0x001b2302; ++ ++} ++ ++module_init(init_jzcodec); ++module_exit(cleanup_jzcodec); +diff --git a/sound/oss/jzdlv.c b/sound/oss/jzdlv.c +new file mode 100644 +index 0000000..772b12f +--- /dev/null ++++ b/sound/oss/jzdlv.c +@@ -0,0 +1,644 @@ ++/* ++ * linux/drivers/sound/jzcodec.c ++ * ++ * JzSOC internal audio driver. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sound_config.h" ++#include "jzdlv.h" ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++extern mixer_info info; ++extern _old_mixer_info old_info; ++extern int codec_volue_shift; ++ ++extern void (*set_codec_mode)(void); ++extern void (*each_time_init_codec)(void); ++extern int (*set_codec_startup_param)(void); ++extern void (*set_codec_record)(void); ++extern void (*set_codec_replay)(void); ++extern void (*set_codec_replay_record)(void); ++extern void (*turn_on_codec)(void); ++extern void (*turn_off_codec)(void); ++extern void (*set_codec_speed)(int rate); ++extern void (*reset_codec)(void); ++extern void (*codec_mixer_old_info_id_name)(void); ++extern void (*codec_mixer_info_id_name)(void); ++extern void (*set_codec_bass)(int val); ++extern void (*set_codec_volume)(int val); ++extern void (*set_codec_mic)(int val); ++extern void (*set_codec_line)(int val); ++extern void (*i2s_resume_codec)(void); ++extern void (*i2s_suspend_codec)(void); ++extern void (*set_codec_direct_mode)(void); ++extern void (*clear_codec_direct_mode)(void); ++ ++ ++void set_dlv_mode(void); ++void each_time_init_jzcodec(void); ++int set_dlv_startup_param(void); ++void set_dlvjzcodec_volume_table(void); ++void set_dlv_replay(void); ++void set_dlv_record(void); ++void set_dlv_speed(int rate); ++void reset_dlv(void); ++void jzcodec_mixer_old_info_id_name(void); ++void jzcodec_mixer_info_id_name(void); ++void set_dlv_volume(int val); ++void set_dlv_mic(int val); ++ ++extern int jz_mic_only; ++int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++#if 0 ++void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++#endif ++ ++void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++void set_dlv_mode(void) ++{ ++ /*REG_CPM_CPCCR &= ~(1 << 31); ++ REG_CPM_CPCCR &= ~(1 << 30);*/ ++ write_codec_file(0, 0xf); ++ ++ REG_AIC_I2SCR = 0x10; ++ __i2s_internal_codec(); ++ __i2s_as_slave(); ++ __i2s_select_i2s(); ++ __aic_select_i2s(); ++ __aic_reset(); ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ ++ /* power on DLV */ ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++} ++void reset_dlv_codec(void) ++{ ++ /* reset DLV codec. from hibernate mode to sleep mode */ ++ write_codec_file(0, 0xf); ++ write_codec_file_bit(6, 0, 0); ++ write_codec_file_bit(6, 0, 1); ++ mdelay(200); ++ //write_codec_file(0, 0xf); ++ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 ++ mdelay(10);//wait for stability ++} ++ ++void each_time_init_dlv(void) ++{ ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __aic_internal_codec(); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++} ++ ++int set_dlv_startup_param(void) ++{ ++ __i2s_disable_transmit_intr(); ++ __i2s_disable_receive_intr(); ++ ++ return 1; ++} ++/* set Audio data replay */ ++void set_audio_data_replay(void) ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++ ++#if 1 /* mask warning */ ++/* set Record MIC input audio without playback */ ++void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* unset Record MIC input audio without playback */ ++void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record LINE input audio without playback */ ++void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record LINE input audio without playback */ ++void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Playback LINE input audio direct only */ ++void set_playback_line_input_audio_direct_only(void) ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Playback LINE input audio direct only */ ++void unset_playback_line_input_audio_direct_only(void) ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio with direct playback */ ++void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio with direct playback */ ++void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record playing audio mixed with MIC input audio */ ++void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record playing audio mixed with MIC input audio */ ++void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 1 ++/* unset Audio data replay */ ++void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++void set_dlv_replay(void) ++{ ++ set_audio_data_replay(); ++} ++ ++void set_dlv_speed(int rate) ++{ ++ int speed = 0, val; ++ speed = 0; ++ switch (rate) { ++ case 8000: ++ speed = 10; ++ break; ++ case 9600: ++ speed = 9; ++ break; ++ case 11025: ++ speed = 8; ++ break; ++ case 12000: ++ speed = 7; ++ break; ++ case 16000: ++ speed = 6; ++ break; ++ case 22050: ++ speed = 5; ++ break; ++ case 24000: ++ speed = 4; ++ break; ++ case 32000: ++ speed = 3; ++ break; ++ case 44100: ++ speed = 2; ++ break; ++ case 48000: ++ speed = 1; ++ break; ++ case 96000: ++ speed = 0; ++ break; ++ default: ++ break; ++ } ++ ++ val = read_codec_file(4); ++ val = (speed << 4) | speed; ++ write_codec_file(4, val); ++} ++ ++void reset_jzcodec(void) ++{ ++ ++} ++ ++void dlv_mixer_old_info_id_name(void) ++{ ++ strncpy(info.id, "JZDLV", sizeof(info.id)); ++ strncpy(info.name,"Jz internal codec dlv on jz4750", sizeof(info.name)); ++} ++ ++void dlv_mixer_info_id_name(void) ++{ ++ strncpy(old_info.id, "JZDLV", sizeof(old_info.id)); ++ strncpy(old_info.name,"Jz internal codec dlv on jz4750", sizeof(old_info.name)); ++} ++ ++void set_dlv_mic(int val) ++{ ++ int cur_vol ; ++ /* set gain */ ++ //write_codec_file_bit(6, 1, 3);//GIM ++ cur_vol = 31 * val / 100; ++ cur_vol |= cur_vol << 4; ++ write_codec_file(19, cur_vol);//GIL,GIR ++} ++ ++void set_dlv_line(int val) ++{ ++ int cur_vol; ++ /* set gain */ ++ cur_vol = 31 * val / 100; ++ cur_vol &= 0x1f; ++ write_codec_file(11, cur_vol);//GO1L ++ write_codec_file(12, cur_vol);//GO1R ++} ++ ++void set_dlv_volume(int val) ++{ ++ unsigned long cur_vol; ++ cur_vol = 31 * (100 - val) / 100; ++ write_codec_file(17, cur_vol | 0xc0); ++ write_codec_file(18, cur_vol); ++} ++ ++static int __init init_dlv(void) ++{ ++ set_codec_mode = set_dlv_mode; ++ each_time_init_codec = each_time_init_dlv; ++ reset_codec = reset_dlv_codec; ++ set_codec_startup_param = set_dlv_startup_param; ++ ++ set_codec_replay = set_dlv_replay; ++ ++ set_codec_speed = set_dlv_speed; ++ ++ codec_mixer_old_info_id_name = dlv_mixer_old_info_id_name; ++ codec_mixer_info_id_name = dlv_mixer_info_id_name; ++ ++ set_codec_volume = set_dlv_volume; ++ set_codec_mic = set_dlv_mic; ++ set_codec_line = set_dlv_line; ++ ++ return 0; ++} ++ ++ ++static void __exit cleanup_dlv(void) ++{ ++ ++} ++ ++module_init(init_dlv); ++module_exit(cleanup_dlv); +diff --git a/sound/oss/jzdlv.h b/sound/oss/jzdlv.h +new file mode 100644 +index 0000000..450e7ea +--- /dev/null ++++ b/sound/oss/jzdlv.h +@@ -0,0 +1,21 @@ ++/* header file for dlv */ ++void write_codec_file(int addr, int val); ++int read_codec_file(int addr); ++void printk_codec_files(void); ++int write_codec_file_bit(int addr, int bitval, int mask_bit); ++void set_audio_data_replay(void); ++void unset_audio_data_replay(void); ++void set_record_mic_input_audio_without_playback(void); ++void unset_record_mic_input_audio_without_playback(void); ++void set_record_line_input_audio_without_playback(void); ++void unset_record_line_input_audio_without_playback(void); ++void set_playback_line_input_audio_direct_only(void); ++void unset_playback_line_input_audio_direct_only(void); ++void set_record_mic_input_audio_with_direct_playback(void); ++void unset_record_mic_input_audio_with_direct_playback(void); ++void set_record_playing_audio_mixed_with_mic_input_audio(void); ++void unset_record_playing_audio_mixed_with_mic_input_audio(void); ++void set_record_mic_input_audio_with_audio_data_replay(void); ++void unset_record_mic_input_audio_with_audio_data_replay(void); ++void set_record_line_input_audio_with_audio_data_replay(void); ++void unset_record_line_input_audio_with_audio_data_replay(void); +diff --git a/sound/oss/os.h b/sound/oss/os.h +index a1a962d..2fb00ab 100644 +--- a/sound/oss/os.h ++++ b/sound/oss/os.h +@@ -9,7 +9,6 @@ + #ifdef __KERNEL__ + #include + #include +-#include + #include + #include + #include +diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig +index d3e786a..e827f85 100644 +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -35,6 +35,8 @@ source "sound/soc/s3c24xx/Kconfig" + source "sound/soc/s6000/Kconfig" + source "sound/soc/sh/Kconfig" + source "sound/soc/txx9/Kconfig" ++source "sound/soc/jz4740/Kconfig" ++source "sound/soc/jz4750/Kconfig" + + # Supported codecs + source "sound/soc/codecs/Kconfig" +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index 6f1e28d..6d72e6d 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -13,3 +13,5 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/ + obj-$(CONFIG_SND_SOC) += s6000/ + obj-$(CONFIG_SND_SOC) += sh/ + obj-$(CONFIG_SND_SOC) += txx9/ ++obj-$(CONFIG_SND_SOC) += jz4740/ ++obj-$(CONFIG_SND_SOC) += jz4750/ +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index bbc97fd..c5dea8c 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -176,3 +176,14 @@ 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..7f53f57 100644 +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -4,6 +4,8 @@ snd-soc-ad73311-objs := ad73311.o + snd-soc-ak4104-objs := ak4104.o + snd-soc-ak4535-objs := ak4535.o + snd-soc-cs4270-objs := cs4270.o ++snd-soc-jzcodec-objs := jzcodec.o ++snd-soc-jzdlv-objs := jzdlv.o + snd-soc-l3-objs := l3.o + snd-soc-pcm3008-objs := pcm3008.o + snd-soc-spdif-objs := spdif_transciever.o +@@ -41,6 +43,8 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o + obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o + obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o + obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o ++obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o ++obj-$(CONFIG_SND_SOC_DLV) += snd-soc-jzdlv.o + obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o + obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o + obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o +diff --git a/sound/soc/codecs/jzcodec.c b/sound/soc/codecs/jzcodec.c +new file mode 100644 +index 0000000..f922845 +--- /dev/null ++++ b/sound/soc/codecs/jzcodec.c +@@ -0,0 +1,729 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../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]); ++ } ++ ++ /* 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]); ++ } ++ ++ 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); ++ ++ /* bit size. codec side */ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ break; ++ } ++ /* sample rate */ ++ reg_val = reg_val & ~(0xf << 8); ++ ++ switch (params_rate(params)) { ++ case 8000: ++ reg_val |= (0x0 << 8); ++ break; ++ case 11025: ++ reg_val |= (0x1 << 8); ++ break; ++ case 12000: ++ reg_val |= (0x2 << 8); ++ break; ++ case 16000: ++ reg_val |= (0x3 << 8); ++ break; ++ case 22050: ++ reg_val |= (0x4 << 8); ++ break; ++ case 24000: ++ reg_val |= (0x5 << 8); ++ break; ++ case 32000: ++ reg_val |= (0x6 << 8); ++ break; ++ case 44100: ++ reg_val |= (0x7 << 8); ++ break; ++ case 48000: ++ reg_val |= (0x8 << 8); ++ break; ++ default: ++ printk(" invalid rate :0x%08x\n",params_rate(params)); ++ } ++ ++ jzcodec_write(codec, ICODEC_2_LOW, reg_val); ++ return 0; ++} ++ ++static int jzcodec_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ 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_PAUSE_RELEASE: ++ break; ++ ++ case SNDRV_PCM_TRIGGER_START: ++ //case SNDRV_PCM_TRIGGER_RESUME: ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ val = 0x7302; ++ jzcodec_write(codec, ICODEC_1_LOW, val); ++ val = 0x0003; ++ jzcodec_write(codec, ICODEC_1_HIGH, val); ++ mdelay(2); ++ val = 0x6000; ++ jzcodec_write(codec, ICODEC_1_LOW, val); ++ val = 0x0300; ++ jzcodec_write(codec, ICODEC_1_HIGH, val); ++ mdelay(2); ++ val = 0x2000; ++ jzcodec_write(codec, ICODEC_1_LOW, val); ++ val = 0x0300; ++ jzcodec_write(codec, ICODEC_1_HIGH, val); ++ } else { ++ val = 0x4300; ++ jzcodec_write(codec, ICODEC_1_LOW, val); ++ val = 0x1402; ++ jzcodec_write(codec, ICODEC_1_HIGH, val); ++ } ++ break; ++ ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ //case SNDRV_PCM_TRIGGER_SUSPEND: ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { ++ val = 0x3300; ++ jzcodec_write(codec, ICODEC_1_LOW, val); ++ val = 0x0003; ++ jzcodec_write(codec, ICODEC_1_HIGH, val); ++ } else { ++ val = 0x3300; ++ jzcodec_write(codec, ICODEC_1_LOW, val); ++ val = 0x0003; ++ jzcodec_write(codec, ICODEC_1_HIGH, val); ++ } ++ break; ++ ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int jzcodec_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ /*struct snd_soc_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_codec_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_codec_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_codec_dai *codec_dai, ++ unsigned int fmt) ++{ ++ /* struct snd_soc_codec *codec = codec_dai->codec; */ ++ ++ /* set master/slave audio interface. codec side */ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBM_CFM: ++ /* set master mode for codec */ ++ break; ++ case SND_SOC_DAIFMT_CBS_CFS: ++ /* set slave mode for codec */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* interface format . set some parameter for codec side */ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ /* set I2S mode for codec */ ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ /* set right J mode */ ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ /* set left J mode */ ++ break; ++ case SND_SOC_DAIFMT_DSP_A: ++ /* set dsp A mode */ ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ /* set dsp B mode */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* clock inversion. codec side */ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* jzcodec_write(codec, 0, val); */ ++ return 0; ++} ++ ++static int jzcodec_dapm_event(struct snd_soc_codec *codec, int event) ++{ ++/* u16 reg_val; */ ++ ++ switch (event) { ++ case SNDRV_CTL_POWER_D0: /* full On */ ++ /* vref/mid, osc on, dac unmute */ ++ /* u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); */ ++ /* jzcodec_write(codec, 0, val); */ ++ break; ++ case SNDRV_CTL_POWER_D1: /* partial On */ ++ case SNDRV_CTL_POWER_D2: /* partial On */ ++ break; ++ case SNDRV_CTL_POWER_D3hot: /* Off, with power */ ++ /* everything off except vref/vmid, */ ++ /*reg_val = 0x0800; ++ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x0017; ++ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ mdelay(2); ++ reg_val = 0x2102; ++ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x001f; ++ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ mdelay(2); ++ reg_val = 0x3302; ++ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x0003; ++ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); ++ REG_ICDC_CDCCR1 = jzcodec_reg[0];*/ ++ break; ++ case SNDRV_CTL_POWER_D3cold: /* Off, without power */ ++ /* everything off, dac mute, inactive */ ++ /*reg_val = 0x2302; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x001b; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); ++ mdelay(1); ++ reg_val = 0x2102; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x001b; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);*/ ++ break; ++ } ++ codec->dapm_state = event; ++ return 0; ++} ++ ++#define JZCODEC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ ++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ ++ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ ++ SNDRV_PCM_RATE_48000) ++ ++#define JZCODEC_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE) ++ ++struct snd_soc_codec_dai jzcodec_dai = { ++ .name = "JZCODEC", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = JZCODEC_RATES, ++ .formats = JZCODEC_FORMATS,}, ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = JZCODEC_RATES, ++ .formats = JZCODEC_FORMATS,}, ++ .ops = { ++ .trigger = jzcodec_pcm_trigger, ++ .prepare = jzcodec_pcm_prepare, ++ .hw_params = jzcodec_hw_params, ++ .shutdown = jzcodec_shutdown, ++ }, ++ .dai_ops = { ++ .digital_mute = jzcodec_mute, ++ .set_sysclk = jzcodec_set_dai_sysclk, ++ .set_fmt = jzcodec_set_dai_fmt, ++ } ++}; ++EXPORT_SYMBOL_GPL(jzcodec_dai); ++ ++#ifdef CONFIG_PM ++static u16 jzcodec_reg_pm[JZCODEC_CACHEREGNUM]; ++static int jzcodec_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ struct snd_soc_codec *codec = socdev->codec; ++ ++ jzcodec_reg_pm[ICODEC_1_LOW] = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); ++ jzcodec_reg_pm[ICODEC_1_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_1_HIGH); ++ jzcodec_reg_pm[ICODEC_2_LOW] = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); ++ jzcodec_reg_pm[ICODEC_2_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH); ++ ++ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold); ++ return 0; ++} ++ ++static int jzcodec_resume(struct platform_device *pdev) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ struct snd_soc_codec *codec = socdev->codec; ++ u16 reg_val; ++ ++ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot); ++ reg_val = jzcodec_reg_pm[ICODEC_1_LOW]; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = jzcodec_reg_pm[ICODEC_1_HIGH]; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); ++ reg_val = jzcodec_reg_pm[ICODEC_2_LOW]; ++ jzcodec_write(codec, ICODEC_2_LOW, reg_val); ++ reg_val = jzcodec_reg_pm[ICODEC_2_HIGH]; ++ jzcodec_write(codec, ICODEC_2_HIGH, reg_val); ++ ++ jzcodec_dapm_event(codec, codec->suspend_dapm_state); ++ return 0; ++} ++#else ++#define jzcodec_suspend NULL ++#define jzcodec_resume NULL ++#endif ++/* ++ * initialise the JZCODEC driver ++ * register the mixer and dsp interfaces with the kernel ++ */ ++static int jzcodec_init(struct snd_soc_device *socdev) ++{ ++ struct snd_soc_codec *codec = socdev->codec; ++ int reg, ret = 0; ++ u16 reg_val; ++ ++ for (reg = 0; reg < JZCODEC_CACHEREGNUM / 2; reg++) { ++ switch (reg) { ++ case 0: ++ jzcodec_reg[reg] = REG_ICDC_CDCCR1; ++ jzcodec_reg_LH[ICODEC_1_LOW] = jzcodec_reg[reg] & 0xffff; ++ jzcodec_reg_LH[ICODEC_1_HIGH] = (jzcodec_reg[reg] & 0xffff0000) >> 16; ++ break; ++ case 1: ++ jzcodec_reg[reg] = REG_ICDC_CDCCR2; ++ jzcodec_reg_LH[ICODEC_2_LOW] = jzcodec_reg[reg] & 0xffff; ++ jzcodec_reg_LH[ICODEC_2_HIGH] = (jzcodec_reg[reg] & 0xffff0000) >> 16; ++ break; ++ } ++ } ++ ++ codec->name = "JZCODEC"; ++ codec->owner = THIS_MODULE; ++ codec->read = jzcodec_read_reg_cache; ++ codec->write = jzcodec_write; ++ codec->dapm_event = jzcodec_dapm_event; ++ codec->dai = &jzcodec_dai; ++ codec->num_dai = 1; ++ codec->reg_cache_size = sizeof(jzcodec_reg_LH); ++ codec->reg_cache = kmemdup(jzcodec_reg_LH, sizeof(jzcodec_reg_LH), GFP_KERNEL); ++ if (codec->reg_cache == NULL) ++ return -ENOMEM; ++ ++ jzcodec_reset(codec); ++ /* register pcms */ ++ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); ++ if (ret < 0) { ++ printk(KERN_ERR "jzcodec: failed to create pcms\n"); ++ goto pcm_err; ++ } ++ ++ /* power on device */ ++ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot); ++ ++ /* clear suspend bit of jz4740 internal codec */ ++ reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); ++ reg_val = reg_val & ~(0x2); ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ /* set vol bits */ ++ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); ++ reg_val = reg_val | 0x3; ++ jzcodec_write(codec, ICODEC_2_LOW, reg_val); ++ /* set line in capture gain bits */ ++ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH); ++ reg_val = reg_val | 0x1f; ++ jzcodec_write(codec, ICODEC_2_HIGH, reg_val); ++ /* set mic boost gain bits */ ++ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); ++ reg_val = reg_val | (0x3 << 4); ++ jzcodec_write(codec, ICODEC_2_LOW, reg_val); ++ mdelay(5); ++ reg_val = 0x3300; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x0003; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); ++ jzcodec_add_controls(codec); ++ jzcodec_add_widgets(codec); ++ ++ ret = snd_soc_register_card(socdev); ++ if (ret < 0) { ++ printk(KERN_ERR "jzcodec: failed to register card\n"); ++ goto card_err; ++ } ++ return ret; ++ ++card_err: ++ snd_soc_free_pcms(socdev); ++ snd_soc_dapm_free(socdev); ++pcm_err: ++ kfree(codec->reg_cache); ++ return ret; ++} ++ ++static struct snd_soc_device *jzcodec_socdev; ++ ++static int write_codec_reg(u16 * add, char * name, int reg) ++{ ++ switch (reg) { ++ case 0: ++ case 1: ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ break; ++ case 2: ++ case 3: ++ REG_ICDC_CDCCR2 = jzcodec_reg[1]; ++ break; ++ } ++ return 0; ++} ++ ++static int jzcodec_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ struct snd_soc_codec *codec; ++ struct jzcodec_priv *jzcodec; ++ int ret = 0; ++ ++ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); ++ if (codec == NULL) ++ return -ENOMEM; ++ ++ jzcodec = kzalloc(sizeof(struct jzcodec_priv), GFP_KERNEL); ++ if (jzcodec == NULL) { ++ kfree(codec); ++ return -ENOMEM; ++ } ++ ++ codec->private_data = jzcodec; ++ socdev->codec = codec; ++ mutex_init(&codec->mutex); ++ INIT_LIST_HEAD(&codec->dapm_widgets); ++ INIT_LIST_HEAD(&codec->dapm_paths); ++ ++ jzcodec_socdev = socdev; ++ ++ /* Add other interfaces here ,no I2C connection */ ++ codec->hw_write = (hw_write_t)write_codec_reg; ++ ret = jzcodec_init(jzcodec_socdev); ++ ++ if (ret < 0) { ++ codec = jzcodec_socdev->codec; ++ err("failed to initialise jzcodec\n"); ++ kfree(codec); ++ } ++ ++ return ret; ++} ++ ++/* power down chip */ ++static int jzcodec_remove(struct platform_device *pdev) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ struct snd_soc_codec *codec = socdev->codec; ++ ++ if (codec->control_data) ++ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold); ++ ++ snd_soc_free_pcms(socdev); ++ snd_soc_dapm_free(socdev); ++ kfree(codec->private_data); ++ kfree(codec); ++ ++ return 0; ++} ++ ++struct snd_soc_codec_device soc_codec_dev_jzcodec = { ++ .probe = jzcodec_probe, ++ .remove = jzcodec_remove, ++ .suspend = jzcodec_suspend, ++ .resume = jzcodec_resume, ++}; ++ ++EXPORT_SYMBOL_GPL(soc_codec_dev_jzcodec); ++ ++MODULE_DESCRIPTION("ASoC JZCODEC driver"); ++MODULE_AUTHOR("Richard"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/codecs/jzcodec.h b/sound/soc/codecs/jzcodec.h +new file mode 100644 +index 0000000..7e4dedf +--- /dev/null ++++ b/sound/soc/codecs/jzcodec.h +@@ -0,0 +1,22 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _ICODEC_H ++#define _ICODEC_H ++ ++/* jzcodec register space */ ++#define ICODEC_1_LOW 0x00 /* bit0 -- bit15 in CDCCR1 */ ++#define ICODEC_1_HIGH 0x01 /* bit16 -- bit31 in CDCCR1 */ ++#define ICODEC_2_LOW 0x02 /* bit0 -- bit16 in CDCCR2 */ ++#define ICODEC_2_HIGH 0x03 /* bit16 -- bit31 in CDCCR2 */ ++ ++#define JZCODEC_CACHEREGNUM 4 ++#define JZCODEC_SYSCLK 0 ++ ++extern struct snd_soc_codec_dai jzcodec_dai; ++extern struct snd_soc_codec_device soc_codec_dev_jzcodec; ++ ++#endif +diff --git a/sound/soc/codecs/jzdlv.c b/sound/soc/codecs/jzdlv.c +new file mode 100644 +index 0000000..2ed2b28 +--- /dev/null ++++ b/sound/soc/codecs/jzdlv.c +@@ -0,0 +1,970 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../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; ++} ++ ++/* set Audio data replay */ ++void set_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x20);// only CCMC ++ mdelay(10); ++ ++ /* DAC path */ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ mdelay(100); ++ write_codec_file_bit(1, 0, 5);//DAC_MUTE->0 ++} ++ ++/* unset Audio data replay */ ++void unset_audio_data_replay(void) ++{ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ mdelay(200); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++ ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++} ++ ++/* set Record MIC input audio without playback */ ++static void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ write_codec_file_bit(1, 1, 2); ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio without playback */ ++static void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++} ++ ++#if 0 ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ // have hp short circuit ++ write_codec_file(8, 0x3f);//mask all interrupt ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++#else ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 1 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ /*if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies;*/ ++ ++ write_codec_file(9, file_9); ++ /*if (file_9 & 0xf) ++ wake_up(&pop_wait_queue);*/ ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++static int jzdlv_reset(struct snd_soc_codec *codec) ++{ ++ /* reset DLV codec. from hibernate mode to sleep mode */ ++ write_codec_file(0, 0xf); ++ write_codec_file_bit(6, 0, 0); ++ write_codec_file_bit(6, 0, 1); ++ mdelay(200); ++ //write_codec_file(0, 0xf); ++ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 ++ mdelay(10);//wait for stability ++ ++ return 0; ++} ++ ++ ++#if 0 ++static int jzdlv_sync(struct snd_soc_codec *codec) ++{ ++ u16 *cache = codec->reg_cache; ++ int i, r = 0; ++ ++ for (i = 0; i < JZDLV_CACHEREGNUM; i++) ++ r |= jzdlv_write(codec, i, cache[i]); ++ ++ return r; ++}; ++#endif ++ ++static const struct snd_kcontrol_new jzdlv_snd_controls[] = { ++ ++ //SOC_DOUBLE_R("Master Playback Volume", 1, 1, 0, 3, 0), ++ SOC_DOUBLE_R("Master Playback Volume", DLV_CGR8, DLV_CGR9, 0, 31, 0), ++ //SOC_DOUBLE_R("MICBG", ICODEC_2_LOW, ICODEC_2_LOW, 4, 3, 0), ++ //SOC_DOUBLE_R("Line", 2, 2, 0, 31, 0), ++ SOC_DOUBLE_R("Line", DLV_CGR10, DLV_CGR10, 0, 31, 0), ++}; ++ ++/* add non dapm controls */ ++static int jzdlv_add_controls(struct snd_soc_codec *codec) ++{ ++ int err, i; ++ ++ for (i = 0; i < ARRAY_SIZE(jzdlv_snd_controls); i++) { ++ if ((err = snd_ctl_add(codec->card, ++ snd_soc_cnew(&jzdlv_snd_controls[i], codec, NULL))) < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = { ++ SND_SOC_DAPM_OUTPUT("LOUT"), ++ SND_SOC_DAPM_OUTPUT("LHPOUT"), ++ SND_SOC_DAPM_OUTPUT("ROUT"), ++ SND_SOC_DAPM_OUTPUT("RHPOUT"), ++ SND_SOC_DAPM_INPUT("MICIN"), ++ SND_SOC_DAPM_INPUT("RLINEIN"), ++ SND_SOC_DAPM_INPUT("LLINEIN"), ++}; ++ ++static const 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 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) ++{ ++ int i,cnt; ++ ++ cnt = ARRAY_SIZE(jzdlv_dapm_widgets); ++ for(i = 0; i < ARRAY_SIZE(jzdlv_dapm_widgets); i++) { ++ snd_soc_dapm_new_control(codec, &jzdlv_dapm_widgets[i]); ++ } ++ ++ /* 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]); ++ } ++ ++ 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_PAUSE_RELEASE: ++ break; ++ case SNDRV_PCM_TRIGGER_START: ++ //case SNDRV_PCM_TRIGGER_RESUME: ++ ++ init_codec(); ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ set_audio_data_replay(); ++ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++ } else { ++ set_record_mic_input_audio_without_playback(); ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++ write_codec_file_bit(5, 1, 7); ++ } ++ ++ break; ++ ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ //case SNDRV_PCM_TRIGGER_SUSPEND: ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ unset_audio_data_replay(); ++ } else { ++ unset_record_mic_input_audio_without_playback(); ++ } ++ break; ++ ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int jzdlv_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ /*struct snd_soc_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_codec_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_codec_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_codec_dai *codec_dai, ++ unsigned int fmt) ++{ ++ /* struct snd_soc_codec *codec = codec_dai->codec; */ ++ ++ /* set master/slave audio interface. codec side */ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBM_CFM: ++ /* set master mode for codec */ ++ break; ++ case SND_SOC_DAIFMT_CBS_CFS: ++ /* set slave mode for codec */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* interface format . set some parameter for codec side */ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ /* set I2S mode for codec */ ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ /* set right J mode */ ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ /* set left J mode */ ++ break; ++ case SND_SOC_DAIFMT_DSP_A: ++ /* set dsp A mode */ ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ /* set dsp B mode */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* clock inversion. codec side */ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* jzcodec_write(codec, 0, val); */ ++ return 0; ++} ++ ++static int jzdlv_dapm_event(struct snd_soc_codec *codec, int event) ++{ ++/* u16 reg_val; */ ++ ++ switch (event) { ++ case SNDRV_CTL_POWER_D0: /* full On */ ++ /* vref/mid, osc on, dac unmute */ ++ /* u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); */ ++ /* jzcodec_write(codec, 0, val); */ ++ break; ++ case SNDRV_CTL_POWER_D1: /* partial On */ ++ case SNDRV_CTL_POWER_D2: /* partial On */ ++ break; ++ case SNDRV_CTL_POWER_D3hot: /* Off, with power */ ++ /* everything off except vref/vmid, */ ++ /*reg_val = 0x0800; ++ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x0017; ++ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ mdelay(2); ++ reg_val = 0x2102; ++ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x001f; ++ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ mdelay(2); ++ reg_val = 0x3302; ++ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x0003; ++ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); ++ REG_ICDC_CDCCR1 = jzcodec_reg[0];*/ ++ break; ++ case SNDRV_CTL_POWER_D3cold: /* Off, without power */ ++ /* everything off, dac mute, inactive */ ++ /*reg_val = 0x2302; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x001b; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); ++ mdelay(1); ++ reg_val = 0x2102; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = 0x001b; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);*/ ++ break; ++ } ++ //codec->dapm_state = event; ++ return 0; ++} ++ ++#define JZDLV_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ ++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ ++ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ ++ SNDRV_PCM_RATE_48000) ++ ++#define JZDLV_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE) ++ ++struct snd_soc_codec_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 u16 jzdlv_reg_pm[JZDLV_CACHEREGNUM]; ++static int jzdlv_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ //struct snd_soc_codec *codec = socdev->codec; ++#if 0 ++ jzcodec_reg_pm[ICODEC_1_LOW] = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); ++ jzcodec_reg_pm[ICODEC_1_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_1_HIGH); ++ jzcodec_reg_pm[ICODEC_2_LOW] = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); ++ jzcodec_reg_pm[ICODEC_2_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH); ++ ++ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold); ++#endif ++ return 0; ++} ++ ++static int jzdlv_resume(struct platform_device *pdev) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ //struct snd_soc_codec *codec = socdev->codec; ++ //u16 reg_val; ++#if 0 ++ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot); ++ reg_val = jzcodec_reg_pm[ICODEC_1_LOW]; ++ jzcodec_write(codec, ICODEC_1_LOW, reg_val); ++ reg_val = jzcodec_reg_pm[ICODEC_1_HIGH]; ++ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); ++ reg_val = jzcodec_reg_pm[ICODEC_2_LOW]; ++ jzcodec_write(codec, ICODEC_2_LOW, reg_val); ++ reg_val = jzcodec_reg_pm[ICODEC_2_HIGH]; ++ jzcodec_write(codec, ICODEC_2_HIGH, reg_val); ++ ++ jzcodec_dapm_event(codec, codec->suspend_dapm_state); ++#endif ++ return 0; ++} ++#else ++#define jzdlv_suspend NULL ++#define jzdlv_resume NULL ++#endif ++/* ++ * initialise the JZDLV driver ++ * register the mixer and dsp interfaces with the kernel ++ */ ++static int jzdlv_init(struct snd_soc_device *socdev) ++{ ++ struct snd_soc_codec *codec = socdev->codec; ++ int ret = 0, retval; ++ ++ /*REG_CPM_CPCCR &= ~(1 << 31); ++ REG_CPM_CPCCR &= ~(1 << 30);*/ ++ write_codec_file(0, 0xf); ++ ++ REG_AIC_I2SCR = 0x10; ++ __i2s_internal_codec(); ++ __i2s_as_slave(); ++ __i2s_select_i2s(); ++ __aic_select_i2s(); ++ __aic_reset(); ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ ++ /* power on DLV */ ++ write_codec_file(8, 0x3f); ++ write_codec_file(9, 0xff); ++ mdelay(10); ++ ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++ ++ codec->name = "JZDLV"; ++ codec->owner = THIS_MODULE; ++ codec->read = jzdlv_read_reg_cache; ++ codec->write = jzdlv_write; ++ //codec->dapm_event = jzdlv_dapm_event; ++ codec->dai = &jzdlv_dai; ++ codec->num_dai = 1; ++ codec->reg_cache_size = sizeof(jzdlv_reg); ++ codec->reg_cache = kmemdup(jzdlv_reg, sizeof(jzdlv_reg), GFP_KERNEL); ++ if (codec->reg_cache == NULL) ++ return -ENOMEM; ++ ++ jzdlv_reset(codec); ++ /* register pcms */ ++ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); ++ if (ret < 0) { ++ printk(KERN_ERR "jzdlv: failed to create pcms\n"); ++ goto pcm_err; ++ } ++ ++ /* power on device */ ++ jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3hot); ++ ++ jzdlv_add_controls(codec); ++ jzdlv_add_widgets(codec); ++ ++ ret = snd_soc_register_card(socdev); ++ if (ret < 0) { ++ printk(KERN_ERR "jzcodec: failed to register card\n"); ++ goto card_err; ++ } ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ /* power on DLV */ ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++ ++ printk_codec_files(); ++ return ret; ++ ++card_err: ++ snd_soc_free_pcms(socdev); ++ snd_soc_dapm_free(socdev); ++pcm_err: ++ kfree(codec->reg_cache); ++ return ret; ++} ++ ++static struct snd_soc_device *jzdlv_socdev; ++ ++static int write_codec_reg(u16 * add, char * name, int reg) ++{ ++ write_codec_file(reg, *add); ++ ++ return 0; ++} ++ ++static int jzdlv_probe(struct platform_device *pdev) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ struct snd_soc_codec *codec; ++ struct jzdlv_priv *jzdlv; ++ int ret = 0; ++ ++ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); ++ if (codec == NULL) ++ return -ENOMEM; ++ ++ jzdlv = kzalloc(sizeof(struct jzdlv_priv), GFP_KERNEL); ++ if (jzdlv == NULL) { ++ kfree(codec); ++ return -ENOMEM; ++ } ++ ++ codec->private_data = jzdlv; ++ socdev->codec = codec; ++ mutex_init(&codec->mutex); ++ INIT_LIST_HEAD(&codec->dapm_widgets); ++ INIT_LIST_HEAD(&codec->dapm_paths); ++ ++ jzdlv_socdev = socdev; ++ ++ /* Add other interfaces here ,no I2C connection */ ++ codec->hw_write = (hw_write_t)write_codec_reg; ++ //codec->hw_read = (hw_read_t)read_codec_reg; ++ ret = jzdlv_init(jzdlv_socdev); ++ ++ if (ret < 0) { ++ codec = jzdlv_socdev->codec; ++ err("failed to initialise jzdlv\n"); ++ kfree(codec); ++ } ++ ++ return ret; ++} ++ ++/* power down chip */ ++static int jzdlv_remove(struct platform_device *pdev) ++{ ++ struct snd_soc_device *socdev = platform_get_drvdata(pdev); ++ struct snd_soc_codec *codec = socdev->codec; ++ ++ if (codec->control_data) ++ jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3cold); ++ ++ snd_soc_free_pcms(socdev); ++ snd_soc_dapm_free(socdev); ++ kfree(codec->private_data); ++ kfree(codec); ++ ++ return 0; ++} ++ ++struct snd_soc_codec_device soc_codec_dev_jzdlv = { ++ .probe = jzdlv_probe, ++ .remove = jzdlv_remove, ++ .suspend = jzdlv_suspend, ++ .resume = jzdlv_resume, ++}; ++ ++EXPORT_SYMBOL_GPL(soc_codec_dev_jzdlv); ++ ++MODULE_DESCRIPTION("ASoC JZDLV driver"); ++MODULE_AUTHOR("Richard"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/codecs/jzdlv.h b/sound/soc/codecs/jzdlv.h +new file mode 100644 +index 0000000..a901a69 +--- /dev/null ++++ b/sound/soc/codecs/jzdlv.h +@@ -0,0 +1,50 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _DLV_H ++#define _DLV_H ++ ++/* jzdlv register space */ ++ ++#define DLV_AICR 0x00 ++#define DLV_CR1 0x01 ++#define DLV_CR2 0x02 ++#define DLV_CCR1 0x03 ++#define DLV_CCR2 0x04 ++#define DLV_PMR1 0x05 ++#define DLV_PMR2 0x06 ++#define DLV_CRR 0x07 ++#define DLV_ICR 0x08 ++#define DLV_IFR 0x09 ++#define DLV_CGR1 0x0a ++#define DLV_CGR2 0x0b ++#define DLV_CGR3 0x0c ++#define DLV_CGR4 0x0d ++#define DLV_CGR5 0x0e ++#define DLV_CGR6 0x0f ++#define DLV_CGR7 0x10 ++#define DLV_CGR8 0x11 ++#define DLV_CGR9 0x12 ++#define DLV_CGR10 0x13 ++#define DLV_TR1 0x14 ++#define DLV_TR2 0x15 ++#define DLV_CR3 0x16 ++#define DLV_AGC1 0x17 ++#define DLV_AGC2 0x18 ++#define DLV_AGC3 0x19 ++#define DLV_AGC4 0x1a ++#define DLV_AGC5 0x1b ++ ++#define JZDLV_CACHEREGNUM (DLV_AGC5+1) ++#define JZDLV_SYSCLK 0 ++ ++int read_codec_file(int addr); ++int write_codec_file_bit(int addr, int bitval, int mask_bit); ++void write_codec_file(int addr, int val); ++extern struct snd_soc_codec_dai jzdlv_dai; ++extern struct snd_soc_codec_device soc_codec_dev_jzdlv; ++ ++#endif +diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig +new file mode 100644 +index 0000000..0bfbffe +--- /dev/null ++++ b/sound/soc/jz4740/Kconfig +@@ -0,0 +1,34 @@ ++config SND_JZ4740_SOC ++ tristate "SoC Audio for Ingenic jz4740 chip" ++ depends on (JZ4740_PAVO || JZ4725_DIPPER || JZ4720_VIRGO) && SND_SOC ++ help ++ Say Y or M if you want to add support for codecs attached to ++ the Jz4740 AC97, I2S or SSP interface. You will also need ++ to select the audio interfaces to support below. ++ ++config SND_JZ4740_SOC_PAVO ++ tristate "SoC Audio support for Ingenic Jz4740 PAVO board" ++ depends on SND_JZ4740_SOC ++ help ++ Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4740 PAVO board. ++ ++config SND_JZ4740_AC97 ++ tristate "select AC97 protocol and AC97 codec pcm core support" ++ depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO ++ select SND_AC97_CODEC ++ help ++ Say Y if you want to add AC97 protocol support for pcm core. ++ ++config SND_JZ4740_SOC_AC97 ++ tristate "SoC Audio (AC97 protocol) for Ingenic jz4740 chip" ++ depends on SND_JZ4740_SOC && SND_JZ4740_AC97 && SND_JZ4740_SOC_PAVO ++ select AC97_BUS ++ select SND_SOC_AC97_BUS ++ help ++ Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4740 PAVO board. ++ ++config SND_JZ4740_SOC_I2S ++ depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO ++ tristate "SoC Audio (I2S protocol) for Ingenic jz4740 chip" ++ help ++ Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4740 PAVO board. +diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile +new file mode 100644 +index 0000000..4c79b13 +--- /dev/null ++++ b/sound/soc/jz4740/Makefile +@@ -0,0 +1,15 @@ ++# ++# Jz4740 Platform Support ++# ++snd-soc-jz4740-objs := jz4740-pcm.o ++snd-soc-jz4740-ac97-objs := jz4740-ac97.o ++snd-soc-jz4740-i2s-objs := jz4740-i2s.o ++ ++obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o ++obj-$(CONFIG_SND_JZ4740_SOC_AC97) += snd-soc-jz4740-ac97.o ++obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o ++ ++# Jz4740 Machine Support ++snd-soc-pavo-objs := pavo.o ++ ++obj-$(CONFIG_SND_JZ4740_SOC_PAVO) += snd-soc-pavo.o +diff --git a/sound/soc/jz4740/jz4740-ac97.c b/sound/soc/jz4740/jz4740-ac97.c +new file mode 100644 +index 0000000..84da470 +--- /dev/null ++++ b/sound/soc/jz4740/jz4740-ac97.c +@@ -0,0 +1,261 @@ ++/* ++ * linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip. ++ * ++ * Author: Richard ++ * Created: Dec 02, 2007 ++ * Copyright: Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "jz4740-pcm.h" ++#include "jz4740-ac97.h" ++ ++static DEFINE_MUTEX(car_mutex); ++static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); ++static volatile long gsr_bits; ++ ++static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97, ++ unsigned short reg) ++{ ++ unsigned short val = -1; ++ volatile u32 *reg_addr; ++ ++ mutex_lock(&car_mutex); ++ ++out: mutex_unlock(&car_mutex); ++ return val; ++} ++ ++static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg, ++ unsigned short val) ++{ ++ volatile u32 *reg_addr; ++ ++ mutex_lock(&car_mutex); ++ ++ mutex_unlock(&car_mutex); ++} ++ ++static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97) ++{ ++ gsr_bits = 0; ++} ++ ++static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97) ++{ ++} ++ ++static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id) ++{ ++ long status; ++ return IRQ_NONE; ++} ++ ++struct snd_ac97_bus_ops soc_ac97_ops = { ++ .read = jz4740_ac97_read, ++ .write = jz4740_ac97_write, ++ .warm_reset = jz4740_ac97_warm_reset, ++ .reset = jz4740_ac97_cold_reset, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = { ++ .name = "AC97 PCM Stereo out", ++ .dev_addr = __PREG(PCDR), ++ .drcmr = &DRCMRTXPCDR, ++ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | ++ DCMD_BURST32 | DCMD_WIDTH4, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = { ++ .name = "AC97 PCM Stereo in", ++ .dev_addr = __PREG(PCDR), ++ .drcmr = &DRCMRRXPCDR, ++ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | ++ DCMD_BURST32 | DCMD_WIDTH4, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = { ++ .name = "AC97 Aux PCM (Slot 5) Mono out", ++ .dev_addr = __PREG(MODR), ++ .drcmr = &DRCMRTXMODR, ++ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | ++ DCMD_BURST16 | DCMD_WIDTH2, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = { ++ .name = "AC97 Aux PCM (Slot 5) Mono in", ++ .dev_addr = __PREG(MODR), ++ .drcmr = &DRCMRRXMODR, ++ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | ++ DCMD_BURST16 | DCMD_WIDTH2, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = { ++ .name = "AC97 Mic PCM (Slot 6) Mono in", ++ .dev_addr = __PREG(MCDR), ++ .drcmr = &DRCMRRXMCDR, ++ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | ++ DCMD_BURST16 | DCMD_WIDTH2, ++}; ++ ++#ifdef CONFIG_PM ++static int jz4740_ac97_suspend(struct platform_device *pdev, ++ struct snd_soc_cpu_dai *dai) ++{ ++ return 0; ++} ++ ++static int jz4740_ac97_resume(struct platform_device *pdev, ++ struct snd_soc_cpu_dai *dai) ++{ ++ return 0; ++} ++ ++#else ++#define jz4740_ac97_suspend NULL ++#define jz4740_ac97_resume NULL ++#endif ++ ++static int jz4740_ac97_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ return 0; ++} ++ ++static void jz4740_ac97_remove(struct platform_device *pdev) ++{ ++} ++ ++static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out; ++ else ++ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in; ++ ++ return 0; ++} ++ ++static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out; ++ else ++ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in; ++ ++ return 0; ++} ++ ++static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ return -ENODEV; ++ else ++ cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in; ++ ++ return 0; ++} ++ ++#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ ++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_48000) ++ ++struct snd_soc_cpu_dai jz4740_ac97_dai[] = { ++{ ++ .name = "jz4740-ac97", ++ .id = 0, ++ .type = SND_SOC_DAI_AC97, ++ .probe = jz4740_ac97_probe, ++ .remove = jz4740_ac97_remove, ++ .suspend = jz4740_ac97_suspend, ++ .resume = jz4740_ac97_resume, ++ .playback = { ++ .stream_name = "AC97 Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .capture = { ++ .stream_name = "AC97 Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .hw_params = jz4740_ac97_hw_params,}, ++}, ++{ ++ .name = "jz4740-ac97-aux", ++ .id = 1, ++ .type = SND_SOC_DAI_AC97, ++ .playback = { ++ .stream_name = "AC97 Aux Playback", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .capture = { ++ .stream_name = "AC97 Aux Capture", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .hw_params = jz4740_ac97_hw_aux_params,}, ++}, ++{ ++ .name = "jz4740-ac97-mic", ++ .id = 2, ++ .type = SND_SOC_DAI_AC97, ++ .capture = { ++ .stream_name = "AC97 Mic Capture", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .hw_params = jz4740_ac97_hw_mic_params,}, ++}, ++}; ++ ++EXPORT_SYMBOL_GPL(jz4740_ac97_dai); ++EXPORT_SYMBOL_GPL(soc_ac97_ops); ++ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4740/jz4740-ac97.h b/sound/soc/jz4740/jz4740-ac97.h +new file mode 100644 +index 0000000..e80e2a0 +--- /dev/null ++++ b/sound/soc/jz4740/jz4740-ac97.h +@@ -0,0 +1,21 @@ ++/* ++ * linux/sound/soc/jz4740/jz4740-ac97.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _JZ4740_AC97_H ++#define _JZ4740_AC97_H ++ ++#define JZ4740_DAI_AC97_HIFI 0 ++#define JZ4740_DAI_AC97_AUX 1 ++#define JZ4740_DAI_AC97_MIC 2 ++ ++extern struct snd_soc_cpu_dai jz4740_ac97_dai[3]; ++ ++/* platform data */ ++extern struct snd_ac97_bus_ops jz4740_ac97_ops; ++ ++#endif +diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c +new file mode 100644 +index 0000000..de40d4d +--- /dev/null ++++ b/sound/soc/jz4740/jz4740-i2s.c +@@ -0,0 +1,296 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz4740-pcm.h" ++#include "jz4740-i2s.h" ++ ++static struct jz4740_dma_client jz4740_dma_client_out = { ++ .name = "I2S PCM Stereo out" ++}; ++ ++static struct jz4740_dma_client jz4740_dma_client_in = { ++ .name = "I2S PCM Stereo in" ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = { ++ .client = &jz4740_dma_client_out, ++ .channel = DMA_ID_AIC_TX, ++ .dma_addr = AIC_DR, ++ .dma_size = 2, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = { ++ .client = &jz4740_dma_client_in, ++ .channel = DMA_ID_AIC_RX, ++ .dma_addr = AIC_DR, ++ .dma_size = 2, ++}; ++ ++static int jz4740_i2s_startup(struct snd_pcm_substream *substream) ++{ ++ /*struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/ ++ ++ return 0; ++} ++ ++static int jz4740_i2s_set_dai_fmt(struct snd_soc_cpu_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_cpu_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; ++ if (channels == 1) ++ __aic_enable_mono2stereo(); ++ else ++ __aic_disable_mono2stereo(); ++ } else ++ cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in; ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S8: ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ break; ++ case SNDRV_PCM_FORMAT_S16_LE: ++ /* playback sample:16 bits, burst:16 bytes */ ++ __i2s_set_transmit_trigger(4); ++ /* capture sample:16 bits, burst:16 bytes */ ++ __i2s_set_receive_trigger(3); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ 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_cpu_dai *dai) ++{ ++ if (!dai->active) ++ return 0; ++ ++ return 0; ++} ++ ++static int jz4740_i2s_resume(struct platform_device *pdev, ++ struct snd_soc_cpu_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_cpu_dai jz4740_i2s_dai = { ++ .name = "jz4740-i2s", ++ .id = 0, ++ .type = SND_SOC_DAI_I2S, ++ .probe = jz4740_i2s_probe, ++ .suspend = jz4740_i2s_suspend, ++ .resume = jz4740_i2s_resume, ++ .playback = { ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = JZ4740_I2S_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = JZ4740_I2S_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .startup = jz4740_i2s_startup, ++ .shutdown = jz4740_i2s_shutdown, ++ .trigger = jz4740_i2s_trigger, ++ .hw_params = jz4740_i2s_hw_params,}, ++ .dai_ops = { ++ .set_fmt = jz4740_i2s_set_dai_fmt, ++ .set_sysclk = jz4740_i2s_set_dai_sysclk, ++ }, ++}; ++ ++EXPORT_SYMBOL_GPL(jz4740_i2s_dai); ++ ++/* Module information */ ++MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn"); ++MODULE_DESCRIPTION("jz4740 I2S SoC Interface"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h +new file mode 100644 +index 0000000..f4cbcec +--- /dev/null ++++ b/sound/soc/jz4740/jz4740-i2s.h +@@ -0,0 +1,18 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _JZ4740_I2S_H ++#define _JZ4740_I2S_H ++ ++/* jz4740 DAI ID's */ ++#define JZ4740_DAI_I2S 0 ++ ++/* I2S clock */ ++#define JZ4740_I2S_SYSCLK 0 ++ ++extern struct snd_soc_cpu_dai jz4740_i2s_dai; ++ ++#endif +diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c +new file mode 100644 +index 0000000..516dd1f +--- /dev/null ++++ b/sound/soc/jz4740/jz4740-pcm.c +@@ -0,0 +1,689 @@ ++/* ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "jz4740-pcm.h" ++ ++static long sum_bytes = 0; ++static int first_transfer = 0; ++static int printk_flag = 0; ++static int tran_bit = 0; ++#ifdef CONFIG_SND_OSSEMUL ++static int hw_params_cnt = 0; ++#endif ++ ++struct jz4740_dma_buf_aic { ++ struct jz4740_dma_buf_aic *next; ++ int size; /* buffer size in bytes */ ++ dma_addr_t data; /* start of DMA data */ ++ dma_addr_t ptr; /* where the DMA got to [1] */ ++ void *id; /* client's id */ ++}; ++ ++struct jz4740_runtime_data { ++ spinlock_t lock; ++ int state; ++ int aic_dma_flag; /* start dma transfer or not */ ++ unsigned int dma_loaded; ++ unsigned int dma_limit; ++ unsigned int dma_period; ++ dma_addr_t dma_start; ++ dma_addr_t dma_pos; ++ dma_addr_t dma_end; ++ struct jz4740_pcm_dma_params *params; ++ ++ dma_addr_t user_cur_addr; /* user current write buffer start address */ ++ unsigned int user_cur_len; /* user current write buffer length */ ++ ++ /* buffer list and information */ ++ struct jz4740_dma_buf_aic *curr; /* current dma buffer */ ++ struct jz4740_dma_buf_aic *next; /* next buffer to load */ ++ struct jz4740_dma_buf_aic *end; /* end of queue */ ++ ++}; ++ ++/* identify hardware playback capabilities */ ++static const struct snd_pcm_hardware jz4740_pcm_hardware = { ++ .info = SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_U16_LE | ++ SNDRV_PCM_FMTBIT_U8 | ++ SNDRV_PCM_FMTBIT_S8, ++ .rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/, ++ .rate_min = 8000, ++ .rate_min = 48000, ++ .channels_min = 1,//2 ++ .channels_max = 2, ++ .buffer_bytes_max = 128 * 1024,//16 * 1024 ++ .period_bytes_min = PAGE_SIZE, ++ .period_bytes_max = PAGE_SIZE * 2, ++ .periods_min = 2, ++ .periods_max = 128,//16, ++ .fifo_size = 32, ++}; ++ ++/* jz4740__dma_buf_enqueue ++ * ++ * queue an given buffer for dma transfer. ++ * ++ * data the physical address of the buffer data ++ * size the size of the buffer in bytes ++ * ++*/ ++static int jz4740_dma_buf_enqueue(struct jz4740_runtime_data *prtd, dma_addr_t data, int size) ++{ ++ struct jz4740_dma_buf_aic *aic_buf; ++ ++ aic_buf = kzalloc(sizeof(struct jz4740_dma_buf_aic), GFP_KERNEL); ++ if (aic_buf == NULL) { ++ printk("aic buffer allocate failed,no memory!\n"); ++ return -ENOMEM; ++ } ++ aic_buf->next = NULL; ++ aic_buf->data = aic_buf->ptr = data; ++ aic_buf->size = size; ++ if( prtd->curr == NULL) { ++ prtd->curr = aic_buf; ++ prtd->end = aic_buf; ++ prtd->next = NULL; ++ } else { ++ if (prtd->end == NULL) ++ printk("prtd->end is NULL\n"); ++ prtd->end->next = aic_buf; ++ prtd->end = aic_buf; ++ } ++ ++ /* if necessary, update the next buffer field */ ++ if (prtd->next == NULL) ++ prtd->next = aic_buf; ++ ++ return 0; ++} ++ ++ ++void audio_start_dma(struct jz4740_runtime_data *prtd, int mode) ++{ ++ unsigned long flags; ++ struct jz4740_dma_buf_aic *aic_buf; ++ int channel; ++ ++ 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; ++ ++ 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_codec_dai *dai, ++ struct snd_pcm *pcm) ++{ ++ int ret = 0; ++ ++ if (!card->dev->dma_mask) ++ card->dev->dma_mask = &jz4740_pcm_dmamask; ++ if (!card->dev->coherent_dma_mask) ++ card->dev->coherent_dma_mask = DMA_32BIT_MASK; ++ ++ if (dai->playback.channels_min) { ++ ret = jz4740_pcm_preallocate_dma_buffer(pcm, ++ SNDRV_PCM_STREAM_PLAYBACK); ++ if (ret) ++ goto out; ++ } ++ ++ if (dai->capture.channels_min) { ++ ret = jz4740_pcm_preallocate_dma_buffer(pcm, ++ SNDRV_PCM_STREAM_CAPTURE); ++ if (ret) ++ goto out; ++ } ++ out: ++ ++ return ret; ++} ++ ++struct snd_soc_platform jz4740_soc_platform = { ++ .name = "jz4740-audio", ++ .pcm_ops = &jz4740_pcm_ops, ++ .pcm_new = jz4740_pcm_new, ++ .pcm_free = jz4740_pcm_free_dma_buffers, ++}; ++ ++EXPORT_SYMBOL_GPL(jz4740_soc_platform); ++ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h +new file mode 100644 +index 0000000..68ea842 +--- /dev/null ++++ b/sound/soc/jz4740/jz4740-pcm.h +@@ -0,0 +1,33 @@ ++/* ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _JZ4740_PCM_H ++#define _JZ4740_PCM_H ++ ++#include ++ ++#define ST_RUNNING (1<<0) ++#define ST_OPENED (1<<1) ++ ++#define AIC_START_DMA (1<<0) ++#define AIC_END_DMA (1<<1) ++ ++struct jz4740_dma_client { ++ char *name; ++}; ++ ++struct jz4740_pcm_dma_params { ++ struct jz4740_dma_client *client; /* stream identifier */ ++ int channel; /* Channel ID */ ++ dma_addr_t dma_addr; ++ int dma_size; /* Size of the DMA transfer */ ++}; ++ ++/* platform data */ ++extern struct snd_soc_platform jz4740_soc_platform; ++ ++#endif +diff --git a/sound/soc/jz4740/pavo.c b/sound/soc/jz4740/pavo.c +new file mode 100644 +index 0000000..9d6056e +--- /dev/null ++++ b/sound/soc/jz4740/pavo.c +@@ -0,0 +1,360 @@ ++/* ++ * pavo.c -- SoC audio for PAVO ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/jzcodec.h" ++#include "jz4740-pcm.h" ++#include "jz4740-i2s.h" ++ ++#define PAVO_HP 0 ++#define PAVO_MIC 1 ++#define PAVO_LINE 2 ++#define PAVO_HEADSET 3 ++#define PAVO_HP_OFF 4 ++#define PAVO_SPK_ON 0 ++#define PAVO_SPK_OFF 1 ++ ++ /* audio clock in Hz - rounded from 12.235MHz */ ++#define PAVO_AUDIO_CLOCK 12288000 ++ ++static int pavo_jack_func; ++static int pavo_spk_func; ++ ++unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) ++{ ++ unsigned short gpio_bit = 0; ++ ++ return gpio_bit; ++} ++ ++unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) ++{ ++ unsigned short gpio_bit = 0; ++ ++ return gpio_bit; ++} ++ ++static void pavo_ext_control(struct snd_soc_codec *codec) ++{ ++ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; ++ ++ /* set up jack connection */ ++ switch (pavo_jack_func) { ++ case PAVO_HP: ++ hp = 1; ++ /* set = unmute headphone */ ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ case PAVO_MIC: ++ mic = 1; ++ /* reset = mute headphone */ ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ case PAVO_LINE: ++ line = 1; ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ case PAVO_HEADSET: ++ hs = 1; ++ mic = 1; ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ } ++ ++ if (pavo_spk_func == PAVO_SPK_ON) ++ spk = 1; ++ ++ /* 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); ++} ++ ++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_codec_dai *codec_dai = rtd->dai->codec_dai; ++ struct snd_soc_cpu_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; ++ ++ snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); ++ snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); ++ ++ /* 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]); ++ } ++ ++ /* 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); ++ return 0; ++} ++ ++/* pavo digital audio interface glue - connects codec <--> CPU */ ++static struct snd_soc_dai_link pavo_dai = { ++ .name = "JZCODEC", ++ .stream_name = "JZCODEC", ++ .cpu_dai = &jz4740_i2s_dai, ++ .codec_dai = &jzcodec_dai, ++ .init = pavo_jzcodec_init, ++ .ops = &pavo_ops, ++}; ++ ++/* pavo audio machine driver */ ++static struct snd_soc_machine snd_soc_machine_pavo = { ++ .name = "Pavo", ++ .dai_link = &pavo_dai, ++ .num_links = 1, ++}; ++ ++/* pavo audio subsystem */ ++static struct snd_soc_device pavo_snd_devdata = { ++ .machine = &snd_soc_machine_pavo, ++ .platform = &jz4740_soc_platform, ++ .codec_dev = &soc_codec_dev_jzcodec, ++ //.codec_data ++}; ++ ++static struct platform_device *pavo_snd_device; ++ ++static int __init pavo_init(void) ++{ ++ int ret; ++ ++ pavo_snd_device = platform_device_alloc("soc-audio", -1); ++ ++ if (!pavo_snd_device) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pavo_snd_device, &pavo_snd_devdata); ++ pavo_snd_devdata.dev = &pavo_snd_device->dev; ++ ret = platform_device_add(pavo_snd_device); ++ ++ if (ret) ++ platform_device_put(pavo_snd_device); ++ ++ return ret; ++} ++ ++static void __exit pavo_exit(void) ++{ ++ platform_device_unregister(pavo_snd_device); ++} ++ ++module_init(pavo_init); ++module_exit(pavo_exit); ++ ++/* Module information */ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("ALSA SoC Pavo"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4750/Kconfig b/sound/soc/jz4750/Kconfig +new file mode 100644 +index 0000000..7cf9b16 +--- /dev/null ++++ b/sound/soc/jz4750/Kconfig +@@ -0,0 +1,34 @@ ++config SND_JZ4750_SOC ++ tristate "SoC Audio for Ingenic jz4750 chip" ++ depends on (JZ4750_APUS || JZ4750_FUWA) && SND_SOC ++ help ++ Say Y or M if you want to add support for codecs attached to ++ the Jz4750 AC97, I2S or SSP interface. You will also need ++ to select the audio interfaces to support below. ++ ++config SND_JZ4750_SOC_APUS ++ tristate "SoC Audio support for Ingenic Jz4750 APUS board" ++ depends on SND_JZ4750_SOC ++ help ++ Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4750 APUS board. ++ ++config SND_JZ4750_AC97 ++ tristate "select AC97 protocol and AC97 codec pcm core support" ++ depends on SND_JZ4750_SOC && SND_JZ4750_SOC_APUS ++ select SND_AC97_CODEC ++ help ++ Say Y if you want to add AC97 protocol support for pcm core. ++ ++config SND_JZ4750_SOC_AC97 ++ tristate "SoC Audio (AC97 protocol) for Ingenic jz4750 chip" ++ depends on SND_JZ4750_SOC && SND_JZ4750_AC97 && SND_JZ4750_SOC_APUS ++ select AC97_BUS ++ select SND_SOC_AC97_BUS ++ help ++ Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4750 APUS board. ++ ++config SND_JZ4750_SOC_I2S ++ depends on SND_JZ4750_SOC && SND_JZ4750_SOC_APUS ++ tristate "SoC Audio (I2S protocol) for Ingenic jz4750 chip" ++ help ++ Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4750 APUS board. +diff --git a/sound/soc/jz4750/Makefile b/sound/soc/jz4750/Makefile +new file mode 100644 +index 0000000..ba5cbfa +--- /dev/null ++++ b/sound/soc/jz4750/Makefile +@@ -0,0 +1,15 @@ ++# ++# Jz4750 Platform Support ++# ++snd-soc-jz4750-objs := jz4750-pcm.o ++snd-soc-jz4750-ac97-objs := jz4750-ac97.o ++snd-soc-jz4750-i2s-objs := jz4750-i2s.o ++ ++obj-$(CONFIG_SND_JZ4750_SOC) += snd-soc-jz4750.o ++obj-$(CONFIG_SND_JZ4750_SOC_AC97) += snd-soc-jz4750-ac97.o ++obj-$(CONFIG_SND_JZ4750_SOC_I2S) += snd-soc-jz4750-i2s.o ++ ++# Jz4750 Machine Support ++snd-soc-apus-objs := apus.o ++ ++obj-$(CONFIG_SND_JZ4750_SOC_APUS) += snd-soc-apus.o +diff --git a/sound/soc/jz4750/apus.c b/sound/soc/jz4750/apus.c +new file mode 100644 +index 0000000..def2104 +--- /dev/null ++++ b/sound/soc/jz4750/apus.c +@@ -0,0 +1,357 @@ ++/* ++ * apus.c -- SoC audio for APUS ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/jzdlv.h" ++#include "jz4750-pcm.h" ++#include "jz4750-i2s.h" ++ ++#define APUS_HP 0 ++#define APUS_MIC 1 ++#define APUS_LINE 2 ++#define APUS_HEADSET 3 ++#define APUS_HP_OFF 4 ++#define APUS_SPK_ON 0 ++#define APUS_SPK_OFF 1 ++ ++static int apus_jack_func; ++static int apus_spk_func; ++ ++unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) ++{ ++ unsigned short gpio_bit = 0; ++ ++ return gpio_bit; ++} ++ ++unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) ++{ ++ unsigned short gpio_bit = 0; ++ ++ return gpio_bit; ++} ++ ++static void apus_ext_control(struct snd_soc_codec *codec) ++{ ++ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; ++ ++ /* set up jack connection */ ++ switch (apus_jack_func) { ++ case APUS_HP: ++ hp = 1; ++ /* set = unmute headphone */ ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ case APUS_MIC: ++ mic = 1; ++ /* reset = mute headphone */ ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ case APUS_LINE: ++ line = 1; ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ case APUS_HEADSET: ++ hs = 1; ++ mic = 1; ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); ++ break; ++ } ++ ++ if (apus_spk_func == APUS_SPK_ON) ++ spk = 1; ++ ++ /* set the enpoints to their new connetion states */ ++ 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); ++} ++ ++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 void apus_shutdown(struct snd_pcm_substream *substream) ++{ ++ /*struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec *codec = rtd->socdev->codec;*/ ++ ++ return; ++} ++ ++static int apus_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; ++ struct snd_soc_cpu_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, 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); ++ 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, 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, int event) ++{ ++ if (SND_SOC_DAPM_EVENT_ON(event)) ++ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); ++ ; ++ else ++ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); ++ ; ++ ++ return 0; ++} ++ ++/* apus machine dapm widgets */ ++static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = { ++SND_SOC_DAPM_HP("Headphone Jack", NULL), ++SND_SOC_DAPM_MIC("Mic Jack",apus_mic_event), ++SND_SOC_DAPM_SPK("Ext Spk", apus_amp_event), ++SND_SOC_DAPM_LINE("Line Jack", NULL), ++SND_SOC_DAPM_HP("Headset Jack", NULL), ++}; ++ ++/* apus machine audio map (connections to the codec pins) */ ++static const 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 apus_enum[] = { ++ SOC_ENUM_SINGLE_EXT(5, jack_function), ++ SOC_ENUM_SINGLE_EXT(2, spk_function), ++}; ++ ++static const struct snd_kcontrol_new jzdlv_apus_controls[] = { ++ SOC_ENUM_EXT("Jack Function", apus_enum[0], apus_get_jack, ++ apus_set_jack), ++ SOC_ENUM_EXT("Speaker Function", apus_enum[1], apus_get_spk, ++ apus_set_spk), ++}; ++ ++/* ++ * Apus for a jzdlv as connected on jz4750 Device ++ */ ++static int apus_jzdlv_init(struct snd_soc_codec *codec) ++{ ++ int i, err; ++ ++ snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); ++ snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); ++ ++ /* 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 */ ++ for(i = 0; i < ARRAY_SIZE(jzdlv_dapm_widgets); i++) { ++ snd_soc_dapm_new_control(codec, &jzdlv_dapm_widgets[i]); ++ } ++ ++ /* Set up apus 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); ++ return 0; ++} ++ ++/* apus digital audio interface glue - connects codec <--> CPU */ ++static struct snd_soc_dai_link apus_dai = { ++ .name = "JZDLV", ++ .stream_name = "JZDLV", ++ .cpu_dai = &jz4750_i2s_dai, ++ .codec_dai = &jzdlv_dai, ++ .init = apus_jzdlv_init, ++ .ops = &apus_ops, ++}; ++ ++/* apus audio machine driver */ ++static struct snd_soc_machine snd_soc_machine_apus = { ++ .name = "Apus", ++ .dai_link = &apus_dai, ++ .num_links = 1, ++}; ++ ++/* apus audio subsystem */ ++static struct snd_soc_device apus_snd_devdata = { ++ .machine = &snd_soc_machine_apus, ++ .platform = &jz4750_soc_platform, ++ .codec_dev = &soc_codec_dev_jzdlv, ++ //.codec_data ++}; ++ ++static struct platform_device *apus_snd_device; ++ ++static int __init apus_init(void) ++{ ++ int ret; ++ ++ apus_snd_device = platform_device_alloc("soc-audio", -1); ++ ++ if (!apus_snd_device) ++ return -ENOMEM; ++ ++ platform_set_drvdata(apus_snd_device, &apus_snd_devdata); ++ apus_snd_devdata.dev = &apus_snd_device->dev; ++ ret = platform_device_add(apus_snd_device); ++ ++ if (ret) ++ platform_device_put(apus_snd_device); ++ ++ return ret; ++} ++ ++static void __exit apus_exit(void) ++{ ++ platform_device_unregister(apus_snd_device); ++} ++ ++module_init(apus_init); ++module_exit(apus_exit); ++ ++/* Module information */ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("ALSA SoC Apus"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4750/jz4750-ac97.c b/sound/soc/jz4750/jz4750-ac97.c +new file mode 100644 +index 0000000..84da470 +--- /dev/null ++++ b/sound/soc/jz4750/jz4750-ac97.c +@@ -0,0 +1,261 @@ ++/* ++ * linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip. ++ * ++ * Author: Richard ++ * Created: Dec 02, 2007 ++ * Copyright: Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "jz4740-pcm.h" ++#include "jz4740-ac97.h" ++ ++static DEFINE_MUTEX(car_mutex); ++static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); ++static volatile long gsr_bits; ++ ++static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97, ++ unsigned short reg) ++{ ++ unsigned short val = -1; ++ volatile u32 *reg_addr; ++ ++ mutex_lock(&car_mutex); ++ ++out: mutex_unlock(&car_mutex); ++ return val; ++} ++ ++static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg, ++ unsigned short val) ++{ ++ volatile u32 *reg_addr; ++ ++ mutex_lock(&car_mutex); ++ ++ mutex_unlock(&car_mutex); ++} ++ ++static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97) ++{ ++ gsr_bits = 0; ++} ++ ++static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97) ++{ ++} ++ ++static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id) ++{ ++ long status; ++ return IRQ_NONE; ++} ++ ++struct snd_ac97_bus_ops soc_ac97_ops = { ++ .read = jz4740_ac97_read, ++ .write = jz4740_ac97_write, ++ .warm_reset = jz4740_ac97_warm_reset, ++ .reset = jz4740_ac97_cold_reset, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = { ++ .name = "AC97 PCM Stereo out", ++ .dev_addr = __PREG(PCDR), ++ .drcmr = &DRCMRTXPCDR, ++ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | ++ DCMD_BURST32 | DCMD_WIDTH4, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = { ++ .name = "AC97 PCM Stereo in", ++ .dev_addr = __PREG(PCDR), ++ .drcmr = &DRCMRRXPCDR, ++ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | ++ DCMD_BURST32 | DCMD_WIDTH4, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = { ++ .name = "AC97 Aux PCM (Slot 5) Mono out", ++ .dev_addr = __PREG(MODR), ++ .drcmr = &DRCMRTXMODR, ++ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | ++ DCMD_BURST16 | DCMD_WIDTH2, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = { ++ .name = "AC97 Aux PCM (Slot 5) Mono in", ++ .dev_addr = __PREG(MODR), ++ .drcmr = &DRCMRRXMODR, ++ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | ++ DCMD_BURST16 | DCMD_WIDTH2, ++}; ++ ++static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = { ++ .name = "AC97 Mic PCM (Slot 6) Mono in", ++ .dev_addr = __PREG(MCDR), ++ .drcmr = &DRCMRRXMCDR, ++ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | ++ DCMD_BURST16 | DCMD_WIDTH2, ++}; ++ ++#ifdef CONFIG_PM ++static int jz4740_ac97_suspend(struct platform_device *pdev, ++ struct snd_soc_cpu_dai *dai) ++{ ++ return 0; ++} ++ ++static int jz4740_ac97_resume(struct platform_device *pdev, ++ struct snd_soc_cpu_dai *dai) ++{ ++ return 0; ++} ++ ++#else ++#define jz4740_ac97_suspend NULL ++#define jz4740_ac97_resume NULL ++#endif ++ ++static int jz4740_ac97_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ return 0; ++} ++ ++static void jz4740_ac97_remove(struct platform_device *pdev) ++{ ++} ++ ++static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out; ++ else ++ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in; ++ ++ return 0; ++} ++ ++static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out; ++ else ++ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in; ++ ++ return 0; ++} ++ ++static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ return -ENODEV; ++ else ++ cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in; ++ ++ return 0; ++} ++ ++#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ ++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_48000) ++ ++struct snd_soc_cpu_dai jz4740_ac97_dai[] = { ++{ ++ .name = "jz4740-ac97", ++ .id = 0, ++ .type = SND_SOC_DAI_AC97, ++ .probe = jz4740_ac97_probe, ++ .remove = jz4740_ac97_remove, ++ .suspend = jz4740_ac97_suspend, ++ .resume = jz4740_ac97_resume, ++ .playback = { ++ .stream_name = "AC97 Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .capture = { ++ .stream_name = "AC97 Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .hw_params = jz4740_ac97_hw_params,}, ++}, ++{ ++ .name = "jz4740-ac97-aux", ++ .id = 1, ++ .type = SND_SOC_DAI_AC97, ++ .playback = { ++ .stream_name = "AC97 Aux Playback", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .capture = { ++ .stream_name = "AC97 Aux Capture", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .hw_params = jz4740_ac97_hw_aux_params,}, ++}, ++{ ++ .name = "jz4740-ac97-mic", ++ .id = 2, ++ .type = SND_SOC_DAI_AC97, ++ .capture = { ++ .stream_name = "AC97 Mic Capture", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = JZ4740_AC97_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .hw_params = jz4740_ac97_hw_mic_params,}, ++}, ++}; ++ ++EXPORT_SYMBOL_GPL(jz4740_ac97_dai); ++EXPORT_SYMBOL_GPL(soc_ac97_ops); ++ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4750/jz4750-ac97.h b/sound/soc/jz4750/jz4750-ac97.h +new file mode 100644 +index 0000000..cd116e9 +--- /dev/null ++++ b/sound/soc/jz4750/jz4750-ac97.h +@@ -0,0 +1,21 @@ ++/* ++ * linux/sound/soc/jz4750/jz4750-ac97.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _JZ4750_AC97_H ++#define _JZ4750_AC97_H ++ ++#define JZ4750_DAI_AC97_HIFI 0 ++#define JZ4750_DAI_AC97_AUX 1 ++#define JZ4750_DAI_AC97_MIC 2 ++ ++extern struct snd_soc_cpu_dai jz4750_ac97_dai[3]; ++ ++/* platform data */ ++extern struct snd_ac97_bus_ops jz4750_ac97_ops; ++ ++#endif +diff --git a/sound/soc/jz4750/jz4750-i2s.c b/sound/soc/jz4750/jz4750-i2s.c +new file mode 100644 +index 0000000..887443e +--- /dev/null ++++ b/sound/soc/jz4750/jz4750-i2s.c +@@ -0,0 +1,311 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz4750-pcm.h" ++#include "jz4750-i2s.h" ++#include "../codecs/jzdlv.h" ++ ++static struct jz4750_dma_client jz4750_dma_client_out = { ++ .name = "I2S PCM Stereo out" ++}; ++ ++static struct jz4750_dma_client jz4750_dma_client_in = { ++ .name = "I2S PCM Stereo in" ++}; ++ ++static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_out = { ++ .client = &jz4750_dma_client_out, ++ .channel = DMA_ID_AIC_TX, ++ .dma_addr = AIC_DR, ++ .dma_size = 2, ++}; ++ ++static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_in = { ++ .client = &jz4750_dma_client_in, ++ .channel = DMA_ID_AIC_RX, ++ .dma_addr = AIC_DR, ++ .dma_size = 2, ++}; ++ ++static int jz4750_i2s_startup(struct snd_pcm_substream *substream) ++{ ++ /*struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/ ++ ++ return 0; ++} ++ ++static int jz4750_i2s_set_dai_fmt(struct snd_soc_cpu_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_cpu_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; ++ ++ 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_cpu_dai *dai) ++{ ++ if (!dai->active) ++ return 0; ++ ++ return 0; ++} ++ ++static int jz4750_i2s_resume(struct platform_device *pdev, ++ struct snd_soc_cpu_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_cpu_dai jz4750_i2s_dai = { ++ .name = "jz4750-i2s", ++ .id = 0, ++ .type = SND_SOC_DAI_I2S, ++ .probe = jz4750_i2s_probe, ++ .suspend = jz4750_i2s_suspend, ++ .resume = jz4750_i2s_resume, ++ .playback = { ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = JZ4750_I2S_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, ++ .capture = { ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = JZ4750_I2S_RATES, ++ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, ++ .ops = { ++ .startup = jz4750_i2s_startup, ++ .shutdown = jz4750_i2s_shutdown, ++ .trigger = jz4750_i2s_trigger, ++ .hw_params = jz4750_i2s_hw_params,}, ++ .dai_ops = { ++ .set_fmt = jz4750_i2s_set_dai_fmt, ++ .set_sysclk = jz4750_i2s_set_dai_sysclk, ++ }, ++}; ++ ++EXPORT_SYMBOL_GPL(jz4750_i2s_dai); ++ ++/* Module information */ ++MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn"); ++MODULE_DESCRIPTION("jz4750 I2S SoC Interface"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4750/jz4750-i2s.h b/sound/soc/jz4750/jz4750-i2s.h +new file mode 100644 +index 0000000..c227cae +--- /dev/null ++++ b/sound/soc/jz4750/jz4750-i2s.h +@@ -0,0 +1,18 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _JZ4750_I2S_H ++#define _JZ4750_I2S_H ++ ++/* jz4750 DAI ID's */ ++#define JZ4750_DAI_I2S 0 ++ ++/* I2S clock */ ++#define JZ4750_I2S_SYSCLK 0 ++ ++extern struct snd_soc_cpu_dai jz4750_i2s_dai; ++ ++#endif +diff --git a/sound/soc/jz4750/jz4750-pcm.c b/sound/soc/jz4750/jz4750-pcm.c +new file mode 100644 +index 0000000..e50d1c8 +--- /dev/null ++++ b/sound/soc/jz4750/jz4750-pcm.c +@@ -0,0 +1,689 @@ ++/* ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "jz4750-pcm.h" ++ ++static long sum_bytes = 0; ++static int first_transfer = 0; ++static int printk_flag = 0; ++static int tran_bit = 0; ++#ifdef CONFIG_SND_OSSEMUL ++static int hw_params_cnt = 0; ++#endif ++ ++struct jz4750_dma_buf_aic { ++ struct jz4750_dma_buf_aic *next; ++ int size; /* buffer size in bytes */ ++ dma_addr_t data; /* start of DMA data */ ++ dma_addr_t ptr; /* where the DMA got to [1] */ ++ void *id; /* client's id */ ++}; ++ ++struct jz4750_runtime_data { ++ spinlock_t lock; ++ int state; ++ int aic_dma_flag; /* start dma transfer or not */ ++ unsigned int dma_loaded; ++ unsigned int dma_limit; ++ unsigned int dma_period; ++ dma_addr_t dma_start; ++ dma_addr_t dma_pos; ++ dma_addr_t dma_end; ++ struct jz4750_pcm_dma_params *params; ++ ++ dma_addr_t user_cur_addr; /* user current write buffer start address */ ++ unsigned int user_cur_len; /* user current write buffer length */ ++ ++ /* buffer list and information */ ++ struct jz4750_dma_buf_aic *curr; /* current dma buffer */ ++ struct jz4750_dma_buf_aic *next; /* next buffer to load */ ++ struct jz4750_dma_buf_aic *end; /* end of queue */ ++ ++}; ++ ++/* identify hardware playback capabilities */ ++static const struct snd_pcm_hardware jz4750_pcm_hardware = { ++ .info = SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_PAUSE | ++ SNDRV_PCM_INFO_RESUME | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_U16_LE | ++ SNDRV_PCM_FMTBIT_U8 | ++ SNDRV_PCM_FMTBIT_S8, ++ .rates = SNDRV_PCM_RATE_8000_96000/*0x3fe*/, ++ .rate_min = 8000, ++ .rate_max = 96000, ++ .channels_min = 1,//2 ++ .channels_max = 2, ++ .buffer_bytes_max = 128 * 1024,//16 * 1024 ++ .period_bytes_min = PAGE_SIZE, ++ .period_bytes_max = PAGE_SIZE * 2, ++ .periods_min = 2, ++ .periods_max = 128,//16, ++ .fifo_size = 32, ++}; ++ ++/* jz4750__dma_buf_enqueue ++ * ++ * queue an given buffer for dma transfer. ++ * ++ * data the physical address of the buffer data ++ * size the size of the buffer in bytes ++ * ++*/ ++static int jz4750_dma_buf_enqueue(struct jz4750_runtime_data *prtd, dma_addr_t data, int size) ++{ ++ struct jz4750_dma_buf_aic *aic_buf; ++ ++ aic_buf = kzalloc(sizeof(struct jz4750_dma_buf_aic), GFP_KERNEL); ++ if (aic_buf == NULL) { ++ printk("aic buffer allocate failed,no memory!\n"); ++ return -ENOMEM; ++ } ++ aic_buf->next = NULL; ++ aic_buf->data = aic_buf->ptr = data; ++ aic_buf->size = size; ++ if( prtd->curr == NULL) { ++ prtd->curr = aic_buf; ++ prtd->end = aic_buf; ++ prtd->next = NULL; ++ } else { ++ if (prtd->end == NULL) ++ printk("prtd->end is NULL\n"); ++ prtd->end->next = aic_buf; ++ prtd->end = aic_buf; ++ } ++ ++ /* if necessary, update the next buffer field */ ++ if (prtd->next == NULL) ++ prtd->next = aic_buf; ++ ++ return 0; ++} ++ ++void audio_start_dma(struct jz4750_runtime_data *prtd, int mode) ++{ ++ unsigned long flags; ++ struct jz4750_dma_buf_aic *aic_buf; ++ int channel; ++ ++ switch (mode) { ++ case DMA_MODE_WRITE: ++ /* free cur aic_buf */ ++ if (first_transfer == 1) { ++ first_transfer = 0; ++ } else { ++ aic_buf = prtd->curr; ++ if (aic_buf != NULL) { ++ prtd->curr = aic_buf->next; ++ prtd->next = aic_buf->next; ++ aic_buf->next = NULL; ++ kfree(aic_buf); ++ aic_buf = NULL; ++ } ++ } ++ ++ aic_buf = prtd->next; ++ channel = prtd->params->channel; ++ if (aic_buf) { ++ flags = claim_dma_lock(); ++ disable_dma(channel); ++ jz_set_alsa_dma(channel, mode, tran_bit); ++ set_dma_addr(channel, aic_buf->data); ++ set_dma_count(channel, aic_buf->size); ++ enable_dma(channel); ++ release_dma_lock(flags); ++ prtd->aic_dma_flag |= AIC_START_DMA; ++ } else { ++ printk("next buffer is NULL for playback\n"); ++ prtd->aic_dma_flag &= ~AIC_START_DMA; ++ return; ++ } ++ break; ++ case DMA_MODE_READ: ++ /* free cur aic_buf */ ++ if (first_transfer == 1) { ++ first_transfer = 0; ++ } else { ++ aic_buf = prtd->curr; ++ if (aic_buf != NULL) { ++ prtd->curr = aic_buf->next; ++ prtd->next = aic_buf->next; ++ aic_buf->next = NULL; ++ kfree(aic_buf); ++ aic_buf = NULL; ++ } ++ } ++ ++ aic_buf = prtd->next; ++ channel = prtd->params->channel; ++ ++ if (aic_buf) { ++ flags = claim_dma_lock(); ++ disable_dma(channel); ++ jz_set_alsa_dma(channel, mode, tran_bit); ++ set_dma_addr(channel, aic_buf->data); ++ set_dma_count(channel, aic_buf->size); ++ enable_dma(channel); ++ release_dma_lock(flags); ++ prtd->aic_dma_flag |= AIC_START_DMA; ++ } else { ++ printk("next buffer is NULL for capture\n"); ++ prtd->aic_dma_flag &= ~AIC_START_DMA; ++ return; ++ } ++ break; ++ } ++} ++ ++/* ++ * place a dma buffer onto the queue for the dma system to handle. ++*/ ++static void jz4750_pcm_enqueue(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd = runtime->private_data; ++ /*struct snd_dma_buffer *buf = &substream->dma_buffer;*/ ++ dma_addr_t pos = prtd->dma_pos; ++ int ret; ++ ++ while (prtd->dma_loaded < prtd->dma_limit) { ++ unsigned long len = prtd->dma_period; ++ ++ if ((pos + len) > prtd->dma_end) { ++ len = prtd->dma_end - pos; ++ } ++ ret = jz4750_dma_buf_enqueue(prtd, pos, len); ++ if (ret == 0) { ++ prtd->dma_loaded++; ++ pos += prtd->dma_period; ++ if (pos >= prtd->dma_end) ++ pos = prtd->dma_start; ++ } else ++ break; ++ } ++ ++ prtd->dma_pos = pos; ++} ++ ++/* ++ * call the function:jz4750_pcm_dma_irq() after DMA has transfered the current buffer ++ */ ++static irqreturn_t jz4750_pcm_dma_irq(int dma_ch, void *dev_id) ++{ ++ struct snd_pcm_substream *substream = dev_id; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd = runtime->private_data; ++ /*struct jz4750_dma_buf_aic *aic_buf = prtd->curr;*/ ++ int channel = prtd->params->channel; ++ unsigned long flags; ++ ++ disable_dma(channel); ++ prtd->aic_dma_flag &= ~AIC_START_DMA; ++ /* must clear TT bit in DCCSR to avoid interrupt again */ ++ if (__dmac_channel_transmit_end_detected(channel)) { ++ __dmac_channel_clear_transmit_end(channel); ++ } ++ if (__dmac_channel_transmit_halt_detected(channel)) { ++ __dmac_channel_clear_transmit_halt(channel); ++ } ++ ++ if (__dmac_channel_address_error_detected(channel)) { ++ __dmac_channel_clear_address_error(channel); ++ } ++ if (substream) ++ snd_pcm_period_elapsed(substream); ++ ++ spin_lock(&prtd->lock); ++ prtd->dma_loaded--; ++ if (prtd->state & ST_RUNNING) { ++ jz4750_pcm_enqueue(substream); ++ } ++ spin_unlock(&prtd->lock); ++ ++ local_irq_save(flags); ++ if (prtd->state & ST_RUNNING) { ++ if (prtd->dma_loaded) { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ audio_start_dma(prtd, DMA_MODE_WRITE); ++ else ++ audio_start_dma(prtd, DMA_MODE_READ); ++ } ++ } ++ local_irq_restore(flags); ++ return IRQ_HANDLED; ++} ++ ++/* some parameter about DMA operation */ ++static int jz4750_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd = runtime->private_data; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct jz4750_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; ++ size_t totbytes = params_buffer_bytes(params); ++ int ret; ++ ++#ifdef CONFIG_SND_OSSEMUL ++ if (hw_params_cnt) ++ return 0; ++ else ++ hw_params_cnt++ ; ++#endif ++ ++ if (!dma) ++ return 0; ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S8: ++ tran_bit = 8; ++ break; ++ case SNDRV_PCM_FORMAT_S16_LE: ++ tran_bit = 16; ++ break; ++ } ++ ++ /* prepare DMA */ ++ prtd->params = dma; ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name, ++ jz4750_pcm_dma_irq, IRQF_DISABLED, substream); ++ if (ret < 0) ++ return ret; ++ prtd->params->channel = ret; ++ } else { ++ ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name, ++ jz4750_pcm_dma_irq, IRQF_DISABLED, substream); ++ if (ret < 0) ++ return ret; ++ prtd->params->channel = ret; ++ } ++ ++ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); ++ runtime->dma_bytes = totbytes; ++ ++ spin_lock_irq(&prtd->lock); ++ prtd->dma_loaded = 0; ++ prtd->aic_dma_flag = 0; ++ prtd->dma_limit = runtime->hw.periods_min; ++ prtd->dma_period = params_period_bytes(params); ++ prtd->dma_start = runtime->dma_addr; ++ prtd->dma_pos = prtd->dma_start; ++ prtd->dma_end = prtd->dma_start + totbytes; ++ prtd->curr = NULL; ++ prtd->next = NULL; ++ prtd->end = NULL; ++ sum_bytes = 0; ++ first_transfer = 1; ++ printk_flag = 0; ++ ++ __dmac_disable_descriptor(prtd->params->channel); ++ __dmac_channel_disable_irq(prtd->params->channel); ++ spin_unlock_irq(&prtd->lock); ++ ++ return ret; ++} ++ ++static int jz4750_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct jz4750_runtime_data *prtd = substream->runtime->private_data; ++ ++ snd_pcm_set_runtime_buffer(substream, NULL); ++ if (prtd->params) { ++ jz_free_dma(prtd->params->channel); ++ prtd->params = NULL; ++ } ++ ++ return 0; ++} ++ ++/* set some dma para for playback/capture */ ++static int jz4750_dma_ctrl(int channel) ++{ ++ disable_dma(channel); ++ ++ /* must clear TT bit in DCCSR to avoid interrupt again */ ++ if (__dmac_channel_transmit_end_detected(channel)) { ++ __dmac_channel_clear_transmit_end(channel); ++ } ++ if (__dmac_channel_transmit_halt_detected(channel)) { ++ __dmac_channel_clear_transmit_halt(channel); ++ } ++ ++ if (__dmac_channel_address_error_detected(channel)) { ++ __dmac_channel_clear_address_error(channel); ++ } ++ ++ return 0; ++ ++} ++ ++static int jz4750_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ struct jz4750_runtime_data *prtd = substream->runtime->private_data; ++ int ret = 0; ++ ++ /* return if this is a bufferless transfer e.g */ ++ if (!prtd->params) ++ return 0; ++ ++ /* flush the DMA channel and DMA channel bit check */ ++ jz4750_dma_ctrl(prtd->params->channel); ++ prtd->dma_loaded = 0; ++ prtd->dma_pos = prtd->dma_start; ++ ++ /* enqueue dma buffers */ ++ jz4750_pcm_enqueue(substream); ++ ++ return ret; ++ ++} ++ ++static int jz4750_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd = runtime->private_data; ++ ++ int ret = 0; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ prtd->state |= ST_RUNNING; ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ audio_start_dma(prtd, DMA_MODE_WRITE); ++ } else { ++ audio_start_dma(prtd, DMA_MODE_READ); ++ } ++ ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ prtd->state &= ~ST_RUNNING; ++ break; ++ ++ case SNDRV_PCM_TRIGGER_RESUME: ++ printk(" RESUME \n"); ++ break; ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ printk(" RESTART \n"); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static snd_pcm_uframes_t ++jz4750_pcm_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd = runtime->private_data; ++ struct jz4750_dma_buf_aic *aic_buf = prtd->curr; ++ long count,res; ++ ++ dma_addr_t ptr; ++ snd_pcm_uframes_t x; ++ int channel = prtd->params->channel; ++ ++ spin_lock(&prtd->lock); ++#if 1 ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ count = get_dma_residue(channel); ++ count = aic_buf->size - count; ++ ptr = aic_buf->data + count; ++ res = ptr - prtd->dma_start; ++ } else { ++ count = get_dma_residue(channel); ++ count = aic_buf->size - count; ++ ptr = aic_buf->data + count; ++ res = ptr - prtd->dma_start; ++ } ++ ++# else ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) { ++ count = get_dma_residue(channel); ++ count = aic_buf->size - count; ++ ptr = aic_buf->data + count; ++ REG_DMAC_DSAR(channel) = ptr; ++ res = ptr - prtd->dma_start; ++ } else { ++ ptr = REG_DMAC_DSAR(channel); ++ if (ptr == 0x0) ++ printk("\ndma address is 00000000 in running!\n"); ++ res = ptr - prtd->dma_start; ++ } ++ } else { ++ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) { ++ count = get_dma_residue(channel); ++ count = aic_buf->size - count; ++ ptr = aic_buf->data + count; ++ REG_DMAC_DTAR(channel) = ptr; ++ res = ptr - prtd->dma_start; ++ } else { ++ ptr = REG_DMAC_DTAR(channel); ++ if (ptr == 0x0) ++ printk("\ndma address is 00000000 in running!\n"); ++ res = ptr - prtd->dma_start; ++ } ++ } ++#endif ++ spin_unlock(&prtd->lock); ++ x = bytes_to_frames(runtime, res); ++ if (x == runtime->buffer_size) ++ x = 0; ++ ++ return x; ++} ++ ++static int jz4750_pcm_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd; ++ ++#ifdef CONFIG_SND_OSSEMUL ++ hw_params_cnt = 0; ++#endif ++ REG_DMAC_DMACKE(0) = 0x3f; ++ REG_DMAC_DMACKE(1) = 0x3f; ++ snd_soc_set_runtime_hwparams(substream, &jz4750_pcm_hardware); ++ prtd = kzalloc(sizeof(struct jz4750_runtime_data), GFP_KERNEL); ++ if (prtd == NULL) ++ return -ENOMEM; ++ ++ spin_lock_init(&prtd->lock); ++ ++ runtime->private_data = prtd; ++ ++ return 0; ++} ++ ++static int jz4750_pcm_close(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct jz4750_runtime_data *prtd = runtime->private_data; ++ struct jz4750_dma_buf_aic *aic_buf = NULL; ++ ++#ifdef CONFIG_SND_OSSEMUL ++ hw_params_cnt = 0; ++#endif ++ ++ if (prtd) ++ aic_buf = prtd->curr; ++ ++ while (aic_buf != NULL) { ++ prtd->curr = aic_buf->next; ++ prtd->next = aic_buf->next; ++ aic_buf->next = NULL; ++ kfree(aic_buf); ++ aic_buf = NULL; ++ aic_buf = prtd->curr; ++ } ++ ++ if (prtd) { ++ prtd->curr = NULL; ++ prtd->next = NULL; ++ prtd->end = NULL; ++ kfree(prtd); ++ } ++ ++ return 0; ++} ++ ++static int jz4750_pcm_mmap(struct snd_pcm_substream *substream, ++ struct vm_area_struct *vma)//include/linux/mm.h ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ unsigned long start; ++ unsigned long off; ++ u32 len; ++ int ret = -ENXIO; ++ ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ start = runtime->dma_addr; ++ ++ len = PAGE_ALIGN((start & ~PAGE_MASK) + runtime->dma_bytes); ++ start &= PAGE_MASK; ++ ++ if ((vma->vm_end - vma->vm_start + off) > len) { ++ return -EINVAL; ++ } ++ ++ off += start; ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_flags |= VM_IO; ++ ++#if defined(CONFIG_MIPS32) ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; ++ /* pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; */ ++#endif ++ ret = io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ ++ return ret; ++} ++ ++struct snd_pcm_ops jz4750_pcm_ops = { ++ .open = jz4750_pcm_open, ++ .close = jz4750_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = jz4750_pcm_hw_params, ++ .hw_free = jz4750_pcm_hw_free, ++ .prepare = jz4750_pcm_prepare, ++ .trigger = jz4750_pcm_trigger, ++ .pointer = jz4750_pcm_pointer, ++ .mmap = jz4750_pcm_mmap, ++}; ++ ++static int jz4750_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) ++{ ++ struct snd_pcm_substream *substream = pcm->streams[stream].substream; ++ struct snd_dma_buffer *buf = &substream->dma_buffer; ++ size_t size = jz4750_pcm_hardware.buffer_bytes_max; ++ buf->dev.type = SNDRV_DMA_TYPE_DEV; ++ buf->dev.dev = pcm->card->dev; ++ buf->private_data = NULL; ++ ++ /*buf->area = dma_alloc_coherent(pcm->card->dev, size, ++ &buf->addr, GFP_KERNEL);*/ ++ buf->area = dma_alloc_noncoherent(pcm->card->dev, size, ++ &buf->addr, GFP_KERNEL); ++ if (!buf->area) ++ return -ENOMEM; ++ buf->bytes = size; ++ return 0; ++} ++ ++static void jz4750_pcm_free_dma_buffers(struct snd_pcm *pcm) ++{ ++ struct snd_pcm_substream *substream; ++ struct snd_dma_buffer *buf; ++ int stream; ++ ++ for (stream = 0; stream < 2; stream++) { ++ substream = pcm->streams[stream].substream; ++ if (!substream) ++ continue; ++ ++ buf = &substream->dma_buffer; ++ if (!buf->area) ++ continue; ++ ++ dma_free_noncoherent(pcm->card->dev, buf->bytes, ++ buf->area, buf->addr); ++ buf->area = NULL; ++ } ++} ++ ++static u64 jz4750_pcm_dmamask = DMA_32BIT_MASK; ++ ++int jz4750_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, ++ struct snd_pcm *pcm) ++{ ++ int ret = 0; ++ ++ if (!card->dev->dma_mask) ++ card->dev->dma_mask = &jz4750_pcm_dmamask; ++ if (!card->dev->coherent_dma_mask) ++ card->dev->coherent_dma_mask = DMA_32BIT_MASK; ++ ++ if (dai->playback.channels_min) { ++ ret = jz4750_pcm_preallocate_dma_buffer(pcm, ++ SNDRV_PCM_STREAM_PLAYBACK); ++ if (ret) ++ goto out; ++ } ++ ++ if (dai->capture.channels_min) { ++ ret = jz4750_pcm_preallocate_dma_buffer(pcm, ++ SNDRV_PCM_STREAM_CAPTURE); ++ if (ret) ++ goto out; ++ } ++ out: ++ ++ return ret; ++} ++ ++struct snd_soc_platform jz4750_soc_platform = { ++ .name = "jz4750-audio", ++ .pcm_ops = &jz4750_pcm_ops, ++ .pcm_new = jz4750_pcm_new, ++ .pcm_free = jz4750_pcm_free_dma_buffers, ++}; ++ ++EXPORT_SYMBOL_GPL(jz4750_soc_platform); ++ ++MODULE_AUTHOR("Richard"); ++MODULE_DESCRIPTION("Ingenic Jz4750 PCM DMA module"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/jz4750/jz4750-pcm.h b/sound/soc/jz4750/jz4750-pcm.h +new file mode 100644 +index 0000000..d7d4f72 +--- /dev/null ++++ b/sound/soc/jz4750/jz4750-pcm.h +@@ -0,0 +1,33 @@ ++/* ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _JZ4750_PCM_H ++#define _JZ4750_PCM_H ++ ++#include ++ ++#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