1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-04-21 12:27:27 +03:00

yet another patchset - 2.6.27

it's basically also provided by ingenic and nativly based on 2.6.27,
adjusted to fit into the OpenWrt-environment
This commit is contained in:
Mirko Vogt
2009-08-18 12:44:38 +02:00
committed by Xiangfu Liu
parent 4a72d4b2fe
commit dc3d3f1c49
452 changed files with 188939 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
2009.04.30
* Fix a bug in using gpio keys when pressing two keys at the same time.
Updated file:
drivers/input/keyboard/gpio_keys.c
<lhhuang@ingenic.cn>
2009.04.28
* Support detecting the power of battery.
Add File:
drivers/power/jz_battery.c
<lhhuang@ingenic.cn>

View File

@@ -0,0 +1,42 @@
#
# linux/arch/mips/boot/compressed/Makefile
#
# create a compressed zImage from the original vmlinux
#
targets := zImage vmlinuz vmlinux.bin.gz head.o misc.o piggy.o dummy.o
OBJS := $(obj)/head.o $(obj)/misc.o
LD_ARGS := -T $(obj)/ld.script -Ttext 0x80600000 -Bstatic
OBJCOPY_ARGS := -O elf32-tradlittlemips
ENTRY := $(obj)/../tools/entry
FILESIZE := $(obj)/../tools/filesize
drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
strip-flags = $(addprefix --remove-section=,$(drop-sections))
$(obj)/vmlinux.bin.gz: vmlinux
rm -f $(obj)/vmlinux.bin.gz
$(OBJCOPY) -O binary $(strip-flags) vmlinux $(obj)/vmlinux.bin
gzip -v9f $(obj)/vmlinux.bin
$(obj)/head.o: $(obj)/head.S $(obj)/vmlinux.bin.gz vmlinux
$(CC) $(KBUILD_AFLAGS) \
-DIMAGESIZE=$(shell sh $(FILESIZE) $(obj)/vmlinux.bin.gz) \
-DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) vmlinux ) \
-DLOADADDR=$(loadaddr) \
-c -o $(obj)/head.o $<
$(obj)/vmlinuz: $(OBJS) $(obj)/ld.script $(obj)/vmlinux.bin.gz $(obj)/dummy.o
$(OBJCOPY) \
--add-section=.image=$(obj)/vmlinux.bin.gz \
--set-section-flags=.image=contents,alloc,load,readonly,data \
$(obj)/dummy.o $(obj)/piggy.o
$(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/piggy.o
$(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap
zImage: $(obj)/vmlinuz
$(OBJCOPY) -O binary $(obj)/vmlinuz $(obj)/zImage

View File

@@ -0,0 +1,4 @@
int main(void)
{
return 0;
}

View File

@@ -0,0 +1,85 @@
/*
* linux/arch/mips/boot/compressed/head.S
*
* Copyright (C) 2005-2008 Ingenic Semiconductor Inc.
*/
#include <asm/asm.h>
#include <asm/cacheops.h>
#include <asm/cachectl.h>
#include <asm/regdef.h>
#define IndexInvalidate_I 0x00
#define IndexWriteBack_D 0x01
.set noreorder
LEAF(startup)
startup:
move s0, a0 /* Save the boot loader transfered args */
move s1, a1
move s2, a2
move s3, a3
la a0, _edata
la a1, _end
1: sw zero, 0(a0) /* Clear BSS section */
bne a1, a0, 1b
addu a0, 4
la sp, (.stack + 8192)
la a0, __image_begin
la a1, IMAGESIZE
la a2, LOADADDR
la ra, 1f
la k0, decompress_kernel
jr k0
nop
1:
move a0, s0
move a1, s1
move a2, s2
move a3, s3
li k0, KERNEL_ENTRY
jr k0
nop
2:
b 32
END(startup)
LEAF(flushcaches)
la t0, 1f
la t1, 0xa0000000
or t0, t0, t1
jr t0
nop
1:
li k0, 0x80000000 # start address
li k1, 0x80004000 # end address (16KB I-Cache)
subu k1, 128
2:
.set mips3
cache IndexWriteBack_D, 0(k0)
cache IndexWriteBack_D, 32(k0)
cache IndexWriteBack_D, 64(k0)
cache IndexWriteBack_D, 96(k0)
cache IndexInvalidate_I, 0(k0)
cache IndexInvalidate_I, 32(k0)
cache IndexInvalidate_I, 64(k0)
cache IndexInvalidate_I, 96(k0)
.set mips0
bne k0, k1, 2b
addu k0, k0, 128
la t0, 3f
jr t0
nop
3:
jr ra
nop
END(flushcaches)
.comm .stack,4096*2,4

View File

@@ -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) }
}

View File

@@ -0,0 +1,242 @@
/*
* linux/arch/mips/boot/compressed/misc.c
*
* This is a collection of several routines from gzip-1.0.3
* adapted for Linux.
*
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
*
* Adapted for JZSOC by Peter Wei, 2008
*
*/
#define size_t int
#define NULL 0
/*
* gzip declarations
*/
#define OF(args) args
#define STATIC static
#undef memset
#undef memcpy
#define memzero(s, n) memset ((s), 0, (n))
typedef unsigned char uch;
typedef unsigned short ush;
typedef unsigned long ulg;
#define WSIZE 0x8000 /* Window size must be at least 32k, */
/* and a power of two */
static uch *inbuf; /* input buffer */
static uch window[WSIZE]; /* Sliding window buffer */
static unsigned insize = 0; /* valid bytes in inbuf */
static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
static unsigned outcnt = 0; /* bytes in output buffer */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
#define RESERVED 0xC0 /* bit 6,7: reserved */
#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
/* Diagnostic functions */
#ifdef DEBUG
# define Assert(cond,msg) {if(!(cond)) error(msg);}
# define Trace(x) fprintf x
# define Tracev(x) {if (verbose) fprintf x ;}
# define Tracevv(x) {if (verbose>1) fprintf x ;}
# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
static int fill_inbuf(void);
static void flush_window(void);
static void error(char *m);
static void gzip_mark(void **);
static void gzip_release(void **);
void* memset(void* s, int c, size_t n);
void* memcpy(void* __dest, __const void* __src, size_t __n);
extern void flushcaches(void); /* defined in head.S */
char *input_data;
int input_len;
static long bytes_out = 0;
static uch *output_data;
static unsigned long output_ptr = 0;
static void *malloc(int size);
static void free(void *where);
static void error(char *m);
static void gzip_mark(void **);
static void gzip_release(void **);
static void puts(const char *str)
{
}
extern unsigned char _end[];
static unsigned long free_mem_ptr;
static unsigned long free_mem_end_ptr;
#define HEAP_SIZE 0x10000
#include "../../../../lib/inflate.c"
static void *malloc(int size)
{
void *p;
if (size <0) error("Malloc error\n");
if (free_mem_ptr == 0) error("Memory error\n");
free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
p = (void *)free_mem_ptr;
free_mem_ptr += size;
if (free_mem_ptr >= free_mem_end_ptr)
error("\nOut of memory\n");
return p;
}
static void free(void *where)
{ /* Don't care */
}
static void gzip_mark(void **ptr)
{
*ptr = (void *) free_mem_ptr;
}
static void gzip_release(void **ptr)
{
free_mem_ptr = (long) *ptr;
}
void* memset(void* s, int c, size_t n)
{
int i;
char *ss = (char*)s;
for (i=0;i<n;i++) ss[i] = c;
return s;
}
void* memcpy(void* __dest, __const void* __src, size_t __n)
{
int i = 0;
unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
for (i = __n >> 3; i > 0; i--) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (__n & 1 << 2) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (__n & 1 << 1) {
*d++ = *s++;
*d++ = *s++;
}
if (__n & 1)
*d++ = *s++;
return __dest;
}
/* ===========================================================================
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
static int fill_inbuf(void)
{
if (insize != 0) {
error("ran out of input data\n");
}
inbuf = input_data;
insize = input_len;
inptr = 1;
return inbuf[0];
}
/* ===========================================================================
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
static void flush_window(void)
{
ulg c = crc; /* temporary variable */
unsigned n;
uch *in, *out, ch;
in = window;
out = &output_data[output_ptr];
for (n = 0; n < outcnt; n++) {
ch = *out++ = *in++;
c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
}
crc = c;
bytes_out += (ulg)outcnt;
output_ptr += (ulg)outcnt;
outcnt = 0;
}
static void error(char *x)
{
puts("\n\n");
puts(x);
puts("\n\n -- System halted");
while(1); /* Halt */
}
void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr)
{
input_data = (char *)imageaddr;
input_len = imagesize;
output_ptr = 0;
output_data = (uch *)loadaddr;
free_mem_ptr = (unsigned long)_end;
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
makecrc();
puts("Uncompressing Linux...");
gunzip();
flushcaches();
puts("Ok, booting the kernel.");
}

View File

@@ -0,0 +1,12 @@
#!/bin/sh
# grab the kernel_entry address from the vmlinux elf image
entry=`$1 $2 | grep kernel_entry`
fs=`echo $entry | grep ffffffff` # check toolchain output
if [ -n "$fs" ]; then
echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'`
else
echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'`
fi

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,892 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.27
# Fri Aug 7 10:22:22 2009
#
CONFIG_MIPS=y
#
# Machine selection
#
# CONFIG_JZ4730_PMP is not set
# CONFIG_JZ4740_PAVO is not set
# CONFIG_JZ4740_LEO is not set
# CONFIG_JZ4740_LYRA is not set
# CONFIG_JZ4725_DIPPER is not set
# CONFIG_JZ4720_VIRGO is not set
# CONFIG_JZ4750_FUWA is not set
# CONFIG_JZ4750_APUS is not set
# CONFIG_JZ4750D_CETUS is not set
CONFIG_JZ4760_F4760=y
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_BASLER_EXCITE is not set
# CONFIG_BCM47XX is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_LEMOTE_FULONG is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MARKEINS is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP28 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SWARM is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SNI_RM is not set
# CONFIG_MACH_TX39XX is not set
# CONFIG_MACH_TX49XX is not set
# CONFIG_MIKROTIK_RB532 is not set
# CONFIG_WR_PPMC is not set
CONFIG_SOC_JZ4760=y
CONFIG_JZ_FPGA=y
CONFIG_JZSOC=y
CONFIG_JZRISC=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_HOTPLUG_CPU is not set
# CONFIG_NO_IOPORT is not set
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
# CPU selection
#
# CONFIG_CPU_LOONGSON2 is not set
CONFIG_CPU_MIPS32_R1=y
# CONFIG_CPU_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_CPU_MIPS32=y
CONFIG_CPU_MIPSR1=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
#
# Kernel type
#
CONFIG_32BIT=y
# CONFIG_64BIT is not set
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
# CONFIG_TICK_ONESHOT is not set
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_FORCE_MAX_ZONEORDER=13
# CONFIG_HZ_48 is not set
CONFIG_HZ_100=y
# CONFIG_HZ_128 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_256 is not set
# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_HZ=100
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_KEXEC is not set
CONFIG_SECCOMP=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CGROUPS is not set
# CONFIG_GROUP_SCHED is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
# CONFIG_NAMESPACES is not set
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_PANIC_TIMEOUT=0
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_PCSPKR_PLATFORM=y
CONFIG_COMPAT_BRK=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_ASHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
# CONFIG_HAVE_IOREMAP_PROT is not set
# CONFIG_HAVE_KPROBES is not set
# CONFIG_HAVE_KRETPROBES is not set
# CONFIG_HAVE_ARCH_TRACEHOOK is not set
# CONFIG_HAVE_DMA_ATTRS is not set
# CONFIG_USE_GENERIC_SMP_HELPERS is not set
# CONFIG_HAVE_CLK is not set
CONFIG_PROC_PAGE_MONITOR=y
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_CLASSIC_RCU=y
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_MMU=y
# CONFIG_PCCARD is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_TRAD_SIGNALS=y
#
# CPU Frequency scaling
#
# CONFIG_CPU_FREQ_JZ is not set
#
# Power management options
#
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PM is not set
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=m
CONFIG_INET_TCP_DIAG=m
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
CONFIG_ANDROID_PARANOID_NETWORK=y
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
#
# Wireless
#
# CONFIG_CFG80211 is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_MISC_DEVICES is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_VETH is not set
CONFIG_PHYLIB=y
#
# MII PHY device drivers
#
# CONFIG_MARVELL_PHY is not set
# CONFIG_DAVICOM_PHY is not set
# CONFIG_QSEMI_PHY is not set
# CONFIG_LXT_PHY is not set
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
# CONFIG_BROADCOM_PHY is not set
# CONFIG_ICPLUS_PHY is not set
# CONFIG_REALTEK_PHY is not set
# CONFIG_FIXED_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_JZ_ETH is not set
CONFIG_JZ4760_ETH=y
# CONFIG_AX88796 is not set
# CONFIG_DM9000 is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
# CONFIG_B44 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
#
# Wireless LAN
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
# CONFIG_IWLWIFI_LEDS is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_ISDN is not set
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
# CONFIG_INPUT_KEYRESET is not set
#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_JZ_GPIO is not set
# CONFIG_KEYBOARD_JZ is not set
# CONFIG_KEYBOARD_JZ_5x5 is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_JZ is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_UCB1400 is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
#
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_LIBPS2 is not set
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_DEVMEM=y
CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=2
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
# CONFIG_I2C is not set
# CONFIG_SPI is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
#
# Sonics Silicon Backplane
#
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
#
# Multifunction device drivers
#
# CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
#
# Multimedia devices
#
#
# Multimedia core support
#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DVB_CORE is not set
# CONFIG_VIDEO_MEDIA is not set
#
# Multimedia drivers
#
# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
# CONFIG_SOUND is not set
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_MMC is not set
# CONFIG_MEMSTICK is not set
# CONFIG_NEW_LEDS is not set
# CONFIG_SWITCH is not set
# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
# CONFIG_UIO is not set
#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
# CONFIG_EXT2_FS_POSIX_ACL is not set
# CONFIG_EXT2_FS_SECURITY is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
# CONFIG_EXT4DEV_FS is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
CONFIG_MINIX_FS=y
# CONFIG_OMFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
CONFIG_NLS_CODEPAGE_936=y
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
# CONFIG_DLM is not set
#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_CMDLINE=""
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_AUTHENC is not set
# CONFIG_CRYPTO_TEST is not set
#
# Authenticated Encryption with Associated Data
#
# CONFIG_CRYPTO_CCM is not set
# CONFIG_CRYPTO_GCM is not set
# CONFIG_CRYPTO_SEQIV is not set
#
# Block modes
#
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_CTS is not set
# CONFIG_CRYPTO_ECB is not set
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_XTS is not set
#
# Hash modes
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_RMD128 is not set
# CONFIG_CRYPTO_RMD160 is not set
# CONFIG_CRYPTO_RMD256 is not set
# CONFIG_CRYPTO_RMD320 is not set
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_WP512 is not set
#
# Ciphers
#
# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_SALSA20 is not set
# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_SERPENT is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_TWOFISH is not set
#
# Compression
#
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_LZO is not set
CONFIG_CRYPTO_HW=y
#
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_GENERIC_FIND_FIRST_BIT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y

View File

@@ -0,0 +1,928 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.24.3
# Fri Jul 4 19:20:22 2008
#
CONFIG_MIPS=y
#
# Machine selection
#
# CONFIG_JZ4730_PMP is not set
# CONFIG_JZ4740_PAVO is not set
# CONFIG_JZ4740_LEO is not set
# CONFIG_JZ4740_LYRA is not set
# CONFIG_JZ4725_DIPPER is not set
# CONFIG_JZ4720_VIRGO is not set
CONFIG_JZ4750_FUWA=y
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_BASLER_EXCITE is not set
# CONFIG_BCM47XX is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_LEMOTE_FULONG is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MARKEINS is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_QEMU is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SWARM is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_PTSWARM is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
# CONFIG_WR_PPMC is not set
CONFIG_SOC_JZ4750=y
CONFIG_JZ_FPGA=y
CONFIG_JZSOC=y
CONFIG_JZRISC=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_HOTPLUG_CPU is not set
# CONFIG_NO_IOPORT is not set
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
# CPU selection
#
# CONFIG_CPU_LOONGSON2 is not set
CONFIG_CPU_MIPS32_R1=y
# CONFIG_CPU_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_CPU_MIPS32=y
CONFIG_CPU_MIPSR1=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
#
# Kernel type
#
CONFIG_32BIT=y
# CONFIG_64BIT is not set
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
# CONFIG_TICK_ONESHOT is not set
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_HZ_48 is not set
CONFIG_HZ_100=y
# CONFIG_HZ_128 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_256 is not set
# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_HZ=100
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_PREEMPT_BKL=y
# CONFIG_KEXEC is not set
CONFIG_SECCOMP=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CGROUPS is not set
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_FAIR_USER_SCHED=y
# CONFIG_FAIR_CGROUP_SCHED is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_MMU=y
# CONFIG_PCCARD is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_TRAD_SIGNALS=y
#
# CPU Frequency scaling
#
# CONFIG_CPU_FREQ_JZ is not set
#
# Power management options
#
# CONFIG_PM is not set
CONFIG_SUSPEND_UP_POSSIBLE=y
#
# Networking
#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=m
CONFIG_INET_TCP_DIAG=m
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
#
# Wireless
#
# CONFIG_CFG80211 is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
#
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
# CONFIG_MTD_NAND_ECC_SMC is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
CONFIG_MTD_NAND_JZ4750=y
# CONFIG_MTD_HW_HM_ECC is not set
# CONFIG_MTD_SW_HM_ECC is not set
# CONFIG_MTD_HW_RS_ECC is not set
CONFIG_MTD_HW_BCH_ECC=y
CONFIG_MTD_NAND_DMA=y
# CONFIG_MTD_NAND_NO_DMA is not set
CONFIG_MTD_HW_BCH_4BIT=y
# CONFIG_MTD_HW_BCH_8BIT is not set
# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
CONFIG_MTD_OOB_COPIES=0
CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
# CONFIG_MTD_ONENAND is not set
#
# UBI - Unsorted block images
#
# CONFIG_MTD_UBI is not set
# CONFIG_MTD_UBI_BLKDEVS is not set
# CONFIG_PARPORT is not set
# CONFIG_PNP is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_VETH is not set
CONFIG_PHYLIB=y
#
# MII PHY device drivers
#
# CONFIG_MARVELL_PHY is not set
# CONFIG_DAVICOM_PHY is not set
# CONFIG_QSEMI_PHY is not set
# CONFIG_LXT_PHY is not set
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
# CONFIG_BROADCOM_PHY is not set
# CONFIG_ICPLUS_PHY is not set
# CONFIG_FIXED_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
CONFIG_JZ_ETH=y
# CONFIG_AX88796 is not set
# CONFIG_DM9000 is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
# CONFIG_B44 is not set
CONFIG_NETDEV_1000=y
CONFIG_NETDEV_10000=y
#
# Wireless LAN
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_ISDN is not set
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
#
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_LIBPS2 is not set
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=2
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_RTC is not set
# CONFIG_RTC_PCF8563 is not set
# CONFIG_RTC_JZ is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
#
# JZSOC char device support
#
# CONFIG_JZCHAR is not set
# CONFIG_I2C is not set
#
# SPI support
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_WATCHDOG is not set
#
# Sonics Silicon Backplane
#
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
#
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DVB_CORE is not set
# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
#
# Sound
#
# CONFIG_SOUND is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
# CONFIG_USB is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
# CONFIG_MMC is not set
# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
#
# Userspace I/O
#
# CONFIG_UIO is not set
#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
# CONFIG_EXT2_FS_POSIX_ACL is not set
# CONFIG_EXT2_FS_SECURITY is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
# CONFIG_EXT4DEV_FS is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
CONFIG_MINIX_FS=y
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NFS_DIRECTIO=y
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
# CONFIG_SUNRPC_BIND34 is not set
CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
CONFIG_NLS_CODEPAGE_936=y
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
# CONFIG_DLM is not set
#
# Yaffs2 Filesystems
#
CONFIG_YAFFS_FS=y
CONFIG_YAFFS_YAFFS1=y
# CONFIG_YAFFS_DOES_ECC is not set
CONFIG_YAFFS_YAFFS2=y
CONFIG_YAFFS_AUTO_YAFFS2=y
# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
CONFIG_INSTRUMENTATION=y
# CONFIG_PROFILING is not set
# CONFIG_MARKERS is not set
#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_SAMPLES is not set
CONFIG_CMDLINE=""
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_ECB is not set
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_XTS is not set
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
# CONFIG_CRYPTO_AUTHENC is not set
# CONFIG_CRYPTO_LZO is not set
CONFIG_CRYPTO_HW=y
#
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,981 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.24.3
# Thu Jun 12 13:53:57 2008
#
CONFIG_MIPS=y
#
# Machine selection
#
# CONFIG_JZ4730_PMP is not set
# CONFIG_JZ4740_PAVO is not set
# CONFIG_JZ4740_LEO is not set
CONFIG_JZ4740_LYRA=y
# CONFIG_JZ4725_DIPPER is not set
# CONFIG_JZ4720_VIRGO is not set
# CONFIG_JZ4750_FUWA is not set
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_BASLER_EXCITE is not set
# CONFIG_BCM47XX is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_LEMOTE_FULONG is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MARKEINS is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_QEMU is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SWARM is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_PTSWARM is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
# CONFIG_WR_PPMC is not set
CONFIG_SOC_JZ4740=y
CONFIG_JZSOC=y
CONFIG_JZRISC=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
# CONFIG_HOTPLUG_CPU is not set
# CONFIG_NO_IOPORT is not set
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
# CPU selection
#
# CONFIG_CPU_LOONGSON2 is not set
CONFIG_CPU_MIPS32_R1=y
# CONFIG_CPU_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_CPU_MIPS32=y
CONFIG_CPU_MIPSR1=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
#
# Kernel type
#
CONFIG_32BIT=y
# CONFIG_64BIT is not set
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
# CONFIG_TICK_ONESHOT is not set
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_HZ_48 is not set
CONFIG_HZ_100=y
# CONFIG_HZ_128 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_256 is not set
# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_HZ=100
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_PREEMPT_BKL=y
# CONFIG_KEXEC is not set
CONFIG_SECCOMP=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CGROUPS is not set
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_FAIR_USER_SCHED=y
# CONFIG_FAIR_CGROUP_SCHED is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_MMU=y
# CONFIG_PCCARD is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_TRAD_SIGNALS=y
#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ_JZ=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
CONFIG_CPU_FREQ_STAT=y
# CONFIG_CPU_FREQ_STAT_DETAILS is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
#
# Power management options
#
CONFIG_PM=y
CONFIG_PM_LEGACY=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
CONFIG_SUSPEND_UP_POSSIBLE=y
CONFIG_SUSPEND=y
#
# Networking
#
# CONFIG_NET is not set
#
# Device Drivers
#
#
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
#
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
CONFIG_MTD_BLOCK2MTD=y
#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
# CONFIG_MTD_NAND_ECC_SMC is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
CONFIG_MTD_NAND_JZ4740=y
# CONFIG_MTD_HW_HM_ECC is not set
# CONFIG_MTD_SW_HM_ECC is not set
CONFIG_MTD_HW_RS_ECC=y
# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
CONFIG_MTD_OOB_COPIES=3
CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
# CONFIG_MTD_ONENAND is not set
#
# UBI - Unsorted block images
#
CONFIG_MTD_UBI=m
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MTD_UBI_BEB_RESERVE=1
CONFIG_MTD_UBI_GLUEBI=y
#
# UBI debugging options
#
# CONFIG_MTD_UBI_DEBUG is not set
# CONFIG_MTD_UBI_BLKDEVS is not set
# CONFIG_PARPORT is not set
# CONFIG_PNP is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_DEBUG is not set
# CONFIG_ATA is not set
# CONFIG_MD is not set
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
#
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_LIBPS2 is not set
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_RTC is not set
# CONFIG_RTC_PCF8563 is not set
CONFIG_RTC_JZ=y
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
#
# JZSOC char device support
#
CONFIG_JZCHAR=y
# CONFIG_JZ_CIM is not set
CONFIG_JZ_TPANEL_ATA2508=y
# CONFIG_JZ_TPANEL is not set
CONFIG_JZ_UDC_HOTPLUG=y
CONFIG_JZ_POWEROFF=y
# CONFIG_JZ_OW is not set
# CONFIG_I2C is not set
#
# SPI support
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
#
# Watchdog Device Drivers
#
CONFIG_JZ_WDT=y
# CONFIG_SOFT_WATCHDOG is not set
#
# Sonics Silicon Backplane
#
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
#
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
# CONFIG_FB_SYS_IMAGEBLIT is not set
# CONFIG_FB_SYS_FOPS is not set
CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
#
# Frame buffer hardware drivers
#
CONFIG_FB_JZSOC=y
# CONFIG_FB_JZ4740_SLCD is not set
CONFIG_FB_JZLCD_4730_4740=y
CONFIG_JZLCD_FRAMEBUFFER_MAX=1
# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
# CONFIG_JZLCD_SAMSUNG_LTP400WQF02 is not set
CONFIG_JZLCD_AUO_A030FL01_V1=y
# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
# CONFIG_JZLCD_HYNIX_HT10X21 is not set
# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
# CONFIG_JZLCD_CSTN_800x600 is not set
# CONFIG_JZLCD_CSTN_320x240 is not set
# CONFIG_JZLCD_MSTN_480x320 is not set
# CONFIG_JZLCD_MSTN_320x240 is not set
# CONFIG_JZLCD_MSTN_240x128 is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
CONFIG_LOGO=y
CONFIG_LOGO_LINUX_MONO=y
CONFIG_LOGO_LINUX_VGA16=y
CONFIG_LOGO_LINUX_CLUT224=y
#
# Sound
#
CONFIG_SOUND=y
#
# Advanced Linux Sound Architecture
#
# CONFIG_SND is not set
#
# Open Sound System
#
CONFIG_SOUND_PRIME=y
CONFIG_OSS_OBSOLETE=y
# CONFIG_SOUND_JZ_AC97 is not set
CONFIG_SOUND_JZ_I2S=y
# CONFIG_SOUND_JZ_PCM is not set
# CONFIG_I2S_AK4642EN is not set
CONFIG_I2S_ICODEC=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
# CONFIG_USB is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
# USB Gadget Support
#
CONFIG_USB_GADGET=m
CONFIG_USB_GADGET_DEBUG_FILES=y
# CONFIG_USB_GADGET_DEBUG_FS is not set
CONFIG_USB_GADGET_SELECTED=y
CONFIG_USB_GADGET_JZ4740=y
CONFIG_USB_JZ4740=m
# CONFIG_USB_GADGET_JZ4730 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_ATMEL_USBA is not set
# CONFIG_USB_GADGET_FSL_USB2 is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_PXA2XX is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_LH7A40X is not set
# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_AT91 is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
# CONFIG_USB_ETH is not set
# CONFIG_USB_GADGETFS is not set
CONFIG_USB_FILE_STORAGE=m
# CONFIG_USB_FILE_STORAGE_TEST is not set
CONFIG_USB_G_SERIAL=m
# CONFIG_USB_MIDI_GADGET is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_UNSAFE_RESUME is not set
#
# MMC/SD Card Drivers
#
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_BOUNCE=y
# CONFIG_SDIO_UART is not set
#
# MMC/SD Host Controller Drivers
#
# CONFIG_MMC_JZ is not set
# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
#
# Userspace I/O
#
# CONFIG_UIO is not set
#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
# CONFIG_EXT2_FS_POSIX_ACL is not set
# CONFIG_EXT2_FS_SECURITY is not set
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
# CONFIG_EXT3_FS_SECURITY is not set
# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
CONFIG_MINIX_FS=y
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS2_FS is not set
CONFIG_UBIFS_FS=m
# CONFIG_UBIFS_FS_XATTR is not set
# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_UBIFS_FS_DEBUG=y
CONFIG_UBIFS_FS_DEBUG_MSG_LVL=0
# CONFIG_UBIFS_FS_DEBUG_CHKS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
# CONFIG_SYSV68_PARTITION is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
CONFIG_NLS_CODEPAGE_936=y
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
#
# Yaffs2 Filesystems
#
CONFIG_YAFFS_FS=y
CONFIG_YAFFS_YAFFS1=y
# CONFIG_YAFFS_DOES_ECC is not set
CONFIG_YAFFS_YAFFS2=y
CONFIG_YAFFS_AUTO_YAFFS2=y
# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
CONFIG_INSTRUMENTATION=y
# CONFIG_PROFILING is not set
# CONFIG_MARKERS is not set
#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_SAMPLES is not set
CONFIG_CMDLINE=""
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_ECB is not set
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_XTS is not set
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_SEED is not set
CONFIG_CRYPTO_DEFLATE=m
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
# CONFIG_CRYPTO_AUTHENC is not set
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_HW=y
#
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
CONFIG_CRC16=m
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
CONFIG_LZO_COMPRESS=m
CONFIG_LZO_DECOMPRESS=m
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -0,0 +1,109 @@
/*
* linux/arch/mips/jz4730/board-pmp.c
*
* JZ4730 PMP board setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned int count = 0;
count ++;
count &= 1;
if (count)
__gpio_set_pin(GPIO_LED_EN);
else
__gpio_clear_pin(GPIO_LED_EN);
}
static void pmp_timer_ack(void)
{
static unsigned int count = 0;
count ++;
if (count % 100 == 0) {
count = 0;
dancing();
}
}
static void __init board_cpm_setup(void)
{
__cpm_start_all();
}
static void __init board_gpio_setup(void)
{
/*
* Most of the gpios have been setup in the bootloader.
*/
__harb_usb0_uhc();
__gpio_as_dma();
__gpio_as_eth();
__gpio_as_usb();
__gpio_as_lcd_master();
#if defined(CONFIG_I2S_AK4642EN)
__gpio_as_scc1();
#endif
#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23)
__gpio_as_ssi();
#endif
//__gpio_as_ac97();
#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23) || defined(CONFIG_I2S_CS42L51)
__gpio_as_i2s_slave();
#endif
__gpio_as_cim();
__gpio_as_msc();
__gpio_as_output(GPIO_LED_EN);
__gpio_set_pin(GPIO_LED_EN);
__gpio_as_output(GPIO_DISP_OFF_N);
__gpio_set_pin(GPIO_DISP_OFF_N);
__gpio_as_output(GPIO_PWM0);
__gpio_set_pin(GPIO_PWM0);
__gpio_as_input(GPIO_RTC_IRQ);
__gpio_as_output(GPIO_USB_CLK_EN);
__gpio_set_pin(GPIO_USB_CLK_EN);
__gpio_as_input(GPIO_CHARG_STAT);
__gpio_disable_pull(GPIO_CHARG_STAT);
__gpio_as_input(GPIO_UDC_HOTPLUG);
__gpio_disable_pull(GPIO_UDC_HOTPLUG);
__gpio_disable_pull(54); /* fixed ic bug, the pull of gpio pin 86 is as pin 54 */
}
void __init jz_board_setup(void)
{
printk("JZ4730 PMP board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = pmp_timer_ack;
}

View File

@@ -0,0 +1,596 @@
/*
* linux/arch/mips/jz4730/cpufreq.c
*
* cpufreq driver for JZ4730
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <asm/jzsoc.h>
#include <asm/processor.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"cpufreq-jz4730", msg)
#undef CHANGE_PLL
#define PLL_UNCHANGED 0
#define PLL_GOES_UP 1
#define PLL_GOES_DOWN 2
#define PLL_WAIT_500NS (500*(__cpm_get_iclk()/1000000000))
/* Saved the boot-time parameters */
static struct {
/* SDRAM parameters */
unsigned int mclk; /* memory clock, KHz */
unsigned int tras; /* RAS pulse width, cycles of mclk */
unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
unsigned int tpc; /* RAS Precharge time, cycles of mclk */
unsigned int trwl; /* Write Precharge Time, cycles of mclk */
unsigned int trc; /* RAS Cycle Time, cycles of mclk */
unsigned int rtcor; /* Refresh Time Constant */
unsigned int sdram_initialized;
/* LCD parameters */
unsigned int lcd_clk; /* LCD clock, Hz */
unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
unsigned int lcd_clks_initialized;
} boot_config;
struct jz4730_freq_percpu_info {
struct cpufreq_frequency_table table[7];
};
static struct jz4730_freq_percpu_info jz4730_freq_table;
/*
* This contains the registers value for an operating point.
* If only part of a register needs to change then there is
* a mask value for that register.
* When going to a new operating point the current register
* value is ANDed with the ~mask and ORed with the new value.
*/
struct dpm_regs {
u32 cfcr; /* Clock Freq Control Register */
u32 cfcr_mask; /* Clock Freq Control Register mask */
u32 cfcr2; /* Clock Freq Control Register 2 */
u32 cfcr2_mask; /* Clock Freq Control Register 2 mask */
u32 plcr1; /* PLL1 Control Register */
u32 plcr1_mask; /* PLL1 Control Register mask */
u32 pll_up_flag; /* New PLL freq is higher than current or not */
};
extern jz_clocks_t jz_clocks;
static void jz_update_clocks(void)
{
/* Next clocks must be updated if we have changed
* the PLL or divisors.
*/
jz_clocks.iclk = __cpm_get_iclk();
jz_clocks.sclk = __cpm_get_sclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.lcdclk = __cpm_get_lcdclk();
jz_clocks.pixclk = __cpm_get_pixclk();
}
static void
jz_init_boot_config(void)
{
if (!boot_config.lcd_clks_initialized) {
/* the first time to scale pll */
boot_config.lcd_clk = __cpm_get_lcdclk();
boot_config.lcdpix_clk = __cpm_get_pixclk();
boot_config.lcd_clks_initialized = 1;
}
if (!boot_config.sdram_initialized) {
/* the first time to scale frequencies */
unsigned int dmcr, rtcor;
unsigned int tras, rcd, tpc, trwl, trc;
dmcr = REG_EMC_DMCR;
rtcor = REG_EMC_RTCOR;
tras = (dmcr >> 13) & 0x7;
rcd = (dmcr >> 11) & 0x3;
tpc = (dmcr >> 8) & 0x7;
trwl = (dmcr >> 5) & 0x3;
trc = (dmcr >> 2) & 0x7;
boot_config.mclk = __cpm_get_mclk() / 1000;
boot_config.tras = tras + 4;
boot_config.rcd = rcd + 1;
boot_config.tpc = tpc + 1;
boot_config.trwl = trwl + 1;
boot_config.trc = trc * 2 + 1;
boot_config.rtcor = rtcor;
boot_config.sdram_initialized = 1;
}
}
static void jz_update_dram_rtcor(unsigned int new_mclk)
{
unsigned int rtcor;
new_mclk /= 1000;
rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
rtcor--;
if (rtcor < 1) rtcor = 1;
if (rtcor > 255) rtcor = 255;
REG_EMC_RTCOR = rtcor;
REG_EMC_RTCNT = rtcor;
}
static void jz_update_dram_dmcr(unsigned int new_mclk)
{
unsigned int dmcr;
unsigned int tras, rcd, tpc, trwl, trc;
unsigned int valid_time, new_time; /* ns */
new_mclk /= 1000;
tras = boot_config.tras * new_mclk / boot_config.mclk;
rcd = boot_config.rcd * new_mclk / boot_config.mclk;
tpc = boot_config.tpc * new_mclk / boot_config.mclk;
trwl = boot_config.trwl * new_mclk / boot_config.mclk;
trc = boot_config.trc * new_mclk / boot_config.mclk;
/* Validation checking */
valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
new_time = (tras * 1000000) / new_mclk;
if (new_time < valid_time) tras += 1;
valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
new_time = (rcd * 1000000) / new_mclk;
if (new_time < valid_time) rcd += 1;
valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
new_time = (tpc * 1000000) / new_mclk;
if (new_time < valid_time) tpc += 1;
valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
new_time = (trwl * 1000000) / new_mclk;
if (new_time < valid_time) trwl += 1;
valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
new_time = (trc * 1000000) / new_mclk;
if (new_time < valid_time) trc += 2;
tras = (tras < 4) ? 4: tras;
tras = (tras > 11) ? 11: tras;
tras -= 4;
rcd = (rcd < 1) ? 1: rcd;
rcd = (rcd > 4) ? 4: rcd;
rcd -= 1;
tpc = (tpc < 1) ? 1: tpc;
tpc = (tpc > 8) ? 8: tpc;
tpc -= 1;
trwl = (trwl < 1) ? 1: trwl;
trwl = (trwl > 4) ? 4: trwl;
trwl -= 1;
trc = (trc < 1) ? 1: trc;
trc = (trc > 15) ? 15: trc;
trc /= 2;
dmcr = REG_EMC_DMCR;
dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
REG_EMC_DMCR = dmcr;
}
static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
* and TRC of DMCR before changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
} else {
/* We're going SLOWER: first update RTCOR value
* before changing the frequency.
*/
jz_update_dram_rtcor(new_mclk);
}
}
static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so update RTCOR
* after changing the frequency
*/
jz_update_dram_rtcor(new_mclk);
} else {
/* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
* and TRC of DMCR after changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
}
}
static void jz_scale_divisors(struct dpm_regs *regs)
{
unsigned int cfcr;
unsigned int cur_mclk, new_mclk;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
cfcr = REG_CPM_CFCR;
cfcr &= ~((unsigned long)regs->cfcr_mask);
cfcr |= regs->cfcr;
cfcr |= CPM_CFCR_UPE; /* update immediately */
cur_mclk = __cpm_get_mclk();
new_mclk = __cpm_get_pllout() / div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT];
/* Update some DRAM parameters before changing frequency */
jz_update_dram_prev(cur_mclk, new_mclk);
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#ifdef CHANGE_PLL
/* Maintain the LCD clock and pixel clock */
static void jz_scale_lcd_divisors(struct dpm_regs *regs)
{
unsigned int new_pll, new_lcd_div, new_lcdpix_div;
unsigned int cfcr;
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
if (!boot_config.lcd_clks_initialized) return;
new_pll = __cpm_get_pllout();
new_lcd_div = new_pll / boot_config.lcd_clk;
new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
if (new_lcd_div < 1)
new_lcd_div = 1;
if (new_lcd_div > 16)
new_lcd_div = 16;
if (new_lcdpix_div < 1)
new_lcdpix_div = 1;
if (new_lcdpix_div > 512)
new_lcdpix_div = 512;
REG_CPM_CFCR2 = new_lcdpix_div - 1;
cfcr = REG_CPM_CFCR;
cfcr &= ~CPM_CFCR_LFR_MASK;
cfcr |= ((new_lcd_div - 1) << CPM_CFCR_LFR_BIT);
cfcr |= CPM_CFCR_UPE; /* update immediately */
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp));
}
static void jz_scale_pll(struct dpm_regs *regs)
{
unsigned int plcr1;
unsigned int cur_mclk, new_mclk, new_pll;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
int od[] = {1, 2, 2, 4};
plcr1 = REG_CPM_PLCR1;
plcr1 &= ~(regs->plcr1_mask | CPM_PLCR1_PLL1S | CPM_PLCR1_PLL1EN | CPM_PLCR1_PLL1ST_MASK);
regs->plcr1 &= ~CPM_PLCR1_PLL1EN;
plcr1 |= (regs->plcr1 | 0xff);
/* Update some DRAM parameters before changing frequency */
new_pll = JZ_EXTAL * ((plcr1>>23)+2) / ((((plcr1>>18)&0x1f)+2) * od[(plcr1>>16)&0x03]);
cur_mclk = __cpm_get_mclk();
new_mclk = new_pll / div[(REG_CPM_CFCR>>16) & 0xf];
/*
* Update some SDRAM parameters
*/
jz_update_dram_prev(cur_mclk, new_mclk);
/*
* Update PLL, align code to cache line.
*/
plcr1 |= CPM_PLCR1_PLL1EN;
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_PLCR1), "r" (plcr1));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#endif
static void jz4730_transition(struct dpm_regs *regs)
{
/*
* Get and save some boot-time conditions.
*/
jz_init_boot_config();
#ifdef CHANGE_PLL
/*
* Disable LCD before scaling pll.
* LCD and LCD pixel clocks should not be changed even if the PLL
* output frequency has been changed.
*/
REG_LCD_CTRL &= ~LCD_CTRL_ENA;
#endif
/*
* Stop module clocks before scaling PLL
*/
__cpm_stop_eth();
__cpm_stop_aic_pclk();
__cpm_stop_aic_bitclk();
/* ... add more as necessary */
if (regs->pll_up_flag == PLL_GOES_UP) {
/* the pll frequency is going up, so change dividors first */
jz_scale_divisors(regs);
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
}
else if (regs->pll_up_flag == PLL_GOES_DOWN) {
/* the pll frequency is going down, so change pll first */
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
jz_scale_divisors(regs);
}
else {
/* the pll frequency is unchanged, so change divisors only */
jz_scale_divisors(regs);
}
/*
* Restart module clocks before scaling PLL
*/
__cpm_start_eth();
__cpm_start_aic_pclk();
__cpm_start_aic_bitclk();
/* ... add more as necessary */
#ifdef CHANGE_PLL
/* Scale the LCD divisors after scaling pll */
if (regs->pll_up_flag != PLL_UNCHANGED) {
jz_scale_lcd_divisors(regs);
}
/* Enable LCD controller */
REG_LCD_CTRL &= ~LCD_CTRL_DIS;
REG_LCD_CTRL |= LCD_CTRL_ENA;
#endif
/* Update system clocks */
jz_update_clocks();
}
extern unsigned int idle_times;
static unsigned int jz4730_freq_get(unsigned int cpu)
{
return (__cpm_get_iclk() / 1000);
}
static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
{
int n2FR[33] = {
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
9
};
int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
unsigned int div_of_cclk, new_freq, i;
regs->pll_up_flag = PLL_UNCHANGED;
regs->cfcr_mask = CPM_CFCR_IFR_MASK | CPM_CFCR_SFR_MASK | CPM_CFCR_PFR_MASK | CPM_CFCR_MFR_MASK;
new_freq = jz4730_freq_table.table[index].frequency;
do {
div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
} while (div_of_cclk==0);
if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
for(i = 1; i<4; i++) {
div[i] = 3;
}
} else {
for(i = 1; i<4; i++) {
div[i] = 2;
}
}
for(i = 0; i<4; i++) {
div[i] *= div_of_cclk;
}
dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
regs->cfcr = (n2FR[div[0]] << CPM_CFCR_IFR_BIT) |
(n2FR[div[1]] << CPM_CFCR_SFR_BIT) |
(n2FR[div[2]] << CPM_CFCR_PFR_BIT) |
(n2FR[div[3]] << CPM_CFCR_MFR_BIT);
return div_of_cclk;
}
static void jz4730_set_cpu_divider_index(unsigned int cpu, unsigned int index)
{
unsigned long divisor, old_divisor;
struct cpufreq_freqs freqs;
struct dpm_regs regs;
old_divisor = __cpm_get_pllout() / __cpm_get_iclk();
divisor = index_to_divisor(index, &regs);
freqs.old = __cpm_get_iclk() / 1000;
freqs.new = __cpm_get_pllout() / (1000 * divisor);
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor)
jz4730_transition(&regs);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int jz4730_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy,
&jz4730_freq_table.table[0],
target_freq, relation, &new_index))
return -EINVAL;
jz4730_set_cpu_divider_index(policy->cpu, new_index);
dprintk("new frequency is %d KHz (REG_CPM_CFCR:0x%x)\n", __cpm_get_iclk() / 1000, REG_CPM_CFCR);
return 0;
}
static int jz4730_freq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
&jz4730_freq_table.table[0]);
}
static int __init jz4730_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *table = &jz4730_freq_table.table[0];
unsigned int MAX_FREQ;
dprintk(KERN_INFO "Jz4730 cpufreq driver\n");
if (policy->cpu != 0)
return -EINVAL;
policy->cur = MAX_FREQ = __cpm_get_iclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = MAX_FREQ/8;
policy->cpuinfo.max_freq = MAX_FREQ;
policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
table[0].index = 0;
table[0].frequency = MAX_FREQ/8;
table[1].index = 1;
table[1].frequency = MAX_FREQ/6;
table[2].index = 2;
table[2].frequency = MAX_FREQ/4;
table[3].index = 3;
table[3].frequency = MAX_FREQ/3;
table[4].index = 4;
table[4].frequency = MAX_FREQ/2;
table[5].index = 5;
table[5].frequency = MAX_FREQ;
table[6].index = 6;
table[6].frequency = CPUFREQ_TABLE_END;
return cpufreq_frequency_table_cpuinfo(policy, table);
}
static struct cpufreq_driver cpufreq_jz4730_driver = {
// .flags = CPUFREQ_STICKY,
.init = jz4730_cpufreq_driver_init,
.verify = jz4730_freq_verify,
.target = jz4730_freq_target,
.get = jz4730_freq_get,
.name = "jz4730",
};
static int __init jz4730_cpufreq_init(void)
{
return cpufreq_register_driver(&cpufreq_jz4730_driver);
}
static void __exit jz4730_cpufreq_exit(void)
{
cpufreq_unregister_driver(&cpufreq_jz4730_driver);
}
module_init(jz4730_cpufreq_init);
module_exit(jz4730_cpufreq_exit);
MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
MODULE_DESCRIPTION("cpufreq driver for Jz4730");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,509 @@
/*
* linux/arch/mips/jz4730/dma.c
*
* JZ4730 DMA PC-like APIs.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/soundcard.h>
#include <asm/system.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/*
* A note on resource allocation:
*
* All drivers needing DMA channels, should allocate and release them
* through the public routines `jz_request_dma()' and `jz_free_dma()'.
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
*
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
* When releasing them, first release the IRQ, then release the DMA. The
* main reason for this order is that, if you are requesting the DMA buffer
* done interrupt, you won't know the irq number until the DMA channel is
* returned from jz_request_dma().
*/
struct jz_dma_chan jz_dma_table[NUM_DMA] = {
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
};
// Device FIFO addresses and default DMA modes
static const struct {
unsigned int fifo_addr;
unsigned int dma_mode;
unsigned int dma_source;
} dma_dev_table[NUM_DMA_DEV] = {
{CPHYSADDR(UART0_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
{CPHYSADDR(UART0_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
{CPHYSADDR(UART1_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
{CPHYSADDR(UART1_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
{CPHYSADDR(UART2_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
{CPHYSADDR(UART2_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
{CPHYSADDR(UART3_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
{CPHYSADDR(UART3_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
{CPHYSADDR(SSI_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT},
{CPHYSADDR(SSI_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_SSIIN},
{CPHYSADDR(MSC_TXFIFO), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT},
{CPHYSADDR(MSC_RXFIFO), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_MSCIN},
{CPHYSADDR(AIC_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
{CPHYSADDR(AIC_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
{0, DMA_AUTOINIT, 0},
};
int jz_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data)
{
int i, len = 0;
struct jz_dma_chan *chan;
for (i = 0; i < NUM_DMA; i++) {
if ((chan = get_dma_chan(i)) != NULL) {
len += sprintf(buf + len, "%2d: %s\n",
i, chan->dev_str);
}
}
if (fpos >= len) {
*start = buf;
*eof = 1;
return 0;
}
*start = buf + fpos;
if ((len -= fpos) > length)
return length;
*eof = 1;
return len;
}
void dump_jz_dma_channel(unsigned int dmanr)
{
struct jz_dma_chan *chan;
if (dmanr > NUM_DMA)
return;
chan = &jz_dma_table[dmanr];
printk(KERN_INFO "DMA%d Register Dump:\n", dmanr);
printk(KERN_INFO " DMACR= 0x%08x\n", REG_DMAC_DMACR);
printk(KERN_INFO " DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
printk(KERN_INFO " DDAR = 0x%08x\n", REG_DMAC_DDAR(dmanr));
printk(KERN_INFO " DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
printk(KERN_INFO " DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
printk(KERN_INFO " DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
}
/**
* jz_request_dma - dynamically allcate an idle DMA channel to return
* @dev_id: the specified dma device id or DMA_ID_RAW_REQ
* @dev_str: the specified dma device string name
* @irqhandler: the irq handler, or NULL
* @irqflags: the irq handler flags
* @irq_dev_id: the irq handler device id for shared irq
*
* Finds a free channel, and binds the requested device to it.
* Returns the allocated channel number, or negative on error.
* Requests the DMA done IRQ if irqhandler != NULL.
*
*/
int jz_request_dma(int dev_id, const char *dev_str,
irqreturn_t (*irqhandler)(int, void *),
unsigned long irqflags,
void *irq_dev_id)
{
struct jz_dma_chan *chan;
int i, ret;
if (dev_id < 0 || dev_id >= NUM_DMA_DEV)
return -EINVAL;
for (i = 0; i < NUM_DMA; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == NUM_DMA)
return -ENODEV;
chan = &jz_dma_table[i];
if (irqhandler) {
chan->irq = IRQ_DMA_0 + i; // see intc.h
chan->irq_dev = irq_dev_id;
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
dev_str, chan->irq_dev))) {
chan->irq = 0;
chan->irq_dev = NULL;
return ret;
}
} else {
chan->irq = 0;
chan->irq_dev = NULL;
}
// fill it in
chan->io = i;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
chan->mode = dma_dev_table[dev_id].dma_mode;
chan->source = dma_dev_table[dev_id].dma_source;
return i;
}
void jz_free_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan) {
printk("Trying to free DMA%d\n", dmanr);
return;
}
disable_dma(dmanr);
if (chan->irq)
free_irq(chan->irq, chan->irq_dev);
chan->irq = 0;
chan->irq_dev = NULL;
chan->dev_id = -1;
}
void jz_set_dma_dest_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCCSR_DWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCCSR_DWDH_8;
break;
case 16:
chan->mode |= DMAC_DCCSR_DWDH_16;
break;
case 32:
chan->mode |= DMAC_DCCSR_DWDH_32;
break;
}
}
void jz_set_dma_src_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCCSR_SWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCCSR_SWDH_8;
break;
case 16:
chan->mode |= DMAC_DCCSR_SWDH_16;
break;
case 32:
chan->mode |= DMAC_DCCSR_SWDH_32;
break;
}
}
void jz_set_dma_block_size(int dmanr, int nbyte)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCCSR_DS_MASK;
switch (nbyte) {
case 1:
chan->mode |= DMAC_DCCSR_DS_8b;
break;
case 2:
chan->mode |= DMAC_DCCSR_DS_16b;
break;
case 4:
chan->mode |= DMAC_DCCSR_DS_32b;
break;
case 16:
chan->mode |= DMAC_DCCSR_DS_16B;
break;
case 32:
chan->mode |= DMAC_DCCSR_DS_32B;
break;
}
}
/**
* jz_set_dma_mode - do the raw settings for the specified DMA channel
* @dmanr: the specified DMA channel
* @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
* @dma_mode: dma raw mode
* @dma_source: dma raw request source
* @fifo_addr: dma raw device fifo address
*
* Ensure call jz_request_dma(DMA_ID_RAW_REQ, ...) first, then call
* jz_set_dma_mode() rather than set_dma_mode() if you work with
* and external request dma device.
*
* NOTE: Don not dynamically allocate dma channel if one external request
* dma device will occupy this channel.
*/
int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
unsigned int dma_mode, unsigned int dma_source,
unsigned int fifo_addr)
{
int dev_id, i;
struct jz_dma_chan *chan;
if (dmanr > NUM_DMA)
return -ENODEV;
for (i = 0; i < NUM_DMA; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == NUM_DMA)
return -ENODEV;
chan = &jz_dma_table[dmanr];
dev_id = chan->dev_id;
if (dev_id > 0) {
printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
__FUNCTION__, dmanr);
return -ENODEV;
}
/* clone it from the dynamically allocated. */
if (i != dmanr) {
chan->irq = jz_dma_table[i].irq;
chan->irq_dev = jz_dma_table[i].irq_dev;
chan->dev_str = jz_dma_table[i].dev_str;
jz_dma_table[i].irq = 0;
jz_dma_table[i].irq_dev = NULL;
jz_dma_table[i].dev_id = -1;
}
chan->dev_id = DMA_ID_RAW_SET;
chan->io = dmanr;
chan->fifo_addr = fifo_addr;
chan->mode = dma_mode;
chan->source = dma_source;
set_dma_mode(dmanr, dma_mode);
return dmanr;
}
void enable_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR);
__dmac_enable_channel(dmanr);
if (chan->irq)
__dmac_channel_enable_irq(dmanr);
}
#define DMA_DISABLE_POLL 0x5000
void disable_dma(unsigned int dmanr)
{
int i;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
if (!__dmac_channel_enabled(dmanr))
return;
for (i = 0; i < DMA_DISABLE_POLL; i++)
if (__dmac_channel_transmit_end_detected(dmanr))
break;
#if 0
if (i == DMA_DISABLE_POLL)
printk(KERN_INFO "disable_dma: poll expired!\n");
#endif
__dmac_disable_channel(dmanr);
if (chan->irq)
__dmac_channel_disable_irq(dmanr);
}
/* note: DMA_MODE_MASK is simulated by sw, DCCSR_MODE_MASK mask hw bits */
void set_dma_mode(unsigned int dmanr, unsigned int mode)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
mode &= DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
chan->mode |= DMAC_DCCSR_DAM;
chan->mode &= ~DMAC_DCCSR_SAM;
} else if (mode == DMA_MODE_WRITE) {
chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM;
chan->mode &= ~DMAC_DCCSR_DAM;
} else {
printk(KERN_DEBUG "set_dma_mode() support DMA_MODE_READ or DMA_MODE_WRITE!\n");
}
REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
}
void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case AFMT_U8:
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
break;
case AFMT_S16_LE:
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCCSR_DAM;
chan->mode &= ~DMAC_DCCSR_SAM;
} else if (mode == DMA_MODE_WRITE) {
mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM |DMAC_DCCSR_DAM);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM;
chan->mode &= ~DMAC_DCCSR_DAM;
} else
printk("jz_set_oss_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case 8:
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
break;
case 16:
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCCSR_DAM;
chan->mode &= ~DMAC_DCCSR_SAM;
} else if (mode == DMA_MODE_WRITE) {
mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM;
chan->mode &= ~DMAC_DCCSR_DAM;
} else
printk("jz_set_alsa_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
void set_dma_addr(unsigned int dmanr, unsigned int a)
{
unsigned int mode;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode = chan->mode & DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
REG_DMAC_DDAR(chan->io) = a;
} else if (mode == DMA_MODE_WRITE) {
REG_DMAC_DSAR(chan->io) = a;
REG_DMAC_DDAR(chan->io) = chan->fifo_addr;
} else
printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
}
void set_dma_count(unsigned int dmanr, unsigned int count)
{
unsigned int mode;
int dma_ds[] = {4, 1, 2, 16, 32};
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT;
count = count / dma_ds[mode];
REG_DMAC_DTCR(chan->io) = count;
}
int get_dma_residue(unsigned int dmanr)
{
int count;
unsigned int mode;
int dma_ds[] = {4, 1, 2, 16, 32};
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT;
count = REG_DMAC_DTCR(chan->io);
count = count * dma_ds[mode];
return count;
}
EXPORT_SYMBOL(jz_dma_table);
EXPORT_SYMBOL(jz_request_dma);
EXPORT_SYMBOL(jz_free_dma);
EXPORT_SYMBOL(jz_set_dma_src_width);
EXPORT_SYMBOL(jz_set_dma_dest_width);
EXPORT_SYMBOL(jz_set_dma_block_size);
EXPORT_SYMBOL(jz_set_dma_mode);
EXPORT_SYMBOL(set_dma_mode);
EXPORT_SYMBOL(jz_set_oss_dma);
EXPORT_SYMBOL(jz_set_alsa_dma);
EXPORT_SYMBOL(set_dma_addr);
EXPORT_SYMBOL(set_dma_count);
EXPORT_SYMBOL(get_dma_residue);
EXPORT_SYMBOL(enable_dma);
EXPORT_SYMBOL(disable_dma);
EXPORT_SYMBOL(dump_jz_dma_channel);

View File

@@ -0,0 +1,214 @@
/*
* linux/arch/mips/jz4730/i2c.c
*
* JZ4730 I2C APIs.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/* I2C protocol */
#define I2C_READ 1
#define I2C_WRITE 0
#define TIMEOUT 1000
/*
* I2C bus protocol basic routines
*/
static int i2c_put_data(unsigned char data)
{
unsigned int timeout = TIMEOUT * 10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (!__i2c_received_ack() && timeout)
timeout--;
if (timeout)
return 0;
else
return -ETIMEDOUT;
}
static int i2c_get_data(unsigned char *data, int ack)
{
int timeout = TIMEOUT*10;
if (!ack)
__i2c_send_nack();
else
__i2c_send_ack();
while (__i2c_check_drf() == 0 && timeout)
timeout--;
if (timeout) {
if (!ack)
__i2c_send_stop();
*data = __i2c_read();
__i2c_clear_drf();
return 0;
} else
return -ETIMEDOUT;
}
/*
* I2C interface
*/
void i2c_open(void)
{
__i2c_set_clk(jz_clocks.devclk, 10000); /* default 10 KHz */
__i2c_enable();
}
void i2c_close(void)
{
udelay(300); /* wait for STOP goes over. */
__i2c_disable();
}
void i2c_setclk(unsigned int i2cclk)
{
__i2c_set_clk(jz_clocks.devclk, i2cclk);
}
int i2c_lseek(unsigned char device, unsigned char offset)
{
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data(offset) < 0)
goto address_err;
return 0;
device_err:
printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
__i2c_send_stop();
return -ENODEV;
address_err:
printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
__i2c_send_stop();
return -EREMOTEIO;
}
int i2c_read(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int timeout = 5;
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data(address) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddr;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddr = address;
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
__i2c_send_stop();
return count - cnt;
device_err:
address_err:
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
EXPORT_SYMBOL(i2c_open);
EXPORT_SYMBOL(i2c_close);
EXPORT_SYMBOL(i2c_setclk);
EXPORT_SYMBOL(i2c_read);
EXPORT_SYMBOL(i2c_write);

View File

@@ -0,0 +1,266 @@
/*
* linux/arch/mips/jz4730/irq.c
*
* JZ4730 interrupt routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
/*
* INTC irq type
*/
static void enable_intc_irq(unsigned int irq)
{
__intc_unmask_irq(irq);
}
static void disable_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
}
static void mask_and_ack_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
__intc_ack_irq(irq);
}
static void end_intc_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
enable_intc_irq(irq);
}
}
static unsigned int startup_intc_irq(unsigned int irq)
{
enable_intc_irq(irq);
return 0;
}
static void shutdown_intc_irq(unsigned int irq)
{
disable_intc_irq(irq);
}
static struct irq_chip intc_irq_type = {
.typename = "INTC",
.startup = startup_intc_irq,
.shutdown = shutdown_intc_irq,
.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<<irq);
irq = plat_real_irq(irq);
do_IRQ(irq);
}

View File

@@ -0,0 +1,140 @@
/*
* Platform device support for Jz4730 SoC.
*
* Copyright 2007, Peter <jlwei@ingenic.cn>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <asm/jzsoc.h>
/* OHCI (USB full speed host controller) */
static struct resource jz_usb_ohci_resources[] = {
[0] = {
.start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
.end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UHC,
.end = IRQ_UHC,
.flags = IORESOURCE_IRQ,
},
};
/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;
static struct platform_device jz_usb_ohci_device = {
.name = "jz-ohci",
.id = 0,
.dev = {
.dma_mask = &ohci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
.resource = jz_usb_ohci_resources,
};
/*** LCD controller ***/
static struct resource jz_lcd_resources[] = {
[0] = {
.start = CPHYSADDR(LCD_BASE),
.end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_lcd_dmamask = ~(u32)0;
static struct platform_device jz_lcd_device = {
.name = "jz-lcd",
.id = 0,
.dev = {
.dma_mask = &jz_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_lcd_resources),
.resource = jz_lcd_resources,
};
/* UDC (USB gadget controller) */
static struct resource jz_usb_gdt_resources[] = {
[0] = {
.start = CPHYSADDR(UDC_BASE),
.end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UDC,
.end = IRQ_UDC,
.flags = IORESOURCE_IRQ,
},
};
static u64 udc_dmamask = ~(u32)0;
static struct platform_device jz_usb_gdt_device = {
.name = "jz-udc",
.id = 0,
.dev = {
.dma_mask = &udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
.resource = jz_usb_gdt_resources,
};
/** MMC/SD controller **/
static struct resource jz_mmc_resources[] = {
[0] = {
.start = CPHYSADDR(MSC_BASE),
.end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_MSC,
.end = IRQ_MSC,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_mmc_dmamask = ~(u32)0;
static struct platform_device jz_mmc_device = {
.name = "jz-mmc",
.id = 0,
.dev = {
.dma_mask = &jz_mmc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_mmc_resources),
.resource = jz_mmc_resources,
};
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
&jz_usb_ohci_device,
&jz_lcd_device,
&jz_usb_gdt_device,
&jz_mmc_device,
};
static int __init jz_platform_init(void)
{
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
arch_initcall(jz_platform_init);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
/*
* linux/arch/mips/jz4730/proc.c
*
* /proc/jz/ procfs for on-chip peripherals.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/jzsoc.h>
struct proc_dir_entry *proc_jz_root;
/*
* EMC Module
*/
static int emc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf (page+len, "BCR: 0x%08x\n", REG_EMC_BCR);
len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4, REG_EMC_SMCR5);
len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4, REG_EMC_SACR5);
len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
len += sprintf (page+len, "DMAR(0-1): 0x%08x 0x%08x\n", REG_EMC_DMAR1, REG_EMC_DMAR2);
return len;
}
/*
* Power Manager Module
*/
static int pmc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned long lpcr = REG_CPM_LPCR;
unsigned long mscr = REG_CPM_MSCR;
len += sprintf (page+len, "LPCR : 0x%08lx\n", lpcr);
len += sprintf (page+len, "Low Power Mode : %s\n",
((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_IDLE)) ?
"idle" : (((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_SLEEP)) ? "sleep" : "hibernate"));
len += sprintf (page+len, "Doze Mode : %s\n",
(lpcr & CPM_LPCR_DOZE) ? "on" : "off");
if (lpcr & CPM_LPCR_DOZE)
len += sprintf (page+len, " duty : %d\n", (int)((lpcr & CPM_LPCR_DUTY_MASK) >> CPM_LPCR_DUTY_BIT));
len += sprintf (page+len, "CKO1 : %s\n",
(REG_CPM_CFCR & CPM_CFCR_CKOEN1) ? "enable" : "disable");
len += sprintf (page+len, "UART0 : %s\n",
(mscr & CPM_MSCR_MSTP_UART0) ? "stopped" : "running");
len += sprintf (page+len, "UART1 : %s\n",
(mscr & CPM_MSCR_MSTP_UART1) ? "stopped" : "running");
len += sprintf (page+len, "UART2 : %s\n",
(mscr & CPM_MSCR_MSTP_UART2) ? "stopped" : "running");
len += sprintf (page+len, "UART3 : %s\n",
(mscr & CPM_MSCR_MSTP_UART3) ? "stopped" : "running");
len += sprintf (page+len, "OST : %s\n",
(mscr & CPM_MSCR_MSTP_OST) ? "stopped" : "running");
len += sprintf (page+len, "DMAC : %s\n",
(mscr & CPM_MSCR_MSTP_DMAC) ? "stopped" : "running");
len += sprintf (page+len, "ETH : %s\n",
(mscr & CPM_MSCR_MSTP_ETH) ? "stopped" : "running");
len += sprintf (page+len, "UHC/UDC : %s\n",
(mscr & CPM_MSCR_MSTP_UHC) ? "stopped" : "running");
len += sprintf (page+len, "PWM0 : %s\n",
(mscr & CPM_MSCR_MSTP_PWM0) ? "stopped" : "running");
len += sprintf (page+len, "PWM1 : %s\n",
(mscr & CPM_MSCR_MSTP_PWM1) ? "stopped" : "running");
len += sprintf (page+len, "I2C : %s\n",
(mscr & CPM_MSCR_MSTP_I2C) ? "stopped" : "running");
len += sprintf (page+len, "SSI : %s\n",
(mscr & CPM_MSCR_MSTP_SSI) ? "stopped" : "running");
len += sprintf (page+len, "SCC : %s\n",
(mscr & CPM_MSCR_MSTP_SCC) ? "stopped" : "running");
return len;
}
static int pmc_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
REG_CPM_MSCR = simple_strtoul(buffer, 0, 16);
return count;
}
/*
* Clock Generation Module
*/
static int cgm_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned int cfcr = REG_CPM_CFCR;
unsigned int plcr1 = REG_CPM_PLCR1;
unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int od[4] = {1, 2, 2, 4};
len += sprintf (page+len, "PLCR1 : 0x%08x\n", plcr1);
len += sprintf (page+len, "CFCR : 0x%08x\n", cfcr);
len += sprintf (page+len, "PLL : %s\n",
(plcr1 & CPM_PLCR1_PLL1EN) ? "ON" : "OFF");
len += sprintf (page+len, "NF:NR:NO : %d:%d:%d\n",
__cpm_plcr1_fd() + 2,
__cpm_plcr1_rd() + 2,
od[__cpm_plcr1_od()]
);
len += sprintf (page+len, "I:S:M:P : %d:%d:%d:%d\n",
div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT],
div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT],
div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT],
div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT]
);
len += sprintf (page+len, "PLL Freq : %d MHz\n", __cpm_get_pllout()/1000000);
len += sprintf (page+len, "ICLK : %d MHz\n", __cpm_get_iclk()/1000000);
len += sprintf (page+len, "SCLK : %d MHz\n", __cpm_get_sclk()/1000000);
len += sprintf (page+len, "MCLK : %d MHz\n", __cpm_get_mclk()/1000000);
len += sprintf (page+len, "PCLK : %d MHz\n", __cpm_get_pclk()/1000000);
len += sprintf (page+len, "DEVCLK : %d MHz\n", __cpm_get_devclk()/1000000);
len += sprintf (page+len, "RTCCLK : %d KHz\n", __cpm_get_rtcclk()/1000);
len += sprintf (page+len, "USBCLK : %d MHz\n", __cpm_get_usbclk()/1000000);
#if defined(CONFIG_FB_JZ)
len += sprintf (page+len, "LCDCLK : %d MHz\n", __cpm_get_lcdclk()/1000000);
len += sprintf (page+len, "PIXCLK : %d MHz\n", __cpm_get_pixclk()/1000000);
#endif
return len;
}
static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG_CPM_CFCR = simple_strtoul(buffer, 0, 16);
return count;
}
/*
* WDT
*/
static int wdt_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf (page+len, "WDT_WTCSR : 0x%08x\n", REG_WDT_WTCSR);
len += sprintf (page+len, "WDT_WTCNT : 0x%08x\n", REG_WDT_WTCNT);
return len;
}
static int wdt_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
unsigned long cnt = simple_strtoul(buffer, 0, 16);
REG_WDT_WTCNT = cnt;
REG_WDT_WTCSR = WDT_WTCSR_START;
return count;
}
/*
* PWM
*/
static int proc_jz_pwm_read_byte(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
return sprintf (page, "0x%02x\n", REG8(data));
}
static int proc_jz_pwm_read_word(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
return sprintf (page, "0x%04x\n", REG16(data));
}
static int proc_jz_pwm_write_byte(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG8(data) = simple_strtoul(buffer, 0, 16);
return count;
}
static int proc_jz_pwm_write_word(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG16(data) = simple_strtoul(buffer, 0, 16);
return count;
}
#define PWM_NUM 2
static int jz_pwm_proc_init(void)
{
struct proc_dir_entry *proc_jz_pwm, *res;
char name[16];
unsigned char i;
for (i = 0; i < PWM_NUM; i++) {
sprintf(name, "pwm%d", i);
proc_jz_pwm = proc_mkdir(name, proc_jz_root);
res = create_proc_entry("control", 0600, proc_jz_pwm);
if ( res) {
res->read_proc = proc_jz_pwm_read_byte;
res->write_proc = proc_jz_pwm_write_byte;
if (i)
res->data = (void * )PWM_CTR(1);
else
res->data = (void * )PWM_CTR(0);
}
res = create_proc_entry("period", 0600, proc_jz_pwm);
if ( res) {
res->read_proc = proc_jz_pwm_read_word;
res->write_proc = proc_jz_pwm_write_word;
if (i)
res->data = (void *)PWM_PER(1);
else
res->data = (void *)PWM_PER(0);
}
res = create_proc_entry("duty", 0600, proc_jz_pwm);
if ( res) {
res->read_proc = proc_jz_pwm_read_word;
res->write_proc = proc_jz_pwm_write_word;
if (i)
res->data = (void * )PWM_DUT(1);
else
res->data = (void * )PWM_DUT(0);
}
}
return 0;
}
/*
* /proc/jz/xxx entry
*
*/
static int __init jz_proc_init(void)
{
struct proc_dir_entry *entry;
/* create /proc/jz */
proc_jz_root = proc_mkdir("jz", 0);
/* create /proc/jz/emc */
entry = create_proc_entry("emc", 0644, proc_jz_root);
if (entry) {
entry->read_proc = emc_read_proc;
entry->write_proc = NULL;
entry->data = NULL;
}
/* create /proc/jz/pmc */
entry = create_proc_entry("pmc", 0644, proc_jz_root);
if (entry) {
entry->read_proc = pmc_read_proc;
entry->write_proc = pmc_write_proc;
entry->data = NULL;
}
/* create /proc/jz/cgm */
entry = create_proc_entry("cgm", 0644, proc_jz_root);
if (entry) {
entry->read_proc = cgm_read_proc;
entry->write_proc = cgm_write_proc;
entry->data = NULL;
}
/* create /proc/jz/wdt */
entry = create_proc_entry("wdt", 0644, proc_jz_root);
if (entry) {
entry->read_proc = wdt_read_proc;
entry->write_proc = wdt_write_proc;
entry->data = NULL;
}
/* PWM */
jz_pwm_proc_init();
return 0;
}
__initcall(jz_proc_init);

View File

@@ -0,0 +1,198 @@
/*
*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, supports YAMON and U-Boot.
*
* Copyright 2000, 2001, 2006 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/jzsoc.h>
/* #define DEBUG_CMDLINE */
int prom_argc;
char **prom_argv, **prom_envp;
char * prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
if (prom_argc > 1)
*cp = '\0';
}
char *prom_getenv(char *envname)
{
#if 0
/*
* Return a pointer to the given environment variable.
* YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
*/
char **env = prom_envp;
int i = strlen(envname);
int yamon = (*env && strchr(*env, '=') == NULL);
while (*env) {
if (yamon) {
if (strcmp(envname, *env++) == 0)
return *env;
} else {
if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
return *env + i + 1;
}
env++;
}
#endif
return NULL;
}
inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0; /* foo */
}
inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
for(i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
#if 0
{
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
#endif
return 0;
}
void __init prom_free_prom_memory(void)
{
}
void __init prom_init(void)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = (int) fw_arg0;
prom_argv = (char **) fw_arg1;
prom_envp = (char **) fw_arg2;
mips_machtype = MACH_INGENIC_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);

View File

@@ -0,0 +1,40 @@
/*
* linux/arch/mips/jz4730/reset.c
*
* JZ4730 reset routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
void jz_restart(char *command)
{
__wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */
__wdt_start();
while (1);
}
void jz_halt(void)
{
__wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */
__wdt_start();
while (1);
}
void jz_power_off(void)
{
jz_halt();
}

View File

@@ -0,0 +1,182 @@
/*
* linux/arch/mips/jz4730/setup.c
*
* JZ4730 CPU common setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
#ifdef CONFIG_PC_KEYB
#include <asm/keyboard.h>
#endif
jz_clocks_t jz_clocks;
extern char * __init prom_getcmdline(void);
extern void __init jz_board_setup(void);
extern void jz_restart(char *);
extern void jz_halt(void);
extern void jz_power_off(void);
extern void jz_time_init(void);
static void __init sysclocks_setup(void)
{
#ifndef CONFIG_JZ4730_URANUS
jz_clocks.iclk = __cpm_get_iclk();
jz_clocks.sclk = __cpm_get_sclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.devclk = __cpm_get_devclk();
jz_clocks.rtcclk = __cpm_get_rtcclk();
jz_clocks.uartclk = __cpm_get_uartclk();
jz_clocks.lcdclk = __cpm_get_lcdclk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.mscclk = __cpm_get_mscclk();
#else /* URANUS FPGA */
#define FPGACLK 8000000
jz_clocks.iclk = FPGACLK;
jz_clocks.sclk = FPGACLK;
jz_clocks.mclk = FPGACLK;
jz_clocks.devclk = FPGACLK;
jz_clocks.rtcclk = FPGACLK;
jz_clocks.uartclk = FPGACLK;
jz_clocks.pixclk = FPGACLK;
jz_clocks.lcdclk = FPGACLK;
jz_clocks.usbclk = FPGACLK;
jz_clocks.i2sclk = FPGACLK;
jz_clocks.mscclk = FPGACLK;
#endif
printk("CPU clock: %dMHz, System clock: %dMHz, Memory clock: %dMHz, Peripheral clock: %dMHz\n",
(jz_clocks.iclk + 500000) / 1000000,
(jz_clocks.sclk + 500000) / 1000000,
(jz_clocks.mclk + 500000) / 1000000,
(jz_clocks.pclk + 500000) / 1000000);
}
static void __init soc_cpm_setup(void)
{
__cpm_idle_mode();
__cpm_enable_cko1();
__cpm_start_all();
/* get system clocks */
sysclocks_setup();
}
static void __init soc_harb_setup(void)
{
// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
__harb_set_priority(0x08); /* DMAC>LCD>CIM>ETH>USB>CIM */
// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
}
static void __init soc_emc_setup(void)
{
}
static void __init soc_dmac_setup(void)
{
__dmac_enable_all_channels();
}
static void __init jz_soc_setup(void)
{
soc_cpm_setup();
soc_harb_setup();
soc_emc_setup();
soc_dmac_setup();
}
static void __init jz_serial_setup(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port s;
memset(&s, 0, sizeof(s));
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = UPIO_MEM;
s.regshift = 2;
s.uartclk = jz_clocks.uartclk;
s.line = 0;
s.membase = (u8 *)UART0_BASE;
s.irq = IRQ_UART0;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS0 setup failed!\n");
}
s.line = 1;
s.membase = (u8 *)UART1_BASE;
s.irq = IRQ_UART1;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS1 setup failed!\n");
}
s.line = 2;
s.membase = (u8 *)UART2_BASE;
s.irq = IRQ_UART2;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS2 setup failed!\n");
}
s.line = 3;
s.membase = (u8 *)UART3_BASE;
s.irq = IRQ_UART3;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS3 setup failed!\n");
}
#endif
}
void __init plat_mem_setup(void)
{
char *argptr;
argptr = prom_getcmdline();
/* IO/MEM resources. */
set_io_port_base(0);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x00000000;
iomem_resource.end = 0xffffffff;
_machine_restart = jz_restart;
_machine_halt = jz_halt;
pm_power_off = jz_power_off;
jz_soc_setup(); /* soc specific setup */
jz_serial_setup(); /* serial port setup */
jz_board_setup(); /* board specific setup */
}

View File

@@ -0,0 +1,307 @@
/*
* linux/arch/mips/jz4730/sleep.S
*
* jz4730 Assembler Sleep/WakeUp Management Routines
*
* Copyright (C) 2005 Ingenic Semiconductor
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/mach-jz4730/regs.h>
.text
.set noreorder
.set noat
.extern jz_flush_cache_all
/*
* jz_cpu_suspend()
*
* Forces CPU into hibernate mode
*/
.globl jz_cpu_suspend
jz_cpu_suspend:
/* save hi, lo and general registers except k0($26) and k1($27) (total 32) */
move k0, sp
addiu k0, k0, -(32*4)
mfhi k1
sw $0, 0(k0)
sw $1, 4(k0)
sw k1, 120(k0) /* hi */
mflo k1
sw $2, 8(k0)
sw $3, 12(k0)
sw k1, 124(k0) /* lo */
sw $4, 16(k0)
sw $5, 20(k0)
sw $6, 24(k0)
sw $7, 28(k0)
sw $8, 32(k0)
sw $9, 36(k0)
sw $10, 40(k0)
sw $11, 44(k0)
sw $12, 48(k0)
sw $13, 52(k0)
sw $14, 56(k0)
sw $15, 60(k0)
sw $16, 64(k0)
sw $17, 68(k0)
sw $18, 72(k0)
sw $19, 76(k0)
sw $20, 80(k0)
sw $21, 84(k0)
sw $22, 88(k0)
sw $23, 92(k0)
sw $24, 96(k0)
sw $25, 100(k0)
sw $28, 104(k0)
sw $29, 108(k0) /* saved sp */
sw $30, 112(k0)
sw $31, 116(k0) /* saved ra */
move sp, k0
/* save CP0 registers and sp (total 26) */
move k0, sp
addiu k0, k0, -(26*4)
mfc0 $1, CP0_INDEX
mfc0 $2, CP0_RANDOM
mfc0 $3, CP0_ENTRYLO0
mfc0 $4, CP0_ENTRYLO1
mfc0 $5, CP0_CONTEXT
mfc0 $6, CP0_PAGEMASK
mfc0 $7, CP0_WIRED
mfc0 $8, CP0_BADVADDR
mfc0 $9, CP0_ENTRYHI
mfc0 $10, CP0_STATUS
/* mfc0 $11, $12, 1*/ /* IntCtl */
mfc0 $12, CP0_CAUSE
mfc0 $13, CP0_EPC
/* mfc0 $14, $15, 1*/ /* EBase */
mfc0 $15, CP0_CONFIG
/* mfc0 $16, CP0_CONFIG, 7*/ /* Config 7 */
mfc0 $17, CP0_LLADDR
mfc0 $18, CP0_WATCHLO
mfc0 $19, CP0_WATCHHI
mfc0 $20, CP0_DEBUG
mfc0 $21, CP0_DEPC
mfc0 $22, CP0_ECC
mfc0 $23, CP0_TAGLO
mfc0 $24, CP0_ERROREPC
mfc0 $25, CP0_DESAVE
sw $1, 0(k0)
sw $2, 4(k0)
sw $3, 8(k0)
sw $4, 12(k0)
sw $5, 16(k0)
sw $6, 20(k0)
sw $7, 24(k0)
sw $8, 28(k0)
sw $9, 32(k0)
sw $10, 36(k0)
sw $11, 40(k0)
sw $12, 44(k0)
sw $13, 48(k0)
sw $14, 52(k0)
sw $15, 56(k0)
sw $16, 60(k0)
sw $17, 64(k0)
sw $18, 68(k0)
sw $19, 72(k0)
sw $20, 76(k0)
sw $21, 80(k0)
sw $22, 84(k0)
sw $23, 88(k0)
sw $24, 92(k0)
sw $25, 96(k0)
sw $29, 100(k0) /* saved sp */
move sp, k0
/* preserve virtual address of stack */
la k0, suspend_save_sp
sw sp, 0(k0)
/* flush caches and write buffers */
jal jz_flush_cache_all
nop
/* set new sdram refresh constant */
li t0, 1
la t1, EMC_RTCOR
sh t0, 0(t1)
/* disable PLL */
la t0, CPM_PLCR1
sw $0, 0(t0)
/* put CPU to hibernate mode */
la t0, CPM_LPCR
lw t1, 0(t0)
li t2, ~CPM_LPCR_LPM_MASK
and t1, t2
ori t1, CPM_LPCR_LPM_HIBERNATE
.align 5
/* align execution to a cache line */
j 1f
.align 5
1:
/* all needed values are now in registers.
* These last instructions should be in cache
*/
nop
nop
/* set hibernate mode */
sw t1, 0(t0)
nop
/* enter hibernate mode */
.set mips3
wait
nop
.set mips2
2: j 2b /* loop waiting for suspended */
nop
/*
* jz_cpu_resume()
*
* entry point from bootloader into kernel during resume
*/
.align 5
.globl jz_cpu_resume
jz_cpu_resume:
/* clear SCR.HGP */
la t0, CPM_SCR
lw t1, 0(t0)
li t2, ~CPM_SCR_HGP
and t1, t2
sw t1, 0(t0)
/* restore LPCR.LPM to IDLE mode */
la t0, CPM_LPCR
lw t1, 0(t0)
li t2, ~CPM_LPCR_LPM_MASK
and t1, t2
ori t1, CPM_LPCR_LPM_IDLE
sw t1, 0(t0)
/* restore saved sp */
la t0, suspend_save_sp
lw sp, 0(t0)
/* restore CP0 registers */
move k0, sp
lw $1, 0(k0)
lw $2, 4(k0)
lw $3, 8(k0)
lw $4, 12(k0)
lw $5, 16(k0)
lw $6, 20(k0)
lw $7, 24(k0)
lw $8, 28(k0)
lw $9, 32(k0)
lw $10, 36(k0)
lw $11, 40(k0)
lw $12, 44(k0)
lw $13, 48(k0)
lw $14, 52(k0)
lw $15, 56(k0)
lw $16, 60(k0)
lw $17, 64(k0)
lw $18, 68(k0)
lw $19, 72(k0)
lw $20, 76(k0)
lw $21, 80(k0)
lw $22, 84(k0)
lw $23, 88(k0)
lw $24, 92(k0)
lw $25, 96(k0)
lw $29, 100(k0) /* saved sp */
mtc0 $1, CP0_INDEX
mtc0 $2, CP0_RANDOM
mtc0 $3, CP0_ENTRYLO0
mtc0 $4, CP0_ENTRYLO1
mtc0 $5, CP0_CONTEXT
mtc0 $6, CP0_PAGEMASK
mtc0 $7, CP0_WIRED
mtc0 $8, CP0_BADVADDR
mtc0 $9, CP0_ENTRYHI
mtc0 $10, CP0_STATUS
/* mtc0 $11, $12, 1*/ /* IntCtl */
mtc0 $12, CP0_CAUSE
mtc0 $13, CP0_EPC
/* mtc0 $14, $15, 1*/ /* EBase */
mtc0 $15, CP0_CONFIG
/* mtc0 $16, CP0_CONFIG, 7*/ /* Config 7 */
mtc0 $17, CP0_LLADDR
mtc0 $18, CP0_WATCHLO
mtc0 $19, CP0_WATCHHI
mtc0 $20, CP0_DEBUG
mtc0 $21, CP0_DEPC
mtc0 $22, CP0_ECC
mtc0 $23, CP0_TAGLO
mtc0 $24, CP0_ERROREPC
mtc0 $25, CP0_DESAVE
/* restore general registers */
move k0, sp
lw k1, 120(k0) /* hi */
lw $0, 0(k0)
lw $1, 4(k0)
mthi k1
lw k1, 124(k0) /* lo */
lw $2, 8(k0)
lw $3, 12(k0)
mtlo k1
lw $4, 16(k0)
lw $5, 20(k0)
lw $6, 24(k0)
lw $7, 28(k0)
lw $8, 32(k0)
lw $9, 36(k0)
lw $10, 40(k0)
lw $11, 44(k0)
lw $12, 48(k0)
lw $13, 52(k0)
lw $14, 56(k0)
lw $15, 60(k0)
lw $16, 64(k0)
lw $17, 68(k0)
lw $18, 72(k0)
lw $19, 76(k0)
lw $20, 80(k0)
lw $21, 84(k0)
lw $22, 88(k0)
lw $23, 92(k0)
lw $24, 96(k0)
lw $25, 100(k0)
lw $28, 104(k0)
lw $29, 108(k0) /* saved sp */
lw $30, 112(k0)
lw $31, 116(k0) /* saved ra */
/* return to caller */
jr ra
nop
suspend_save_sp:
.word 0 /* preserve sp here */
.set reorder

View File

@@ -0,0 +1,129 @@
/*
* linux/arch/mips/jz4730/time.c
*
* Setting up the clock on the JZ4730 boards.
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
#define JZ_TIMER_CHAN 0
#define JZ_TIMER_IRQ IRQ_OST0
#define JZ_TIMER_CLOCK JZ_EXTAL
static unsigned int timer_latch;
void (*jz_timer_callback)(void);
static void jz_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}
static struct clock_event_device jz_clockevent_device = {
.name = "jz-timer",
.features = CLOCK_EVT_FEAT_PERIODIC,
/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
.rating = 300,
.irq = JZ_TIMER_IRQ,
.set_mode = jz_set_mode,
};
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = dev_id;
__ost_clear_uf(JZ_TIMER_CHAN); /* ACK timer */
if (jz_timer_callback)
jz_timer_callback();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction jz_irqaction = {
.handler = jz_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU,
.name = "jz-timer",
};
cycle_t jz_get_cycles(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();
}

View File

@@ -0,0 +1,26 @@
#
# Makefile for the Ingenic JZ4740.
#
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
platform.o i2c.o
obj-$(CONFIG_PROC_FS) += proc.o
# board specific support
obj-$(CONFIG_JZ4740_PAVO) += board-pavo.o
obj-$(CONFIG_JZ4740_LEO) += board-leo.o
obj-$(CONFIG_JZ4740_LYRA) += board-lyra.o
obj-$(CONFIG_JZ4725_DIPPER) += board-dipper.o
obj-$(CONFIG_JZ4720_VIRGO) += board-virgo.o
# PM support
obj-$(CONFIG_PM) +=pm.o
# CPU Frequency scaling support
obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o

View File

@@ -0,0 +1,117 @@
/*
* linux/arch/mips/jz4740/board-dipper.c
*
* JZ4725 Dipper board setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
#if 0
static void dancing(void)
{
static unsigned int count = 0;
count ++;
count &= 1;
if (count)
__gpio_set_pin(GPIO_LED_EN);
else
__gpio_clear_pin(GPIO_LED_EN);
}
#endif
static void dipper_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
// dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4740/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Most of the GPIO pins should have been initialized by the boot-loader
*/
/*
* Initialize MSC pins
*/
__gpio_as_msc();
/*
* Initialize Smart LCD pins
*/
// __gpio_as_slcd_18bit();
/*
* Initialize SSI pins
*/
__gpio_as_ssi();
/*
* Initialize I2C pins
*/
__gpio_as_i2c();
/*
* Initialize Other pins
*/
__gpio_as_output(GPIO_SD_VCC_EN_N);
__gpio_clear_pin(GPIO_SD_VCC_EN_N);
__gpio_as_input(GPIO_SD_CD_N);
__gpio_disable_pull(GPIO_SD_CD_N);
__gpio_as_input(GPIO_SD_WP);
__gpio_disable_pull(GPIO_SD_WP);
__gpio_as_input(GPIO_DC_DETE_N);
__gpio_as_input(GPIO_CHARG_STAT_N);
__gpio_as_input(GPIO_USB_DETE);
__gpio_as_output(GPIO_DISP_OFF_N);
// __gpio_as_output(GPIO_LED_EN);
}
void __init jz_board_setup(void)
{
printk("JZ4725 DIPPER board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = dipper_timer_callback;
}

View File

@@ -0,0 +1,67 @@
/*
* linux/arch/mips/jz4740/board-leo.c
*
* JZ4740 LEO board setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned char slash[] = "\\|/-";
static volatile unsigned char *p = (unsigned char *)0xb6000016;
static unsigned int count = 0;
*p = slash[count++];
count &= 3;
}
static void leo_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 10 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4740/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/* All GPIO pins should have been initialized by the boot-loader */
}
void __init jz_board_setup(void)
{
board_cpm_setup();
board_gpio_setup();
printk(" BOARD SETUP");
jz_timer_callback = leo_timer_callback;
}

View File

@@ -0,0 +1,114 @@
/*
* linux/arch/mips/jz4740/board-lyra.c
*
* JZ4740 LYRA board setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned int count = 0;
count ++;
count &= 1;
if (count)
__gpio_set_pin(GPIO_LED_EN);
else
__gpio_clear_pin(GPIO_LED_EN);
}
static void lyra_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4740/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Most of the GPIO pins should have been initialized by the boot-loader
*/
/*
* Initialize MSC pins
*/
__gpio_as_msc();
/*
* Initialize LCD pins
*/
__gpio_as_lcd_18bit();
/*
* Initialize SSI pins
*/
__gpio_as_ssi();
/*
* Initialize I2C pins
*/
__gpio_as_i2c();
/*
* Initialize Other pins
*/
__gpio_as_output(GPIO_SD_VCC_EN_N);
__gpio_clear_pin(GPIO_SD_VCC_EN_N);
__gpio_as_input(GPIO_SD_CD_N);
__gpio_disable_pull(GPIO_SD_CD_N);
__gpio_as_input(GPIO_SD_WP);
__gpio_disable_pull(GPIO_SD_WP);
__gpio_as_input(GPIO_DC_DETE_N);
__gpio_as_input(GPIO_CHARG_STAT_N);
__gpio_as_input(GPIO_USB_DETE);
__gpio_as_output(GPIO_DISP_OFF_N);
__gpio_as_output(GPIO_LED_EN);
}
void __init jz_board_setup(void)
{
printk("JZ4740 LYRA board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = lyra_timer_callback;
}

View File

@@ -0,0 +1,114 @@
/*
* linux/arch/mips/jz4740/board-pavo.c
*
* JZ4740 PAVO board setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned int count = 0;
count ++;
count &= 1;
if (count)
__gpio_set_pin(GPIO_LED_EN);
else
__gpio_clear_pin(GPIO_LED_EN);
}
static void pavo_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4740/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Most of the GPIO pins should have been initialized by the boot-loader
*/
/*
* Initialize MSC pins
*/
__gpio_as_msc();
/*
* Initialize LCD pins
*/
__gpio_as_lcd_18bit();
/*
* Initialize SSI pins
*/
__gpio_as_ssi();
/*
* Initialize I2C pins
*/
__gpio_as_i2c();
/*
* Initialize Other pins
*/
__gpio_as_output(GPIO_SD_VCC_EN_N);
__gpio_clear_pin(GPIO_SD_VCC_EN_N);
__gpio_as_input(GPIO_SD_CD_N);
__gpio_disable_pull(GPIO_SD_CD_N);
__gpio_as_input(GPIO_SD_WP);
__gpio_disable_pull(GPIO_SD_WP);
__gpio_as_input(GPIO_DC_DETE_N);
__gpio_as_input(GPIO_CHARG_STAT_N);
__gpio_as_input(GPIO_USB_DETE);
__gpio_as_output(GPIO_DISP_OFF_N);
__gpio_as_output(GPIO_LED_EN);
}
void __init jz_board_setup(void)
{
printk("JZ4740 PAVO board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = pavo_timer_callback;
}

View File

@@ -0,0 +1,114 @@
/*
* linux/arch/mips/jz4740/board-virgo.c
*
* JZ4720 VIRGO board setup routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned int count = 0;
count ++;
count &= 1;
if (count)
__gpio_set_pin(GPIO_LED_EN);
else
__gpio_clear_pin(GPIO_LED_EN);
}
static void virgo_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4740/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Most of the GPIO pins should have been initialized by the boot-loader
*/
/*
* Initialize MSC pins
*/
__gpio_as_msc();
/*
* Initialize LCD pins
*/
// __gpio_as_lcd_18bit();
/*
* Initialize SSI pins
*/
__gpio_as_ssi();
/*
* Initialize I2C pins
*/
__gpio_as_i2c();
/*
* Initialize Other pins
*/
__gpio_as_output(GPIO_SD_VCC_EN_N);
__gpio_clear_pin(GPIO_SD_VCC_EN_N);
__gpio_as_input(GPIO_SD_CD_N);
__gpio_disable_pull(GPIO_SD_CD_N);
// __gpio_as_input(GPIO_SD_WP);
// __gpio_disable_pull(GPIO_SD_WP);
__gpio_as_input(GPIO_DC_DETE_N);
// __gpio_as_input(GPIO_CHARG_STAT_N);
__gpio_as_input(GPIO_USB_DETE);
__gpio_as_output(GPIO_DISP_OFF_N);
// __gpio_as_output(GPIO_LED_EN);
}
void __init jz_board_setup(void)
{
printk("JZ4720 VIRGO board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = virgo_timer_callback;
}

View File

@@ -0,0 +1,602 @@
/*
* linux/arch/mips/jz4740/cpufreq.c
*
* cpufreq driver for JZ4740
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <asm/jzsoc.h>
#include <asm/processor.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"cpufreq-jz4740", msg)
#undef CHANGE_PLL
#define PLL_UNCHANGED 0
#define PLL_GOES_UP 1
#define PLL_GOES_DOWN 2
#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
/* Saved the boot-time parameters */
static struct {
/* SDRAM parameters */
unsigned int mclk; /* memory clock, KHz */
unsigned int tras; /* RAS pulse width, cycles of mclk */
unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
unsigned int tpc; /* RAS Precharge time, cycles of mclk */
unsigned int trwl; /* Write Precharge Time, cycles of mclk */
unsigned int trc; /* RAS Cycle Time, cycles of mclk */
unsigned int rtcor; /* Refresh Time Constant */
unsigned int sdram_initialized;
/* LCD parameters */
unsigned int lcd_clk; /* LCD clock, Hz */
unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
unsigned int lcd_clks_initialized;
} boot_config;
struct jz4740_freq_percpu_info {
struct cpufreq_frequency_table table[7];
};
static struct jz4740_freq_percpu_info jz4740_freq_table;
/*
* This contains the registers value for an operating point.
* If only part of a register needs to change then there is
* a mask value for that register.
* When going to a new operating point the current register
* value is ANDed with the ~mask and ORed with the new value.
*/
struct dpm_regs {
u32 cpccr; /* Clock Freq Control Register */
u32 cpccr_mask; /* Clock Freq Control Register mask */
u32 cppcr; /* PLL1 Control Register */
u32 cppcr_mask; /* PLL1 Control Register mask */
u32 pll_up_flag; /* New PLL freq is higher than current or not */
};
extern jz_clocks_t jz_clocks;
static void jz_update_clocks(void)
{
/* Next clocks must be updated if we have changed
* the PLL or divisors.
*/
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.lcdclk = __cpm_get_lcdclk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk();
}
static void
jz_init_boot_config(void)
{
if (!boot_config.lcd_clks_initialized) {
/* the first time to scale pll */
boot_config.lcd_clk = __cpm_get_lcdclk();
boot_config.lcdpix_clk = __cpm_get_pixclk();
boot_config.lcd_clks_initialized = 1;
}
if (!boot_config.sdram_initialized) {
/* the first time to scale frequencies */
unsigned int dmcr, rtcor;
unsigned int tras, rcd, tpc, trwl, trc;
dmcr = REG_EMC_DMCR;
rtcor = REG_EMC_RTCOR;
tras = (dmcr >> 13) & 0x7;
rcd = (dmcr >> 11) & 0x3;
tpc = (dmcr >> 8) & 0x7;
trwl = (dmcr >> 5) & 0x3;
trc = (dmcr >> 2) & 0x7;
boot_config.mclk = __cpm_get_mclk() / 1000;
boot_config.tras = tras + 4;
boot_config.rcd = rcd + 1;
boot_config.tpc = tpc + 1;
boot_config.trwl = trwl + 1;
boot_config.trc = trc * 2 + 1;
boot_config.rtcor = rtcor;
boot_config.sdram_initialized = 1;
}
}
static void jz_update_dram_rtcor(unsigned int new_mclk)
{
unsigned int rtcor;
new_mclk /= 1000;
rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
rtcor--;
if (rtcor < 1) rtcor = 1;
if (rtcor > 255) rtcor = 255;
REG_EMC_RTCOR = rtcor;
REG_EMC_RTCNT = rtcor;
}
static void jz_update_dram_dmcr(unsigned int new_mclk)
{
unsigned int dmcr;
unsigned int tras, rcd, tpc, trwl, trc;
unsigned int valid_time, new_time; /* ns */
new_mclk /= 1000;
tras = boot_config.tras * new_mclk / boot_config.mclk;
rcd = boot_config.rcd * new_mclk / boot_config.mclk;
tpc = boot_config.tpc * new_mclk / boot_config.mclk;
trwl = boot_config.trwl * new_mclk / boot_config.mclk;
trc = boot_config.trc * new_mclk / boot_config.mclk;
/* Validation checking */
valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
new_time = (tras * 1000000) / new_mclk;
if (new_time < valid_time) tras += 1;
valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
new_time = (rcd * 1000000) / new_mclk;
if (new_time < valid_time) rcd += 1;
valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
new_time = (tpc * 1000000) / new_mclk;
if (new_time < valid_time) tpc += 1;
valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
new_time = (trwl * 1000000) / new_mclk;
if (new_time < valid_time) trwl += 1;
valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
new_time = (trc * 1000000) / new_mclk;
if (new_time < valid_time) trc += 2;
tras = (tras < 4) ? 4: tras;
tras = (tras > 11) ? 11: tras;
tras -= 4;
rcd = (rcd < 1) ? 1: rcd;
rcd = (rcd > 4) ? 4: rcd;
rcd -= 1;
tpc = (tpc < 1) ? 1: tpc;
tpc = (tpc > 8) ? 8: tpc;
tpc -= 1;
trwl = (trwl < 1) ? 1: trwl;
trwl = (trwl > 4) ? 4: trwl;
trwl -= 1;
trc = (trc < 1) ? 1: trc;
trc = (trc > 15) ? 15: trc;
trc /= 2;
dmcr = REG_EMC_DMCR;
dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
REG_EMC_DMCR = dmcr;
}
static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
* and TRC of DMCR before changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
} else {
/* We're going SLOWER: first update RTCOR value
* before changing the frequency.
*/
jz_update_dram_rtcor(new_mclk);
}
}
static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so update RTCOR
* after changing the frequency
*/
jz_update_dram_rtcor(new_mclk);
} else {
/* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
* and TRC of DMCR after changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
}
}
static void jz_scale_divisors(struct dpm_regs *regs)
{
unsigned int cpccr;
unsigned int cur_mclk, new_mclk;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
cpccr = REG_CPM_CPCCR;
cpccr &= ~((unsigned long)regs->cpccr_mask);
cpccr |= regs->cpccr;
cpccr |= CPM_CPCCR_CE; /* update immediately */
cur_mclk = __cpm_get_mclk();
new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
/* Update some DRAM parameters before changing frequency */
jz_update_dram_prev(cur_mclk, new_mclk);
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#ifdef CHANGE_PLL
/* Maintain the LCD clock and pixel clock */
static void jz_scale_lcd_divisors(struct dpm_regs *regs)
{
unsigned int new_pll, new_lcd_div, new_lcdpix_div;
unsigned int cpccr;
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
if (!boot_config.lcd_clks_initialized) return;
new_pll = __cpm_get_pllout();
new_lcd_div = new_pll / boot_config.lcd_clk;
new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
if (new_lcd_div < 1)
new_lcd_div = 1;
if (new_lcd_div > 16)
new_lcd_div = 16;
if (new_lcdpix_div < 1)
new_lcdpix_div = 1;
if (new_lcdpix_div > 512)
new_lcdpix_div = 512;
// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
cpccr = REG_CPM_CPCCR;
cpccr &= ~CPM_CPCCR_LDIV_MASK;
cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
cpccr |= CPM_CPCCR_CE; /* update immediately */
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
}
static void jz_scale_pll(struct dpm_regs *regs)
{
unsigned int cppcr;
unsigned int cur_mclk, new_mclk, new_pll;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
int od[] = {1, 2, 2, 4};
cppcr = REG_CPM_CPPCR;
cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
regs->cppcr &= ~CPM_CPPCR_PLLEN;
cppcr |= (regs->cppcr | 0xff);
/* Update some DRAM parameters before changing frequency */
new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
cur_mclk = __cpm_get_mclk();
new_mclk = new_pll / div[(REG_CPM_CPCCR>>CPM_CPCCR_MDIV_BIT) & 0xf];
/*
* Update some SDRAM parameters
*/
jz_update_dram_prev(cur_mclk, new_mclk);
/*
* Update PLL, align code to cache line.
*/
cppcr |= CPM_CPPCR_PLLEN;
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPPCR), "r" (cppcr));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#endif
static void jz4740_transition(struct dpm_regs *regs)
{
/*
* Get and save some boot-time conditions.
*/
jz_init_boot_config();
#ifdef CHANGE_PLL
/*
* Disable LCD before scaling pll.
* LCD and LCD pixel clocks should not be changed even if the PLL
* output frequency has been changed.
*/
REG_LCD_CTRL &= ~LCD_CTRL_ENA;
/*
* Stop module clocks before scaling PLL
*/
__cpm_stop_eth();
__cpm_stop_aic(1);
__cpm_stop_aic(2);
#endif
/* ... add more as necessary */
if (regs->pll_up_flag == PLL_GOES_UP) {
/* the pll frequency is going up, so change dividors first */
jz_scale_divisors(regs);
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
}
else if (regs->pll_up_flag == PLL_GOES_DOWN) {
/* the pll frequency is going down, so change pll first */
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
jz_scale_divisors(regs);
}
else {
/* the pll frequency is unchanged, so change divisors only */
jz_scale_divisors(regs);
}
#ifdef CHANGE_PLL
/*
* Restart module clocks before scaling PLL
*/
__cpm_start_eth();
__cpm_start_aic(1);
__cpm_start_aic(2);
/* ... add more as necessary */
/* Scale the LCD divisors after scaling pll */
if (regs->pll_up_flag != PLL_UNCHANGED) {
jz_scale_lcd_divisors(regs);
}
/* Enable LCD controller */
REG_LCD_CTRL &= ~LCD_CTRL_DIS;
REG_LCD_CTRL |= LCD_CTRL_ENA;
#endif
/* Update system clocks */
jz_update_clocks();
}
extern unsigned int idle_times;
static unsigned int jz4740_freq_get(unsigned int cpu)
{
return (__cpm_get_cclk() / 1000);
}
static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
{
int n2FR[33] = {
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
9
};
int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
unsigned int div_of_cclk, new_freq, i;
regs->pll_up_flag = PLL_UNCHANGED;
regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
new_freq = jz4740_freq_table.table[index].frequency;
do {
div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
} while (div_of_cclk==0);
if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
for(i = 1; i<4; i++) {
div[i] = 3;
}
} else {
for(i = 1; i<4; i++) {
div[i] = 2;
}
}
for(i = 0; i<4; i++) {
div[i] *= div_of_cclk;
}
dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
regs->cpccr =
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
return div_of_cclk;
}
static void jz4740_set_cpu_divider_index(unsigned int cpu, unsigned int index)
{
unsigned long divisor, old_divisor;
struct cpufreq_freqs freqs;
struct dpm_regs regs;
old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
divisor = index_to_divisor(index, &regs);
freqs.old = __cpm_get_cclk() / 1000;
freqs.new = __cpm_get_pllout() / (1000 * divisor);
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor)
jz4740_transition(&regs);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int jz4740_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy,
&jz4740_freq_table.table[0],
target_freq, relation, &new_index))
return -EINVAL;
jz4740_set_cpu_divider_index(policy->cpu, new_index);
dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
return 0;
}
static int jz4740_freq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
&jz4740_freq_table.table[0]);
}
static int __init jz4740_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *table = &jz4740_freq_table.table[0];
unsigned int MAX_FREQ;
dprintk(KERN_INFO "Jz4740 cpufreq driver\n");
if (policy->cpu != 0)
return -EINVAL;
policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = MAX_FREQ/8;
policy->cpuinfo.max_freq = MAX_FREQ;
policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
table[0].index = 0;
table[0].frequency = MAX_FREQ/8;
table[1].index = 1;
table[1].frequency = MAX_FREQ/6;
table[2].index = 2;
table[2].frequency = MAX_FREQ/4;
table[3].index = 3;
table[3].frequency = MAX_FREQ/3;
table[4].index = 4;
table[4].frequency = MAX_FREQ/2;
table[5].index = 5;
table[5].frequency = MAX_FREQ;
table[6].index = 6;
table[6].frequency = CPUFREQ_TABLE_END;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
#endif
return cpufreq_frequency_table_cpuinfo(policy, table);
}
static struct cpufreq_driver cpufreq_jz4740_driver = {
// .flags = CPUFREQ_STICKY,
.init = jz4740_cpufreq_driver_init,
.verify = jz4740_freq_verify,
.target = jz4740_freq_target,
.get = jz4740_freq_get,
.name = "jz4740",
};
static int __init jz4740_cpufreq_init(void)
{
return cpufreq_register_driver(&cpufreq_jz4740_driver);
}
static void __exit jz4740_cpufreq_exit(void)
{
cpufreq_unregister_driver(&cpufreq_jz4740_driver);
}
module_init(jz4740_cpufreq_init);
module_exit(jz4740_cpufreq_exit);
MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
MODULE_DESCRIPTION("cpufreq driver for Jz4740");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,768 @@
/*
* linux/arch/mips/jz4740/dma.c
*
* Support functions for the JZ4740 internal DMA channels.
* No-descriptor transfer only.
* Descriptor transfer should also call jz_request_dma() to get a free
* channel and call jz_free_dma() to free the channel. And driver should
* build the DMA descriptor and setup the DMA channel by itself.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/soundcard.h>
#include <asm/system.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/*
* A note on resource allocation:
*
* All drivers needing DMA channels, should allocate and release them
* through the public routines `jz_request_dma()' and `jz_free_dma()'.
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
*
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
* When releasing them, first release the IRQ, then release the DMA. The
* main reason for this order is that, if you are requesting the DMA buffer
* done interrupt, you won't know the irq number until the DMA channel is
* returned from jz_request_dma().
*/
struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
};
// Device FIFO addresses and default DMA modes
static const struct {
unsigned int fifo_addr;
unsigned int dma_mode;
unsigned int dma_source;
} dma_dev_table[DMA_ID_MAX] = {
{CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
{CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
{CPHYSADDR(SSI_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT},
{CPHYSADDR(SSI_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSIIN},
{CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
{CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
{CPHYSADDR(MSC_TXFIFO), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT},
{CPHYSADDR(MSC_RXFIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSCIN},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
{},
};
int jz_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data)
{
int i, len = 0;
struct jz_dma_chan *chan;
for (i = 0; i < MAX_DMA_NUM; i++) {
if ((chan = get_dma_chan(i)) != NULL) {
len += sprintf(buf + len, "%2d: %s\n",
i, chan->dev_str);
}
}
if (fpos >= len) {
*start = buf;
*eof = 1;
return 0;
}
*start = buf + fpos;
if ((len -= fpos) > length)
return length;
*eof = 1;
return len;
}
void dump_jz_dma_channel(unsigned int dmanr)
{
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return;
chan = &jz_dma_table[dmanr];
printk("DMA%d Registers:\n", dmanr);
printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR);
printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR);
}
/**
* jz_request_dma - dynamically allcate an idle DMA channel to return
* @dev_id: the specified dma device id or DMA_ID_RAW_SET
* @dev_str: the specified dma device string name
* @irqhandler: the irq handler, or NULL
* @irqflags: the irq handler flags
* @irq_dev_id: the irq handler device id for shared irq
*
* Finds a free channel, and binds the requested device to it.
* Returns the allocated channel number, or negative on error.
* Requests the DMA done IRQ if irqhandler != NULL.
*
*/
/*int jz_request_dma(int dev_id, const char *dev_str,
void (*irqhandler)(int, void *, struct pt_regs *),
unsigned long irqflags,
void *irq_dev_id)
*/
int jz_request_dma(int dev_id, const char *dev_str,
irqreturn_t (*irqhandler)(int, void *),
unsigned long irqflags,
void *irq_dev_id)
{
struct jz_dma_chan *chan;
int i, ret;
if (dev_id < 0 || dev_id >= DMA_ID_MAX)
return -EINVAL;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM) /* no free channel */
return -ENODEV;
/* we got a free channel */
chan = &jz_dma_table[i];
if (irqhandler) {
chan->irq = IRQ_DMA_0 + i; // allocate irq number
chan->irq_dev = irq_dev_id;
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
dev_str, chan->irq_dev))) {
chan->irq = -1;
chan->irq_dev = NULL;
return ret;
}
} else {
chan->irq = -1;
chan->irq_dev = NULL;
}
// fill it in
chan->io = i;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
chan->mode = dma_dev_table[dev_id].dma_mode;
chan->source = dma_dev_table[dev_id].dma_source;
return i;
}
void jz_free_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan) {
printk("Trying to free DMA%d\n", dmanr);
return;
}
disable_dma(dmanr);
if (chan->irq)
free_irq(chan->irq, chan->irq_dev);
chan->irq = -1;
chan->irq_dev = NULL;
chan->dev_id = -1;
}
void jz_set_dma_dest_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_DWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_DWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_DWDH_32;
break;
}
}
void jz_set_dma_src_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_SWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_SWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_SWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_SWDH_32;
break;
}
}
void jz_set_dma_block_size(int dmanr, int nbyte)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DS_MASK;
switch (nbyte) {
case 1:
chan->mode |= DMAC_DCMD_DS_8BIT;
break;
case 2:
chan->mode |= DMAC_DCMD_DS_16BIT;
break;
case 4:
chan->mode |= DMAC_DCMD_DS_32BIT;
break;
case 16:
chan->mode |= DMAC_DCMD_DS_16BYTE;
break;
case 32:
chan->mode |= DMAC_DCMD_DS_32BYTE;
break;
}
}
unsigned int jz_get_dma_command(int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
return chan->mode;
}
/**
* jz_set_dma_mode - do the raw settings for the specified DMA channel
* @dmanr: the specified DMA channel
* @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
* @dma_mode: dma raw mode
* @dma_source: dma raw request source
* @fifo_addr: dma raw device fifo address
*
* Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
* jz_set_dma_mode() rather than set_dma_mode() if you work with
* and external request dma device.
*
* NOTE: Don not dynamically allocate dma channel if one external request
* dma device will occupy this channel.
*/
int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
unsigned int dma_mode, unsigned int dma_source,
unsigned int fifo_addr)
{
int dev_id, i;
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return -ENODEV;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM)
return -ENODEV;
chan = &jz_dma_table[dmanr];
dev_id = chan->dev_id;
if (dev_id > 0) {
printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
__FUNCTION__, dmanr);
return -ENODEV;
}
/* clone it from the dynamically allocated. */
if (i != dmanr) {
chan->irq = jz_dma_table[i].irq;
chan->irq_dev = jz_dma_table[i].irq_dev;
chan->dev_str = jz_dma_table[i].dev_str;
jz_dma_table[i].irq = 0;
jz_dma_table[i].irq_dev = NULL;
jz_dma_table[i].dev_id = -1;
}
chan->dev_id = DMA_ID_RAW_SET;
chan->io = dmanr;
chan->fifo_addr = fifo_addr;
chan->mode = dma_mode;
chan->source = dma_source;
set_dma_mode(dmanr, dma_mode);
return dmanr;
}
void enable_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
__dmac_enable_channel(dmanr);
if (chan->irq)
__dmac_channel_enable_irq(dmanr);
}
#define DMA_DISABLE_POLL 0x10000
void disable_dma(unsigned int dmanr)
{
int i;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
if (!__dmac_channel_enabled(dmanr))
return;
for (i = 0; i < DMA_DISABLE_POLL; i++)
if (__dmac_channel_transmit_end_detected(dmanr))
break;
#if 0
if (i == DMA_DISABLE_POLL)
printk(KERN_INFO "disable_dma: poll expired!\n");
#endif
__dmac_disable_channel(dmanr);
if (chan->irq)
__dmac_channel_disable_irq(dmanr);
}
/* Note: DMA_MODE_MASK is simulated by sw */
void set_dma_mode(unsigned int dmanr, unsigned int mode)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else {
printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
}
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
}
void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
{
unsigned int mode;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode = chan->mode & DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
REG_DMAC_DTAR(chan->io) = phyaddr;
} else if (mode == DMA_MODE_WRITE) {
REG_DMAC_DSAR(chan->io) = phyaddr;
REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
} else
printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
}
void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
int dma_ds[] = {4, 1, 2, 16, 32};
unsigned int ds;
if (!chan)
return;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
}
unsigned int get_dma_residue(unsigned int dmanr)
{
unsigned int count, ds;
int dma_ds[] = {4, 1, 2, 16, 32};
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
count = REG_DMAC_DTCR(chan->io);
count = count * dma_ds[ds];
return count;
}
void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case AFMT_U8:
/* burst mode : 32BIT */
break;
case AFMT_S16_LE:
/* burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case 8:
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
break;
case 16:
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
#undef JZ4740_DMAC_TEST_ENABLE
#ifdef JZ4740_DMAC_TEST_ENABLE
/*
* DMA test: external address <--> external address
*/
#define TEST_DMA_SIZE 16*1024
static jz_dma_desc *dma_desc;
static int dma_chan;
static dma_addr_t dma_desc_phys_addr;
static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
static int dma_check_result(void *src, void *dst, int size)
{
unsigned int addr1, addr2, i, err = 0;
addr1 = (unsigned int)src;
addr2 = (unsigned int)dst;
for (i = 0; i < size; i += 4) {
if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
err++;
printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
}
addr1 += 4;
addr2 += 4;
}
printk("check DMA result err=%d\n", err);
return err;
}
static void jz4740_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
{
printk("jz4740_dma_irq %d\n", irq);
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
if (__dmac_channel_transmit_halt_detected(dma_chan)) {
printk("DMA HALT\n");
__dmac_channel_clear_transmit_halt(dma_chan);
}
if (__dmac_channel_address_error_detected(dma_chan)) {
printk("DMA ADDR ERROR\n");
__dmac_channel_clear_address_error(dma_chan);
}
if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
printk("DMA DESC INVALID\n");
__dmac_channel_clear_descriptor_invalid(dma_chan);
}
if (__dmac_channel_count_terminated_detected(dma_chan)) {
printk("DMA CT\n");
__dmac_channel_clear_count_terminated(dma_chan);
}
if (__dmac_channel_transmit_end_detected(dma_chan)) {
printk("DMA TT\n");
__dmac_channel_clear_transmit_end(dma_chan);
dump_jz_dma_channel(dma_chan);
dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
}
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
void dma_nodesc_test(void)
{
unsigned int addr, i;
printk("dma_nodesc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq,
SA_INTERRUPT, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Init DMA module */
printk("Starting DMA\n");
REG_DMAC_DMACR = 0;
REG_DMAC_DCCSR(dma_chan) = 0;
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
REG_DMAC_DTCR(dma_chan) = 512;
REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
}
void dma_desc_test(void)
{
unsigned int next, addr, i;
static jz_dma_desc *desc;
printk("dma_desc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq,
SA_INTERRUPT, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Allocate DMA descriptors */
dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
/* Setup DMA descriptors */
desc = dma_desc;
next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr; /* DMA source address */
desc->dtadr = dma_dst_phys_addr; /* DMA target address */
desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
/* Setup DMA descriptor address */
REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
/* Setup request source */
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
/* Setup DMA channel control/status register */
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
/* Enable DMA */
REG_DMAC_DMACR = DMAC_DMACR_DMAE;
/* DMA doorbell set -- start DMA now ... */
REG_DMAC_DMADBSR = 1 << dma_chan;
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
}
#endif
//EXPORT_SYMBOL_NOVERS(jz_dma_table);
EXPORT_SYMBOL(jz_dma_table);
EXPORT_SYMBOL(jz_request_dma);
EXPORT_SYMBOL(jz_free_dma);
EXPORT_SYMBOL(jz_set_dma_src_width);
EXPORT_SYMBOL(jz_set_dma_dest_width);
EXPORT_SYMBOL(jz_set_dma_block_size);
EXPORT_SYMBOL(jz_set_dma_mode);
EXPORT_SYMBOL(set_dma_mode);
EXPORT_SYMBOL(jz_set_oss_dma);
EXPORT_SYMBOL(jz_set_alsa_dma);
EXPORT_SYMBOL(set_dma_addr);
EXPORT_SYMBOL(set_dma_count);
EXPORT_SYMBOL(get_dma_residue);
EXPORT_SYMBOL(enable_dma);
EXPORT_SYMBOL(disable_dma);
EXPORT_SYMBOL(dump_jz_dma_channel);

View File

@@ -0,0 +1,273 @@
/*
* linux/arch/mips/jz4740/i2c.c
*
* Jz4740 I2C routines.
*
* Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/* I2C protocol */
#define I2C_READ 1
#define I2C_WRITE 0
#define TIMEOUT 1000
/*
* I2C bus protocol basic routines
*/
static int i2c_put_data(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (!__i2c_received_ack() && timeout)
timeout--;
if (timeout)
return 0;
else
return -ETIMEDOUT;
}
#ifdef CONFIG_JZ_TPANEL_ATA2508
static int i2c_put_data_nack(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (timeout--);
return 0;
}
#endif
static int i2c_get_data(unsigned char *data, int ack)
{
int timeout = TIMEOUT*10;
if (!ack)
__i2c_send_nack();
else
__i2c_send_ack();
while (__i2c_check_drf() == 0 && timeout)
timeout--;
if (timeout) {
if (!ack)
__i2c_send_stop();
*data = __i2c_read();
__i2c_clear_drf();
return 0;
} else
return -ETIMEDOUT;
}
/*
* I2C interface
*/
void i2c_open(void)
{
__i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
__i2c_enable();
}
void i2c_close(void)
{
udelay(300); /* wait for STOP goes over. */
__i2c_disable();
}
void i2c_setclk(unsigned int i2cclk)
{
__i2c_set_clk(jz_clocks.extalclk, i2cclk);
}
int i2c_lseek(unsigned char device, unsigned char offset)
{
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data(offset) < 0)
goto address_err;
return 0;
device_err:
printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
__i2c_send_stop();
return -ENODEV;
address_err:
printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
__i2c_send_stop();
return -EREMOTEIO;
}
int i2c_read(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int timeout = 5;
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data(address) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddr;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddr = address;
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
#ifdef CONFIG_JZ_TPANEL_ATA2508
if (address == 0xff) {
if (i2c_put_data_nack(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data_nack(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
else {
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
#else
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
#endif
__i2c_send_stop();
return count - cnt;
device_err:
address_err:
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
EXPORT_SYMBOL(i2c_open);
EXPORT_SYMBOL(i2c_close);
EXPORT_SYMBOL(i2c_setclk);
EXPORT_SYMBOL(i2c_read);
EXPORT_SYMBOL(i2c_write);

View File

@@ -0,0 +1,265 @@
/*
* linux/arch/mips/jz4740/irq.c
*
* JZ4740 interrupt routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
/*
* INTC irq type
*/
static void enable_intc_irq(unsigned int irq)
{
__intc_unmask_irq(irq);
}
static void disable_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
}
static void mask_and_ack_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
__intc_ack_irq(irq);
}
static void end_intc_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
enable_intc_irq(irq);
}
}
static unsigned int startup_intc_irq(unsigned int irq)
{
enable_intc_irq(irq);
return 0;
}
static void shutdown_intc_irq(unsigned int irq)
{
disable_intc_irq(irq);
}
static struct irq_chip intc_irq_type = {
.typename = "INTC",
.startup = startup_intc_irq,
.shutdown = shutdown_intc_irq,
.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<<irq);
irq = plat_real_irq(irq);
do_IRQ(irq);
}

View File

@@ -0,0 +1,169 @@
/*
* Platform device support for Jz4740 SoC.
*
* Copyright 2007, <yliu@ingenic.cn>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <asm/jzsoc.h>
/* OHCI (USB full speed host controller) */
static struct resource jz_usb_ohci_resources[] = {
[0] = {
.start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
.end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UHC,
.end = IRQ_UHC,
.flags = IORESOURCE_IRQ,
},
};
/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;
static struct platform_device jz_usb_ohci_device = {
.name = "jz-ohci",
.id = 0,
.dev = {
.dma_mask = &ohci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
.resource = jz_usb_ohci_resources,
};
/*** LCD controller ***/
static struct resource jz_lcd_resources[] = {
[0] = {
.start = CPHYSADDR(LCD_BASE),
.end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_lcd_dmamask = ~(u32)0;
static struct platform_device jz_lcd_device = {
.name = "jz-lcd",
.id = 0,
.dev = {
.dma_mask = &jz_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_lcd_resources),
.resource = jz_lcd_resources,
};
/* UDC (USB gadget controller) */
static struct resource jz_usb_gdt_resources[] = {
[0] = {
.start = CPHYSADDR(UDC_BASE),
.end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UDC,
.end = IRQ_UDC,
.flags = IORESOURCE_IRQ,
},
};
static u64 udc_dmamask = ~(u32)0;
static struct platform_device jz_usb_gdt_device = {
.name = "jz-udc",
.id = 0,
.dev = {
.dma_mask = &udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
.resource = jz_usb_gdt_resources,
};
/** MMC/SD controller **/
static struct resource jz_mmc_resources[] = {
[0] = {
.start = CPHYSADDR(MSC_BASE),
.end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_MSC,
.end = IRQ_MSC,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_mmc_dmamask = ~(u32)0;
static struct platform_device jz_mmc_device = {
.name = "jz-mmc",
.id = 0,
.dev = {
.dma_mask = &jz_mmc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_mmc_resources),
.resource = jz_mmc_resources,
};
/** I2C controller **/
static struct resource jz_i2c_resources[] = {
[0] = {
.start = CPHYSADDR(I2C_BASE),
.end = CPHYSADDR(I2C_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_I2C,
.end = IRQ_I2C,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_i2c_dmamask = ~(u32)0;
static struct platform_device jz_i2c_device = {
.name = "jz_i2c",
.id = 0,
.dev = {
.dma_mask = &jz_i2c_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_i2c_resources),
.resource = jz_i2c_resources,
};
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
&jz_usb_ohci_device,
&jz_lcd_device,
&jz_usb_gdt_device,
&jz_mmc_device,
&jz_i2c_device,
};
static int __init jz_platform_init(void)
{
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
arch_initcall(jz_platform_init);

View File

@@ -0,0 +1,410 @@
/*
* linux/arch/mips/jz4740/common/pm.c
*
* JZ4740 Power Management Routines
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/suspend.h>
#include <asm/cacheops.h>
#include <asm/jzsoc.h>
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define dprintk(x...) printk(x)
#else
#define dprintk(x...)
#endif
#define GPIO_WAKEUP 125 /* set SW7(GPIO 125) as WAKEUP key */
/*
* __gpio_as_sleep set all pins to pull-disable, and set all pins as input
* except sdram, nand flash pins and the pins which can be used as CS1_N
* to CS4_N for chip select.
*/
#define __gpio_as_sleep() \
do { \
REG_GPIO_PXFUNC(1) = ~0x9ff9ffff; \
REG_GPIO_PXSELC(1) = ~0x9ff9ffff; \
REG_GPIO_PXDIRC(1) = ~0x9ff9ffff; \
REG_GPIO_PXPES(1) = 0xffffffff; \
REG_GPIO_PXFUNC(2) = ~0x37000000; \
REG_GPIO_PXSELC(2) = ~0x37000000; \
REG_GPIO_PXDIRC(2) = ~0x37000000; \
REG_GPIO_PXPES(2) = 0xffffffff; \
REG_GPIO_PXFUNC(3) = 0xffffffff; \
REG_GPIO_PXSELC(3) = 0xffffffff; \
REG_GPIO_PXDIRC(3) = 0xffffffff; \
REG_GPIO_PXPES(3) = 0xffffffff; \
} while (0)
static int jz_pm_do_hibernate(void)
{
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/*
* RTC Wakeup or 1Hz interrupt can be enabled or disabled
* through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
*/
/* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
/* Set reset pin low-level assertion time after wakeup: must > 60ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
/* Scratch pad register to be reserved */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HSPR = 0x12345678;
/* clear wakeup status register */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWRSR = 0x0;
/* Put CPU to power down mode */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HCR = RTC_HCR_PD;
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
while(1);
/* We can't get here */
return 0;
}
/* NOTES:
* 1: Pins that are floated (NC) should be set as input and pull-enable.
* 2: Pins that are pull-up or pull-down by outside should be set as input
* and pull-disable.
* 3: Pins that are connected to a chip except sdram and nand flash
* should be set as input and pull-disable, too.
*/
static void jz_board_do_sleep(unsigned long *ptr)
{
unsigned char i;
/* Print messages of GPIO registers for debug */
for(i=0;i<4;i++) {
dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
}
/* Save GPIO registers */
for(i = 1; i < 4; i++) {
*ptr++ = REG_GPIO_PXFUN(i);
*ptr++ = REG_GPIO_PXSEL(i);
*ptr++ = REG_GPIO_PXDIR(i);
*ptr++ = REG_GPIO_PXPE(i);
*ptr++ = REG_GPIO_PXIM(i);
*ptr++ = REG_GPIO_PXDAT(i);
*ptr++ = REG_GPIO_PXTRG(i);
}
/*
* Set all pins to pull-disable, and set all pins as input except
* sdram, nand flash pins and the pins which can be used as CS1_N
* to CS4_N for chip select.
*/
__gpio_as_sleep();
/*
* Set proper status for GPB25 to GPB28 which can be used as CS1_N to CS4_N.
* Keep the pins' function used for chip select(CS) here according to your
* system to avoid chip select crashing with sdram when resuming from sleep mode.
*/
#if defined(CONFIG_JZ4740_PAVO)
/* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
/* GPB26/CS2_N is connected to nand flash, needn't be changed. */
/* GPB27/CS3_N is used as EXT_INT for CS8900 on debug board, it should be set as input.*/
__gpio_as_input(32+27);
/* GPB28/CS4_N is used as cs8900's chip select, shouldn't be changed. */
#endif
/*
* Enable pull for NC pins here according to your system
*/
#if defined(CONFIG_JZ4740_PAVO)
/* GPB30-27 <-> J1: WE_N RD_N CS4_N EXT_INT */
for(i=27;i<31;i++) {
__gpio_enable_pull(32+i);
}
/* GPC27<-> WAIT_N */
__gpio_enable_pull(32*2+27);
/* GPD16<->SD_WP; GPD13-10<->MSC_D0-3; GPD9<->MSC_CMD; GPD8<->MSC_CLK */
__gpio_enable_pull(32*3+16);
for(i=8;i<14;i++) {
__gpio_enable_pull(32*3+i);
}
#endif
/*
* If you must set some GPIOs as output to high level or low level,
* you can set them here, using:
* __gpio_as_output(n);
* __gpio_set_pin(n); or __gpio_clear_pin(n);
*/
#if defined(CONFIG_JZ4740_PAVO)
/* GPD16 which is used as AMPEN_N should be set to high to disable audio amplifier */
__gpio_set_pin(32*3+4);
#endif
#ifdef DEBUG
/* Keep uart0 function for printing debug message */
__gpio_as_uart0();
/* Print messages of GPIO registers for debug */
for(i=0;i<4;i++) {
dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
}
#endif
}
static void jz_board_do_resume(unsigned long *ptr)
{
unsigned char i;
/* Restore GPIO registers */
for(i = 1; i < 4; i++) {
REG_GPIO_PXFUNS(i) = *ptr;
REG_GPIO_PXFUNC(i) = ~(*ptr++);
REG_GPIO_PXSELS(i) = *ptr;
REG_GPIO_PXSELC(i) = ~(*ptr++);
REG_GPIO_PXDIRS(i) = *ptr;
REG_GPIO_PXDIRC(i) = ~(*ptr++);
REG_GPIO_PXPES(i) = *ptr;
REG_GPIO_PXPEC(i) = ~(*ptr++);
REG_GPIO_PXIMS(i)=*ptr;
REG_GPIO_PXIMC(i)=~(*ptr++);
REG_GPIO_PXDATS(i)=*ptr;
REG_GPIO_PXDATC(i)=~(*ptr++);
REG_GPIO_PXTRGS(i)=*ptr;
REG_GPIO_PXTRGC(i)=~(*ptr++);
}
/* Print messages of GPIO registers for debug */
for(i=0;i<4;i++) {
dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
}
}
static int jz_pm_do_sleep(void)
{
unsigned long delta;
unsigned long nfcsr = REG_EMC_NFCSR;
unsigned long scr = REG_CPM_SCR;
unsigned long imr = REG_INTC_IMR;
unsigned long sadc = REG_SADC_ENA;
unsigned long sleep_gpio_save[7*3];
/* Preserve current time */
delta = xtime.tv_sec - REG_RTC_RSR;
/* Disable nand flash */
REG_EMC_NFCSR = ~0xff;
/* stop sadc */
REG_SADC_ENA &= ~0x7;
while((REG_SADC_ENA & 0x7) != 0);
udelay(100);
/*stop udc and usb*/
REG_CPM_SCR &= ~( 1<<6 | 1<<7);
REG_CPM_SCR |= 0<<6 | 1<<7;
/* Sleep on-board modules */
jz_board_do_sleep(sleep_gpio_save);
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/* Just allow following interrupts to wakeup the system.
* Note: modify this according to your system.
*/
/* enable RTC alarm */
__intc_unmask_irq(IRQ_RTC);
#if 0
/* make system wake up after n seconds by RTC alarm */
unsigned int v, n;
n = 10;
while (!__rtc_write_ready());
__rtc_enable_alarm();
while (!__rtc_write_ready());
__rtc_enable_alarm_irq();
while (!__rtc_write_ready());
v = __rtc_get_second();
while (!__rtc_write_ready());
__rtc_set_alarm_second(v+n);
#endif
/* WAKEUP key */
__gpio_as_irq_rise_edge(GPIO_WAKEUP);
__gpio_unmask_irq(GPIO_WAKEUP);
__intc_unmask_irq(IRQ_GPIO3); /* IRQ_GPIOn depends on GPIO_WAKEUP */
/* Enter SLEEP mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
/* Restore to IDLE mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
/* Restore nand flash control register */
REG_EMC_NFCSR = nfcsr;
/* Restore interrupts */
REG_INTC_IMSR = imr;
REG_INTC_IMCR = ~imr;
/* Restore sadc */
REG_SADC_ENA = sadc;
/* Resume on-board modules */
jz_board_do_resume(sleep_gpio_save);
/* Restore sleep control register */
REG_CPM_SCR = scr;
/* Restore current time */
xtime.tv_sec = REG_RTC_RSR + delta;
return 0;
}
/* Put CPU to HIBERNATE mode */
int jz_pm_hibernate(void)
{
printk("Put CPU into hibernate mode.\n");
return jz_pm_do_hibernate();
}
#ifndef CONFIG_JZ_POWEROFF
static irqreturn_t pm_irq_handler (int irq, void *dev_id)
{
return IRQ_HANDLED;
}
#endif
/* Put CPU to SLEEP mode */
int jz_pm_sleep(void)
{
int retval;
#ifndef CONFIG_JZ_POWEROFF
if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
"PM", NULL))) {
printk ("PM could not get IRQ for GPIO_WAKEUP\n");
return retval;
}
#endif
printk("Put CPU into sleep mode.\n");
retval = jz_pm_do_sleep();
#ifndef CONFIG_JZ_POWEROFF
free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
#endif
return retval;
}
/*
* valid states, only support standby(sleep) and mem(hibernate)
*/
static int jz_pm_valid(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
return 1;
default:
return 0;
}
}
/*
* Jz CPU enter save power mode
*/
static int jz_pm_enter(suspend_state_t state)
{
if (state == PM_SUSPEND_STANDBY)
jz_pm_sleep();
else
jz_pm_hibernate();
return 0;
}
static struct platform_suspend_ops jz_pm_ops = {
.valid = jz_pm_valid,
.enter = jz_pm_enter,
};
/*
* Initialize power interface
*/
int __init jz_pm_init(void)
{
printk("Power Management for JZ\n");
suspend_set_ops(&jz_pm_ops);
return 0;
}
//module_init(jz_pm_init);

View File

@@ -0,0 +1,873 @@
/*
* linux/arch/mips/jz4740/proc.c
*
* /proc/jz/ procfs for jz4740 on-chip modules.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/page-flags.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/jzsoc.h>
//#define DEBUG 1
#undef DEBUG
struct proc_dir_entry *proc_jz_root;
/*
* EMC Modules
*/
static int emc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
return len;
}
/*
* Power Manager Module
*/
static int pmc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned long lcr = REG_CPM_LCR;
unsigned long clkgr = REG_CPM_CLKGR;
len += sprintf (page+len, "Low Power Mode : %s\n",
((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
"IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
"SLEEP" : "HIBERNATE"));
len += sprintf (page+len, "Doze Mode : %s\n",
(lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
if (lcr & CPM_LCR_DOZE_ON)
len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
len += sprintf (page+len, "IPU : %s\n",
(clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
len += sprintf (page+len, "DMAC : %s\n",
(clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
len += sprintf (page+len, "UHC : %s\n",
(clkgr & CPM_CLKGR_UHC) ? "stopped" : "running");
len += sprintf (page+len, "UDC : %s\n",
(clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
len += sprintf (page+len, "LCD : %s\n",
(clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
len += sprintf (page+len, "CIM : %s\n",
(clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
len += sprintf (page+len, "SADC : %s\n",
(clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
len += sprintf (page+len, "MSC : %s\n",
(clkgr & CPM_CLKGR_MSC) ? "stopped" : "running");
len += sprintf (page+len, "AIC1 : %s\n",
(clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running");
len += sprintf (page+len, "AIC2 : %s\n",
(clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running");
len += sprintf (page+len, "SSI : %s\n",
(clkgr & CPM_CLKGR_SSI) ? "stopped" : "running");
len += sprintf (page+len, "I2C : %s\n",
(clkgr & CPM_CLKGR_I2C) ? "stopped" : "running");
len += sprintf (page+len, "RTC : %s\n",
(clkgr & CPM_CLKGR_RTC) ? "stopped" : "running");
len += sprintf (page+len, "TCU : %s\n",
(clkgr & CPM_CLKGR_TCU) ? "stopped" : "running");
len += sprintf (page+len, "UART1 : %s\n",
(clkgr & CPM_CLKGR_UART1) ? "stopped" : "running");
len += sprintf (page+len, "UART0 : %s\n",
(clkgr & CPM_CLKGR_UART0) ? "stopped" : "running");
return len;
}
static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16);
return count;
}
/*
* Clock Generation Module
*/
#define TO_MHZ(x) (x/1000000),(x%1000000)/10000
#define TO_KHZ(x) (x/1000),(x%1000)/10
static int cgm_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */
unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */
unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int od[4] = {1, 2, 2, 4};
len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr);
len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr);
len += sprintf (page+len, "PLL : %s\n",
(cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF");
len += sprintf (page+len, "m:n:o : %d:%d:%d\n",
__cpm_get_pllm() + 2,
__cpm_get_plln() + 2,
od[__cpm_get_pllod()]
);
len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n",
div[__cpm_get_cdiv()],
div[__cpm_get_hdiv()],
div[__cpm_get_mdiv()],
div[__cpm_get_pdiv()]
);
len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout()));
len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk()));
len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk()));
len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk()));
len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk()));
len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk()));
len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk()));
len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk()));
len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk()));
len += sprintf (page+len, "MSCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk()));
len += sprintf (page+len, "EXTALCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk()));
len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk()));
return len;
}
static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16);
return count;
}
/* USAGE:
* echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages.
* echo FF > /proc/jz/ipu // 255, free all buffer
* echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx
* echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l)
* echo 0 > /proc/jz/ipu // debug, print ipu_buf
* od -X /proc/jz/ipu // read mem addr
*/
typedef struct _ipu_buf {
unsigned int addr; /* phys addr */
unsigned int page_shift;
} ipu_buf_t;
#define IPU_BUF_MAX 4 /* 4 buffers */
static struct _ipu_buf ipu_buf[IPU_BUF_MAX];
static int ipu_buf_cnt = 0;
static unsigned char g_asid=0;
extern void local_flush_tlb_all(void);
/* CP0 hazard avoidance. */
#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
"nop; nop; nop; nop; nop; nop;\n\t" \
".set reorder\n\t")
void show_tlb(void)
{
#define ASID_MASK 0xFF
unsigned long flags;
unsigned int old_ctx;
unsigned int entry;
unsigned int entrylo0, entrylo1, entryhi;
unsigned int pagemask;
local_irq_save(flags);
/* Save old context */
old_ctx = (read_c0_entryhi() & 0xff);
printk("TLB content:\n");
entry = 0;
while(entry < 32) {
write_c0_index(entry);
BARRIER;
tlb_read();
BARRIER;
entryhi = read_c0_entryhi();
entrylo0 = read_c0_entrylo0();
entrylo1 = read_c0_entrylo1();
pagemask = read_c0_pagemask();
printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK);
printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
printk("\t\tpagemask=0x%08x", pagemask);
printk("\tentryhi=0x%08x\n", entryhi);
printk("\t\tentrylo0=0x%08x", entrylo0);
printk("\tentrylo1=0x%08x\n", entrylo1);
entry++;
}
BARRIER;
write_c0_entryhi(old_ctx);
local_irq_restore(flags);
}
static void ipu_add_wired_entry(unsigned long pid,
unsigned long entrylo0, unsigned long entrylo1,
unsigned long entryhi, unsigned long pagemask)
{
unsigned long flags;
unsigned long wired;
unsigned long old_pagemask;
unsigned long old_ctx;
struct task_struct *g, *p;
/* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */
wired = read_c0_wired();
if (wired) return;
do_each_thread(g, p) {
if (p->pid == pid )
g_asid = p->mm->context[0];
} while_each_thread(g, p);
local_irq_save(flags);
entrylo0 = entrylo0 >> 6; /* PFN */
entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */
/* Save old context and create impossible VPN2 value */
old_ctx = read_c0_entryhi() & 0xff;
old_pagemask = read_c0_pagemask();
write_c0_wired(wired + 1);
write_c0_index(wired);
BARRIER;
entryhi &= ~0xff; /* new add, 20070906 */
entryhi |= g_asid; /* new add, 20070906 */
// entryhi |= old_ctx; /* new add, 20070906 */
write_c0_pagemask(pagemask);
write_c0_entryhi(entryhi);
write_c0_entrylo0(entrylo0);
write_c0_entrylo1(entrylo1);
BARRIER;
tlb_write_indexed();
BARRIER;
write_c0_entryhi(old_ctx);
BARRIER;
write_c0_pagemask(old_pagemask);
local_flush_tlb_all();
local_irq_restore(flags);
#if defined(DEBUG)
printk("\nold_ctx=%03d\n", old_ctx);
show_tlb();
#endif
}
static void ipu_del_wired_entry( void )
{
unsigned long flags;
unsigned long wired;
/* Free all lock entry */
local_irq_save(flags);
wired = read_c0_wired();
if (wired)
write_c0_wired(0);
local_irq_restore(flags);
}
static inline void ipu_buf_get( unsigned int page_shift )
{
unsigned char * virt_addr;
int i;
for ( i=0; i< IPU_BUF_MAX; ++i ) {
if ( ipu_buf[i].addr == 0 ) {
break;
}
}
if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) {
printk("Error, no free ipu buffer.\n");
return ;
}
virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
if ( virt_addr ) {
ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr);
ipu_buf[ipu_buf_cnt].page_shift = page_shift;
for (i = 0; i < (1<<page_shift); i++) {
SetPageReserved(virt_to_page(virt_addr));
virt_addr += PAGE_SIZE;
}
}
else {
printk("get memory Failed.\n");
}
}
static inline void ipu_buf_free( unsigned int phys_addr )
{
unsigned char * virt_addr, *addr;
int cnt, i;
if ( phys_addr == 0 )
return ;
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
if ( phys_addr == ipu_buf[cnt].addr )
break;
if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
}
virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
addr = virt_addr;
for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
ClearPageReserved(virt_to_page(addr));
addr += PAGE_SIZE;
}
if ( cnt == 0 )
ipu_del_wired_entry();
free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
ipu_buf[cnt].addr = 0;
ipu_buf[cnt].page_shift = 0;
}
static int ipu_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
/* read as binary */
unsigned int * pint;
pint = (unsigned int *) (page+len);
if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
printk("no free buffer.\n");
*pint = 0;
}
else
*pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
len += sizeof(unsigned int);
#if defined(DEBUG)
show_tlb();
#endif
return len;
}
static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
unsigned int val ;
int cnt,i;
char buf[12];
unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
#if defined(DEBUG)
printk("ipu write count=%u\n", count);
#endif
if (count == (8*5+1)) {
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*0, 8);
pid = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*1, 8);
entrylo0 = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*2, 8);
entrylo1 = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*3, 8);
entryhi = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*4, 8);
pagemask = simple_strtoul(buf, 0, 16);
#if defined(DEBUG)
printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
pid, entrylo0, entrylo1, entryhi, pagemask);
#endif
ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
return 41;
} else if ( count <= 8+1 ) {
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer, 8);
val = simple_strtoul(buf, 0, 16);
} else if (count == 44) {
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer, 10);
pid = simple_strtoul(buf, 0, 16);
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer + 11, 10);
entryhi = simple_strtoul(buf, 0, 16);//vaddr
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer + 22, 10);
entrylo0 = simple_strtoul(buf, 0, 16);//paddr
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer + 33, 10);
pagemask = simple_strtoul(buf, 0, 16);
pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
return 44;
} else {
printk("ipu write count error, count=%d\n.", (unsigned int)count);
return -1;
}
/* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
if ( val == 0 ) { /* debug, print ipu_buf info */
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
#if defined(DEBUG)
show_tlb();
#endif
}
else if ( 0< val && val < 10 ) {
ipu_buf_get(val);
}
else if ( val == 0xff ) { /* 255: free all ipu_buf */
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
ipu_buf_free(ipu_buf[cnt].addr);
}
}
else {
ipu_buf_free(val);
}
return count;
}
/*
* UDC hotplug
*/
#ifdef CONFIG_JZ_UDC_HOTPLUG
extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */
#endif
#ifndef GPIO_UDC_HOTPLUG
#define GPIO_UDC_HOTPLUG 86
#endif
static int udc_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) {
#ifdef CONFIG_JZ_UDC_HOTPLUG
/* Cable has connected, wait for disconnection. */
__gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG);
if (jz_udc_active)
len += sprintf (page+len, "CONNECT_CABLE\n");
else
len += sprintf (page+len, "CONNECT_POWER\n");
#else
len += sprintf (page+len, "CONNECT\n");
#endif
}
else {
#ifdef CONFIG_JZ_UDC_HOTPLUG
/* Cable has disconnected, wait for connection. */
__gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG);
#endif
len += sprintf (page+len, "REMOVE\n");
}
return len;
}
/*
* MMC/SD hotplug
*/
#ifndef MSC_HOTPLUG_PIN
#define MSC_HOTPLUG_PIN 90
#endif
static int mmc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
#if defined(CONFIG_JZ4740_LYRA)
if (!(__gpio_get_pin(MSC_HOTPLUG_PIN)))
#else
if (__gpio_get_pin(MSC_HOTPLUG_PIN))
#endif
len += sprintf (page+len, "REMOVE\n");
else
len += sprintf (page+len, "INSERT\n");
return len;
}
/***********************************************************************
* IPU memory management (used by mplayer and other apps)
*
* We reserved 4MB memory for IPU
* The memory base address is jz_ipu_framebuf
*/
/* Usage:
*
* echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
* echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
* echo FF > /proc/jz/ipu // FF, free all buffers
* od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
*/
//#define DEBUG_IMEM 1
#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */
static unsigned int jz_imem_base; /* physical base address of ipu memory */
static unsigned int allocated_phys_addr = 0;
/*
* Allocated buffer list
*/
typedef struct imem_list {
unsigned int phys_start; /* physical start addr */
unsigned int phys_end; /* physical end addr */
struct imem_list *next;
} imem_list_t;
static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
#ifdef DEBUG_IMEM
static void dump_imem_list(void)
{
struct imem_list *imem;
printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head);
imem = imem_list_head;
while (imem) {
printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
imem = imem->next;
}
}
#endif
/* allocate 2^order pages inside the 4MB memory */
static int imem_alloc(unsigned int order)
{
int alloc_ok = 0;
unsigned int start, end;
unsigned int size = (1 << order) * PAGE_SIZE;
struct imem_list *imem, *imemn, *imemp;
allocated_phys_addr = 0;
start = jz_imem_base;
end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
imem = imem_list_head;
while (imem) {
if ((imem->phys_start - start) >= size) {
/* we got a valid address range */
alloc_ok = 1;
break;
}
start = imem->phys_end + 1;
imem = imem->next;
}
if (!alloc_ok) {
if ((end - start) >= size)
alloc_ok = 1;
}
if (alloc_ok) {
end = start + size - 1;
allocated_phys_addr = start;
/* add to imem_list, up sorted by phys_start */
imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
if (!imemn) {
return -ENOMEM;
}
imemn->phys_start = start;
imemn->phys_end = end;
imemn->next = NULL;
if (!imem_list_head)
imem_list_head = imemn;
else {
imem = imemp = imem_list_head;
while (imem) {
if (start < imem->phys_start) {
break;
}
imemp = imem;
imem = imem->next;
}
if (imem == imem_list_head) {
imem_list_head = imemn;
imemn->next = imem;
}
else {
imemn->next = imemp->next;
imemp->next = imemn;
}
}
}
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
return 0;
}
static void imem_free(unsigned int phys_addr)
{
struct imem_list *imem, *imemp;
imem = imemp = imem_list_head;
while (imem) {
if (phys_addr == imem->phys_start) {
if (imem == imem_list_head) {
imem_list_head = imem->next;
}
else {
imemp->next = imem->next;
}
kfree(imem);
break;
}
imemp = imem;
imem = imem->next;
}
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
}
static void imem_free_all(void)
{
struct imem_list *imem;
imem = imem_list_head;
while (imem) {
kfree(imem);
imem = imem->next;
}
imem_list_head = NULL;
allocated_phys_addr = 0;
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
}
/*
* Return the allocated buffer address and the max order of free buffer
*/
static int imem_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned int start_addr, end_addr, max_order, max_size;
struct imem_list *imem;
unsigned int *tmp = (unsigned int *)(page + len);
start_addr = jz_imem_base;
end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
if (!imem_list_head)
max_size = end_addr - start_addr;
else {
max_size = 0;
imem = imem_list_head;
while (imem) {
if (max_size < (imem->phys_start - start_addr))
max_size = imem->phys_start - start_addr;
start_addr = imem->phys_end + 1;
imem = imem->next;
}
if (max_size < (end_addr - start_addr))
max_size = end_addr - start_addr;
}
if (max_size > 0) {
max_order = get_order(max_size);
if (((1 << max_order) * PAGE_SIZE) > max_size)
max_order--;
}
else {
max_order = 0xffffffff; /* No any free buffer */
}
*tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */
*tmp = max_order; /* max order of current free buffers */
len += 2 * sizeof(unsigned int);
return len;
}
static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
unsigned int val;
val = simple_strtoul(buffer, 0, 16);
if (val == 0xff) {
/* free all memory */
imem_free_all();
ipu_del_wired_entry();
}
else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) {
/* allocate 2^val pages */
imem_alloc(val);
}
else {
/* free buffer which phys_addr is val */
imem_free(val);
}
return count;
}
/*
* /proc/jz/xxx entry
*
*/
static int __init jz_proc_init(void)
{
struct proc_dir_entry *res;
unsigned int virt_addr, i;
proc_jz_root = proc_mkdir("jz", 0);
/* External Memory Controller */
res = create_proc_entry("emc", 0644, proc_jz_root);
if (res) {
res->read_proc = emc_read_proc;
res->write_proc = NULL;
res->data = NULL;
}
/* Power Management Controller */
res = create_proc_entry("pmc", 0644, proc_jz_root);
if (res) {
res->read_proc = pmc_read_proc;
res->write_proc = pmc_write_proc;
res->data = NULL;
}
/* Clock Generation Module */
res = create_proc_entry("cgm", 0644, proc_jz_root);
if (res) {
res->read_proc = cgm_read_proc;
res->write_proc = cgm_write_proc;
res->data = NULL;
}
/* Image process unit */
res = create_proc_entry("ipu", 0644, proc_jz_root);
if (res) {
res->read_proc = ipu_read_proc;
res->write_proc = ipu_write_proc;
res->data = NULL;
}
/* udc hotplug */
res = create_proc_entry("udc", 0644, proc_jz_root);
if (res) {
res->read_proc = udc_read_proc;
res->write_proc = NULL;
res->data = NULL;
}
/* mmc hotplug */
res = create_proc_entry("mmc", 0644, proc_jz_root);
if (res) {
res->read_proc = mmc_read_proc;
res->write_proc = NULL;
res->data = NULL;
}
/*
* Reserve a 4MB memory for IPU on JZ4740.
*/
jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER);
if (jz_imem_base) {
/* imem (IPU memory management) */
res = create_proc_entry("imem", 0644, proc_jz_root);
if (res) {
res->read_proc = imem_read_proc;
res->write_proc = imem_write_proc;
res->data = NULL;
}
/* Set page reserved */
virt_addr = jz_imem_base;
for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) {
SetPageReserved(virt_to_page((void *)virt_addr));
virt_addr += PAGE_SIZE;
}
/* Convert to physical address */
jz_imem_base = virt_to_phys((void *)jz_imem_base);
printk("Total %dMB memory at 0x%x was reserved for IPU\n",
(unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base);
}
return 0;
}
__initcall(jz_proc_init);

View File

@@ -0,0 +1,198 @@
/*
*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, supports YAMON and U-Boot.
*
* Copyright 2000, 2001, 2006 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/jzsoc.h>
/* #define DEBUG_CMDLINE */
int prom_argc;
char **prom_argv, **prom_envp;
char * prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
if (prom_argc > 1)
*cp = '\0';
}
char *prom_getenv(char *envname)
{
#if 0
/*
* Return a pointer to the given environment variable.
* YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
*/
char **env = prom_envp;
int i = strlen(envname);
int yamon = (*env && strchr(*env, '=') == NULL);
while (*env) {
if (yamon) {
if (strcmp(envname, *env++) == 0)
return *env;
} else {
if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
return *env + i + 1;
}
env++;
}
#endif
return NULL;
}
inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0; /* foo */
}
inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
for(i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
#if 0
{
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
#endif
return 0;
}
void __init prom_free_prom_memory(void)
{
}
void __init prom_init(void)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = (int) fw_arg0;
prom_argv = (char **) fw_arg1;
prom_envp = (char **) fw_arg2;
mips_machtype = MACH_INGENIC_JZ4740;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x04000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
/* used by early printk */
void prom_putchar(char c)
{
volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR);
volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR);
/* Wait for fifo to shift out some bytes */
while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
*uart_tdr = (u8)c;
}
const char *get_system_type(void)
{
return "JZ4740";
}
EXPORT_SYMBOL(prom_getcmdline);
EXPORT_SYMBOL(get_ethernet_addr);
EXPORT_SYMBOL(str2eaddr);

View File

@@ -0,0 +1,46 @@
/*
* linux/arch/mips/jz4740/reset.c
*
* JZ4740 reset routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <yliu@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
void jz_restart(char *command)
{
printk("Restarting after 4 ms\n");
REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
REG_WDT_TCNT = 0;
REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */
REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
while (1);
}
void jz_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
}
void jz_power_off(void)
{
jz_halt();
}

View File

@@ -0,0 +1,188 @@
/*
* linux/arch/mips/jz4740/common/setup.c
*
* JZ4740 common setup routines.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
#ifdef CONFIG_PM
#include <asm/suspend.h>
#endif
#ifdef CONFIG_PC_KEYB
#include <asm/keyboard.h>
#endif
jz_clocks_t jz_clocks;
extern char * __init prom_getcmdline(void);
extern void __init jz_board_setup(void);
extern void jz_restart(char *);
extern void jz_halt(void);
extern void jz_power_off(void);
extern void jz_time_init(void);
static void __init sysclocks_setup(void)
{
#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.lcdclk = __cpm_get_lcdclk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk();
jz_clocks.extalclk = __cpm_get_extalclk();
jz_clocks.rtcclk = __cpm_get_rtcclk();
#else
#define FPGACLK 8000000
jz_clocks.cclk = FPGACLK;
jz_clocks.hclk = FPGACLK;
jz_clocks.pclk = FPGACLK;
jz_clocks.mclk = FPGACLK;
jz_clocks.lcdclk = FPGACLK;
jz_clocks.pixclk = FPGACLK;
jz_clocks.i2sclk = FPGACLK;
jz_clocks.usbclk = FPGACLK;
jz_clocks.mscclk = FPGACLK;
jz_clocks.extalclk = FPGACLK;
jz_clocks.rtcclk = FPGACLK;
#endif
printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
(jz_clocks.cclk + 500000) / 1000000,
(jz_clocks.hclk + 500000) / 1000000,
(jz_clocks.pclk + 500000) / 1000000,
(jz_clocks.mclk + 500000) / 1000000);
}
static void __init soc_cpm_setup(void)
{
/* Start all module clocks
*/
__cpm_start_all();
/* Enable CKO to external memory */
__cpm_enable_cko();
/* CPU enters IDLE mode when executing 'wait' instruction */
__cpm_idle_mode();
/* Setup system clocks */
sysclocks_setup();
}
static void __init soc_harb_setup(void)
{
// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
}
static void __init soc_emc_setup(void)
{
}
static void __init soc_dmac_setup(void)
{
__dmac_enable_module();
}
static void __init jz_soc_setup(void)
{
soc_cpm_setup();
soc_harb_setup();
soc_emc_setup();
soc_dmac_setup();
}
static void __init jz_serial_setup(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port s;
REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
memset(&s, 0, sizeof(s));
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = SERIAL_IO_MEM;
s.regshift = 2;
s.uartclk = jz_clocks.extalclk ;
s.line = 0;
s.membase = (u8 *)UART0_BASE;
s.irq = IRQ_UART0;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS0 setup failed!\n");
}
s.line = 1;
s.membase = (u8 *)UART1_BASE;
s.irq = IRQ_UART1;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS1 setup failed!\n");
}
#endif
}
void __init plat_mem_setup(void)
{
char *argptr;
argptr = prom_getcmdline();
/* IO/MEM resources. Which will be the addtion value in `inX' and
* `outX' macros defined in asm/io.h */
set_io_port_base(0);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x00000000;
iomem_resource.end = 0xffffffff;
_machine_restart = jz_restart;
_machine_halt = jz_halt;
pm_power_off = jz_power_off;
#ifdef CONFIG_PM
jz_pm_init();
#endif
jz_soc_setup();
jz_serial_setup();
jz_board_setup();
}

View File

@@ -0,0 +1,159 @@
/*
* linux/arch/mips/jz4740/time.c
*
* Setting up the clock on the JZ4740 boards.
*
* Copyright (C) 2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
/* This is for machines which generate the exact clock. */
#define JZ_TIMER_CHAN 0
#define JZ_TIMER_IRQ IRQ_TCU0
#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
static struct clocksource clocksource_jz; /* Jz clock source */
static struct clock_event_device jz_clockevent_device; /* Jz clock event */
void (*jz_timer_callback)(void);
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = dev_id;
REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */
if (jz_timer_callback)
jz_timer_callback();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction jz_irqaction = {
.handler = jz_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
.name = "jz-timerirq",
};
cycle_t jz_get_cycles(void)
{
/* convert jiffes to jz timer cycles */
return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_TCNT(JZ_TIMER_CHAN));
}
static struct clocksource clocksource_jz = {
.name = "jz_clocksource",
.rating = 300,
.read = jz_get_cycles,
.mask = 0xFFFF,
.shift = 10,
.flags = CLOCK_SOURCE_WATCHDOG,
};
static int __init jz_clocksource_init(void)
{
clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
clocksource_register(&clocksource_jz);
return 0;
}
static int jz_set_next_event(unsigned long evt,
struct clock_event_device *unused)
{
return 0;
}
static void jz_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}
static struct clock_event_device jz_clockevent_device = {
.name = "jz-clockenvent",
.features = CLOCK_EVT_FEAT_PERIODIC,
// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
.mult = 1,
.rating = 300,
.irq = JZ_TIMER_IRQ,
.set_mode = jz_set_mode,
.set_next_event = jz_set_next_event,
};
static void __init jz_clockevent_init(void)
{
struct clock_event_device *cd = &jz_clockevent_device;
unsigned int cpu = smp_processor_id();
cd->cpumask = cpumask_of_cpu(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();
}

View File

@@ -0,0 +1,23 @@
#
# Makefile for the Ingenic JZ4750.
#
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
platform.o i2c.o
obj-$(CONFIG_PROC_FS) += proc.o
# board specific support
obj-$(CONFIG_JZ4750_FUWA) += board-fuwa.o
obj-$(CONFIG_JZ4750_APUS) += board-apus.o
# PM support
obj-$(CONFIG_PM) +=pm.o
# CPU Frequency scaling support
obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o

View File

@@ -0,0 +1,303 @@
/*
* linux/arch/mips/jz4750/board-apus.c
*
* JZ4750 APUS board setup routines.
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
//#define DEBUG
/*********************************************************************************
* Power management routines
********************************************************************************/
/*
* __gpio_as_sleep set all pins to pull-disable, and set all pins as input
* except sdram and the pins which can be used as CS1_N to CS4_N for chip select.
*/
#define __gpio_as_sleep() \
do { \
REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \
REG_GPIO_PXSELC(1) = ~0x03ff7fff; \
REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \
REG_GPIO_PXPES(1) = ~0x03ff7fff; \
REG_GPIO_PXFUNC(2) = ~0x01e00000; \
REG_GPIO_PXSELC(2) = ~0x01e00000; \
REG_GPIO_PXDIRC(2) = ~0x01e00000; \
REG_GPIO_PXPES(2) = ~0x01e00000; \
REG_GPIO_PXFUNC(3) = 0xffffffff; \
REG_GPIO_PXSELC(3) = 0xffffffff; \
REG_GPIO_PXDIRC(3) = 0xffffffff; \
REG_GPIO_PXPES(3) = 0xffffffff; \
REG_GPIO_PXFUNC(4) = 0xffffffff; \
REG_GPIO_PXSELC(4) = 0xffffffff; \
REG_GPIO_PXDIRC(4) = 0xffffffff; \
REG_GPIO_PXPES(4) = 0xffffffff; \
REG_GPIO_PXFUNC(5) = 0xffffffff; \
REG_GPIO_PXSELC(5) = 0xffffffff; \
REG_GPIO_PXDIRC(5) = 0xffffffff; \
REG_GPIO_PXPES(5) = 0xffffffff; \
} while (0)
extern void (*jz_timer_callback)(void);
struct wakeup_key_s {
int gpio; /* gpio pin number */
int active_low; /* the key interrupt pin is low voltage
or fall edge acitve */
};
/* add wakeup keys here */
static struct wakeup_key_s wakeup_key[] = {
{
.gpio = GPIO_CALL,
.active_low = ACTIVE_LOW_CALL,
},
{
.gpio = GPIO_HOME,
.active_low = ACTIVE_LOW_HOME,
},
{
.gpio = GPIO_BACK,
.active_low = ACTIVE_LOW_BACK,
},
{
.gpio = GPIO_MENU,
.active_low = ACTIVE_LOW_MENU,
},
{
.gpio = GPIO_ENDCALL,
.active_low = ACTIVE_LOW_ENDCALL,
},
{
.gpio = GPIO_ADKEY_INT,
.active_low = ACTIVE_LOW_ADKEY,
},
};
static void wakeup_key_setup(void)
{
int i;
int num = sizeof(wakeup_key) / sizeof(wakeup_key[0]);
for(i = 0; i < num; i++) {
#if 0
if(wakeup_key[i].active_low)
__gpio_as_irq_fall_edge(wakeup_key[i].gpio);
else
__gpio_as_irq_rise_edge(wakeup_key[i].gpio);
#endif
__gpio_ack_irq(wakeup_key[i].gpio);
__gpio_unmask_irq(wakeup_key[i].gpio);
__intc_unmask_irq(IRQ_GPIO0 - (wakeup_key[i].gpio/32)); /* unmask IRQ_GPIOn */
}
}
/* NOTES:
* 1: Pins that are floated (NC) should be set as input and pull-enable.
* 2: Pins that are pull-up or pull-down by outside should be set as input
* and pull-disable.
* 3: Pins that are connected to a chip except sdram and nand flash
* should be set as input and pull-disable, too.
*/
void jz_board_do_sleep(unsigned long *ptr)
{
unsigned char i;
#ifdef DEBUG
__intc_unmask_irq(IRQ_UART3);
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
printk("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));
}
#endif
/* Save GPIO registers */
for(i = 1; i < GPIO_PORT_NUM; i++) {
*ptr++ = REG_GPIO_PXFUN(i);
*ptr++ = REG_GPIO_PXSEL(i);
*ptr++ = REG_GPIO_PXDIR(i);
*ptr++ = REG_GPIO_PXPE(i);
}
/*
* Mask the ethernet irq
*/
__gpio_mask_irq(GPIO_NET_INT);
/*
* Set all pins to pull-disable, and set all pins as input except
* sdram and the pins which can be used as CS1_N to CS4_N for chip select.
*/
// __gpio_as_sleep();
/*
* Set proper status for GPC21 to GPC24 which can be used as CS1_N to CS4_N.
* Keep the pins' function used for chip select(CS) here according to your
* system to avoid chip select crashing with sdram when resuming from sleep mode.
*/
/* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
/* GPB26/CS2_N is connected to nand flash, needn't be changed. */
/* GPB28/CS3_N is used as cs8900's chip select, shouldn't be changed. */
/* GPB27/CS4_N is used as NOR's chip select, shouldn't be changed. */
/*
* Enable pull for NC pins here according to your system
*/
/*
* 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);
*/
/* AMPEN_N should be set to high to disable audio amplifier */
__gpio_as_output(GPIO_AMPEN_N);
__gpio_set_pin(GPIO_AMPEN_N);
#ifdef DEBUG
/* Keep uart function for printing debug message */
__gpio_as_uart0();
__gpio_as_uart1();
__gpio_as_uart2();
__gpio_as_uart3();
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
printk("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));
}
__intc_mask_irq(IRQ_UART3);
#endif
/*
* Just allow following interrupts to wakeup the system.
*/
#ifdef CONFIG_RTC_CLASS
/* 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
#endif
/* setup wakeup keys before sleeping */
wakeup_key_setup();
}
void jz_board_do_resume(unsigned long *ptr)
{
unsigned char i;
/* Restore GPIO registers */
for(i = 1; i < GPIO_PORT_NUM; i++) {
REG_GPIO_PXFUNS(i) = *ptr;
REG_GPIO_PXFUNC(i) = ~(*ptr++);
REG_GPIO_PXSELS(i) = *ptr;
REG_GPIO_PXSELC(i) = ~(*ptr++);
REG_GPIO_PXDIRS(i) = *ptr;
REG_GPIO_PXDIRC(i) = ~(*ptr++);
REG_GPIO_PXPES(i) = *ptr;
REG_GPIO_PXPEC(i) = ~(*ptr++);
}
#ifdef DEBUG
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
printk("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));
}
#endif
}
/*********************************************************************************
* Basic setup routines
********************************************************************************/
#if 0
static inline void dancing(void)
{
}
static void apus_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
#endif
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)
{
__lcd_close_backlight();
__gpio_as_pcm();
}
void __init jz_board_setup(void)
{
printk("JZ4750 APUS board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = NULL;/* apus_timer_callback; */
}
/**
* Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'.
* Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc.
*/
const char *get_board_type(void)
{
return "apus";
}

View File

@@ -0,0 +1,114 @@
/*
* linux/arch/mips/jz4750/board-fuwa.c
*
* JZ4750 FUWA board setup routines.
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned char slash[] = "\\|/-";
// static volatile unsigned char *p = (unsigned char *)0xb6000058;
static volatile unsigned char *p = (unsigned char *)0xb6000016;
static unsigned int count = 0;
*p = slash[count++];
count &= 3;
}
static void fuwa_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4750/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Initialize SDRAM pins
*/
/* PORT A: D0 ~ D31 */
REG_GPIO_PXFUNS(0) = 0xffffffff;
REG_GPIO_PXSELC(0) = 0xffffffff;
/* PORT B: A0 ~ A16, DCS#, RAS#, CAS#, CKE#, RDWE#, CKO#, WE0# */
REG_GPIO_PXFUNS(1) = 0x81f9ffff;
REG_GPIO_PXSELC(1) = 0x81f9ffff;
/* PORT C: WE1#, WE2#, WE3# */
REG_GPIO_PXFUNS(2) = 0x07000000;
REG_GPIO_PXSELC(2) = 0x07000000;
/*
* Initialize UART0 pins
*/
/* PORT D: TXD/RXD */
REG_GPIO_PXFUNS(3) = 0x06000000;
REG_GPIO_PXSELS(3) = 0x06000000;
/*
* Initialize LED pins
*/
__gpio_as_lcd_18bit();
/* CS2# */
REG_GPIO_PXFUNS(1) = 0x04000000;
REG_GPIO_PXSELC(1) = 0x04000000;
__gpio_as_pcm();
}
void __init jz_board_setup(void)
{
printk("JZ4750 FUWA board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = fuwa_timer_callback;
}
/**
* Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'.
* Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc.
*/
const char *get_board_type(void)
{
return "fuwa";
}

View File

@@ -0,0 +1,601 @@
/*
* linux/arch/mips/jz4750/cpufreq.c
*
* cpufreq driver for JZ4750
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <asm/jzsoc.h>
#include <asm/processor.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"cpufreq-jz4750", msg)
#undef CHANGE_PLL
#define PLL_UNCHANGED 0
#define PLL_GOES_UP 1
#define PLL_GOES_DOWN 2
#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
/* Saved the boot-time parameters */
static struct {
/* SDRAM parameters */
unsigned int mclk; /* memory clock, KHz */
unsigned int tras; /* RAS pulse width, cycles of mclk */
unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
unsigned int tpc; /* RAS Precharge time, cycles of mclk */
unsigned int trwl; /* Write Precharge Time, cycles of mclk */
unsigned int trc; /* RAS Cycle Time, cycles of mclk */
unsigned int rtcor; /* Refresh Time Constant */
unsigned int sdram_initialized;
/* LCD parameters */
unsigned int lcd_clk; /* LCD clock, Hz */
unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
unsigned int lcd_clks_initialized;
} boot_config;
struct jz4750_freq_percpu_info {
struct cpufreq_frequency_table table[7];
};
static struct jz4750_freq_percpu_info jz4750_freq_table;
/*
* This contains the registers value for an operating point.
* If only part of a register needs to change then there is
* a mask value for that register.
* When going to a new operating point the current register
* value is ANDed with the ~mask and ORed with the new value.
*/
struct dpm_regs {
u32 cpccr; /* Clock Freq Control Register */
u32 cpccr_mask; /* Clock Freq Control Register mask */
u32 cppcr; /* PLL1 Control Register */
u32 cppcr_mask; /* PLL1 Control Register mask */
u32 pll_up_flag; /* New PLL freq is higher than current or not */
};
extern jz_clocks_t jz_clocks;
static void jz_update_clocks(void)
{
/* Next clocks must be updated if we have changed
* the PLL or divisors.
*/
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.lcdclk = __cpm_get_lcdclk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk(0);
}
static void
jz_init_boot_config(void)
{
if (!boot_config.lcd_clks_initialized) {
/* the first time to scale pll */
boot_config.lcd_clk = __cpm_get_lcdclk();
boot_config.lcdpix_clk = __cpm_get_pixclk();
boot_config.lcd_clks_initialized = 1;
}
if (!boot_config.sdram_initialized) {
/* the first time to scale frequencies */
unsigned int dmcr, rtcor;
unsigned int tras, rcd, tpc, trwl, trc;
dmcr = REG_EMC_DMCR;
rtcor = REG_EMC_RTCOR;
tras = (dmcr >> 13) & 0x7;
rcd = (dmcr >> 11) & 0x3;
tpc = (dmcr >> 8) & 0x7;
trwl = (dmcr >> 5) & 0x3;
trc = (dmcr >> 2) & 0x7;
boot_config.mclk = __cpm_get_mclk() / 1000;
boot_config.tras = tras + 4;
boot_config.rcd = rcd + 1;
boot_config.tpc = tpc + 1;
boot_config.trwl = trwl + 1;
boot_config.trc = trc * 2 + 1;
boot_config.rtcor = rtcor;
boot_config.sdram_initialized = 1;
}
}
static void jz_update_dram_rtcor(unsigned int new_mclk)
{
unsigned int rtcor;
new_mclk /= 1000;
rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
rtcor--;
if (rtcor < 1) rtcor = 1;
if (rtcor > 255) rtcor = 255;
REG_EMC_RTCOR = rtcor;
REG_EMC_RTCNT = rtcor;
}
static void jz_update_dram_dmcr(unsigned int new_mclk)
{
unsigned int dmcr;
unsigned int tras, rcd, tpc, trwl, trc;
unsigned int valid_time, new_time; /* ns */
new_mclk /= 1000;
tras = boot_config.tras * new_mclk / boot_config.mclk;
rcd = boot_config.rcd * new_mclk / boot_config.mclk;
tpc = boot_config.tpc * new_mclk / boot_config.mclk;
trwl = boot_config.trwl * new_mclk / boot_config.mclk;
trc = boot_config.trc * new_mclk / boot_config.mclk;
/* Validation checking */
valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
new_time = (tras * 1000000) / new_mclk;
if (new_time < valid_time) tras += 1;
valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
new_time = (rcd * 1000000) / new_mclk;
if (new_time < valid_time) rcd += 1;
valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
new_time = (tpc * 1000000) / new_mclk;
if (new_time < valid_time) tpc += 1;
valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
new_time = (trwl * 1000000) / new_mclk;
if (new_time < valid_time) trwl += 1;
valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
new_time = (trc * 1000000) / new_mclk;
if (new_time < valid_time) trc += 2;
tras = (tras < 4) ? 4: tras;
tras = (tras > 11) ? 11: tras;
tras -= 4;
rcd = (rcd < 1) ? 1: rcd;
rcd = (rcd > 4) ? 4: rcd;
rcd -= 1;
tpc = (tpc < 1) ? 1: tpc;
tpc = (tpc > 8) ? 8: tpc;
tpc -= 1;
trwl = (trwl < 1) ? 1: trwl;
trwl = (trwl > 4) ? 4: trwl;
trwl -= 1;
trc = (trc < 1) ? 1: trc;
trc = (trc > 15) ? 15: trc;
trc /= 2;
dmcr = REG_EMC_DMCR;
dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
REG_EMC_DMCR = dmcr;
}
static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
* and TRC of DMCR before changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
} else {
/* We're going SLOWER: first update RTCOR value
* before changing the frequency.
*/
jz_update_dram_rtcor(new_mclk);
}
}
static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so update RTCOR
* after changing the frequency
*/
jz_update_dram_rtcor(new_mclk);
} else {
/* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
* and TRC of DMCR after changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
}
}
static void jz_scale_divisors(struct dpm_regs *regs)
{
unsigned int cpccr;
unsigned int cur_mclk, new_mclk;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
cpccr = REG_CPM_CPCCR;
cpccr &= ~((unsigned long)regs->cpccr_mask);
cpccr |= regs->cpccr;
cpccr |= CPM_CPCCR_CE; /* update immediately */
cur_mclk = __cpm_get_mclk();
new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
/* Update some DRAM parameters before changing frequency */
jz_update_dram_prev(cur_mclk, new_mclk);
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#ifdef CHANGE_PLL
/* Maintain the LCD clock and pixel clock */
static void jz_scale_lcd_divisors(struct dpm_regs *regs)
{
unsigned int new_pll, new_lcd_div, new_lcdpix_div;
unsigned int cpccr;
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
if (!boot_config.lcd_clks_initialized) return;
new_pll = __cpm_get_pllout();
new_lcd_div = new_pll / boot_config.lcd_clk;
new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
if (new_lcd_div < 1)
new_lcd_div = 1;
if (new_lcd_div > 16)
new_lcd_div = 16;
if (new_lcdpix_div < 1)
new_lcdpix_div = 1;
if (new_lcdpix_div > 512)
new_lcdpix_div = 512;
// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
cpccr = REG_CPM_CPCCR;
cpccr &= ~CPM_CPCCR_LDIV_MASK;
cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
cpccr |= CPM_CPCCR_CE; /* update immediately */
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
}
static void jz_scale_pll(struct dpm_regs *regs)
{
unsigned int cppcr;
unsigned int cur_mclk, new_mclk, new_pll;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
int od[] = {1, 2, 2, 4};
cppcr = REG_CPM_CPPCR;
cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
regs->cppcr &= ~CPM_CPPCR_PLLEN;
cppcr |= (regs->cppcr | 0xff);
/* Update some DRAM parameters before changing frequency */
new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
cur_mclk = __cpm_get_mclk();
new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf];
/*
* Update some SDRAM parameters
*/
jz_update_dram_prev(cur_mclk, new_mclk);
/*
* Update PLL, align code to cache line.
*/
cppcr |= CPM_CPPCR_PLLEN;
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPPCR), "r" (cppcr));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#endif
static void jz4750_transition(struct dpm_regs *regs)
{
/*
* Get and save some boot-time conditions.
*/
jz_init_boot_config();
#ifdef CHANGE_PLL
/*
* Disable LCD before scaling pll.
* LCD and LCD pixel clocks should not be changed even if the PLL
* output frequency has been changed.
*/
REG_LCD_CTRL &= ~LCD_CTRL_ENA;
/*
* Stop module clocks before scaling PLL
*/
__cpm_stop_eth();
__cpm_stop_aic(1);
__cpm_stop_aic(2);
#endif
/* ... add more as necessary */
if (regs->pll_up_flag == PLL_GOES_UP) {
/* the pll frequency is going up, so change dividors first */
jz_scale_divisors(regs);
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
}
else if (regs->pll_up_flag == PLL_GOES_DOWN) {
/* the pll frequency is going down, so change pll first */
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
jz_scale_divisors(regs);
}
else {
/* the pll frequency is unchanged, so change divisors only */
jz_scale_divisors(regs);
}
#ifdef CHANGE_PLL
/*
* Restart module clocks before scaling PLL
*/
__cpm_start_eth();
__cpm_start_aic(1);
__cpm_start_aic(2);
/* ... add more as necessary */
/* Scale the LCD divisors after scaling pll */
if (regs->pll_up_flag != PLL_UNCHANGED) {
jz_scale_lcd_divisors(regs);
}
/* Enable LCD controller */
REG_LCD_CTRL &= ~LCD_CTRL_DIS;
REG_LCD_CTRL |= LCD_CTRL_ENA;
#endif
/* Update system clocks */
jz_update_clocks();
}
extern unsigned int idle_times;
static unsigned int jz4750_freq_get(unsigned int cpu)
{
return (__cpm_get_cclk() / 1000);
}
static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
{
int n2FR[33] = {
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
9
};
int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
unsigned int div_of_cclk, new_freq, i;
regs->pll_up_flag = PLL_UNCHANGED;
regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
new_freq = jz4750_freq_table.table[index].frequency;
do {
div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
} while (div_of_cclk==0);
if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
for(i = 1; i<4; i++) {
div[i] = 3;
}
} else {
for(i = 1; i<4; i++) {
div[i] = 2;
}
}
for(i = 0; i<4; i++) {
div[i] *= div_of_cclk;
}
dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
regs->cpccr =
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
return div_of_cclk;
}
static void jz4750_set_cpu_divider_index(unsigned int cpu, unsigned int index)
{
unsigned long divisor, old_divisor;
struct cpufreq_freqs freqs;
struct dpm_regs regs;
old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
divisor = index_to_divisor(index, &regs);
freqs.old = __cpm_get_cclk() / 1000;
freqs.new = __cpm_get_pllout() / (1000 * divisor);
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor)
jz4750_transition(&regs);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int jz4750_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy,
&jz4750_freq_table.table[0],
target_freq, relation, &new_index))
return -EINVAL;
jz4750_set_cpu_divider_index(policy->cpu, new_index);
dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
return 0;
}
static int jz4750_freq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
&jz4750_freq_table.table[0]);
}
static int __init jz4750_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *table = &jz4750_freq_table.table[0];
unsigned int MAX_FREQ;
dprintk(KERN_INFO "Jz4750 cpufreq driver\n");
if (policy->cpu != 0)
return -EINVAL;
policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = MAX_FREQ/8;
policy->cpuinfo.max_freq = MAX_FREQ;
policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
table[0].index = 0;
table[0].frequency = MAX_FREQ/8;
table[1].index = 1;
table[1].frequency = MAX_FREQ/6;
table[2].index = 2;
table[2].frequency = MAX_FREQ/4;
table[3].index = 3;
table[3].frequency = MAX_FREQ/3;
table[4].index = 4;
table[4].frequency = MAX_FREQ/2;
table[5].index = 5;
table[5].frequency = MAX_FREQ;
table[6].index = 6;
table[6].frequency = CPUFREQ_TABLE_END;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
#endif
return cpufreq_frequency_table_cpuinfo(policy, table);
}
static struct cpufreq_driver cpufreq_jz4750_driver = {
// .flags = CPUFREQ_STICKY,
.init = jz4750_cpufreq_driver_init,
.verify = jz4750_freq_verify,
.target = jz4750_freq_target,
.get = jz4750_freq_get,
.name = "jz4750",
};
static int __init jz4750_cpufreq_init(void)
{
return cpufreq_register_driver(&cpufreq_jz4750_driver);
}
static void __exit jz4750_cpufreq_exit(void)
{
cpufreq_unregister_driver(&cpufreq_jz4750_driver);
}
module_init(jz4750_cpufreq_init);
module_exit(jz4750_cpufreq_exit);
MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
MODULE_DESCRIPTION("cpufreq driver for Jz4750");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,836 @@
/*
* linux/arch/mips/jz4750/dma.c
*
* Support functions for the JZ4750 internal DMA channels.
* No-descriptor transfer only.
* Descriptor transfer should also call jz_request_dma() to get a free
* channel and call jz_free_dma() to free the channel. And driver should
* build the DMA descriptor and setup the DMA channel by itself.
*
* Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/soundcard.h>
#include <asm/system.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/*
* A note on resource allocation:
*
* All drivers needing DMA channels, should allocate and release them
* through the public routines `jz_request_dma()' and `jz_free_dma()'.
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
*
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
* When releasing them, first release the IRQ, then release the DMA. The
* main reason for this order is that, if you are requesting the DMA buffer
* done interrupt, you won't know the irq number until the DMA channel is
* returned from jz_request_dma().
*/
struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
{dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */
{dev_id:-1,}, /* DMAC0 channel 1 */
{dev_id:-1,}, /* DMAC0 channel 2 */
{dev_id:-1,}, /* DMAC0 channel 3 */
{dev_id:-1,}, /* DMAC0 channel 4 */
{dev_id:-1,}, /* DMAC0 channel 5 */
{dev_id:-1,}, /* DMAC1 channel 0 */
{dev_id:-1,}, /* DMAC1 channel 1 */
{dev_id:-1,}, /* DMAC1 channel 2 */
{dev_id:-1,}, /* DMAC1 channel 3 */
{dev_id:-1,}, /* DMAC1 channel 4 */
{dev_id:-1,}, /* DMAC1 channel 5 */
};
// Device FIFO addresses and default DMA modes
static const struct {
unsigned int fifo_addr;
unsigned int dma_mode;
unsigned int dma_source;
} dma_dev_table[DMA_ID_MAX] = {
{0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
{0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
{CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
{CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
{CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
{CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
{CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
{CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
{CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
{CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
{CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
{CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
{CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
{CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
{CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT},
{CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
{SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */
{CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */
{CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */
{CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT},
{CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN},
{CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT},
{CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN},
{},
};
int jz_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data)
{
int i, len = 0;
struct jz_dma_chan *chan;
for (i = 0; i < MAX_DMA_NUM; i++) {
if ((chan = get_dma_chan(i)) != NULL) {
len += sprintf(buf + len, "%2d: %s\n",
i, chan->dev_str);
}
}
if (fpos >= len) {
*start = buf;
*eof = 1;
return 0;
}
*start = buf + fpos;
if ((len -= fpos) > length)
return length;
*eof = 1;
return len;
}
void dump_jz_dma_channel(unsigned int dmanr)
{
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return;
chan = &jz_dma_table[dmanr];
printk("DMA%d Registers:\n", dmanr);
printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM));
printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM));
}
/**
* jz_request_dma - dynamically allcate an idle DMA channel to return
* @dev_id: the specified dma device id or DMA_ID_RAW_SET
* @dev_str: the specified dma device string name
* @irqhandler: the irq handler, or NULL
* @irqflags: the irq handler flags
* @irq_dev_id: the irq handler device id for shared irq
*
* Finds a free channel, and binds the requested device to it.
* Returns the allocated channel number, or negative on error.
* Requests the DMA done IRQ if irqhandler != NULL.
*
*/
/*int jz_request_dma(int dev_id, const char *dev_str,
void (*irqhandler)(int, void *, struct pt_regs *),
unsigned long irqflags,
void *irq_dev_id)
*/
int jz_request_dma(int dev_id, const char *dev_str,
irqreturn_t (*irqhandler)(int, void *),
unsigned long irqflags,
void *irq_dev_id)
{
struct jz_dma_chan *chan;
int i, ret, chan0;
if (dev_id < 0 || dev_id >= DMA_ID_MAX)
return -EINVAL;
/* Because of a bug in DMA controller of jz4750, which causes auto
request and device request can't be allocated in a same DMA
controller, all device requests should be put in the second DMA
controller
*/
if (dev_id > DMA_ID_AUTO)
chan0 = 6;
else
chan0 = 0;
for (i = chan0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM) /* no free channel */
return -ENODEV;
/* we got a free channel */
chan = &jz_dma_table[i];
if (irqhandler) {
chan->irq = IRQ_DMA_0 + i; // allocate irq number
chan->irq_dev = irq_dev_id;
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
dev_str, chan->irq_dev))) {
chan->irq = -1;
chan->irq_dev = NULL;
return ret;
}
} else {
chan->irq = -1;
chan->irq_dev = NULL;
}
// fill it in
chan->io = i;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
chan->mode = dma_dev_table[dev_id].dma_mode;
chan->source = dma_dev_table[dev_id].dma_source;
if (i < 6)
REG_DMAC_DMACKE(0) = 1 << i;
else
REG_DMAC_DMACKE(1) = 1 << (i - 6);
return i;
}
void jz_free_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan) {
printk("Trying to free DMA%d\n", dmanr);
return;
}
disable_dma(dmanr);
if (chan->irq)
free_irq(chan->irq, chan->irq_dev);
chan->irq = -1;
chan->irq_dev = NULL;
chan->dev_id = -1;
}
void jz_set_dma_dest_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_DWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_DWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_DWDH_32;
break;
}
}
void jz_set_dma_src_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_SWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_SWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_SWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_SWDH_32;
break;
}
}
void jz_set_dma_block_size(int dmanr, int nbyte)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DS_MASK;
switch (nbyte) {
case 1:
chan->mode |= DMAC_DCMD_DS_8BIT;
break;
case 2:
chan->mode |= DMAC_DCMD_DS_16BIT;
break;
case 4:
chan->mode |= DMAC_DCMD_DS_32BIT;
break;
case 16:
chan->mode |= DMAC_DCMD_DS_16BYTE;
break;
case 32:
chan->mode |= DMAC_DCMD_DS_32BYTE;
break;
}
}
unsigned int jz_get_dma_command(int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
return chan->mode;
}
/**
* jz_set_dma_mode - do the raw settings for the specified DMA channel
* @dmanr: the specified DMA channel
* @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
* @dma_mode: dma raw mode
* @dma_source: dma raw request source
* @fifo_addr: dma raw device fifo address
*
* Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
* jz_set_dma_mode() rather than set_dma_mode() if you work with
* and external request dma device.
*
* NOTE: Don not dynamically allocate dma channel if one external request
* dma device will occupy this channel.
*/
int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
unsigned int dma_mode, unsigned int dma_source,
unsigned int fifo_addr)
{
int dev_id, i;
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return -ENODEV;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM)
return -ENODEV;
chan = &jz_dma_table[dmanr];
dev_id = chan->dev_id;
if (dev_id > 0) {
printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
__FUNCTION__, dmanr);
return -ENODEV;
}
/* clone it from the dynamically allocated. */
if (i != dmanr) {
chan->irq = jz_dma_table[i].irq;
chan->irq_dev = jz_dma_table[i].irq_dev;
chan->dev_str = jz_dma_table[i].dev_str;
jz_dma_table[i].irq = 0;
jz_dma_table[i].irq_dev = NULL;
jz_dma_table[i].dev_id = -1;
}
chan->dev_id = DMA_ID_RAW_SET;
chan->io = dmanr;
chan->fifo_addr = fifo_addr;
chan->mode = dma_mode;
chan->source = dma_source;
set_dma_mode(dmanr, dma_mode);
return dmanr;
}
void enable_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
__dmac_enable_channel(dmanr);
if (chan->irq)
__dmac_channel_enable_irq(dmanr);
}
#define DMA_DISABLE_POLL 0x10000
void disable_dma(unsigned int dmanr)
{
int i;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
if (!__dmac_channel_enabled(dmanr))
return;
for (i = 0; i < DMA_DISABLE_POLL; i++)
if (__dmac_channel_transmit_end_detected(dmanr))
break;
#if 0
if (i == DMA_DISABLE_POLL)
printk(KERN_INFO "disable_dma: poll expired!\n");
#endif
__dmac_disable_channel(dmanr);
if (chan->irq)
__dmac_channel_disable_irq(dmanr);
}
/* Note: DMA_MODE_MASK is simulated by sw */
void set_dma_mode(unsigned int dmanr, unsigned int mode)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else {
printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
}
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
}
void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
{
unsigned int mode;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode = chan->mode & DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
REG_DMAC_DTAR(chan->io) = phyaddr;
} else if (mode == DMA_MODE_WRITE) {
REG_DMAC_DSAR(chan->io) = phyaddr;
REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
} else
printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
}
void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
int dma_ds[] = {4, 1, 2, 16, 32};
unsigned int ds;
if (!chan)
return;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
}
unsigned int get_dma_residue(unsigned int dmanr)
{
unsigned int count, ds;
int dma_ds[] = {4, 1, 2, 16, 32};
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
count = REG_DMAC_DTCR(chan->io);
count = count * dma_ds[ds];
return count;
}
void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case AFMT_U8:
/* burst mode : 32BIT */
break;
case AFMT_S16_LE:
/* burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
//chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case 8:
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
break;
case 16:
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
//#define JZ4750_DMAC_TEST_ENABLE
#undef JZ4750_DMAC_TEST_ENABLE
#ifdef JZ4750_DMAC_TEST_ENABLE
/*
* DMA test: external address <--> external address
*/
#define TEST_DMA_SIZE 16*1024
static jz_dma_desc *dma_desc;
static int dma_chan;
static dma_addr_t dma_desc_phys_addr;
static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
static int dma_check_result(void *src, void *dst, int size)
{
unsigned int addr1, addr2, i, err = 0;
addr1 = (unsigned int)src;
addr2 = (unsigned int)dst;
for (i = 0; i < size; i += 4) {
if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
err++;
printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
}
addr1 += 4;
addr2 += 4;
}
printk("check DMA result err=%d\n", err);
return err;
}
static irqreturn_t jz4750_dma_irq(int irq, void *dev_id)
{
printk("jz4750_dma_irq %d\n", irq);
if (__dmac_channel_transmit_halt_detected(dma_chan)) {
printk("DMA HALT\n");
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
__dmac_channel_clear_transmit_halt(dma_chan);
}
if (__dmac_channel_address_error_detected(dma_chan)) {
printk("DMA ADDR ERROR\n");
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */
REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */
__dmac_channel_clear_address_error(dma_chan);
}
if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
printk("DMA DESC INVALID\n");
__dmac_channel_clear_descriptor_invalid(dma_chan);
}
if (__dmac_channel_count_terminated_detected(dma_chan)) {
printk("DMA CT\n");
__dmac_channel_clear_count_terminated(dma_chan);
}
if (__dmac_channel_transmit_end_detected(dma_chan)) {
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
printk("DMA TT\n");
__dmac_channel_clear_transmit_end(dma_chan);
dump_jz_dma_channel(dma_chan);
dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
}
return IRQ_HANDLED;
}
void dma_nodesc_test(void)
{
unsigned int addr, i;
printk("dma_nodesc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq,
IRQF_DISABLED, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Init DMA module */
printk("Starting DMA\n");
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
REG_DMAC_DCCSR(dma_chan) = 0;
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
REG_DMAC_DTCR(dma_chan) = 512;
REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
/* wait a long time, ensure transfer end */
printk("wait 3s...\n");
mdelay(3000); /* wait 3s */
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
void dma_desc_test(void)
{
unsigned int next, addr, i;
static jz_dma_desc *desc;
printk("dma_desc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq,
IRQF_DISABLED, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Allocate DMA descriptors */
dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
/* Setup DMA descriptors */
desc = dma_desc;
next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr; /* DMA source address */
desc->dtadr = dma_dst_phys_addr; /* DMA target address */
desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
/* Setup DMA descriptor address */
REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
/* Setup request source */
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
/* Setup DMA channel control/status register */
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
/* Enable DMA */
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE;
/* DMA doorbell set -- start DMA now ... */
REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan;
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
/* wait a long time, ensure transfer end */
printk("wait 3s...\n");
mdelay(3000); /* wait 3s */
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
#endif
//EXPORT_SYMBOL_NOVERS(jz_dma_table);
EXPORT_SYMBOL(jz_dma_table);
EXPORT_SYMBOL(jz_request_dma);
EXPORT_SYMBOL(jz_free_dma);
EXPORT_SYMBOL(jz_set_dma_src_width);
EXPORT_SYMBOL(jz_set_dma_dest_width);
EXPORT_SYMBOL(jz_set_dma_block_size);
EXPORT_SYMBOL(jz_set_dma_mode);
EXPORT_SYMBOL(set_dma_mode);
EXPORT_SYMBOL(jz_set_oss_dma);
EXPORT_SYMBOL(jz_set_alsa_dma);
EXPORT_SYMBOL(set_dma_addr);
EXPORT_SYMBOL(set_dma_count);
EXPORT_SYMBOL(get_dma_residue);
EXPORT_SYMBOL(enable_dma);
EXPORT_SYMBOL(disable_dma);
EXPORT_SYMBOL(dump_jz_dma_channel);

View File

@@ -0,0 +1,386 @@
/*
* linux/arch/mips/jz4750/i2c.c
*
* Jz4750 I2C routines.
*
* Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/* I2C protocol */
#define I2C_READ 1
#define I2C_WRITE 0
#define TIMEOUT 1000
/*
* I2C bus protocol basic routines
*/
static int i2c_put_data(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (!__i2c_received_ack() && timeout)
timeout--;
if (timeout)
return 0;
else
return -ETIMEDOUT;
}
static int i2c_put_data_nack(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (timeout--);
return 0;
}
static int i2c_get_data(unsigned char *data, int ack)
{
int timeout = TIMEOUT*10;
if (!ack)
__i2c_send_nack();
else
__i2c_send_ack();
while (__i2c_check_drf() == 0 && timeout)
timeout--;
if (timeout) {
if (!ack)
__i2c_send_stop();
*data = __i2c_read();
__i2c_clear_drf();
return 0;
} else
return -ETIMEDOUT;
}
/*
* I2C interface
*/
void i2c_open(void)
{
__i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
__i2c_enable();
}
void i2c_close(void)
{
udelay(300); /* wait for STOP goes over. */
__i2c_disable();
}
void i2c_setclk(unsigned int i2cclk)
{
__i2c_set_clk(jz_clocks.extalclk, i2cclk);
}
int i2c_lseek(unsigned char device, unsigned char offset)
{
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data(offset) < 0)
goto address_err;
return 0;
device_err:
printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
__i2c_send_stop();
return -ENODEV;
address_err:
printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
__i2c_send_stop();
return -EREMOTEIO;
}
int i2c_read(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int timeout = 5;
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data(address) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddr;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddr = address;
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
#ifdef CONFIG_JZ_TPANEL_ATA2508
if (address == 0xff) {
if (i2c_put_data_nack(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data_nack(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
else {
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
#else
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
#endif
__i2c_send_stop();
return count - cnt;
device_err:
address_err:
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
int i2c_read_16(unsigned char device, unsigned char *buf,
unsigned short address, int count)
{
int cnt = count;
int timeout = 5;
unsigned char tmpaddrh, tmpaddrl;
tmpaddrh = (unsigned char)((address >> 8) & 0xff);
tmpaddrl = (unsigned char)(address & 0xff);
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data_nack(tmpaddrh) < 0)
goto address_err;
if (i2c_put_data(tmpaddrl) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write_16(unsigned char device, unsigned char *buf,
unsigned short address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddrh, tmpaddrl;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddrh = (unsigned char)((address >> 8) & 0xff);
tmpaddrl = (unsigned char)(address & 0xff);
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data_nack(tmpaddrh) < 0)
goto address_err;
if (i2c_put_data(tmpaddrl) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddrh += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
__i2c_send_stop();
return count - cnt;
device_err:
printk("1:Write I2C device 0x%2x failed.\n", device);
address_err:
printk("2:Write I2C address 0x%2x failed.\n", address);
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk("3:Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
EXPORT_SYMBOL(i2c_open);
EXPORT_SYMBOL(i2c_close);
EXPORT_SYMBOL(i2c_setclk);
EXPORT_SYMBOL(i2c_read);
EXPORT_SYMBOL(i2c_write);
EXPORT_SYMBOL(i2c_read_16);
EXPORT_SYMBOL(i2c_write_16);

View File

@@ -0,0 +1,299 @@
/*
* linux/arch/mips/jz4750/irq.c
*
* JZ4750 interrupt routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
/*
* INTC irq type
*/
static void enable_intc_irq(unsigned int irq)
{
__intc_unmask_irq(irq);
}
static void disable_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
}
static void mask_and_ack_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
__intc_ack_irq(irq);
}
static void end_intc_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
enable_intc_irq(irq);
}
}
static unsigned int startup_intc_irq(unsigned int irq)
{
enable_intc_irq(irq);
return 0;
}
static void shutdown_intc_irq(unsigned int irq)
{
disable_intc_irq(irq);
}
static struct irq_chip intc_irq_type = {
.typename = "INTC",
.startup = startup_intc_irq,
.shutdown = shutdown_intc_irq,
.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<<irq);
irq = plat_real_irq(irq);
do_IRQ(irq);
}

View File

@@ -0,0 +1,147 @@
/*
* Platform device support for Jz4740 SoC.
*
* Copyright 2007, <yliu@ingenic.cn>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <asm/jzsoc.h>
/* OHCI (USB full speed host controller) */
static struct resource jz_usb_ohci_resources[] = {
[0] = {
.start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
.end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UHC,
.end = IRQ_UHC,
.flags = IORESOURCE_IRQ,
},
};
/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;
static struct platform_device jz_usb_ohci_device = {
.name = "jz-ohci",
.id = 0,
.dev = {
.dma_mask = &ohci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
.resource = jz_usb_ohci_resources,
};
/*** LCD controller ***/
static struct resource jz_lcd_resources[] = {
[0] = {
.start = CPHYSADDR(LCD_BASE),
.end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_lcd_dmamask = ~(u32)0;
static struct platform_device jz_lcd_device = {
.name = "jz-lcd",
.id = 0,
.dev = {
.dma_mask = &jz_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_lcd_resources),
.resource = jz_lcd_resources,
};
/* UDC (USB gadget controller) */
static struct resource jz_usb_gdt_resources[] = {
[0] = {
.start = CPHYSADDR(UDC_BASE),
.end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UDC,
.end = IRQ_UDC,
.flags = IORESOURCE_IRQ,
},
};
static u64 udc_dmamask = ~(u32)0;
static struct platform_device jz_usb_gdt_device = {
.name = "jz-udc",
.id = 0,
.dev = {
.dma_mask = &udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
.resource = jz_usb_gdt_resources,
};
/** MMC/SD controller **/
static struct resource jz_mmc_resources[] = {
[0] = {
.start = CPHYSADDR(MSC_BASE),
.end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_MSC0,
.end = IRQ_MSC0,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_mmc_dmamask = ~(u32)0;
static struct platform_device jz_mmc_device = {
.name = "jz-mmc",
.id = 0,
.dev = {
.dma_mask = &jz_mmc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_mmc_resources),
.resource = jz_mmc_resources,
};
struct platform_device jz4750_rtc_device = {
.name = "jz4750-rtc",
.id = -1,
};
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
&jz_usb_ohci_device,
&jz_lcd_device,
&jz_usb_gdt_device,
&jz_mmc_device,
&jz4750_rtc_device,
};
static int __init jz_platform_init(void)
{
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
arch_initcall(jz_platform_init);

View File

@@ -0,0 +1,203 @@
/*
* linux/arch/mips/jz4750/common/pm.c
*
* JZ4750 Power Management Routines
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/module.h>
#include <linux/suspend.h>
#include <asm/cacheops.h>
#include <asm/jzsoc.h>
extern void jz_board_do_sleep(unsigned long *ptr);
extern void jz_board_do_resume(unsigned long *ptr);
static void jz_pm_do_hibernate(void)
{
printk("Put CPU into hibernate mode.\n");
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/*
* RTC Wakeup or 1Hz interrupt can be enabled or disabled
* through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
*/
/* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
/* Set reset pin low-level assertion time after wakeup: must > 60ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
/* Scratch pad register to be reserved */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HSPR = 0x12345678;
/* clear wakeup status register */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWRSR = 0x0;
/* Put CPU to power down mode */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HCR = RTC_HCR_PD;
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
while(1);
/* We can't get here */
}
static int jz_pm_do_sleep(void)
{
unsigned long delta;
unsigned long nfcsr = REG_EMC_NFCSR;
unsigned long opcr = REG_CPM_OPCR;
unsigned long imr = REG_INTC_IMR;
unsigned long sadc = REG_SADC_ENA;
unsigned long sleep_gpio_save[4*(GPIO_PORT_NUM-1)];
printk("Put CPU into sleep mode.\n");
/* Preserve current time */
delta = xtime.tv_sec - REG_RTC_RSR;
/* Disable nand flash */
REG_EMC_NFCSR = ~0xff;
/* stop sadc */
REG_SADC_ENA &= ~0x7;
while((REG_SADC_ENA & 0x7) != 0);
udelay(100);
/*stop udc and usb*/
__cpm_suspend_uhcphy();
__cpm_suspend_udcphy();
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/* Sleep on-board modules and setup wake event */
jz_board_do_sleep(sleep_gpio_save);
/* disable externel clock Oscillator in sleep mode */
__cpm_disable_osc_in_sleep();
/* select 32K crystal as RTC clock in sleep mode */
__cpm_select_rtcclk_rtc();
/* Enter SLEEP mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
/* Restore to IDLE mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
/* Restore nand flash control register */
REG_EMC_NFCSR = nfcsr;
/* Restore interrupts */
REG_INTC_IMSR = imr;
REG_INTC_IMCR = ~imr;
/* Restore sadc */
REG_SADC_ENA = sadc;
/* Resume on-board modules */
jz_board_do_resume(sleep_gpio_save);
/* Restore Oscillator and Power Control Register */
REG_CPM_OPCR = opcr;
/* Restore current time */
xtime.tv_sec = REG_RTC_RSR + delta;
printk("Resume CPU from sleep mode.\n");
return 0;
}
/* Put CPU to HIBERNATE mode
*----------------------------------------------------------------------------
* Power Management sleep sysctl interface
*
* Write "mem" to /sys/power/state invokes this function
* which initiates a poweroff.
*/
void jz_pm_hibernate(void)
{
jz_pm_do_hibernate();
}
/* Put CPU to SLEEP mode
*----------------------------------------------------------------------------
* Power Management sleep sysctl interface
*
* Write "standby" to /sys/power/state invokes this function
* which initiates a sleep.
*/
int jz_pm_sleep(void)
{
return jz_pm_do_sleep();
}
/*
* valid states, only support standby(sleep) and mem(hibernate)
*/
static int jz4750_pm_valid(suspend_state_t state)
{
return state == PM_SUSPEND_MEM;
}
/*
* Jz CPU enter save power mode
*/
static int jz4750_pm_enter(suspend_state_t state)
{
return jz_pm_do_sleep();
}
static struct platform_suspend_ops jz4750_pm_ops = {
.valid = jz4750_pm_valid,
.enter = jz4750_pm_enter,
};
/*
* Initialize power interface
*/
int __init jz_pm_init(void)
{
printk("JZ4750 Power Management\n");
suspend_set_ops(&jz4750_pm_ops);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,198 @@
/*
*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, supports YAMON and U-Boot.
*
* Copyright 2000, 2001, 2006 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/jzsoc.h>
/* #define DEBUG_CMDLINE */
int prom_argc;
char **prom_argv, **prom_envp;
char * prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
if (prom_argc > 1)
*cp = '\0';
}
char *prom_getenv(char *envname)
{
#if 0
/*
* Return a pointer to the given environment variable.
* YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
*/
char **env = prom_envp;
int i = strlen(envname);
int yamon = (*env && strchr(*env, '=') == NULL);
while (*env) {
if (yamon) {
if (strcmp(envname, *env++) == 0)
return *env;
} else {
if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
return *env + i + 1;
}
env++;
}
#endif
return NULL;
}
inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0; /* foo */
}
inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
for(i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
#if 0
{
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
#endif
return 0;
}
void __init prom_free_prom_memory(void)
{
}
void __init prom_init(void)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = (int) fw_arg0;
prom_argv = (char **) fw_arg1;
prom_envp = (char **) fw_arg2;
mips_machtype = MACH_INGENIC_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);

View File

@@ -0,0 +1,46 @@
/*
* linux/arch/mips/jz4750/reset.c
*
* JZ4750 reset routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <yliu@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
void jz_restart(char *command)
{
printk("Restarting after 4 ms\n");
REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
REG_WDT_TCNT = 0;
REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */
REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
while (1);
}
void jz_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
}
void jz_power_off(void)
{
jz_halt();
}

View File

@@ -0,0 +1,206 @@
/*
* linux/arch/mips/jz4750/common/setup.c
*
* JZ4750 common setup routines.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
#ifdef CONFIG_PM
#include <asm/suspend.h>
#endif
#ifdef CONFIG_PC_KEYB
#include <asm/keyboard.h>
#endif
jz_clocks_t jz_clocks;
extern char * __init prom_getcmdline(void);
extern void __init jz_board_setup(void);
extern void jz_restart(char *);
extern void jz_halt(void);
extern void jz_power_off(void);
extern void jz_pm_hibernate(void);
extern void jz_time_init(void);
static void __init sysclocks_setup(void)
{
#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.lcdclk = __cpm_get_lcdclk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk(0);
jz_clocks.extalclk = __cpm_get_extalclk();
jz_clocks.rtcclk = __cpm_get_rtcclk();
#else
#define FPGACLK 8000000
jz_clocks.cclk = FPGACLK;
jz_clocks.hclk = FPGACLK;
jz_clocks.pclk = FPGACLK;
jz_clocks.mclk = FPGACLK;
jz_clocks.lcdclk = FPGACLK;
jz_clocks.pixclk = FPGACLK;
jz_clocks.i2sclk = FPGACLK;
jz_clocks.usbclk = FPGACLK;
jz_clocks.mscclk = FPGACLK;
jz_clocks.extalclk = FPGACLK;
jz_clocks.rtcclk = FPGACLK;
#endif
printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
(jz_clocks.cclk + 500000) / 1000000,
(jz_clocks.hclk + 500000) / 1000000,
(jz_clocks.pclk + 500000) / 1000000,
(jz_clocks.mclk + 500000) / 1000000);
}
static void __init soc_cpm_setup(void)
{
/* Start all module clocks
*/
__cpm_start_all();
/* Enable CKO to external memory */
__cpm_enable_cko();
/* CPU enters IDLE mode when executing 'wait' instruction */
__cpm_idle_mode();
/* Setup system clocks */
sysclocks_setup();
}
static void __init soc_harb_setup(void)
{
// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
}
static void __init soc_emc_setup(void)
{
}
static void __init soc_dmac_setup(void)
{
__dmac_enable_module(0);
__dmac_enable_module(1);
}
static void __init jz_soc_setup(void)
{
soc_cpm_setup();
soc_harb_setup();
soc_emc_setup();
soc_dmac_setup();
}
static void __init jz_serial_setup(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port s;
REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
memset(&s, 0, sizeof(s));
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = SERIAL_IO_MEM;
s.regshift = 2;
s.uartclk = jz_clocks.extalclk ;
s.line = 0;
s.membase = (u8 *)UART0_BASE;
s.irq = IRQ_UART0;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS0 setup failed!\n");
}
s.line = 1;
s.membase = (u8 *)UART1_BASE;
s.irq = IRQ_UART1;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS1 setup failed!\n");
}
s.line = 2;
s.membase = (u8 *)UART2_BASE;
s.irq = IRQ_UART2;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS2 setup failed!\n");
}
s.line = 3;
s.membase = (u8 *)UART3_BASE;
s.irq = IRQ_UART3;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS3 setup failed!\n");
}
#endif
}
void __init plat_mem_setup(void)
{
char *argptr;
argptr = prom_getcmdline();
/* IO/MEM resources. Which will be the addtion value in `inX' and
* `outX' macros defined in asm/io.h */
set_io_port_base(0);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x00000000;
iomem_resource.end = 0xffffffff;
_machine_restart = jz_restart;
_machine_halt = jz_halt;
pm_power_off = jz_pm_hibernate;
jz_soc_setup();
jz_serial_setup();
jz_board_setup();
#ifdef CONFIG_PM
jz_pm_init();
#endif
}

View File

@@ -0,0 +1,157 @@
/*
* linux/arch/mips/jz4750/time.c
*
* Setting up the clock on the JZ4750 boards.
*
* Copyright (C) 2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
/* This is for machines which generate the exact clock. */
#define JZ_TIMER_IRQ IRQ_TCU0
#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
static struct clocksource clocksource_jz; /* Jz clock source */
static struct clock_event_device jz_clockevent_device; /* Jz clock event */
void (*jz_timer_callback)(void);
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = dev_id;
REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
if (jz_timer_callback)
jz_timer_callback();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction jz_irqaction = {
.handler = jz_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
.name = "jz-timerirq",
};
cycle_t jz_get_cycles(void)
{
/* convert jiffes to jz timer cycles */
return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT);
}
static struct clocksource clocksource_jz = {
.name = "jz_clocksource",
.rating = 300,
.read = jz_get_cycles,
.mask = 0xFFFFFFFF,
.shift = 10,
.flags = CLOCK_SOURCE_WATCHDOG,
};
static int __init jz_clocksource_init(void)
{
clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
clocksource_register(&clocksource_jz);
return 0;
}
static int jz_set_next_event(unsigned long evt,
struct clock_event_device *unused)
{
return 0;
}
static void jz_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}
static struct clock_event_device jz_clockevent_device = {
.name = "jz-clockenvent",
.features = CLOCK_EVT_FEAT_PERIODIC,
// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
.mult = 1,
.rating = 300,
.irq = JZ_TIMER_IRQ,
.set_mode = jz_set_mode,
.set_next_event = jz_set_next_event,
};
static void __init jz_clockevent_init(void)
{
struct clock_event_device *cd = &jz_clockevent_device;
unsigned int cpu = smp_processor_id();
cd->cpumask = cpumask_of_cpu(cpu);
clockevents_register_device(cd);
}
static void __init jz_timer_setup(void)
{
jz_clocksource_init(); /* init jz clock source */
jz_clockevent_init(); /* init jz clock event */
/*
* Make irqs happen for the system timer
*/
jz_irqaction.dev_id = &jz_clockevent_device;
setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
}
void __init plat_time_init(void)
{
unsigned int latch;
/* Init timer */
latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN;
REG_TCU_OSTCNT = 0;
REG_TCU_OSTDR = latch;
REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */
REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */
REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */
jz_timer_setup();
}

View File

@@ -0,0 +1,23 @@
#
# Makefile for the Ingenic JZ4750D.
#
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
platform.o i2c.o
obj-$(CONFIG_PROC_FS) += proc.o
# board specific support
obj-$(CONFIG_JZ4750D_FUWA1) += board-fuwa1.o
obj-$(CONFIG_JZ4750D_CETUS) += board-cetus.o
# PM support
obj-$(CONFIG_PM) +=pm.o
# CPU Frequency scaling support
obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o

View File

@@ -0,0 +1,301 @@
/*
* linux/arch/mips/jz4750d/board-cetus.c
*
* JZ4750D CETUS board setup routines.
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
/*********************************************************************************
* Power management routines
********************************************************************************/
/*
* __gpio_as_sleep set all pins to pull-disable, and set all pins as input
* except sdram and the pins which can be used as CS1_N to CS4_N for chip select.
*/
#define __gpio_as_sleep() \
do { \
REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \
REG_GPIO_PXSELC(1) = ~0x03ff7fff; \
REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \
REG_GPIO_PXPES(1) = ~0x03ff7fff; \
REG_GPIO_PXFUNC(2) = ~0x01e00000; \
REG_GPIO_PXSELC(2) = ~0x01e00000; \
REG_GPIO_PXDIRC(2) = ~0x01e00000; \
REG_GPIO_PXPES(2) = ~0x01e00000; \
REG_GPIO_PXFUNC(3) = 0xffffffff; \
REG_GPIO_PXSELC(3) = 0xffffffff; \
REG_GPIO_PXDIRC(3) = 0xffffffff; \
REG_GPIO_PXPES(3) = 0xffffffff; \
REG_GPIO_PXFUNC(4) = 0xffffffff; \
REG_GPIO_PXSELC(4) = 0xffffffff; \
REG_GPIO_PXDIRC(4) = 0xffffffff; \
REG_GPIO_PXPES(4) = 0xffffffff; \
REG_GPIO_PXFUNC(5) = 0xffffffff; \
REG_GPIO_PXSELC(5) = 0xffffffff; \
REG_GPIO_PXDIRC(5) = 0xffffffff; \
REG_GPIO_PXPES(5) = 0xffffffff; \
} while (0)
extern void (*jz_timer_callback)(void);
struct wakeup_key_s {
int gpio; /* gpio pin number */
int active_low; /* the key interrupt pin is low voltage
or fall edge acitve */
};
/* add wakeup keys here */
static struct wakeup_key_s wakeup_key[] = {
{
.gpio = GPIO_CALL,
.active_low = ACTIVE_LOW_CALL,
},
{
.gpio = GPIO_HOME,
.active_low = ACTIVE_LOW_HOME,
},
{
.gpio = GPIO_BACK,
.active_low = ACTIVE_LOW_BACK,
},
{
.gpio = GPIO_MENU,
.active_low = ACTIVE_LOW_MENU,
},
{
.gpio = GPIO_ENDCALL,
.active_low = ACTIVE_LOW_ENDCALL,
},
{
.gpio = GPIO_ADKEY_INT,
.active_low = ACTIVE_LOW_ADKEY,
},
};
static void wakeup_key_setup(void)
{
int i;
int num = sizeof(wakeup_key) / sizeof(wakeup_key[0]);
for(i = 0; i < num; i++) {
#if 0
if(wakeup_key[i].active_low)
__gpio_as_irq_fall_edge(wakeup_key[i].gpio);
else
__gpio_as_irq_rise_edge(wakeup_key[i].gpio);
#endif
__gpio_ack_irq(wakeup_key[i].gpio);
__gpio_unmask_irq(wakeup_key[i].gpio);
__intc_unmask_irq(IRQ_GPIO0 - (wakeup_key[i].gpio/32)); /* unmask IRQ_GPIOn */
}
}
/* NOTES:
* 1: Pins that are floated (NC) should be set as input and pull-enable.
* 2: Pins that are pull-up or pull-down by outside should be set as input
* and pull-disable.
* 3: Pins that are connected to a chip except sdram and nand flash
* should be set as input and pull-disable, too.
*/
void jz_board_do_sleep(unsigned long *ptr)
{
unsigned char i;
#ifdef DEBUG
__intc_unmask_irq(IRQ_UART3);
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
printk("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));
}
#endif
/* Save GPIO registers */
for(i = 1; i < GPIO_PORT_NUM; i++) {
*ptr++ = REG_GPIO_PXFUN(i);
*ptr++ = REG_GPIO_PXSEL(i);
*ptr++ = REG_GPIO_PXDIR(i);
*ptr++ = REG_GPIO_PXPE(i);
}
/*
* Mask the ethernet irq
*/
// __gpio_mask_irq(GPIO_NET_INT);
/*
* Set all pins to pull-disable, and set all pins as input except
* sdram and the pins which can be used as CS1_N to CS4_N for chip select.
*/
// __gpio_as_sleep();
/*
* Set proper status for GPC21 to GPC24 which can be used as CS1_N to CS4_N.
* Keep the pins' function used for chip select(CS) here according to your
* system to avoid chip select crashing with sdram when resuming from sleep mode.
*/
/* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
/* GPB26/CS2_N is connected to nand flash, needn't be changed. */
/* GPB28/CS3_N is used as cs8900's chip select, shouldn't be changed. */
/* GPB27/CS4_N is used as NOR's chip select, shouldn't be changed. */
/*
* Enable pull for NC pins here according to your system
*/
/*
* 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);
*/
/* AMPEN_N should be set to high to disable audio amplifier */
__gpio_as_output(GPIO_AMPEN_N);
__gpio_set_pin(GPIO_AMPEN_N);
#ifdef DEBUG
/* Keep uart function for printing debug message */
__gpio_as_uart0();
__gpio_as_uart1();
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
printk("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));
}
__intc_mask_irq(IRQ_UART1);
#endif
/*
* Just allow following interrupts to wakeup the system.
*/
#ifdef CONFIG_RTC_CLASS
/* 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
#endif
/* setup wakeup keys before sleeping */
wakeup_key_setup();
}
void jz_board_do_resume(unsigned long *ptr)
{
unsigned char i;
/* Restore GPIO registers */
for(i = 1; i < GPIO_PORT_NUM; i++) {
REG_GPIO_PXFUNS(i) = *ptr;
REG_GPIO_PXFUNC(i) = ~(*ptr++);
REG_GPIO_PXSELS(i) = *ptr;
REG_GPIO_PXSELC(i) = ~(*ptr++);
REG_GPIO_PXDIRS(i) = *ptr;
REG_GPIO_PXDIRC(i) = ~(*ptr++);
REG_GPIO_PXPES(i) = *ptr;
REG_GPIO_PXPEC(i) = ~(*ptr++);
}
#ifdef DEBUG
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
printk("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));
}
#endif
}
#if 0
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;
}
}
#endif
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
*/
__lcd_close_backlight();
}
void __init jz_board_setup(void)
{
printk("JZ4750D CETUS board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = NULL;//cetus_timer_callback;
}
/**
* Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'.
* Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc.
*/
const char *get_board_type(void)
{
return "cetus";
}

View File

@@ -0,0 +1,81 @@
/*
* linux/arch/mips/jz4750d/board-fuwa1.c
*
* JZ4750D FUWA1 board setup routines.
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned char slash[] = "\\|/-";
// static volatile unsigned char *p = (unsigned char *)0xb6000058;
static volatile unsigned char *p = (unsigned char *)0xb6000016;
static unsigned int count = 0;
*p = slash[count++];
count &= 3;
}
static void fuwa1_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4750d/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Initialize SDRAM pins
*/
}
void __init jz_board_setup(void)
{
printk("JZ4750D FUWA1 board setup\n");
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = fuwa1_timer_callback;
}
/**
* Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'.
* Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc.
*/
const char *get_board_type(void)
{
return "fuwa1";
}

View File

@@ -0,0 +1,600 @@
/*
* linux/arch/mips/jz4750d/cpufreq.c
*
* cpufreq driver for JZ4750D
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <asm/jzsoc.h>
#include <asm/processor.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"cpufreq-jz4750d", msg)
#undef CHANGE_PLL
#define PLL_UNCHANGED 0
#define PLL_GOES_UP 1
#define PLL_GOES_DOWN 2
#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
/* Saved the boot-time parameters */
static struct {
/* SDRAM parameters */
unsigned int mclk; /* memory clock, KHz */
unsigned int tras; /* RAS pulse width, cycles of mclk */
unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
unsigned int tpc; /* RAS Precharge time, cycles of mclk */
unsigned int trwl; /* Write Precharge Time, cycles of mclk */
unsigned int trc; /* RAS Cycle Time, cycles of mclk */
unsigned int rtcor; /* Refresh Time Constant */
unsigned int sdram_initialized;
/* LCD parameters */
unsigned int ah1_clk; /* LCD clock, Hz */
unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
unsigned int lcd_clks_initialized;
} boot_config;
struct jz4750d_freq_percpu_info {
struct cpufreq_frequency_table table[7];
};
static struct jz4750d_freq_percpu_info jz4750d_freq_table;
/*
* This contains the registers value for an operating point.
* If only part of a register needs to change then there is
* a mask value for that register.
* When going to a new operating point the current register
* value is ANDed with the ~mask and ORed with the new value.
*/
struct dpm_regs {
u32 cpccr; /* Clock Freq Control Register */
u32 cpccr_mask; /* Clock Freq Control Register mask */
u32 cppcr; /* PLL1 Control Register */
u32 cppcr_mask; /* PLL1 Control Register mask */
u32 pll_up_flag; /* New PLL freq is higher than current or not */
};
extern jz_clocks_t jz_clocks;
static void jz_update_clocks(void)
{
/* Next clocks must be updated if we have changed
* the PLL or divisors.
*/
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.h1clk = __cpm_get_h1clk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk(0);
}
static void
jz_init_boot_config(void)
{
if (!boot_config.lcd_clks_initialized) {
/* the first time to scale pll */
boot_config.lcdpix_clk = __cpm_get_pixclk();
boot_config.lcd_clks_initialized = 1;
}
if (!boot_config.sdram_initialized) {
/* the first time to scale frequencies */
unsigned int dmcr, rtcor;
unsigned int tras, rcd, tpc, trwl, trc;
dmcr = REG_EMC_DMCR;
rtcor = REG_EMC_RTCOR;
tras = (dmcr >> 13) & 0x7;
rcd = (dmcr >> 11) & 0x3;
tpc = (dmcr >> 8) & 0x7;
trwl = (dmcr >> 5) & 0x3;
trc = (dmcr >> 2) & 0x7;
boot_config.mclk = __cpm_get_mclk() / 1000;
boot_config.tras = tras + 4;
boot_config.rcd = rcd + 1;
boot_config.tpc = tpc + 1;
boot_config.trwl = trwl + 1;
boot_config.trc = trc * 2 + 1;
boot_config.rtcor = rtcor;
boot_config.sdram_initialized = 1;
}
}
static void jz_update_dram_rtcor(unsigned int new_mclk)
{
unsigned int rtcor;
new_mclk /= 1000;
rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
rtcor--;
if (rtcor < 1) rtcor = 1;
if (rtcor > 255) rtcor = 255;
REG_EMC_RTCOR = rtcor;
REG_EMC_RTCNT = rtcor;
}
static void jz_update_dram_dmcr(unsigned int new_mclk)
{
unsigned int dmcr;
unsigned int tras, rcd, tpc, trwl, trc;
unsigned int valid_time, new_time; /* ns */
new_mclk /= 1000;
tras = boot_config.tras * new_mclk / boot_config.mclk;
rcd = boot_config.rcd * new_mclk / boot_config.mclk;
tpc = boot_config.tpc * new_mclk / boot_config.mclk;
trwl = boot_config.trwl * new_mclk / boot_config.mclk;
trc = boot_config.trc * new_mclk / boot_config.mclk;
/* Validation checking */
valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
new_time = (tras * 1000000) / new_mclk;
if (new_time < valid_time) tras += 1;
valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
new_time = (rcd * 1000000) / new_mclk;
if (new_time < valid_time) rcd += 1;
valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
new_time = (tpc * 1000000) / new_mclk;
if (new_time < valid_time) tpc += 1;
valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
new_time = (trwl * 1000000) / new_mclk;
if (new_time < valid_time) trwl += 1;
valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
new_time = (trc * 1000000) / new_mclk;
if (new_time < valid_time) trc += 2;
tras = (tras < 4) ? 4: tras;
tras = (tras > 11) ? 11: tras;
tras -= 4;
rcd = (rcd < 1) ? 1: rcd;
rcd = (rcd > 4) ? 4: rcd;
rcd -= 1;
tpc = (tpc < 1) ? 1: tpc;
tpc = (tpc > 8) ? 8: tpc;
tpc -= 1;
trwl = (trwl < 1) ? 1: trwl;
trwl = (trwl > 4) ? 4: trwl;
trwl -= 1;
trc = (trc < 1) ? 1: trc;
trc = (trc > 15) ? 15: trc;
trc /= 2;
dmcr = REG_EMC_DMCR;
dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
REG_EMC_DMCR = dmcr;
}
static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
* and TRC of DMCR before changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
} else {
/* We're going SLOWER: first update RTCOR value
* before changing the frequency.
*/
jz_update_dram_rtcor(new_mclk);
}
}
static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so update RTCOR
* after changing the frequency
*/
jz_update_dram_rtcor(new_mclk);
} else {
/* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
* and TRC of DMCR after changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
}
}
static void jz_scale_divisors(struct dpm_regs *regs)
{
unsigned int cpccr;
unsigned int cur_mclk, new_mclk;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
cpccr = REG_CPM_CPCCR;
cpccr &= ~((unsigned long)regs->cpccr_mask);
cpccr |= regs->cpccr;
cpccr |= CPM_CPCCR_CE; /* update immediately */
cur_mclk = __cpm_get_mclk();
new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
/* Update some DRAM parameters before changing frequency */
jz_update_dram_prev(cur_mclk, new_mclk);
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#ifdef CHANGE_PLL
/* Maintain the LCD clock and pixel clock */
static void jz_scale_lcd_divisors(struct dpm_regs *regs)
{
unsigned int new_pll, new_lcd_div, new_lcdpix_div;
unsigned int cpccr;
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
if (!boot_config.lcd_clks_initialized) return;
new_pll = __cpm_get_pllout();
new_lcd_div = new_pll / boot_config.lcd_clk;
new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
if (new_lcd_div < 1)
new_lcd_div = 1;
if (new_lcd_div > 16)
new_lcd_div = 16;
if (new_lcdpix_div < 1)
new_lcdpix_div = 1;
if (new_lcdpix_div > 512)
new_lcdpix_div = 512;
// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
cpccr = REG_CPM_CPCCR;
cpccr &= ~CPM_CPCCR_LDIV_MASK;
cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
cpccr |= CPM_CPCCR_CE; /* update immediately */
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
}
static void jz_scale_pll(struct dpm_regs *regs)
{
unsigned int cppcr;
unsigned int cur_mclk, new_mclk, new_pll;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
int od[] = {1, 2, 2, 4};
cppcr = REG_CPM_CPPCR;
cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
regs->cppcr &= ~CPM_CPPCR_PLLEN;
cppcr |= (regs->cppcr | 0xff);
/* Update some DRAM parameters before changing frequency */
new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
cur_mclk = __cpm_get_mclk();
new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf];
/*
* Update some SDRAM parameters
*/
jz_update_dram_prev(cur_mclk, new_mclk);
/*
* Update PLL, align code to cache line.
*/
cppcr |= CPM_CPPCR_PLLEN;
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPPCR), "r" (cppcr));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#endif
static void jz4750d_transition(struct dpm_regs *regs)
{
/*
* Get and save some boot-time conditions.
*/
jz_init_boot_config();
#ifdef CHANGE_PLL
/*
* Disable LCD before scaling pll.
* LCD and LCD pixel clocks should not be changed even if the PLL
* output frequency has been changed.
*/
REG_LCD_CTRL &= ~LCD_CTRL_ENA;
/*
* Stop module clocks before scaling PLL
*/
__cpm_stop_eth();
__cpm_stop_aic(1);
__cpm_stop_aic(2);
#endif
/* ... add more as necessary */
if (regs->pll_up_flag == PLL_GOES_UP) {
/* the pll frequency is going up, so change dividors first */
jz_scale_divisors(regs);
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
}
else if (regs->pll_up_flag == PLL_GOES_DOWN) {
/* the pll frequency is going down, so change pll first */
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
jz_scale_divisors(regs);
}
else {
/* the pll frequency is unchanged, so change divisors only */
jz_scale_divisors(regs);
}
#ifdef CHANGE_PLL
/*
* Restart module clocks before scaling PLL
*/
__cpm_start_eth();
__cpm_start_aic(1);
__cpm_start_aic(2);
/* ... add more as necessary */
/* Scale the LCD divisors after scaling pll */
if (regs->pll_up_flag != PLL_UNCHANGED) {
jz_scale_lcd_divisors(regs);
}
/* Enable LCD controller */
REG_LCD_CTRL &= ~LCD_CTRL_DIS;
REG_LCD_CTRL |= LCD_CTRL_ENA;
#endif
/* Update system clocks */
jz_update_clocks();
}
extern unsigned int idle_times;
static unsigned int jz4750d_freq_get(unsigned int cpu)
{
return (__cpm_get_cclk() / 1000);
}
static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
{
int n2FR[33] = {
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
9
};
int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
unsigned int div_of_cclk, new_freq, i;
regs->pll_up_flag = PLL_UNCHANGED;
regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
new_freq = jz4750d_freq_table.table[index].frequency;
do {
div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
} while (div_of_cclk==0);
if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
for(i = 1; i<4; i++) {
div[i] = 3;
}
} else {
for(i = 1; i<4; i++) {
div[i] = 2;
}
}
for(i = 0; i<4; i++) {
div[i] *= div_of_cclk;
}
dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
regs->cpccr =
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
return div_of_cclk;
}
static void jz4750d_set_cpu_divider_index(unsigned int cpu, unsigned int index)
{
unsigned long divisor, old_divisor;
struct cpufreq_freqs freqs;
struct dpm_regs regs;
old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
divisor = index_to_divisor(index, &regs);
freqs.old = __cpm_get_cclk() / 1000;
freqs.new = __cpm_get_pllout() / (1000 * divisor);
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor)
jz4750d_transition(&regs);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int jz4750d_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy,
&jz4750d_freq_table.table[0],
target_freq, relation, &new_index))
return -EINVAL;
jz4750d_set_cpu_divider_index(policy->cpu, new_index);
dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
return 0;
}
static int jz4750d_freq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
&jz4750d_freq_table.table[0]);
}
static int __init jz4750d_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *table = &jz4750d_freq_table.table[0];
unsigned int MAX_FREQ;
dprintk(KERN_INFO "Jz4750d cpufreq driver\n");
if (policy->cpu != 0)
return -EINVAL;
policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = MAX_FREQ/8;
policy->cpuinfo.max_freq = MAX_FREQ;
policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
table[0].index = 0;
table[0].frequency = MAX_FREQ/8;
table[1].index = 1;
table[1].frequency = MAX_FREQ/6;
table[2].index = 2;
table[2].frequency = MAX_FREQ/4;
table[3].index = 3;
table[3].frequency = MAX_FREQ/3;
table[4].index = 4;
table[4].frequency = MAX_FREQ/2;
table[5].index = 5;
table[5].frequency = MAX_FREQ;
table[6].index = 6;
table[6].frequency = CPUFREQ_TABLE_END;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
#endif
return cpufreq_frequency_table_cpuinfo(policy, table);
}
static struct cpufreq_driver cpufreq_jz4750d_driver = {
// .flags = CPUFREQ_STICKY,
.init = jz4750d_cpufreq_driver_init,
.verify = jz4750d_freq_verify,
.target = jz4750d_freq_target,
.get = jz4750d_freq_get,
.name = "jz4750d",
};
static int __init jz4750d_cpufreq_init(void)
{
return cpufreq_register_driver(&cpufreq_jz4750d_driver);
}
static void __exit jz4750d_cpufreq_exit(void)
{
cpufreq_unregister_driver(&cpufreq_jz4750d_driver);
}
module_init(jz4750d_cpufreq_init);
module_exit(jz4750d_cpufreq_exit);
MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
MODULE_DESCRIPTION("cpufreq driver for Jz4750d");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,822 @@
/*
* linux/arch/mips/jz4750d/dma.c
*
* Support functions for the JZ4750D internal DMA channels.
* No-descriptor transfer only.
* Descriptor transfer should also call jz_request_dma() to get a free
* channel and call jz_free_dma() to free the channel. And driver should
* build the DMA descriptor and setup the DMA channel by itself.
*
* Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/soundcard.h>
#include <asm/system.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/*
* A note on resource allocation:
*
* All drivers needing DMA channels, should allocate and release them
* through the public routines `jz_request_dma()' and `jz_free_dma()'.
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
*
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
* When releasing them, first release the IRQ, then release the DMA. The
* main reason for this order is that, if you are requesting the DMA buffer
* done interrupt, you won't know the irq number until the DMA channel is
* returned from jz_request_dma().
*/
struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
{dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */
{dev_id:-1,}, /* DMAC0 channel 1 */
{dev_id:-1,}, /* DMAC0 channel 2 */
{dev_id:-1,}, /* DMAC0 channel 3 */
{dev_id:-1,}, /* DMAC1 channel 0 */
{dev_id:-1,}, /* DMAC1 channel 1 */
{dev_id:-1,}, /* DMAC1 channel 2 */
{dev_id:-1,}, /* DMAC1 channel 3 */
};
// Device FIFO addresses and default DMA modes
static const struct {
unsigned int fifo_addr;
unsigned int dma_mode;
unsigned int dma_source;
} dma_dev_table[DMA_ID_MAX] = {
{0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
{0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
{CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
{CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
{CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
{CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
{CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
{CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
{CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
{CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
{CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
{CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
{CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
{CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
{CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT},
{CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
{SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */
{CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */
{CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */
{CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT},
{CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN},
{CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT},
{CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN},
{},
};
int jz_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data)
{
int i, len = 0;
struct jz_dma_chan *chan;
for (i = 0; i < MAX_DMA_NUM; i++) {
if ((chan = get_dma_chan(i)) != NULL) {
len += sprintf(buf + len, "%2d: %s\n",
i, chan->dev_str);
}
}
if (fpos >= len) {
*start = buf;
*eof = 1;
return 0;
}
*start = buf + fpos;
if ((len -= fpos) > length)
return length;
*eof = 1;
return len;
}
void dump_jz_dma_channel(unsigned int dmanr)
{
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return;
chan = &jz_dma_table[dmanr];
printk("DMA%d Registers:\n", dmanr);
printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM));
printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM));
}
/**
* jz_request_dma - dynamically allcate an idle DMA channel to return
* @dev_id: the specified dma device id or DMA_ID_RAW_SET
* @dev_str: the specified dma device string name
* @irqhandler: the irq handler, or NULL
* @irqflags: the irq handler flags
* @irq_dev_id: the irq handler device id for shared irq
*
* Finds a free channel, and binds the requested device to it.
* Returns the allocated channel number, or negative on error.
* Requests the DMA done IRQ if irqhandler != NULL.
*
*/
/*int jz_request_dma(int dev_id, const char *dev_str,
void (*irqhandler)(int, void *, struct pt_regs *),
unsigned long irqflags,
void *irq_dev_id)
*/
int jz_request_dma(int dev_id, const char *dev_str,
irqreturn_t (*irqhandler)(int, void *),
unsigned long irqflags,
void *irq_dev_id)
{
struct jz_dma_chan *chan;
int i, ret;
if (dev_id < 0 || dev_id >= DMA_ID_MAX)
return -EINVAL;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM) /* no free channel */
return -ENODEV;
/* we got a free channel */
chan = &jz_dma_table[i];
if (irqhandler) {
chan->irq = IRQ_DMA_0 + i; // allocate irq number
chan->irq_dev = irq_dev_id;
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
dev_str, chan->irq_dev))) {
chan->irq = -1;
chan->irq_dev = NULL;
return ret;
}
} else {
chan->irq = -1;
chan->irq_dev = NULL;
}
// fill it in
chan->io = i;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
chan->mode = dma_dev_table[dev_id].dma_mode;
chan->source = dma_dev_table[dev_id].dma_source;
if (i < HALF_DMA_NUM)
REG_DMAC_DMACKE(0) = 1 << i;
else
REG_DMAC_DMACKE(1) = 1 << (i - HALF_DMA_NUM);
return i;
}
void jz_free_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan) {
printk("Trying to free DMA%d\n", dmanr);
return;
}
disable_dma(dmanr);
if (chan->irq)
free_irq(chan->irq, chan->irq_dev);
chan->irq = -1;
chan->irq_dev = NULL;
chan->dev_id = -1;
}
void jz_set_dma_dest_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_DWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_DWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_DWDH_32;
break;
}
}
void jz_set_dma_src_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_SWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_SWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_SWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_SWDH_32;
break;
}
}
void jz_set_dma_block_size(int dmanr, int nbyte)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DS_MASK;
switch (nbyte) {
case 1:
chan->mode |= DMAC_DCMD_DS_8BIT;
break;
case 2:
chan->mode |= DMAC_DCMD_DS_16BIT;
break;
case 4:
chan->mode |= DMAC_DCMD_DS_32BIT;
break;
case 16:
chan->mode |= DMAC_DCMD_DS_16BYTE;
break;
case 32:
chan->mode |= DMAC_DCMD_DS_32BYTE;
break;
}
}
unsigned int jz_get_dma_command(int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
return chan->mode;
}
/**
* jz_set_dma_mode - do the raw settings for the specified DMA channel
* @dmanr: the specified DMA channel
* @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
* @dma_mode: dma raw mode
* @dma_source: dma raw request source
* @fifo_addr: dma raw device fifo address
*
* Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
* jz_set_dma_mode() rather than set_dma_mode() if you work with
* and external request dma device.
*
* NOTE: Don not dynamically allocate dma channel if one external request
* dma device will occupy this channel.
*/
int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
unsigned int dma_mode, unsigned int dma_source,
unsigned int fifo_addr)
{
int dev_id, i;
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return -ENODEV;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM)
return -ENODEV;
chan = &jz_dma_table[dmanr];
dev_id = chan->dev_id;
if (dev_id > 0) {
printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
__FUNCTION__, dmanr);
return -ENODEV;
}
/* clone it from the dynamically allocated. */
if (i != dmanr) {
chan->irq = jz_dma_table[i].irq;
chan->irq_dev = jz_dma_table[i].irq_dev;
chan->dev_str = jz_dma_table[i].dev_str;
jz_dma_table[i].irq = 0;
jz_dma_table[i].irq_dev = NULL;
jz_dma_table[i].dev_id = -1;
}
chan->dev_id = DMA_ID_RAW_SET;
chan->io = dmanr;
chan->fifo_addr = fifo_addr;
chan->mode = dma_mode;
chan->source = dma_source;
set_dma_mode(dmanr, dma_mode);
return dmanr;
}
void enable_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
__dmac_enable_channel(dmanr);
if (chan->irq)
__dmac_channel_enable_irq(dmanr);
}
#define DMA_DISABLE_POLL 0x10000
void disable_dma(unsigned int dmanr)
{
int i;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
if (!__dmac_channel_enabled(dmanr))
return;
for (i = 0; i < DMA_DISABLE_POLL; i++)
if (__dmac_channel_transmit_end_detected(dmanr))
break;
#if 0
if (i == DMA_DISABLE_POLL)
printk(KERN_INFO "disable_dma: poll expired!\n");
#endif
__dmac_disable_channel(dmanr);
if (chan->irq)
__dmac_channel_disable_irq(dmanr);
}
/* Note: DMA_MODE_MASK is simulated by sw */
void set_dma_mode(unsigned int dmanr, unsigned int mode)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else {
printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
}
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
}
void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
{
unsigned int mode;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode = chan->mode & DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
REG_DMAC_DTAR(chan->io) = phyaddr;
} else if (mode == DMA_MODE_WRITE) {
REG_DMAC_DSAR(chan->io) = phyaddr;
REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
} else
printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
}
void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
int dma_ds[] = {4, 1, 2, 16, 32};
unsigned int ds;
if (!chan)
return;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
}
unsigned int get_dma_residue(unsigned int dmanr)
{
unsigned int count, ds;
int dma_ds[] = {4, 1, 2, 16, 32};
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
count = REG_DMAC_DTCR(chan->io);
count = count * dma_ds[ds];
return count;
}
void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case AFMT_U8:
/* burst mode : 32BIT */
break;
case AFMT_S16_LE:
/* burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
//chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case 8:
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
break;
case 16:
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
//#define JZ4750D_DMAC_TEST_ENABLE
#undef JZ4750D_DMAC_TEST_ENABLE
#ifdef JZ4750D_DMAC_TEST_ENABLE
/*
* DMA test: external address <--> external address
*/
#define TEST_DMA_SIZE 16*1024
static jz_dma_desc *dma_desc;
static int dma_chan;
static dma_addr_t dma_desc_phys_addr;
static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
static int dma_check_result(void *src, void *dst, int size)
{
unsigned int addr1, addr2, i, err = 0;
addr1 = (unsigned int)src;
addr2 = (unsigned int)dst;
for (i = 0; i < size; i += 4) {
if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
err++;
printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
}
addr1 += 4;
addr2 += 4;
}
printk("check DMA result err=%d\n", err);
return err;
}
static irqreturn_t jz4750d_dma_irq(int irq, void *dev_id)
{
printk("jz4750d_dma_irq %d\n", irq);
if (__dmac_channel_transmit_halt_detected(dma_chan)) {
printk("DMA HALT\n");
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
__dmac_channel_clear_transmit_halt(dma_chan);
}
if (__dmac_channel_address_error_detected(dma_chan)) {
printk("DMA ADDR ERROR\n");
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */
REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */
__dmac_channel_clear_address_error(dma_chan);
}
if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
printk("DMA DESC INVALID\n");
__dmac_channel_clear_descriptor_invalid(dma_chan);
}
if (__dmac_channel_count_terminated_detected(dma_chan)) {
printk("DMA CT\n");
__dmac_channel_clear_count_terminated(dma_chan);
}
if (__dmac_channel_transmit_end_detected(dma_chan)) {
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
printk("DMA TT\n");
__dmac_channel_clear_transmit_end(dma_chan);
dump_jz_dma_channel(dma_chan);
dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
}
return IRQ_HANDLED;
}
void dma_nodesc_test(void)
{
unsigned int addr, i;
printk("dma_nodesc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq,
IRQF_DISABLED, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Init DMA module */
printk("Starting DMA\n");
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
REG_DMAC_DCCSR(dma_chan) = 0;
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
REG_DMAC_DTCR(dma_chan) = 512;
REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
/* wait a long time, ensure transfer end */
printk("wait 3s...\n");
mdelay(3000); /* wait 3s */
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
void dma_desc_test(void)
{
unsigned int next, addr, i;
static jz_dma_desc *desc;
printk("dma_desc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq,
IRQF_DISABLED, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Allocate DMA descriptors */
dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
/* Setup DMA descriptors */
desc = dma_desc;
next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr; /* DMA source address */
desc->dtadr = dma_dst_phys_addr; /* DMA target address */
desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
/* Setup DMA descriptor address */
REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
/* Setup request source */
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
/* Setup DMA channel control/status register */
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
/* Enable DMA */
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE;
/* DMA doorbell set -- start DMA now ... */
REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan;
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
/* wait a long time, ensure transfer end */
printk("wait 3s...\n");
mdelay(3000); /* wait 3s */
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
#endif
//EXPORT_SYMBOL_NOVERS(jz_dma_table);
EXPORT_SYMBOL(jz_dma_table);
EXPORT_SYMBOL(jz_request_dma);
EXPORT_SYMBOL(jz_free_dma);
EXPORT_SYMBOL(jz_set_dma_src_width);
EXPORT_SYMBOL(jz_set_dma_dest_width);
EXPORT_SYMBOL(jz_set_dma_block_size);
EXPORT_SYMBOL(jz_set_dma_mode);
EXPORT_SYMBOL(set_dma_mode);
EXPORT_SYMBOL(jz_set_oss_dma);
EXPORT_SYMBOL(jz_set_alsa_dma);
EXPORT_SYMBOL(set_dma_addr);
EXPORT_SYMBOL(set_dma_count);
EXPORT_SYMBOL(get_dma_residue);
EXPORT_SYMBOL(enable_dma);
EXPORT_SYMBOL(disable_dma);
EXPORT_SYMBOL(dump_jz_dma_channel);

View File

@@ -0,0 +1,385 @@
/*
* linux/arch/mips/jz4750d/i2c.c
*
* Jz4750D I2C routines.
*
* Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/* I2C protocol */
#define I2C_READ 1
#define I2C_WRITE 0
#define TIMEOUT 1000
/*
* I2C bus protocol basic routines
*/
static int i2c_put_data(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (!__i2c_received_ack() && timeout)
timeout--;
if (timeout)
return 0;
else
return -ETIMEDOUT;
}
static int i2c_put_data_nack(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (timeout--);
return 0;
}
static int i2c_get_data(unsigned char *data, int ack)
{
int timeout = TIMEOUT*10;
if (!ack)
__i2c_send_nack();
else
__i2c_send_ack();
while (__i2c_check_drf() == 0 && timeout)
timeout--;
if (timeout) {
if (!ack)
__i2c_send_stop();
*data = __i2c_read();
__i2c_clear_drf();
return 0;
} else
return -ETIMEDOUT;
}
/*
* I2C interface
*/
void i2c_open(void)
{
__i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
__i2c_enable();
}
void i2c_close(void)
{
udelay(300); /* wait for STOP goes over. */
__i2c_disable();
}
void i2c_setclk(unsigned int i2cclk)
{
__i2c_set_clk(jz_clocks.extalclk, i2cclk);
}
int i2c_lseek(unsigned char device, unsigned char offset)
{
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data(offset) < 0)
goto address_err;
return 0;
device_err:
printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
__i2c_send_stop();
return -ENODEV;
address_err:
printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
__i2c_send_stop();
return -EREMOTEIO;
}
int i2c_read(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int timeout = 5;
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data(address) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddr;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddr = address;
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
#ifdef CONFIG_JZ_TPANEL_ATA2508
if (address == 0xff) {
if (i2c_put_data_nack(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data_nack(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
else {
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
#else
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
#endif
__i2c_send_stop();
return count - cnt;
device_err:
address_err:
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
int i2c_read_16(unsigned char device, unsigned char *buf,
unsigned short address, int count)
{
int cnt = count;
int timeout = 5;
unsigned char tmpaddrh, tmpaddrl;
tmpaddrh = (unsigned char)((address >> 8) & 0xff);
tmpaddrl = (unsigned char)(address & 0xff);
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data_nack(tmpaddrh) < 0)
goto address_err;
if (i2c_put_data(tmpaddrl) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write_16(unsigned char device, unsigned char *buf,
unsigned short address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddrh, tmpaddrl;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddrh = (unsigned char)((address >> 8) & 0xff);
tmpaddrl = (unsigned char)(address & 0xff);
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data_nack(tmpaddrh) < 0)
goto address_err;
if (i2c_put_data(tmpaddrl) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddrh += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
__i2c_send_stop();
return count - cnt;
device_err:
printk("1:Write I2C device 0x%2x failed.\n", device);
address_err:
printk("2:Write I2C address 0x%2x failed.\n", address);
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk("3:Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
EXPORT_SYMBOL(i2c_open);
EXPORT_SYMBOL(i2c_close);
EXPORT_SYMBOL(i2c_setclk);
EXPORT_SYMBOL(i2c_read);
EXPORT_SYMBOL(i2c_write);
EXPORT_SYMBOL(i2c_read_16);
EXPORT_SYMBOL(i2c_write_16);

View File

@@ -0,0 +1,299 @@
/*
* linux/arch/mips/jz4750d/irq.c
*
* JZ4750D interrupt routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
/*
* INTC irq type
*/
static void enable_intc_irq(unsigned int irq)
{
__intc_unmask_irq(irq);
}
static void disable_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
}
static void mask_and_ack_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
__intc_ack_irq(irq);
}
static void end_intc_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
enable_intc_irq(irq);
}
}
static unsigned int startup_intc_irq(unsigned int irq)
{
enable_intc_irq(irq);
return 0;
}
static void shutdown_intc_irq(unsigned int irq)
{
disable_intc_irq(irq);
}
static struct irq_chip intc_irq_type = {
.typename = "INTC",
.startup = startup_intc_irq,
.shutdown = shutdown_intc_irq,
.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<<irq);
irq = plat_real_irq(irq);
do_IRQ(irq);
}

View File

@@ -0,0 +1,147 @@
/*
* Platform device support for Jz4740 SoC.
*
* Copyright 2007, <yliu@ingenic.cn>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <asm/jzsoc.h>
#if 0
/* OHCI (USB full speed host controller) */
static struct resource jz_usb_ohci_resources[] = {
[0] = {
.start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
.end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UHC,
.end = IRQ_UHC,
.flags = IORESOURCE_IRQ,
},
};
/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;
static struct platform_device jz_usb_ohci_device = {
.name = "jz-ohci",
.id = 0,
.dev = {
.dma_mask = &ohci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
.resource = jz_usb_ohci_resources,
};
#endif
/*** LCD controller ***/
static struct resource jz_lcd_resources[] = {
[0] = {
.start = CPHYSADDR(LCD_BASE),
.end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_lcd_dmamask = ~(u32)0;
static struct platform_device jz_lcd_device = {
.name = "jz-lcd",
.id = 0,
.dev = {
.dma_mask = &jz_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_lcd_resources),
.resource = jz_lcd_resources,
};
/* UDC (USB gadget controller) */
static struct resource jz_usb_gdt_resources[] = {
[0] = {
.start = CPHYSADDR(UDC_BASE),
.end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UDC,
.end = IRQ_UDC,
.flags = IORESOURCE_IRQ,
},
};
static u64 udc_dmamask = ~(u32)0;
static struct platform_device jz_usb_gdt_device = {
.name = "jz-udc",
.id = 0,
.dev = {
.dma_mask = &udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
.resource = jz_usb_gdt_resources,
};
/** MMC/SD controller **/
static struct resource jz_mmc_resources[] = {
[0] = {
.start = CPHYSADDR(MSC_BASE),
.end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_MSC0,
.end = IRQ_MSC0,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_mmc_dmamask = ~(u32)0;
static struct platform_device jz_mmc_device = {
.name = "jz-mmc",
.id = 0,
.dev = {
.dma_mask = &jz_mmc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_mmc_resources),
.resource = jz_mmc_resources,
};
struct platform_device jz4750_rtc_device = {
.name = "jz4750-rtc",
.id = -1,
};
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
// &jz_usb_ohci_device,
&jz_lcd_device,
&jz_usb_gdt_device,
&jz_mmc_device,
&jz4750_rtc_device,
};
static int __init jz_platform_init(void)
{
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
arch_initcall(jz_platform_init);

View File

@@ -0,0 +1,201 @@
/*
* linux/arch/mips/jz4750d/pm.c
*
* JZ4750D Power Management Routines
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/module.h>
#include <linux/suspend.h>
#include <asm/cacheops.h>
#include <asm/jzsoc.h>
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define dprintk(x...) printk(x)
#else
#define dprintk(x...)
#endif
extern void jz_board_do_sleep(unsigned long *ptr);
extern void jz_board_do_resume(unsigned long *ptr);
static void jz_pm_do_hibernate(void)
{
printk("Put CPU into hibernate mode.\n");
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/*
* RTC Wakeup or 1Hz interrupt can be enabled or disabled
* through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
*/
/* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
/* Set reset pin low-level assertion time after wakeup: must > 60ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
/* Scratch pad register to be reserved */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HSPR = 0x12345678;
/* clear wakeup status register */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWRSR = 0x0;
/* Put CPU to power down mode */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HCR = RTC_HCR_PD;
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
while(1);
}
static int jz_pm_do_sleep(void)
{
unsigned long delta;
unsigned long nfcsr = REG_EMC_NFCSR;
unsigned long opcr = REG_CPM_OPCR;
unsigned long imr = REG_INTC_IMR;
unsigned long sadc = REG_SADC_ENA;
unsigned long sleep_gpio_save[4*(GPIO_PORT_NUM-1)];
printk("Put CPU into sleep mode.\n");
/* Preserve current time */
delta = xtime.tv_sec - REG_RTC_RSR;
/* Disable nand flash */
REG_EMC_NFCSR = ~0xff;
/* stop sadc */
REG_SADC_ENA &= ~0x7;
while((REG_SADC_ENA & 0x7) != 0);
udelay(100);
/*stop udc and usb*/
__cpm_suspend_uhcphy();
__cpm_suspend_udcphy();
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/* Sleep on-board modules and setup wake event */
jz_board_do_sleep(sleep_gpio_save);
/* disable externel clock Oscillator in sleep mode */
__cpm_disable_osc_in_sleep();
/* select 32K crystal as RTC clock in sleep mode */
__cpm_select_rtcclk_rtc();
/* Enter SLEEP mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
/* Restore to IDLE mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
/* Restore nand flash control register */
REG_EMC_NFCSR = nfcsr;
/* Restore interrupts */
REG_INTC_IMSR = imr;
REG_INTC_IMCR = ~imr;
/* Restore sadc */
REG_SADC_ENA = sadc;
/* Resume on-board modules */
jz_board_do_resume(sleep_gpio_save);
/* Restore Oscillator and Power Control Register */
REG_CPM_OPCR = opcr;
/* Restore current time */
xtime.tv_sec = REG_RTC_RSR + delta;
printk("Resume CPU from sleep mode.\n");
return 0;
}
/* Put CPU to HIBERNATE mode */
void jz_pm_hibernate(void)
{
jz_pm_do_hibernate();
}
/* Put CPU to SLEEP mode */
int jz_pm_sleep(void)
{
return jz_pm_do_sleep();
}
/*
* valid states, only support standby(sleep) and mem(hibernate)
*/
static int jz4750_pm_valid(suspend_state_t state)
{
return state == PM_SUSPEND_MEM;
}
/*
* Jz CPU enter save power mode
*/
static int jz4750_pm_enter(suspend_state_t state)
{
return jz_pm_do_sleep();
}
static struct platform_suspend_ops jz4750_pm_ops = {
.valid = jz4750_pm_valid,
.enter = jz4750_pm_enter,
};
/*
* Initialize power interface
*/
int __init jz_pm_init(void)
{
printk("Power Management for JZ\n");
suspend_set_ops(&jz4750_pm_ops);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,198 @@
/*
*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, supports YAMON and U-Boot.
*
* Copyright 2000, 2001, 2006 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/jzsoc.h>
/* #define DEBUG_CMDLINE */
int prom_argc;
char **prom_argv, **prom_envp;
char * prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
if (prom_argc > 1)
*cp = '\0';
}
char *prom_getenv(char *envname)
{
#if 0
/*
* Return a pointer to the given environment variable.
* YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
*/
char **env = prom_envp;
int i = strlen(envname);
int yamon = (*env && strchr(*env, '=') == NULL);
while (*env) {
if (yamon) {
if (strcmp(envname, *env++) == 0)
return *env;
} else {
if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
return *env + i + 1;
}
env++;
}
#endif
return NULL;
}
inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0; /* foo */
}
inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
for(i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
#if 0
{
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
#endif
return 0;
}
void __init prom_free_prom_memory(void)
{
}
void __init prom_init(void)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = (int) fw_arg0;
prom_argv = (char **) fw_arg1;
prom_envp = (char **) fw_arg2;
mips_machtype = MACH_INGENIC_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);

View File

@@ -0,0 +1,46 @@
/*
* linux/arch/mips/jz4750/reset.c
*
* JZ4750 reset routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <yliu@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
void jz_restart(char *command)
{
printk("Restarting after 4 ms\n");
REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
REG_WDT_TCNT = 0;
REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */
REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
while (1);
}
void jz_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
}
void jz_power_off(void)
{
jz_halt();
}

View File

@@ -0,0 +1,207 @@
/*
* linux/arch/mips/jz4750d/common/setup.c
*
* JZ4750D common setup routines.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
#ifdef CONFIG_PM
#include <asm/suspend.h>
#endif
#ifdef CONFIG_PC_KEYB
#include <asm/keyboard.h>
#endif
jz_clocks_t jz_clocks;
extern char * __init prom_getcmdline(void);
extern void __init jz_board_setup(void);
extern void jz_restart(char *);
extern void jz_halt(void);
extern void jz_power_off(void);
extern void jz_time_init(void);
extern void jz_pm_hibernate(void);
static void __init sysclocks_setup(void)
{
#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.h1clk = __cpm_get_h1clk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk(0);
jz_clocks.extalclk = __cpm_get_extalclk();
jz_clocks.rtcclk = __cpm_get_rtcclk();
#else
#define FPGACLK 8000000
jz_clocks.cclk = FPGACLK;
jz_clocks.hclk = FPGACLK;
jz_clocks.pclk = FPGACLK;
jz_clocks.mclk = FPGACLK;
jz_clocks.h1clk = FPGACLK;
jz_clocks.pixclk = FPGACLK;
jz_clocks.i2sclk = FPGACLK;
jz_clocks.usbclk = FPGACLK;
jz_clocks.mscclk = FPGACLK;
jz_clocks.extalclk = FPGACLK;
jz_clocks.rtcclk = FPGACLK;
#endif
printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
(jz_clocks.cclk + 500000) / 1000000,
(jz_clocks.hclk + 500000) / 1000000,
(jz_clocks.pclk + 500000) / 1000000,
(jz_clocks.mclk + 500000) / 1000000);
}
static void __init soc_cpm_setup(void)
{
/* Start all module clocks
*/
__cpm_start_all();
/* Enable CKO to external memory */
__cpm_enable_cko();
/* CPU enters IDLE mode when executing 'wait' instruction */
__cpm_idle_mode();
/* Setup system clocks */
sysclocks_setup();
}
static void __init soc_harb_setup(void)
{
// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
}
static void __init soc_emc_setup(void)
{
}
static void __init soc_dmac_setup(void)
{
__dmac_enable_module(0);
__dmac_enable_module(1);
}
static void __init jz_soc_setup(void)
{
soc_cpm_setup();
soc_harb_setup();
soc_emc_setup();
soc_dmac_setup();
}
static void __init jz_serial_setup(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port s;
REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
memset(&s, 0, sizeof(s));
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = SERIAL_IO_MEM;
s.regshift = 2;
s.uartclk = jz_clocks.extalclk ;
s.line = 0;
s.membase = (u8 *)UART0_BASE;
s.irq = IRQ_UART0;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS0 setup failed!\n");
}
s.line = 1;
s.membase = (u8 *)UART1_BASE;
s.irq = IRQ_UART1;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS1 setup failed!\n");
}
s.line = 2;
s.membase = (u8 *)UART2_BASE;
s.irq = IRQ_UART2;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS2 setup failed!\n");
}
/*
s.line = 3;
s.membase = (u8 *)UART3_BASE;
s.irq = IRQ_UART3;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS3 setup failed!\n");
}
*/
#endif
}
void __init plat_mem_setup(void)
{
char *argptr;
argptr = prom_getcmdline();
/* IO/MEM resources. Which will be the addtion value in `inX' and
* `outX' macros defined in asm/io.h */
set_io_port_base(0);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x00000000;
iomem_resource.end = 0xffffffff;
_machine_restart = jz_restart;
_machine_halt = jz_halt;
pm_power_off = jz_pm_hibernate;
jz_soc_setup();
jz_serial_setup();
jz_board_setup();
#ifdef CONFIG_PM
jz_pm_init();
#endif
}

View File

@@ -0,0 +1,157 @@
/*
* linux/arch/mips/jz4750d/time.c
*
* Setting up the clock on the JZ4750D boards.
*
* Copyright (C) 2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
/* This is for machines which generate the exact clock. */
#define JZ_TIMER_IRQ IRQ_TCU0
#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
static struct clocksource clocksource_jz; /* Jz clock source */
static struct clock_event_device jz_clockevent_device; /* Jz clock event */
void (*jz_timer_callback)(void);
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = dev_id;
REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
if (jz_timer_callback)
jz_timer_callback();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction jz_irqaction = {
.handler = jz_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
.name = "jz-timerirq",
};
cycle_t jz_get_cycles(void)
{
/* convert jiffes to jz timer cycles */
return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT);
}
static struct clocksource clocksource_jz = {
.name = "jz_clocksource",
.rating = 300,
.read = jz_get_cycles,
.mask = 0xFFFFFFFF,
.shift = 10,
.flags = CLOCK_SOURCE_WATCHDOG,
};
static int __init jz_clocksource_init(void)
{
clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
clocksource_register(&clocksource_jz);
return 0;
}
static int jz_set_next_event(unsigned long evt,
struct clock_event_device *unused)
{
return 0;
}
static void jz_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}
static struct clock_event_device jz_clockevent_device = {
.name = "jz-clockenvent",
.features = CLOCK_EVT_FEAT_PERIODIC,
// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
.mult = 1,
.rating = 300,
.irq = JZ_TIMER_IRQ,
.set_mode = jz_set_mode,
.set_next_event = jz_set_next_event,
};
static void __init jz_clockevent_init(void)
{
struct clock_event_device *cd = &jz_clockevent_device;
unsigned int cpu = smp_processor_id();
cd->cpumask = cpumask_of_cpu(cpu);
clockevents_register_device(cd);
}
static void __init jz_timer_setup(void)
{
jz_clocksource_init(); /* init jz clock source */
jz_clockevent_init(); /* init jz clock event */
/*
* Make irqs happen for the system timer
*/
jz_irqaction.dev_id = &jz_clockevent_device;
setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
}
void __init plat_time_init(void)
{
unsigned int latch;
/* Init timer */
latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN;
REG_TCU_OSTCNT = 0;
REG_TCU_OSTDR = latch;
REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */
REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */
REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */
jz_timer_setup();
}

View File

@@ -0,0 +1,22 @@
#
# Makefile for the Ingenic JZ4760.
#
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
platform.o i2c.o
obj-$(CONFIG_PROC_FS) += proc.o
# board specific support
obj-$(CONFIG_JZ4760_F4760) += board-f4760.o
# PM support
obj-$(CONFIG_PM_LEGACY) +=pm.o
# CPU Frequency scaling support
obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o

View File

@@ -0,0 +1,81 @@
/*
* linux/arch/mips/jz4760/board-f4760.c
*
* JZ4760 F4760 board setup routines.
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/jzsoc.h>
extern void (*jz_timer_callback)(void);
static void dancing(void)
{
static unsigned char slash[] = "\\|/-";
// static volatile unsigned char *p = (unsigned char *)0xb6000058;
static volatile unsigned char *p = (unsigned char *)0xb6000016;
static unsigned int count = 0;
*p = slash[count++];
count &= 3;
}
static void f4760_timer_callback(void)
{
static unsigned long count = 0;
if ((++count) % 50 == 0) {
dancing();
count = 0;
}
}
static void __init board_cpm_setup(void)
{
/* Stop unused module clocks here.
* We have started all module clocks at arch/mips/jz4760/setup.c.
*/
}
static void __init board_gpio_setup(void)
{
/*
* Initialize SDRAM pins
*/
}
void __init jz_board_setup(void)
{
printk("JZ4760 F4760 board setup\n");
// jz_restart(NULL);
board_cpm_setup();
board_gpio_setup();
jz_timer_callback = f4760_timer_callback;
}
/**
* Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'.
* Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc.
*/
const char *get_board_type(void)
{
return "f4760";
}

View File

@@ -0,0 +1,598 @@
/*
* linux/arch/mips/jz4760/cpufreq.c
*
* cpufreq driver for JZ4760
*
* Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <asm/jzsoc.h>
#include <asm/processor.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"cpufreq-jz4760", msg)
#undef CHANGE_PLL
#define PLL_UNCHANGED 0
#define PLL_GOES_UP 1
#define PLL_GOES_DOWN 2
#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
/* Saved the boot-time parameters */
static struct {
/* SDRAM parameters */
unsigned int mclk; /* memory clock, KHz */
unsigned int tras; /* RAS pulse width, cycles of mclk */
unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
unsigned int tpc; /* RAS Precharge time, cycles of mclk */
unsigned int trwl; /* Write Precharge Time, cycles of mclk */
unsigned int trc; /* RAS Cycle Time, cycles of mclk */
unsigned int rtcor; /* Refresh Time Constant */
unsigned int sdram_initialized;
/* LCD parameters */
unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
unsigned int lcd_clks_initialized;
} boot_config;
struct jz4760_freq_percpu_info {
struct cpufreq_frequency_table table[7];
};
static struct jz4760_freq_percpu_info jz4760_freq_table;
/*
* This contains the registers value for an operating point.
* If only part of a register needs to change then there is
* a mask value for that register.
* When going to a new operating point the current register
* value is ANDed with the ~mask and ORed with the new value.
*/
struct dpm_regs {
u32 cpccr; /* Clock Freq Control Register */
u32 cpccr_mask; /* Clock Freq Control Register mask */
u32 cppcr; /* PLL1 Control Register */
u32 cppcr_mask; /* PLL1 Control Register mask */
u32 pll_up_flag; /* New PLL freq is higher than current or not */
};
extern jz_clocks_t jz_clocks;
static void jz_update_clocks(void)
{
/* Next clocks must be updated if we have changed
* the PLL or divisors.
*/
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_hclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk(0);
}
static void
jz_init_boot_config(void)
{
if (!boot_config.lcd_clks_initialized) {
/* the first time to scale pll */
boot_config.lcdpix_clk = __cpm_get_pixclk();
boot_config.lcd_clks_initialized = 1;
}
if (!boot_config.sdram_initialized) {
/* the first time to scale frequencies */
unsigned int dmcr, rtcor;
unsigned int tras, rcd, tpc, trwl, trc;
dmcr = REG_EMC_DMCR;
rtcor = REG_EMC_RTCOR;
tras = (dmcr >> 13) & 0x7;
rcd = (dmcr >> 11) & 0x3;
tpc = (dmcr >> 8) & 0x7;
trwl = (dmcr >> 5) & 0x3;
trc = (dmcr >> 2) & 0x7;
boot_config.mclk = __cpm_get_mclk() / 1000;
boot_config.tras = tras + 4;
boot_config.rcd = rcd + 1;
boot_config.tpc = tpc + 1;
boot_config.trwl = trwl + 1;
boot_config.trc = trc * 2 + 1;
boot_config.rtcor = rtcor;
boot_config.sdram_initialized = 1;
}
}
static void jz_update_dram_rtcor(unsigned int new_mclk)
{
unsigned int rtcor;
new_mclk /= 1000;
rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
rtcor--;
if (rtcor < 1) rtcor = 1;
if (rtcor > 255) rtcor = 255;
REG_EMC_RTCOR = rtcor;
REG_EMC_RTCNT = rtcor;
}
static void jz_update_dram_dmcr(unsigned int new_mclk)
{
unsigned int dmcr;
unsigned int tras, rcd, tpc, trwl, trc;
unsigned int valid_time, new_time; /* ns */
new_mclk /= 1000;
tras = boot_config.tras * new_mclk / boot_config.mclk;
rcd = boot_config.rcd * new_mclk / boot_config.mclk;
tpc = boot_config.tpc * new_mclk / boot_config.mclk;
trwl = boot_config.trwl * new_mclk / boot_config.mclk;
trc = boot_config.trc * new_mclk / boot_config.mclk;
/* Validation checking */
valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
new_time = (tras * 1000000) / new_mclk;
if (new_time < valid_time) tras += 1;
valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
new_time = (rcd * 1000000) / new_mclk;
if (new_time < valid_time) rcd += 1;
valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
new_time = (tpc * 1000000) / new_mclk;
if (new_time < valid_time) tpc += 1;
valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
new_time = (trwl * 1000000) / new_mclk;
if (new_time < valid_time) trwl += 1;
valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
new_time = (trc * 1000000) / new_mclk;
if (new_time < valid_time) trc += 2;
tras = (tras < 4) ? 4: tras;
tras = (tras > 11) ? 11: tras;
tras -= 4;
rcd = (rcd < 1) ? 1: rcd;
rcd = (rcd > 4) ? 4: rcd;
rcd -= 1;
tpc = (tpc < 1) ? 1: tpc;
tpc = (tpc > 8) ? 8: tpc;
tpc -= 1;
trwl = (trwl < 1) ? 1: trwl;
trwl = (trwl > 4) ? 4: trwl;
trwl -= 1;
trc = (trc < 1) ? 1: trc;
trc = (trc > 15) ? 15: trc;
trc /= 2;
dmcr = REG_EMC_DMCR;
dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
REG_EMC_DMCR = dmcr;
}
static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
* and TRC of DMCR before changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
} else {
/* We're going SLOWER: first update RTCOR value
* before changing the frequency.
*/
jz_update_dram_rtcor(new_mclk);
}
}
static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
{
/* No risk, no fun: run with interrupts on! */
if (new_mclk > cur_mclk) {
/* We're going FASTER, so update RTCOR
* after changing the frequency
*/
jz_update_dram_rtcor(new_mclk);
} else {
/* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
* and TRC of DMCR after changing the frequency.
*/
jz_update_dram_dmcr(new_mclk);
}
}
static void jz_scale_divisors(struct dpm_regs *regs)
{
unsigned int cpccr;
unsigned int cur_mclk, new_mclk;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
cpccr = REG_CPM_CPCCR;
cpccr &= ~((unsigned long)regs->cpccr_mask);
cpccr |= regs->cpccr;
cpccr |= CPM_CPCCR_CE; /* update immediately */
cur_mclk = __cpm_get_mclk();
new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
/* Update some DRAM parameters before changing frequency */
jz_update_dram_prev(cur_mclk, new_mclk);
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#ifdef CHANGE_PLL
/* Maintain the LCD clock and pixel clock */
static void jz_scale_lcd_divisors(struct dpm_regs *regs)
{
unsigned int new_pll, new_lcd_div, new_lcdpix_div;
unsigned int cpccr;
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
if (!boot_config.lcd_clks_initialized) return;
new_pll = __cpm_get_pllout();
new_lcd_div = new_pll / boot_config.lcd_clk;
new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
if (new_lcd_div < 1)
new_lcd_div = 1;
if (new_lcd_div > 16)
new_lcd_div = 16;
if (new_lcdpix_div < 1)
new_lcdpix_div = 1;
if (new_lcdpix_div > 512)
new_lcdpix_div = 512;
// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
cpccr = REG_CPM_CPCCR;
cpccr &= ~CPM_CPCCR_LDIV_MASK;
cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
cpccr |= CPM_CPCCR_CE; /* update immediately */
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
}
static void jz_scale_pll(struct dpm_regs *regs)
{
unsigned int cppcr;
unsigned int cur_mclk, new_mclk, new_pll;
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
int od[] = {1, 2, 2, 4};
cppcr = REG_CPM_CPPCR;
cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
regs->cppcr &= ~CPM_CPPCR_PLLEN;
cppcr |= (regs->cppcr | 0xff);
/* Update some DRAM parameters before changing frequency */
new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
cur_mclk = __cpm_get_mclk();
new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf];
/*
* Update some SDRAM parameters
*/
jz_update_dram_prev(cur_mclk, new_mclk);
/*
* Update PLL, align code to cache line.
*/
cppcr |= CPM_CPPCR_PLLEN;
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CPPCR), "r" (cppcr));
/* Update some other DRAM parameters after changing frequency */
jz_update_dram_post(cur_mclk, new_mclk);
}
#endif
static void jz4760_transition(struct dpm_regs *regs)
{
/*
* Get and save some boot-time conditions.
*/
jz_init_boot_config();
#ifdef CHANGE_PLL
/*
* Disable LCD before scaling pll.
* LCD and LCD pixel clocks should not be changed even if the PLL
* output frequency has been changed.
*/
REG_LCD_CTRL &= ~LCD_CTRL_ENA;
/*
* Stop module clocks before scaling PLL
*/
__cpm_stop_eth();
__cpm_stop_aic(1);
__cpm_stop_aic(2);
#endif
/* ... add more as necessary */
if (regs->pll_up_flag == PLL_GOES_UP) {
/* the pll frequency is going up, so change dividors first */
jz_scale_divisors(regs);
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
}
else if (regs->pll_up_flag == PLL_GOES_DOWN) {
/* the pll frequency is going down, so change pll first */
#ifdef CHANGE_PLL
jz_scale_pll(regs);
#endif
jz_scale_divisors(regs);
}
else {
/* the pll frequency is unchanged, so change divisors only */
jz_scale_divisors(regs);
}
#ifdef CHANGE_PLL
/*
* Restart module clocks before scaling PLL
*/
__cpm_start_eth();
__cpm_start_aic(1);
__cpm_start_aic(2);
/* ... add more as necessary */
/* Scale the LCD divisors after scaling pll */
if (regs->pll_up_flag != PLL_UNCHANGED) {
jz_scale_lcd_divisors(regs);
}
/* Enable LCD controller */
REG_LCD_CTRL &= ~LCD_CTRL_DIS;
REG_LCD_CTRL |= LCD_CTRL_ENA;
#endif
/* Update system clocks */
jz_update_clocks();
}
extern unsigned int idle_times;
static unsigned int jz4760_freq_get(unsigned int cpu)
{
return (__cpm_get_cclk() / 1000);
}
static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
{
int n2FR[33] = {
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
9
};
int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
unsigned int div_of_cclk, new_freq, i;
regs->pll_up_flag = PLL_UNCHANGED;
regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
new_freq = jz4760_freq_table.table[index].frequency;
do {
div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
} while (div_of_cclk==0);
if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
for(i = 1; i<4; i++) {
div[i] = 3;
}
} else {
for(i = 1; i<4; i++) {
div[i] = 2;
}
}
for(i = 0; i<4; i++) {
div[i] *= div_of_cclk;
}
dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
regs->cpccr =
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
return div_of_cclk;
}
static void jz4760_set_cpu_divider_index(unsigned int cpu, unsigned int index)
{
unsigned long divisor, old_divisor;
struct cpufreq_freqs freqs;
struct dpm_regs regs;
old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
divisor = index_to_divisor(index, &regs);
freqs.old = __cpm_get_cclk() / 1000;
freqs.new = __cpm_get_pllout() / (1000 * divisor);
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor)
jz4760_transition(&regs);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int jz4760_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy,
&jz4760_freq_table.table[0],
target_freq, relation, &new_index))
return -EINVAL;
jz4760_set_cpu_divider_index(policy->cpu, new_index);
dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
return 0;
}
static int jz4760_freq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
&jz4760_freq_table.table[0]);
}
static int __init jz4760_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *table = &jz4760_freq_table.table[0];
unsigned int MAX_FREQ;
dprintk(KERN_INFO "Jz4760 cpufreq driver\n");
if (policy->cpu != 0)
return -EINVAL;
policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = MAX_FREQ/8;
policy->cpuinfo.max_freq = MAX_FREQ;
policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
table[0].index = 0;
table[0].frequency = MAX_FREQ/8;
table[1].index = 1;
table[1].frequency = MAX_FREQ/6;
table[2].index = 2;
table[2].frequency = MAX_FREQ/4;
table[3].index = 3;
table[3].frequency = MAX_FREQ/3;
table[4].index = 4;
table[4].frequency = MAX_FREQ/2;
table[5].index = 5;
table[5].frequency = MAX_FREQ;
table[6].index = 6;
table[6].frequency = CPUFREQ_TABLE_END;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
#endif
return cpufreq_frequency_table_cpuinfo(policy, table);
}
static struct cpufreq_driver cpufreq_jz4760_driver = {
// .flags = CPUFREQ_STICKY,
.init = jz4760_cpufreq_driver_init,
.verify = jz4760_freq_verify,
.target = jz4760_freq_target,
.get = jz4760_freq_get,
.name = "jz4760",
};
static int __init jz4760_cpufreq_init(void)
{
return cpufreq_register_driver(&cpufreq_jz4760_driver);
}
static void __exit jz4760_cpufreq_exit(void)
{
cpufreq_unregister_driver(&cpufreq_jz4760_driver);
}
module_init(jz4760_cpufreq_init);
module_exit(jz4760_cpufreq_exit);
MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
MODULE_DESCRIPTION("cpufreq driver for Jz4760");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,822 @@
/*
* linux/arch/mips/jz4760/dma.c
*
* Support functions for the JZ4760 internal DMA channels.
* No-descriptor transfer only.
* Descriptor transfer should also call jz_request_dma() to get a free
* channel and call jz_free_dma() to free the channel. And driver should
* build the DMA descriptor and setup the DMA channel by itself.
*
* Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/soundcard.h>
#include <asm/system.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/*
* A note on resource allocation:
*
* All drivers needing DMA channels, should allocate and release them
* through the public routines `jz_request_dma()' and `jz_free_dma()'.
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
*
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
* When releasing them, first release the IRQ, then release the DMA. The
* main reason for this order is that, if you are requesting the DMA buffer
* done interrupt, you won't know the irq number until the DMA channel is
* returned from jz_request_dma().
*/
struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
{dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */
{dev_id:-1,}, /* DMAC0 channel 1 */
{dev_id:-1,}, /* DMAC0 channel 2 */
{dev_id:-1,}, /* DMAC0 channel 3 */
{dev_id:-1,}, /* DMAC1 channel 0 */
{dev_id:-1,}, /* DMAC1 channel 1 */
{dev_id:-1,}, /* DMAC1 channel 2 */
{dev_id:-1,}, /* DMAC1 channel 3 */
};
// Device FIFO addresses and default DMA modes
static const struct {
unsigned int fifo_addr;
unsigned int dma_mode;
unsigned int dma_source;
} dma_dev_table[DMA_ID_MAX] = {
{0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
{0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
{CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
{CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
{CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
{CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
{CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
{CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
{CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
{CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
{CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
{CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
{CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
{CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
{CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
{CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT},
{CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN},
{0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
{SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */
{CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */
{CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */
{CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT},
{CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN},
// {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT},
// {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN},
{},
};
int jz_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data)
{
int i, len = 0;
struct jz_dma_chan *chan;
for (i = 0; i < MAX_DMA_NUM; i++) {
if ((chan = get_dma_chan(i)) != NULL) {
len += sprintf(buf + len, "%2d: %s\n",
i, chan->dev_str);
}
}
if (fpos >= len) {
*start = buf;
*eof = 1;
return 0;
}
*start = buf + fpos;
if ((len -= fpos) > length)
return length;
*eof = 1;
return len;
}
void dump_jz_dma_channel(unsigned int dmanr)
{
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return;
chan = &jz_dma_table[dmanr];
printk("DMA%d Registers:\n", dmanr);
printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM));
printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM));
}
/**
* jz_request_dma - dynamically allcate an idle DMA channel to return
* @dev_id: the specified dma device id or DMA_ID_RAW_SET
* @dev_str: the specified dma device string name
* @irqhandler: the irq handler, or NULL
* @irqflags: the irq handler flags
* @irq_dev_id: the irq handler device id for shared irq
*
* Finds a free channel, and binds the requested device to it.
* Returns the allocated channel number, or negative on error.
* Requests the DMA done IRQ if irqhandler != NULL.
*
*/
/*int jz_request_dma(int dev_id, const char *dev_str,
void (*irqhandler)(int, void *, struct pt_regs *),
unsigned long irqflags,
void *irq_dev_id)
*/
int jz_request_dma(int dev_id, const char *dev_str,
irqreturn_t (*irqhandler)(int, void *),
unsigned long irqflags,
void *irq_dev_id)
{
struct jz_dma_chan *chan;
int i, ret;
if (dev_id < 0 || dev_id >= DMA_ID_MAX)
return -EINVAL;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM) /* no free channel */
return -ENODEV;
/* we got a free channel */
chan = &jz_dma_table[i];
if (irqhandler) {
chan->irq = IRQ_DMA_0 + i; // allocate irq number
chan->irq_dev = irq_dev_id;
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
dev_str, chan->irq_dev))) {
chan->irq = -1;
chan->irq_dev = NULL;
return ret;
}
} else {
chan->irq = -1;
chan->irq_dev = NULL;
}
// fill it in
chan->io = i;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
chan->mode = dma_dev_table[dev_id].dma_mode;
chan->source = dma_dev_table[dev_id].dma_source;
if (i < HALF_DMA_NUM)
REG_DMAC_DMACKE(0) = 1 << i;
else
REG_DMAC_DMACKE(1) = 1 << (i - HALF_DMA_NUM);
return i;
}
void jz_free_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan) {
printk("Trying to free DMA%d\n", dmanr);
return;
}
disable_dma(dmanr);
if (chan->irq)
free_irq(chan->irq, chan->irq_dev);
chan->irq = -1;
chan->irq_dev = NULL;
chan->dev_id = -1;
}
void jz_set_dma_dest_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_DWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_DWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_DWDH_32;
break;
}
}
void jz_set_dma_src_width(int dmanr, int nbit)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_SWDH_MASK;
switch (nbit) {
case 8:
chan->mode |= DMAC_DCMD_SWDH_8;
break;
case 16:
chan->mode |= DMAC_DCMD_SWDH_16;
break;
case 32:
chan->mode |= DMAC_DCMD_SWDH_32;
break;
}
}
void jz_set_dma_block_size(int dmanr, int nbyte)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode &= ~DMAC_DCMD_DS_MASK;
switch (nbyte) {
case 1:
chan->mode |= DMAC_DCMD_DS_8BIT;
break;
case 2:
chan->mode |= DMAC_DCMD_DS_16BIT;
break;
case 4:
chan->mode |= DMAC_DCMD_DS_32BIT;
break;
case 16:
chan->mode |= DMAC_DCMD_DS_16BYTE;
break;
case 32:
chan->mode |= DMAC_DCMD_DS_32BYTE;
break;
}
}
unsigned int jz_get_dma_command(int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
return chan->mode;
}
/**
* jz_set_dma_mode - do the raw settings for the specified DMA channel
* @dmanr: the specified DMA channel
* @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
* @dma_mode: dma raw mode
* @dma_source: dma raw request source
* @fifo_addr: dma raw device fifo address
*
* Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
* jz_set_dma_mode() rather than set_dma_mode() if you work with
* and external request dma device.
*
* NOTE: Don not dynamically allocate dma channel if one external request
* dma device will occupy this channel.
*/
int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
unsigned int dma_mode, unsigned int dma_source,
unsigned int fifo_addr)
{
int dev_id, i;
struct jz_dma_chan *chan;
if (dmanr > MAX_DMA_NUM)
return -ENODEV;
for (i = 0; i < MAX_DMA_NUM; i++) {
if (jz_dma_table[i].dev_id < 0)
break;
}
if (i == MAX_DMA_NUM)
return -ENODEV;
chan = &jz_dma_table[dmanr];
dev_id = chan->dev_id;
if (dev_id > 0) {
printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
__FUNCTION__, dmanr);
return -ENODEV;
}
/* clone it from the dynamically allocated. */
if (i != dmanr) {
chan->irq = jz_dma_table[i].irq;
chan->irq_dev = jz_dma_table[i].irq_dev;
chan->dev_str = jz_dma_table[i].dev_str;
jz_dma_table[i].irq = 0;
jz_dma_table[i].irq_dev = NULL;
jz_dma_table[i].dev_id = -1;
}
chan->dev_id = DMA_ID_RAW_SET;
chan->io = dmanr;
chan->fifo_addr = fifo_addr;
chan->mode = dma_mode;
chan->source = dma_source;
set_dma_mode(dmanr, dma_mode);
return dmanr;
}
void enable_dma(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
__dmac_enable_channel(dmanr);
if (chan->irq)
__dmac_channel_enable_irq(dmanr);
}
#define DMA_DISABLE_POLL 0x10000
void disable_dma(unsigned int dmanr)
{
int i;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
if (!__dmac_channel_enabled(dmanr))
return;
for (i = 0; i < DMA_DISABLE_POLL; i++)
if (__dmac_channel_transmit_end_detected(dmanr))
break;
#if 0
if (i == DMA_DISABLE_POLL)
printk(KERN_INFO "disable_dma: poll expired!\n");
#endif
__dmac_disable_channel(dmanr);
if (chan->irq)
__dmac_channel_disable_irq(dmanr);
}
/* Note: DMA_MODE_MASK is simulated by sw */
void set_dma_mode(unsigned int dmanr, unsigned int mode)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else {
printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
}
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
}
void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
{
unsigned int mode;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
mode = chan->mode & DMA_MODE_MASK;
if (mode == DMA_MODE_READ) {
REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
REG_DMAC_DTAR(chan->io) = phyaddr;
} else if (mode == DMA_MODE_WRITE) {
REG_DMAC_DSAR(chan->io) = phyaddr;
REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
} else
printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
}
void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
int dma_ds[] = {4, 1, 2, 16, 32};
unsigned int ds;
if (!chan)
return;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
}
unsigned int get_dma_residue(unsigned int dmanr)
{
unsigned int count, ds;
int dma_ds[] = {4, 1, 2, 16, 32};
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
count = REG_DMAC_DTCR(chan->io);
count = count * dma_ds[ds];
return count;
}
void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case AFMT_U8:
/* burst mode : 32BIT */
break;
case AFMT_S16_LE:
/* burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
//chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
switch (audio_fmt) {
case 8:
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
break;
case 16:
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
if (mode == DMA_MODE_READ) {
chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_DAI;
chan->mode &= ~DMAC_DCMD_SAI;
} else if (mode == DMA_MODE_WRITE) {
chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
mode &= DMA_MODE_MASK;
chan->mode |= DMAC_DCMD_SAI;
chan->mode &= ~DMAC_DCMD_DAI;
} else
printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
REG_DMAC_DRSR(chan->io) = chan->source;
break;
}
}
//#define JZ4760_DMAC_TEST_ENABLE
#undef JZ4760_DMAC_TEST_ENABLE
#ifdef JZ4760_DMAC_TEST_ENABLE
/*
* DMA test: external address <--> external address
*/
#define TEST_DMA_SIZE 16*1024
static jz_dma_desc *dma_desc;
static int dma_chan;
static dma_addr_t dma_desc_phys_addr;
static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
static int dma_check_result(void *src, void *dst, int size)
{
unsigned int addr1, addr2, i, err = 0;
addr1 = (unsigned int)src;
addr2 = (unsigned int)dst;
for (i = 0; i < size; i += 4) {
if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
err++;
printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
}
addr1 += 4;
addr2 += 4;
}
printk("check DMA result err=%d\n", err);
return err;
}
static irqreturn_t jz4760_dma_irq(int irq, void *dev_id)
{
printk("jz4760_dma_irq %d\n", irq);
if (__dmac_channel_transmit_halt_detected(dma_chan)) {
printk("DMA HALT\n");
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
__dmac_channel_clear_transmit_halt(dma_chan);
}
if (__dmac_channel_address_error_detected(dma_chan)) {
printk("DMA ADDR ERROR\n");
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */
REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */
__dmac_channel_clear_address_error(dma_chan);
}
if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
printk("DMA DESC INVALID\n");
__dmac_channel_clear_descriptor_invalid(dma_chan);
}
if (__dmac_channel_count_terminated_detected(dma_chan)) {
printk("DMA CT\n");
__dmac_channel_clear_count_terminated(dma_chan);
}
if (__dmac_channel_transmit_end_detected(dma_chan)) {
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
printk("DMA TT\n");
__dmac_channel_clear_transmit_end(dma_chan);
dump_jz_dma_channel(dma_chan);
dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
}
return IRQ_HANDLED;
}
void dma_nodesc_test(void)
{
unsigned int addr, i;
printk("dma_nodesc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4760_dma_irq,
IRQF_DISABLED, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Init DMA module */
printk("Starting DMA\n");
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
REG_DMAC_DCCSR(dma_chan) = 0;
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
REG_DMAC_DTCR(dma_chan) = 512;
REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
/* wait a long time, ensure transfer end */
printk("wait 3s...\n");
mdelay(3000); /* wait 3s */
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
void dma_desc_test(void)
{
unsigned int next, addr, i;
static jz_dma_desc *desc;
printk("dma_desc_test\n");
/* Request DMA channel and setup irq handler */
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4760_dma_irq,
IRQF_DISABLED, NULL);
if (dma_chan < 0) {
printk("Setup irq failed\n");
return;
}
printk("Requested DMA channel = %d\n", dma_chan);
/* Allocate DMA buffers */
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
/* Prepare data for source buffer */
addr = (unsigned int)dma_src_addr;
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
*(volatile unsigned int *)addr = addr;
addr += 4;
}
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
/* Init target buffer */
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
/* Allocate DMA descriptors */
dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
/* Setup DMA descriptors */
desc = dma_desc;
next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr; /* DMA source address */
desc->dtadr = dma_dst_phys_addr; /* DMA target address */
desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
desc++;
next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
/* Setup DMA descriptor address */
REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
/* Setup request source */
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
/* Setup DMA channel control/status register */
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
/* Enable DMA */
REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE;
/* DMA doorbell set -- start DMA now ... */
REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan;
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
/* wait a long time, ensure transfer end */
printk("wait 3s...\n");
mdelay(3000); /* wait 3s */
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
/* free buffers */
printk("free DMA buffers\n");
free_pages(dma_src_addr, 2);
free_pages(dma_dst_addr, 2);
if (dma_desc)
free_pages((unsigned int)dma_desc, 0);
/* free dma */
jz_free_dma(dma_chan);
}
#endif
//EXPORT_SYMBOL_NOVERS(jz_dma_table);
EXPORT_SYMBOL(jz_dma_table);
EXPORT_SYMBOL(jz_request_dma);
EXPORT_SYMBOL(jz_free_dma);
EXPORT_SYMBOL(jz_set_dma_src_width);
EXPORT_SYMBOL(jz_set_dma_dest_width);
EXPORT_SYMBOL(jz_set_dma_block_size);
EXPORT_SYMBOL(jz_set_dma_mode);
EXPORT_SYMBOL(set_dma_mode);
EXPORT_SYMBOL(jz_set_oss_dma);
EXPORT_SYMBOL(jz_set_alsa_dma);
EXPORT_SYMBOL(set_dma_addr);
EXPORT_SYMBOL(set_dma_count);
EXPORT_SYMBOL(get_dma_residue);
EXPORT_SYMBOL(enable_dma);
EXPORT_SYMBOL(disable_dma);
EXPORT_SYMBOL(dump_jz_dma_channel);

View File

@@ -0,0 +1,273 @@
/*
* linux/arch/mips/jz4760/i2c.c
*
* Jz4760 I2C routines.
*
* Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
/* I2C protocol */
#define I2C_READ 1
#define I2C_WRITE 0
#define TIMEOUT 1000
/*
* I2C bus protocol basic routines
*/
static int i2c_put_data(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (!__i2c_received_ack() && timeout)
timeout--;
if (timeout)
return 0;
else
return -ETIMEDOUT;
}
#ifdef CONFIG_JZ_TPANEL_ATA2508
static int i2c_put_data_nack(unsigned char data)
{
unsigned int timeout = TIMEOUT*10;
__i2c_write(data);
__i2c_set_drf();
while (__i2c_check_drf() != 0);
while (!__i2c_transmit_ended());
while (timeout--);
return 0;
}
#endif
static int i2c_get_data(unsigned char *data, int ack)
{
int timeout = TIMEOUT*10;
if (!ack)
__i2c_send_nack();
else
__i2c_send_ack();
while (__i2c_check_drf() == 0 && timeout)
timeout--;
if (timeout) {
if (!ack)
__i2c_send_stop();
*data = __i2c_read();
__i2c_clear_drf();
return 0;
} else
return -ETIMEDOUT;
}
/*
* I2C interface
*/
void i2c_open(void)
{
__i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
__i2c_enable();
}
void i2c_close(void)
{
udelay(300); /* wait for STOP goes over. */
__i2c_disable();
}
void i2c_setclk(unsigned int i2cclk)
{
__i2c_set_clk(jz_clocks.extalclk, i2cclk);
}
int i2c_lseek(unsigned char device, unsigned char offset)
{
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
if (i2c_put_data(offset) < 0)
goto address_err;
return 0;
device_err:
printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
__i2c_send_stop();
return -ENODEV;
address_err:
printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
__i2c_send_stop();
return -EREMOTEIO;
}
int i2c_read(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int timeout = 5;
L_try_again:
if (timeout < 0)
goto L_timeout;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_werr;
if (i2c_put_data(address) < 0)
goto address_err;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
goto device_rerr;
__i2c_send_ack(); /* Master sends ACK for continue reading */
while (cnt) {
if (cnt == 1) {
if (i2c_get_data(buf, 0) < 0)
break;
} else {
if (i2c_get_data(buf, 1) < 0)
break;
}
cnt--;
buf++;
}
__i2c_send_stop();
return count - cnt;
device_rerr:
device_werr:
address_err:
timeout --;
__i2c_send_stop();
goto L_try_again;
L_timeout:
__i2c_send_stop();
printk("Read I2C device 0x%2x failed.\n", device);
return -ENODEV;
}
int i2c_write(unsigned char device, unsigned char *buf,
unsigned char address, int count)
{
int cnt = count;
int cnt_in_pg;
int timeout = 5;
unsigned char *tmpbuf;
unsigned char tmpaddr;
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
W_try_again:
if (timeout < 0)
goto W_timeout;
cnt = count;
tmpbuf = (unsigned char *)buf;
tmpaddr = address;
start_write_page:
cnt_in_pg = 0;
__i2c_send_start();
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
goto device_err;
#ifdef CONFIG_JZ_TPANEL_ATA2508
if (address == 0xff) {
if (i2c_put_data_nack(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data_nack(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
else {
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
}
#else
if (i2c_put_data(tmpaddr) < 0)
goto address_err;
while (cnt) {
if (++cnt_in_pg > 8) {
__i2c_send_stop();
mdelay(1);
tmpaddr += 8;
goto start_write_page;
}
if (i2c_put_data(*tmpbuf) < 0)
break;
cnt--;
tmpbuf++;
}
#endif
__i2c_send_stop();
return count - cnt;
device_err:
address_err:
timeout--;
__i2c_send_stop();
goto W_try_again;
W_timeout:
printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
__i2c_send_stop();
return -ENODEV;
}
EXPORT_SYMBOL(i2c_open);
EXPORT_SYMBOL(i2c_close);
EXPORT_SYMBOL(i2c_setclk);
EXPORT_SYMBOL(i2c_read);
EXPORT_SYMBOL(i2c_write);

View File

@@ -0,0 +1,299 @@
/*
* linux/arch/mips/jz4760/irq.c
*
* JZ4760 interrupt routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
/*
* INTC irq type
*/
static void enable_intc_irq(unsigned int irq)
{
__intc_unmask_irq(irq);
}
static void disable_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
}
static void mask_and_ack_intc_irq(unsigned int irq)
{
__intc_mask_irq(irq);
__intc_ack_irq(irq);
}
static void end_intc_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
enable_intc_irq(irq);
}
}
static unsigned int startup_intc_irq(unsigned int irq)
{
enable_intc_irq(irq);
return 0;
}
static void shutdown_intc_irq(unsigned int irq)
{
disable_intc_irq(irq);
}
static struct irq_chip intc_irq_type = {
.typename = "INTC",
.startup = startup_intc_irq,
.shutdown = shutdown_intc_irq,
.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<<irq);
irq = plat_real_irq(irq);
do_IRQ(irq);
}

View File

@@ -0,0 +1,166 @@
/*
* Platform device support for Jz4760 SoC.
*
* Copyright 2007, <yliu@ingenic.cn>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <asm/jzsoc.h>
#include <linux/usb/musb.h>
#if 0
/* OHCI (USB full speed host controller) */
static struct resource jz_usb_ohci_resources[] = {
[0] = {
.start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
.end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_UHC,
.end = IRQ_UHC,
.flags = IORESOURCE_IRQ,
},
};
/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;
static struct platform_device jz_usb_ohci_device = {
.name = "jz-ohci",
.id = 0,
.dev = {
.dma_mask = &ohci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
.resource = jz_usb_ohci_resources,
};
#endif
/*** LCD controller ***/
static struct resource jz_lcd_resources[] = {
[0] = {
.start = CPHYSADDR(LCD_BASE),
.end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_lcd_dmamask = ~(u32)0;
static struct platform_device jz_lcd_device = {
.name = "jz-lcd",
.id = 0,
.dev = {
.dma_mask = &jz_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_lcd_resources),
.resource = jz_lcd_resources,
};
/* USB OTG Controller */
static struct musb_hdrc_config jz_usb_otg_config = {
.multipoint = 0,
.dyn_fifo = 0,
.soft_con = 1,
.dma = 1,
.num_eps = 5,
.dma_channels = 5,
};
static struct musb_hdrc_platform_data jz_usb_otg_platform_data = {
#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
.mode = MUSB_HOST,
#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
.mode = MUSB_PERIPHERAL,
#endif
.config = &jz_usb_otg_config,
};
static struct resource jz_usb_otg_resources[] = {
[0] = {
.start = CPHYSADDR(UDC_BASE),
.end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_OTG,
.end = IRQ_OTG,
.flags = IORESOURCE_IRQ,
},
};
static u64 usb_otg_dmamask = ~(u32)0;
static struct platform_device jz_usb_otg_device = {
.name = "musb_hdrc",
.id = 0,
.dev = {
.dma_mask = &usb_otg_dmamask,
.coherent_dma_mask = 0xffffffff,
.platform_data = &jz_usb_otg_platform_data,
},
.num_resources = ARRAY_SIZE(jz_usb_otg_resources),
.resource = jz_usb_otg_resources,
};
/** MMC/SD controller **/
static struct resource jz_mmc_resources[] = {
[0] = {
.start = CPHYSADDR(MSC0_BASE),
.end = CPHYSADDR(MSC0_BASE) + 0x10000 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_MSC0,
.end = IRQ_MSC0,
.flags = IORESOURCE_IRQ,
}
};
static u64 jz_mmc_dmamask = ~(u32)0;
static struct platform_device jz_mmc_device = {
.name = "jz-mmc",
.id = 0,
.dev = {
.dma_mask = &jz_mmc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(jz_mmc_resources),
.resource = jz_mmc_resources,
};
/* All */
static struct platform_device *jz_platform_devices[] __initdata = {
// &jz_usb_ohci_device,
&jz_usb_otg_device,
&jz_lcd_device,
&jz_mmc_device,
};
static int __init jz_platform_init(void)
{
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
}
arch_initcall(jz_platform_init);

View File

@@ -0,0 +1,461 @@
/*
* linux/arch/mips/jz4760/common/pm.c
*
* JZ4760 Power Management Routines
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/pm_legacy.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <asm/cacheops.h>
#include <asm/jzsoc.h>
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define dprintk(x...) printk(x)
#else
#define dprintk(x...)
#endif
#define GPIO_PORT_NUM 6
/*
* __gpio_as_sleep set all pins to pull-disable, and set all pins as input
* except sdram and the pins which can be used as CS1_N to CS4_N for chip select.
*/
#define __gpio_as_sleep() \
do { \
REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \
REG_GPIO_PXSELC(1) = ~0x03ff7fff; \
REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \
REG_GPIO_PXPES(1) = 0xffffffff; \
REG_GPIO_PXFUNC(2) = ~0x01e00000; \
REG_GPIO_PXSELC(2) = ~0x01e00000; \
REG_GPIO_PXDIRC(2) = ~0x01e00000; \
REG_GPIO_PXPES(2) = 0xffffffff; \
REG_GPIO_PXFUNC(3) = 0xffffffff; \
REG_GPIO_PXSELC(3) = 0xffffffff; \
REG_GPIO_PXDIRC(3) = 0xffffffff; \
REG_GPIO_PXPES(3) = 0xffffffff; \
REG_GPIO_PXFUNC(4) = 0xffffffff; \
REG_GPIO_PXSELC(4) = 0xffffffff; \
REG_GPIO_PXDIRC(4) = 0xffffffff; \
REG_GPIO_PXPES(4) = 0xffffffff; \
REG_GPIO_PXFUNC(5) = 0xffffffff; \
REG_GPIO_PXSELC(5) = 0xffffffff; \
REG_GPIO_PXDIRC(5) = 0xffffffff; \
REG_GPIO_PXPES(5) = 0xffffffff; \
} while (0)
static int jz_pm_do_hibernate(void)
{
printk("Put CPU into hibernate mode.\n");
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/*
* RTC Wakeup or 1Hz interrupt can be enabled or disabled
* through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
*/
/* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
/* Set reset pin low-level assertion time after wakeup: must > 60ms */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
/* Scratch pad register to be reserved */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HSPR = 0x12345678;
/* clear wakeup status register */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HWRSR = 0x0;
/* Put CPU to power down mode */
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
REG_RTC_HCR = RTC_HCR_PD;
while (!(REG_RTC_RCR & RTC_RCR_WRDY));
while(1);
/* We can't get here */
return 0;
}
/* NOTES:
* 1: Pins that are floated (NC) should be set as input and pull-enable.
* 2: Pins that are pull-up or pull-down by outside should be set as input
* and pull-disable.
* 3: Pins that are connected to a chip except sdram and nand flash
* should be set as input and pull-disable, too.
*/
static void jz_board_do_sleep(unsigned long *ptr)
{
unsigned char i;
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
}
/* Save GPIO registers */
for(i = 1; i < GPIO_PORT_NUM; i++) {
*ptr++ = REG_GPIO_PXFUN(i);
*ptr++ = REG_GPIO_PXSEL(i);
*ptr++ = REG_GPIO_PXDIR(i);
*ptr++ = REG_GPIO_PXPE(i);
*ptr++ = REG_GPIO_PXIM(i);
*ptr++ = REG_GPIO_PXDAT(i);
*ptr++ = REG_GPIO_PXTRG(i);
}
/*
* Set all pins to pull-disable, and set all pins as input except
* sdram and the pins which can be used as CS1_N to CS4_N for chip select.
*/
__gpio_as_sleep();
/*
* Set proper status for GPC21 to GPC24 which can be used as CS1_N to CS4_N.
* Keep the pins' function used for chip select(CS) here according to your
* system to avoid chip select crashing with sdram when resuming from sleep mode.
*/
#if defined(CONFIG_JZ4760_APUS)
/* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
/* GPB26/CS2_N is connected to nand flash, needn't be changed. */
/* GPB28/CS3_N is used as cs8900's chip select, shouldn't be changed. */
/* GPB27/CS4_N is used as NOR's chip select, shouldn't be changed. */
#endif
/*
* Enable pull for NC pins here according to your system
*/
#if defined(CONFIG_JZ4760_APUS)
#endif
/*
* If you must set some GPIOs as output to high level or low level,
* you can set them here, using:
* __gpio_as_output(n);
* __gpio_set_pin(n); or __gpio_clear_pin(n);
*/
#if defined(CONFIG_JZ4760_APUS)
/* GPC7 which is used as AMPEN_N should be set to high to disable audio amplifier */
__gpio_as_output(32*2+7);
__gpio_set_pin(32*2+7);
#endif
#ifdef DEBUG
/* Keep uart function for printing debug message */
__gpio_as_uart0();
__gpio_as_uart1();
__gpio_as_uart2();
__gpio_as_uart3();
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
}
#endif
}
static void jz_board_do_resume(unsigned long *ptr)
{
unsigned char i;
/* Restore GPIO registers */
for(i = 1; i < GPIO_PORT_NUM; i++) {
REG_GPIO_PXFUNS(i) = *ptr;
REG_GPIO_PXFUNC(i) = ~(*ptr++);
REG_GPIO_PXSELS(i) = *ptr;
REG_GPIO_PXSELC(i) = ~(*ptr++);
REG_GPIO_PXDIRS(i) = *ptr;
REG_GPIO_PXDIRC(i) = ~(*ptr++);
REG_GPIO_PXPES(i) = *ptr;
REG_GPIO_PXPEC(i) = ~(*ptr++);
REG_GPIO_PXIMS(i)=*ptr;
REG_GPIO_PXIMC(i)=~(*ptr++);
REG_GPIO_PXDATS(i)=*ptr;
REG_GPIO_PXDATC(i)=~(*ptr++);
REG_GPIO_PXTRGS(i)=*ptr;
REG_GPIO_PXTRGC(i)=~(*ptr++);
}
/* Print messages of GPIO registers for debug */
for(i=0;i<GPIO_PORT_NUM;i++) {
dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
}
}
static int jz_pm_do_sleep(void)
{
unsigned long delta;
unsigned long nfcsr = REG_EMC_NFCSR;
unsigned long opcr = REG_CPM_OPCR;
unsigned long imr = REG_INTC_IMR;
unsigned long sadc = REG_SADC_ENA;
unsigned long sleep_gpio_save[7*(GPIO_PORT_NUM-1)];
printk("Put CPU into sleep mode.\n");
/* Preserve current time */
delta = xtime.tv_sec - REG_RTC_RSR;
/* Disable nand flash */
REG_EMC_NFCSR = ~0xff;
/* stop sadc */
REG_SADC_ENA &= ~0x7;
while((REG_SADC_ENA & 0x7) != 0);
udelay(100);
/*stop udc and usb*/
__cpm_suspend_uhcphy();
__cpm_suspend_udcphy();
/* Sleep on-board modules */
jz_board_do_sleep(sleep_gpio_save);
/* Mask all interrupts */
REG_INTC_IMSR = 0xffffffff;
/* Just allow following interrupts to wakeup the system.
* Note: modify this according to your system.
*/
/* enable RTC alarm */
__intc_unmask_irq(IRQ_RTC);
#if 0
/* make system wake up after n seconds by RTC alarm */
unsigned int v, n;
n = 10;
while (!__rtc_write_ready());
__rtc_enable_alarm();
while (!__rtc_write_ready());
__rtc_enable_alarm_irq();
while (!__rtc_write_ready());
v = __rtc_get_second();
while (!__rtc_write_ready());
__rtc_set_alarm_second(v+n);
#endif
/* WAKEUP key */
__gpio_as_irq_rise_edge(GPIO_WAKEUP);
__gpio_unmask_irq(GPIO_WAKEUP);
__intc_unmask_irq(IRQ_GPIO0 - (GPIO_WAKEUP/32)); /* unmask IRQ_GPIOn depends on GPIO_WAKEUP */
/* disable externel clock Oscillator in sleep mode */
__cpm_disable_osc_in_sleep();
/* select 32K crystal as RTC clock in sleep mode */
__cpm_select_rtcclk_rtc();
/* Enter SLEEP mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
/* Restore to IDLE mode */
REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
/* Restore nand flash control register */
REG_EMC_NFCSR = nfcsr;
/* Restore interrupts */
REG_INTC_IMSR = imr;
REG_INTC_IMCR = ~imr;
/* Restore sadc */
REG_SADC_ENA = sadc;
/* Resume on-board modules */
jz_board_do_resume(sleep_gpio_save);
/* Restore Oscillator and Power Control Register */
REG_CPM_OPCR = opcr;
/* Restore current time */
xtime.tv_sec = REG_RTC_RSR + delta;
return 0;
}
/* Put CPU to HIBERNATE mode */
int jz_pm_hibernate(void)
{
return jz_pm_do_hibernate();
}
#ifndef CONFIG_JZ_POWEROFF
static irqreturn_t pm_irq_handler (int irq, void *dev_id)
{
return IRQ_HANDLED;
}
#endif
/* Put CPU to SLEEP mode */
int jz_pm_sleep(void)
{
int retval;
#ifndef CONFIG_JZ_POWEROFF
if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
"PM", NULL))) {
printk ("PM could not get IRQ for GPIO_WAKEUP\n");
return retval;
}
#endif
pm_send_all(PM_SUSPEND, (void *)3);
retval = jz_pm_do_sleep();
pm_send_all(PM_RESUME, (void *)0);
#ifndef CONFIG_JZ_POWEROFF
free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
#endif
return retval;
}
#if 0
/* Deprecated ,was used by dpm */
void jz_pm_idle(void)
{
local_irq_disable();
if (!need_resched()) {
local_irq_enable();
cpu_wait();
}
}
#endif
#ifdef CONFIG_SYSCTL
/*
* Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6
* when all the PM interfaces exist nicely.
*/
#define CTL_PM_SUSPEND 1
#define CTL_PM_HIBERNATE 2
/*----------------------------------------------------------------------------
* Power Management sleep sysctl proc interface
*
* A write to /proc/sys/pm/suspend invokes this function
* which initiates a sleep.
*--------------------------------------------------------------------------*/
static int sysctl_jz_pm_sleep(void)
{
return jz_pm_sleep();
}
/*----------------------------------------------------------------------------
* Power Management sleep sysctl proc interface
*
* A write to /proc/sys/pm/hibernate invokes this function
* which initiates a poweroff.
*--------------------------------------------------------------------------*/
static int sysctl_jz_pm_hibernate(void)
{
return jz_pm_hibernate();
}
static struct ctl_table pm_table[] =
{
{
.ctl_name = CTL_UNNUMBERED,
.procname = "suspend",
.data = NULL,
.maxlen = 0,
.mode = 0600,
.proc_handler = &sysctl_jz_pm_sleep,
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "hibernate",
.data = NULL,
.maxlen = 0,
.mode = 0600,
.proc_handler = &sysctl_jz_pm_hibernate,
},
{ .ctl_name = 0}
};
static struct ctl_table pm_dir_table[] =
{
{
.ctl_name = CTL_UNNUMBERED,
.procname = "pm",
.mode = 0555,
.child = pm_table,
},
{ .ctl_name = 0}
};
#endif /* CONFIG_SYSCTL */
/*
* Initialize power interface
*/
static int __init jz_pm_init(void)
{
printk("Power Management for JZ\n");
#ifdef CONFIG_SYSCTL
register_sysctl_table(pm_dir_table);
#endif
return 0;
}
module_init(jz_pm_init);

View File

@@ -0,0 +1,885 @@
/*
* linux/arch/mips/jz4760/proc.c
*
* /proc/jz/ procfs for jz4760 on-chip modules.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/page-flags.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/jzsoc.h>
//#define DEBUG 1
#undef DEBUG
struct proc_dir_entry *proc_jz_root;
/*
* EMC Modules
*/
static int emc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
return len;
}
/*
* Power Manager Module
*/
static int pmc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned long lcr = REG_CPM_LCR;
unsigned long clkgr = REG_CPM_CLKGR;
len += sprintf (page+len, "Low Power Mode : %s\n",
((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
"IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
"SLEEP" : "HIBERNATE"));
len += sprintf (page+len, "Doze Mode : %s\n",
(lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
if (lcr & CPM_LCR_DOZE_ON)
len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
len += sprintf (page+len, "AUX_CPU : %s\n",
(clkgr & CPM_CLKGR_AUX_CPU) ? "stopped" : "running");
len += sprintf (page+len, "AHB1 : %s\n",
(clkgr & CPM_CLKGR_AHB1) ? "stopped" : "running");
len += sprintf (page+len, "IDCT : %s\n",
(clkgr & CPM_CLKGR_IDCT) ? "stopped" : "running");
len += sprintf (page+len, "DB : %s\n",
(clkgr & CPM_CLKGR_DB) ? "stopped" : "running");
len += sprintf (page+len, "ME : %s\n",
(clkgr & CPM_CLKGR_ME) ? "stopped" : "running");
len += sprintf (page+len, "MC : %s\n",
(clkgr & CPM_CLKGR_MC) ? "stopped" : "running");
len += sprintf (page+len, "TVE : %s\n",
(clkgr & CPM_CLKGR_TVE) ? "stopped" : "running");
len += sprintf (page+len, "TSSI : %s\n",
(clkgr & CPM_CLKGR_TSSI) ? "stopped" : "running");
len += sprintf (page+len, "IPU : %s\n",
(clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
len += sprintf (page+len, "DMAC : %s\n",
(clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
len += sprintf (page+len, "UDC : %s\n",
(clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
len += sprintf (page+len, "LCD : %s\n",
(clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
len += sprintf (page+len, "CIM : %s\n",
(clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
len += sprintf (page+len, "SADC : %s\n",
(clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
len += sprintf (page+len, "MSC0 : %s\n",
(clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running");
len += sprintf (page+len, "MSC1 : %s\n",
(clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running");
len += sprintf (page+len, "SSI : %s\n",
(clkgr & CPM_CLKGR_SSI) ? "stopped" : "running");
len += sprintf (page+len, "I2C : %s\n",
(clkgr & CPM_CLKGR_I2C) ? "stopped" : "running");
len += sprintf (page+len, "RTC : %s\n",
(clkgr & CPM_CLKGR_RTC) ? "stopped" : "running");
len += sprintf (page+len, "TCU : %s\n",
(clkgr & CPM_CLKGR_TCU) ? "stopped" : "running");
len += sprintf (page+len, "UART1 : %s\n",
(clkgr & CPM_CLKGR_UART1) ? "stopped" : "running");
len += sprintf (page+len, "UART0 : %s\n",
(clkgr & CPM_CLKGR_UART0) ? "stopped" : "running");
return len;
}
static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16);
return count;
}
/*
* Clock Generation Module
*/
#define TO_MHZ(x) (x/1000000),(x%1000000)/10000
#define TO_KHZ(x) (x/1000),(x%1000)/10
static int cgm_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */
unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */
unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
unsigned int od[4] = {1, 2, 2, 4};
len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr);
len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr);
len += sprintf (page+len, "PLL : %s\n",
(cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF");
len += sprintf (page+len, "m:n:o : %d:%d:%d\n",
__cpm_get_pllm() + 2,
__cpm_get_plln() + 2,
od[__cpm_get_pllod()]
);
len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n",
div[__cpm_get_cdiv()],
div[__cpm_get_hdiv()],
div[__cpm_get_mdiv()],
div[__cpm_get_pdiv()]
);
len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout()));
len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk()));
len += sprintf (page+len, "H0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_h0clk()));
len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk()));
len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk()));
len += sprintf (page+len, "H1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_h1clk()));
len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk()));
len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk()));
len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk()));
len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0)));
len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1)));
len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0()));
len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk()));
len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk()));
return len;
}
static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16);
return count;
}
/* USAGE:
* echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages.
* echo FF > /proc/jz/ipu // 255, free all buffer
* echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx
* echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l)
* echo 0 > /proc/jz/ipu // debug, print ipu_buf
* od -X /proc/jz/ipu // read mem addr
*/
typedef struct _ipu_buf {
unsigned int addr; /* phys addr */
unsigned int page_shift;
} ipu_buf_t;
#define IPU_BUF_MAX 4 /* 4 buffers */
static struct _ipu_buf ipu_buf[IPU_BUF_MAX];
static int ipu_buf_cnt = 0;
static unsigned char g_asid=0;
extern void local_flush_tlb_all(void);
/* CP0 hazard avoidance. */
#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
"nop; nop; nop; nop; nop; nop;\n\t" \
".set reorder\n\t")
void show_tlb(void)
{
#define ASID_MASK 0xFF
unsigned long flags;
unsigned int old_ctx;
unsigned int entry;
unsigned int entrylo0, entrylo1, entryhi;
unsigned int pagemask;
local_irq_save(flags);
/* Save old context */
old_ctx = (read_c0_entryhi() & 0xff);
printk("TLB content:\n");
entry = 0;
while(entry < 32) {
write_c0_index(entry);
BARRIER;
tlb_read();
BARRIER;
entryhi = read_c0_entryhi();
entrylo0 = read_c0_entrylo0();
entrylo1 = read_c0_entrylo1();
pagemask = read_c0_pagemask();
printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK);
printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
printk("\t\tpagemask=0x%08x", pagemask);
printk("\tentryhi=0x%08x\n", entryhi);
printk("\t\tentrylo0=0x%08x", entrylo0);
printk("\tentrylo1=0x%08x\n", entrylo1);
entry++;
}
BARRIER;
write_c0_entryhi(old_ctx);
local_irq_restore(flags);
}
static void ipu_add_wired_entry(unsigned long pid,
unsigned long entrylo0, unsigned long entrylo1,
unsigned long entryhi, unsigned long pagemask)
{
unsigned long flags;
unsigned long wired;
unsigned long old_pagemask;
unsigned long old_ctx;
struct task_struct *g, *p;
/* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */
wired = read_c0_wired();
if (wired) return;
do_each_thread(g, p) {
if (p->pid == pid )
g_asid = p->mm->context[0];
} while_each_thread(g, p);
local_irq_save(flags);
entrylo0 = entrylo0 >> 6; /* PFN */
entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */
/* Save old context and create impossible VPN2 value */
old_ctx = read_c0_entryhi() & 0xff;
old_pagemask = read_c0_pagemask();
wired = read_c0_wired();
write_c0_wired(wired + 1);
write_c0_index(wired);
BARRIER;
entryhi &= ~0xff; /* new add, 20070906 */
entryhi |= g_asid; /* new add, 20070906 */
// entryhi |= old_ctx; /* new add, 20070906 */
write_c0_pagemask(pagemask);
write_c0_entryhi(entryhi);
write_c0_entrylo0(entrylo0);
write_c0_entrylo1(entrylo1);
BARRIER;
tlb_write_indexed();
BARRIER;
write_c0_entryhi(old_ctx);
BARRIER;
write_c0_pagemask(old_pagemask);
local_flush_tlb_all();
local_irq_restore(flags);
#if defined(DEBUG)
printk("\nold_ctx=%03d\n", old_ctx);
show_tlb();
#endif
}
static void ipu_del_wired_entry( void )
{
unsigned long flags;
unsigned long wired;
local_irq_save(flags);
wired = read_c0_wired();
if ( wired > 0 ) {
write_c0_wired(wired - 1);
}
local_irq_restore(flags);
}
static inline void ipu_buf_get( unsigned int page_shift )
{
unsigned char * virt_addr;
int i;
for ( i=0; i< IPU_BUF_MAX; ++i ) {
if ( ipu_buf[i].addr == 0 ) {
break;
}
}
if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) {
printk("Error, no free ipu buffer.\n");
return ;
}
virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
if ( virt_addr ) {
ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr);
ipu_buf[ipu_buf_cnt].page_shift = page_shift;
for (i = 0; i < (1<<page_shift); i++) {
SetPageReserved(virt_to_page(virt_addr));
virt_addr += PAGE_SIZE;
}
}
else {
printk("get memory Failed.\n");
}
}
static inline void ipu_buf_free( unsigned int phys_addr )
{
unsigned char * virt_addr, *addr;
int cnt, i;
if ( phys_addr == 0 )
return ;
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
if ( phys_addr == ipu_buf[cnt].addr )
break;
if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
}
virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
addr = virt_addr;
for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
ClearPageReserved(virt_to_page(addr));
addr += PAGE_SIZE;
}
if ( cnt == 0 )
ipu_del_wired_entry();
free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
ipu_buf[cnt].addr = 0;
ipu_buf[cnt].page_shift = 0;
}
static int ipu_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
/* read as binary */
unsigned int * pint;
pint = (unsigned int *) (page+len);
if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
printk("no free buffer.\n");
*pint = 0;
}
else
*pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
len += sizeof(unsigned int);
#if defined(DEBUG)
show_tlb();
#endif
return len;
}
static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
unsigned int val ;
int cnt,i;
char buf[12];
unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
#if defined(DEBUG)
printk("ipu write count=%u\n", count);
#endif
if (count == (8*5+1)) {
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*0, 8);
pid = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*1, 8);
entrylo0 = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*2, 8);
entrylo1 = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*3, 8);
entryhi = simple_strtoul(buf, 0, 16);
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer+8*4, 8);
pagemask = simple_strtoul(buf, 0, 16);
#if defined(DEBUG)
printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
pid, entrylo0, entrylo1, entryhi, pagemask);
#endif
ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
return 41;
}
else if ( count <= 8+1 ) {
for (i=0;i<12;i++) buf[i]=0;
strncpy(buf, buffer, 8);
val = simple_strtoul(buf, 0, 16);
} else if (count == 44) {
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer, 10);
pid = simple_strtoul(buf, 0, 16);
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer + 11, 10);
entryhi = simple_strtoul(buf, 0, 16);//vaddr
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer + 22, 10);
entrylo0 = simple_strtoul(buf, 0, 16);//paddr
for (i = 0; i < 12; i++)
buf[i] = 0;
strncpy(buf, buffer + 33, 10);
pagemask = simple_strtoul(buf, 0, 16);
pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
return 44;
} else {
printk("ipu write count error, count=%d\n.", (unsigned int)count);
return -1;
}
/* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
if ( val == 0 ) { /* debug, print ipu_buf info */
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
#if defined(DEBUG)
show_tlb();
#endif
}
else if ( 0< val && val < 10 ) {
ipu_buf_get(val);
}
else if ( val == 0xff ) { /* 255: free all ipu_buf */
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
ipu_buf_free(ipu_buf[cnt].addr);
}
}
else {
ipu_buf_free(val);
}
return count;
}
/*
* UDC hotplug
*/
#ifdef CONFIG_JZ_UDC_HOTPLUG
extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */
#endif
#ifndef GPIO_UDC_HOTPLUG
#define GPIO_UDC_HOTPLUG 86
#endif
static int udc_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) {
#ifdef CONFIG_JZ_UDC_HOTPLUG
/* Cable has connected, wait for disconnection. */
__gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG);
if (jz_udc_active)
len += sprintf (page+len, "CONNECT_CABLE\n");
else
len += sprintf (page+len, "CONNECT_POWER\n");
#else
len += sprintf (page+len, "CONNECT\n");
#endif
}
else {
#ifdef CONFIG_JZ_UDC_HOTPLUG
/* Cable has disconnected, wait for connection. */
__gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG);
#endif
len += sprintf (page+len, "REMOVE\n");
}
return len;
}
/*
* MMC/SD hotplug
*/
#ifndef MSC_HOTPLUG_PIN
#define MSC_HOTPLUG_PIN 90
#endif
static int mmc_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
if (__gpio_get_pin(MSC_HOTPLUG_PIN))
len += sprintf (page+len, "REMOVE\n");
else
len += sprintf (page+len, "INSERT\n");
return len;
}
/***********************************************************************
* IPU memory management (used by mplayer and other apps)
*
* We reserved 4MB memory for IPU
* The memory base address is jz_ipu_framebuf
*/
/* Usage:
*
* echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
* echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
* echo FF > /proc/jz/ipu // FF, free all buffers
* od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
*/
//#define DEBUG_IMEM 1
#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */
static unsigned int jz_imem_base; /* physical base address of ipu memory */
static unsigned int allocated_phys_addr = 0;
/*
* Allocated buffer list
*/
typedef struct imem_list {
unsigned int phys_start; /* physical start addr */
unsigned int phys_end; /* physical end addr */
struct imem_list *next;
} imem_list_t;
static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
#ifdef DEBUG_IMEM
static void dump_imem_list(void)
{
struct imem_list *imem;
printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head);
imem = imem_list_head;
while (imem) {
printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
imem = imem->next;
}
}
#endif
/* allocate 2^order pages inside the 4MB memory */
static int imem_alloc(unsigned int order)
{
int alloc_ok = 0;
unsigned int start, end;
unsigned int size = (1 << order) * PAGE_SIZE;
struct imem_list *imem, *imemn, *imemp;
allocated_phys_addr = 0;
start = jz_imem_base;
end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
imem = imem_list_head;
while (imem) {
if ((imem->phys_start - start) >= size) {
/* we got a valid address range */
alloc_ok = 1;
break;
}
start = imem->phys_end + 1;
imem = imem->next;
}
if (!alloc_ok) {
if ((end - start) >= size)
alloc_ok = 1;
}
if (alloc_ok) {
end = start + size - 1;
allocated_phys_addr = start;
/* add to imem_list, up sorted by phys_start */
imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
if (!imemn) {
return -ENOMEM;
}
imemn->phys_start = start;
imemn->phys_end = end;
imemn->next = NULL;
if (!imem_list_head)
imem_list_head = imemn;
else {
imem = imemp = imem_list_head;
while (imem) {
if (start < imem->phys_start) {
break;
}
imemp = imem;
imem = imem->next;
}
if (imem == imem_list_head) {
imem_list_head = imemn;
imemn->next = imem;
}
else {
imemn->next = imemp->next;
imemp->next = imemn;
}
}
}
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
return 0;
}
static void imem_free(unsigned int phys_addr)
{
struct imem_list *imem, *imemp;
imem = imemp = imem_list_head;
while (imem) {
if (phys_addr == imem->phys_start) {
if (imem == imem_list_head) {
imem_list_head = imem->next;
}
else {
imemp->next = imem->next;
}
kfree(imem);
break;
}
imemp = imem;
imem = imem->next;
}
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
}
static void imem_free_all(void)
{
struct imem_list *imem;
imem = imem_list_head;
while (imem) {
kfree(imem);
imem = imem->next;
}
imem_list_head = NULL;
allocated_phys_addr = 0;
#ifdef DEBUG_IMEM
dump_imem_list();
#endif
}
/*
* Return the allocated buffer address and the max order of free buffer
*/
static int imem_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
unsigned int start_addr, end_addr, max_order, max_size;
struct imem_list *imem;
unsigned int *tmp = (unsigned int *)(page + len);
start_addr = jz_imem_base;
end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
if (!imem_list_head)
max_size = end_addr - start_addr;
else {
max_size = 0;
imem = imem_list_head;
while (imem) {
if (max_size < (imem->phys_start - start_addr))
max_size = imem->phys_start - start_addr;
start_addr = imem->phys_end + 1;
imem = imem->next;
}
if (max_size < (end_addr - start_addr))
max_size = end_addr - start_addr;
}
if (max_size > 0) {
max_order = get_order(max_size);
if (((1 << max_order) * PAGE_SIZE) > max_size)
max_order--;
}
else {
max_order = 0xffffffff; /* No any free buffer */
}
*tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */
*tmp = max_order; /* max order of current free buffers */
len += 2 * sizeof(unsigned int);
return len;
}
static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
unsigned int val;
val = simple_strtoul(buffer, 0, 16);
if (val == 0xff) {
/* free all memory */
imem_free_all();
}
else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) {
/* allocate 2^val pages */
imem_alloc(val);
}
else {
/* free buffer which phys_addr is val */
imem_free(val);
}
return count;
}
/*
* /proc/jz/xxx entry
*
*/
static int __init jz_proc_init(void)
{
struct proc_dir_entry *res;
unsigned int virt_addr, i;
proc_jz_root = proc_mkdir("jz", 0);
/* External Memory Controller */
res = create_proc_entry("emc", 0644, proc_jz_root);
if (res) {
res->read_proc = emc_read_proc;
res->write_proc = NULL;
res->data = NULL;
}
/* Power Management Controller */
res = create_proc_entry("pmc", 0644, proc_jz_root);
if (res) {
res->read_proc = pmc_read_proc;
res->write_proc = pmc_write_proc;
res->data = NULL;
}
/* Clock Generation Module */
res = create_proc_entry("cgm", 0644, proc_jz_root);
if (res) {
res->read_proc = cgm_read_proc;
res->write_proc = cgm_write_proc;
res->data = NULL;
}
/* Image process unit */
res = create_proc_entry("ipu", 0644, proc_jz_root);
if (res) {
res->read_proc = ipu_read_proc;
res->write_proc = ipu_write_proc;
res->data = NULL;
}
/* udc hotplug */
res = create_proc_entry("udc", 0644, proc_jz_root);
if (res) {
res->read_proc = udc_read_proc;
res->write_proc = NULL;
res->data = NULL;
}
/* mmc hotplug */
res = create_proc_entry("mmc", 0644, proc_jz_root);
if (res) {
res->read_proc = mmc_read_proc;
res->write_proc = NULL;
res->data = NULL;
}
/*
* Reserve a 4MB memory for IPU on JZ4760.
*/
jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER);
if (jz_imem_base) {
/* imem (IPU memory management) */
res = create_proc_entry("imem", 0644, proc_jz_root);
if (res) {
res->read_proc = imem_read_proc;
res->write_proc = imem_write_proc;
res->data = NULL;
}
/* Set page reserved */
virt_addr = jz_imem_base;
for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) {
SetPageReserved(virt_to_page((void *)virt_addr));
virt_addr += PAGE_SIZE;
}
/* Convert to physical address */
jz_imem_base = virt_to_phys((void *)jz_imem_base);
printk("Total %dMB memory at 0x%x was reserved for IPU\n",
(unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base);
}
return 0;
}
__initcall(jz_proc_init);

View File

@@ -0,0 +1,198 @@
/*
*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, supports YAMON and U-Boot.
*
* Copyright 2000, 2001, 2006 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/jzsoc.h>
/* #define DEBUG_CMDLINE */
int prom_argc;
char **prom_argv, **prom_envp;
char * prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
if (prom_argc > 1)
*cp = '\0';
}
char *prom_getenv(char *envname)
{
#if 0
/*
* Return a pointer to the given environment variable.
* YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
*/
char **env = prom_envp;
int i = strlen(envname);
int yamon = (*env && strchr(*env, '=') == NULL);
while (*env) {
if (yamon) {
if (strcmp(envname, *env++) == 0)
return *env;
} else {
if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
return *env + i + 1;
}
env++;
}
#endif
return NULL;
}
inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0; /* foo */
}
inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
int i;
for(i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
#if 0
{
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
#endif
return 0;
}
void __init prom_free_prom_memory(void)
{
}
void __init prom_init(void)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = (int) fw_arg0;
prom_argv = (char **) fw_arg1;
prom_envp = (char **) fw_arg2;
mips_machtype = MACH_INGENIC_JZ4760;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x04000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
/* used by early printk */
void prom_putchar(char c)
{
volatile u8 *uart_lsr = (volatile u8 *)(UART1_BASE + OFF_LSR);
volatile u8 *uart_tdr = (volatile u8 *)(UART1_BASE + OFF_TDR);
/* Wait for fifo to shift out some bytes */
while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
*uart_tdr = (u8)c;
}
const char *get_system_type(void)
{
return "JZ4760";
}
EXPORT_SYMBOL(prom_getcmdline);
EXPORT_SYMBOL(get_ethernet_addr);
EXPORT_SYMBOL(str2eaddr);

View File

@@ -0,0 +1,46 @@
/*
* linux/arch/mips/jz4760/reset.c
*
* JZ4760 reset routines.
*
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
* Author: <yliu@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/jzsoc.h>
void jz_restart(char *command)
{
printk("Restarting after 4 ms\n");
REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
REG_WDT_TCNT = 0;
REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */
REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
while (1);
}
void jz_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
}
void jz_power_off(void)
{
jz_halt();
}

View File

@@ -0,0 +1,199 @@
/*
* linux/arch/mips/jz4760/common/setup.c
*
* JZ4760 common setup routines.
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/ioport.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
#ifdef CONFIG_PC_KEYB
#include <asm/keyboard.h>
#endif
jz_clocks_t jz_clocks;
extern char * __init prom_getcmdline(void);
extern void __init jz_board_setup(void);
extern void jz_restart(char *);
extern void jz_halt(void);
extern void jz_power_off(void);
extern void jz_time_init(void);
static void __init sysclocks_setup(void)
{
#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
jz_clocks.cclk = __cpm_get_cclk();
jz_clocks.hclk = __cpm_get_h0clk();
jz_clocks.pclk = __cpm_get_pclk();
jz_clocks.mclk = __cpm_get_mclk();
jz_clocks.h1clk = __cpm_get_h1clk();
jz_clocks.pixclk = __cpm_get_pixclk();
jz_clocks.i2sclk = __cpm_get_i2sclk();
jz_clocks.usbclk = __cpm_get_usbclk();
jz_clocks.mscclk = __cpm_get_mscclk(0);
jz_clocks.extalclk = __cpm_get_extalclk();
jz_clocks.rtcclk = __cpm_get_rtcclk();
#else
#define FPGACLK 8000000
jz_clocks.cclk = FPGACLK;
jz_clocks.hclk = FPGACLK;
jz_clocks.pclk = FPGACLK;
jz_clocks.mclk = FPGACLK;
jz_clocks.h1clk = FPGACLK;
jz_clocks.pixclk = FPGACLK;
jz_clocks.i2sclk = FPGACLK;
jz_clocks.usbclk = FPGACLK;
jz_clocks.mscclk = FPGACLK;
jz_clocks.extalclk = FPGACLK;
jz_clocks.rtcclk = FPGACLK;
#endif
printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
(jz_clocks.cclk + 500000) / 1000000,
(jz_clocks.hclk + 500000) / 1000000,
(jz_clocks.pclk + 500000) / 1000000,
(jz_clocks.mclk + 500000) / 1000000);
}
static void __init soc_cpm_setup(void)
{
/* Start all module clocks
*/
__cpm_start_all();
/* Enable CKO to external memory */
__cpm_enable_cko();
/* CPU enters IDLE mode when executing 'wait' instruction */
__cpm_idle_mode();
/* Setup system clocks */
sysclocks_setup();
}
static void __init soc_harb_setup(void)
{
// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
}
static void __init soc_emc_setup(void)
{
}
static void __init soc_dmac_setup(void)
{
__dmac_enable_module(0);
__dmac_enable_module(1);
}
static void __init jz_soc_setup(void)
{
soc_cpm_setup();
soc_harb_setup();
soc_emc_setup();
soc_dmac_setup();
}
static void __init jz_serial_setup(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port s;
REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
memset(&s, 0, sizeof(s));
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = SERIAL_IO_MEM;
s.regshift = 2;
s.uartclk = jz_clocks.extalclk ;
s.line = 0;
s.membase = (u8 *)UART0_BASE;
s.irq = IRQ_UART0;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS0 setup failed!\n");
}
s.line = 1;
s.membase = (u8 *)UART1_BASE;
s.irq = IRQ_UART1;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS1 setup failed!\n");
}
s.line = 2;
s.membase = (u8 *)UART2_BASE;
s.irq = IRQ_UART2;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS2 setup failed!\n");
}
/*
s.line = 3;
s.membase = (u8 *)UART3_BASE;
s.irq = IRQ_UART3;
if (early_serial_setup(&s) != 0) {
printk(KERN_ERR "Serial ttyS3 setup failed!\n");
}
*/
#endif
}
void __init plat_mem_setup(void)
{
char *argptr;
argptr = prom_getcmdline();
/* IO/MEM resources. Which will be the addtion value in `inX' and
* `outX' macros defined in asm/io.h */
set_io_port_base(0);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x00000000;
iomem_resource.end = 0xffffffff;
_machine_restart = jz_restart;
_machine_halt = jz_halt;
pm_power_off = jz_power_off;
jz_soc_setup();
jz_serial_setup();
jz_board_setup();
}

View File

@@ -0,0 +1,156 @@
/*
* linux/arch/mips/jz4760/time.c
*
* Setting up the clock on the JZ4760 boards.
*
* Copyright (C) 2008 Ingenic Semiconductor Inc.
* Author: <jlwei@ingenic.cn>
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <asm/time.h>
#include <asm/jzsoc.h>
/* This is for machines which generate the exact clock. */
#define JZ_TIMER_IRQ IRQ_TCU0
#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
static struct clocksource clocksource_jz; /* Jz clock source */
static struct clock_event_device jz_clockevent_device; /* Jz clock event */
void (*jz_timer_callback)(void);
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = dev_id;
REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
if (jz_timer_callback)
jz_timer_callback();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction jz_irqaction = {
.handler = jz_timer_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
.name = "jz-timerirq",
};
cycle_t jz_get_cycles(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();
}

View File

@@ -0,0 +1,330 @@
/*
* i2c_jz47xx.c
* I2C adapter for the INGENIC I2C bus access.
*
* Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
* Author: <cwjia@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
#include <asm/addrspace.h>
#include <asm/jzsoc.h>
#include "i2c-jz47xx.h"
/* I2C protocol */
#define I2C_READ 1
#define I2C_WRITE 0
#define TIMEOUT 1000
unsigned 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);

View File

@@ -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

View File

@@ -0,0 +1,413 @@
/*
* linux/drivers/input/keyboard/jz_gpio_keys.c
*
* Keypad driver based on GPIO pins for Jz4750 APUS board.
*
* User applications can access to this device via /dev/input/eventX.
*
* Copyright (c) 2005 - 2009 Ingenic Semiconductor Inc.
*
* Author: Richard <cjfeng@ingenic.cn>
* Regen <lhhuang@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>
#include <asm/jzsoc.h>
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define dprintk(x...) printk(x)
#else
#define dprintk(x...)
#endif
/* Device name */
#ifdef CONFIG_JZ4750_APUS
#define DEV_NAME "apus-keypad"
#else
#ifdef CONFIG_JZ4750D_CETUS
#define DEV_NAME "cetus-keypad"
#else
#define DEV_NAME "jz-keypad"
#endif
#endif
/* Key codes */
#define ANDROID_MENU KEY_MENU
#define ANDROID_CALL KEY_SEND
#define ANDROID_HOME KEY_HOME
#define ANDROID_ENDCALL KEY_END
#define ANDROID_BACK KEY_BACK
/* Timer interval */
#define SCAN_INTERVAL 5
/*
* GPIO Buttons
*/
static struct gpio_keys_button board_buttons[] = {
#if 0
{
.gpio = GPIO_WAKEUP,
.code = KEY_1,
.desc = "Button 0",
.active_low = 1,
},
#endif
{
.gpio = GPIO_CALL,
.code = ANDROID_CALL,
.desc = "Button 1",
.active_low = ACTIVE_LOW_CALL,
},
{
.gpio = GPIO_HOME,
.code = ANDROID_HOME,
.desc = "Button 2",
.active_low = ACTIVE_LOW_HOME,
},
{
.gpio = GPIO_BACK,
.code = ANDROID_BACK,
.desc = "Button 3",
.active_low = ACTIVE_LOW_BACK,
},
{
.gpio = GPIO_MENU,
.code = ANDROID_MENU,
.desc = "Button 4",
.active_low = ACTIVE_LOW_MENU,
},
{
.gpio = GPIO_ENDCALL,
.code = ANDROID_ENDCALL,
.desc = "Button 5",
.active_low = ACTIVE_LOW_ENDCALL,
},
#if 0
{
.gpio = GPIO_SW7,
.code = KEY_7,
.desc = "Button 6",
.active_low = 1,
},
#endif
};
static struct timer_list button_timer;
static int button_no;
static struct gpio_keys_platform_data board_button_data = {
.buttons = board_buttons,
.nbuttons = ARRAY_SIZE(board_buttons),
};
static struct platform_device board_button_device = {
.name = DEV_NAME,
.id = -1,
.num_resources = 0,
.dev = {
.platform_data = &board_button_data,
}
};
static void enable_gpio_irqs(struct gpio_keys_platform_data *pdata)
{
int i;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
if (button->active_low)
__gpio_as_irq_fall_edge(button->gpio);
else
__gpio_as_irq_rise_edge(button->gpio);
}
}
static void button_timer_callback(unsigned long data)
{
int gpio = board_buttons[button_no].gpio;
int code = board_buttons[button_no].code;
int active_low = board_buttons[button_no].active_low;
struct platform_device *pdev = (struct platform_device *)data;
struct input_dev *input = platform_get_drvdata(pdev);
int state;
static int button_pressed = 0;
state = __gpio_get_pin(gpio);
if (active_low) {
if (state == 0) {
/* button pressed */
button_pressed = 1;
input_report_key(input, code, 1);
input_sync(input);
mod_timer(&button_timer, jiffies + SCAN_INTERVAL);
dprintk("gpio %d down, code:%d \n", gpio, code);
} else {
/* button released */
if (button_pressed) {
input_report_key(input, code, 0);
input_sync(input);
button_pressed = 0;
dprintk("gpio %d up, code:%d \n", gpio, code);
}
__gpio_as_irq_fall_edge(gpio);
}
} else {
if (state == 1) {
/* button pressed */
button_pressed = 1;
input_report_key(input, code, 1);
input_sync(input);
mod_timer(&button_timer, jiffies + SCAN_INTERVAL);
dprintk("gpio %d down code:%d \n", gpio, code);
} else {
/* button released */
if (button_pressed) {
input_report_key(input, code, 0);
input_sync(input);
dprintk("gpio %d up code:%d \n", gpio, code);
}
__gpio_as_irq_rise_edge(gpio);
}
}
}
static irqreturn_t jz_gpio_interrupt(int irq, void *dev_id)
{
int i;
struct platform_device *pdev = dev_id;
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
dprintk("--irq of gpio:%d\n", irq - IRQ_GPIO_0);
__gpio_ack_irq(irq - IRQ_GPIO_0); /* clear flag */
if (!timer_pending(&button_timer)) {
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
int gpio = button->gpio;
if (irq == (gpio + IRQ_GPIO_0) ) {
/* start timer */
__gpio_as_input(gpio);
button_no = i;
mod_timer(&button_timer, jiffies + SCAN_INTERVAL);
dprintk("--mod_timer for gpio:%d\n", gpio);
break;
}
}
}
return IRQ_HANDLED;
}
static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input;
int i, error;
int wakeup = 0;
input = input_allocate_device();
if (!input)
return -ENOMEM;
platform_set_drvdata(pdev, input);
input->name = pdev->name;
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
input->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN);
set_bit(ANDROID_MENU, input->keybit);
set_bit(ANDROID_HOME, input->keybit);
set_bit(ANDROID_CALL, input->keybit);
set_bit(ANDROID_BACK, input->keybit);
set_bit(ANDROID_ENDCALL, input->keybit);
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
int irq;
unsigned int type = button->type ?: EV_KEY;
irq = IRQ_GPIO_0 + button->gpio;
if (irq < 0) {
error = irq;
pr_err("%s: Unable to get irq number"
" for GPIO %d, error %d\n", DEV_NAME,
button->gpio, error);
goto fail;
}
error = request_irq(irq, jz_gpio_interrupt,
IRQF_SAMPLE_RANDOM | IRQF_DISABLED,
button->desc ? button->desc : "gpio_keys",
pdev);
if (error) {
pr_err("%s: Unable to claim irq %d; error %d\n",
DEV_NAME, irq, error);
goto fail;
}
if (button->wakeup)
wakeup = 1;
input_set_capability(input, type, button->code);
}
/* Enable all GPIO irqs */
enable_gpio_irqs(pdata);
/* Init timer */
init_timer(&button_timer);
button_timer.data = (unsigned long)&board_button_device;
button_timer.function = button_timer_callback;
error = input_register_device(input);
if (error) {
pr_err("%s: Unable to register input device, "
"error: %d\n", DEV_NAME, error);
goto fail;
}
device_init_wakeup(&pdev->dev, wakeup);
return 0;
fail:
while (--i >= 0) {
free_irq(pdata->buttons[i].gpio + IRQ_GPIO_0 , pdev);
}
platform_set_drvdata(pdev, NULL);
input_free_device(input);
return error;
}
static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input = platform_get_drvdata(pdev);
int i;
device_init_wakeup(&pdev->dev, 0);
for (i = 0; i < pdata->nbuttons; i++) {
int irq = pdata->buttons[i].gpio + IRQ_GPIO_0;
free_irq(irq, pdev);
}
input_unregister_device(input);
return 0;
}
#ifdef CONFIG_PM
static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
{
#if 0
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
if (device_may_wakeup(&pdev->dev)) {
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
if (button->wakeup) {
int irq = button->gpio + IRQ_GPIO_0;
enable_irq_wake(irq);
}
}
}
#endif
return 0;
}
static int gpio_keys_resume(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
#if 0
int i;
if (device_may_wakeup(&pdev->dev)) {
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
if (button->wakeup) {
int irq = button->gpio + IRQ_GPIO_0;
disable_irq_wake(irq);
}
}
}
#endif
/* Enable all GPIO irqs */
enable_gpio_irqs(pdata);
return 0;
}
#else
#define gpio_keys_suspend NULL
#define gpio_keys_resume NULL
#endif
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.suspend = gpio_keys_suspend,
.resume = gpio_keys_resume,
.driver = {
.name = DEV_NAME,
}
};
static int __init gpio_keys_init(void)
{
int ret;
platform_device_register(&board_button_device);
ret = platform_driver_register(&gpio_keys_device_driver);
return ret;
}
static void __exit gpio_keys_exit(void)
{
platform_device_unregister(&board_button_device);
platform_driver_unregister(&gpio_keys_device_driver);
}
module_init(gpio_keys_init);
module_exit(gpio_keys_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Regen Huang <lhhuang@ingenic.cn>");
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");

View File

@@ -0,0 +1,357 @@
/*
* linux/drivers/input/keyboard/jz_keypad.c
*
* JZ Keypad Driver
*
* Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc.
*
* Author: Richard <cjfeng@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>
#include <asm/jzsoc.h>
#define KB_ROWS 3
#define KB_COLS 3
#define SCAN_INTERVAL (10)
static unsigned short col[KB_COLS] = {85,87,91};
static unsigned short row[KB_ROWS] = {60,61,62};
static unsigned short s0[KB_COLS];
static unsigned short s1[KB_COLS]={7,7,7};
static unsigned short precol,prerow;
static const unsigned int jz_kbd_keycode[KB_COLS * KB_ROWS] = {
KEY_1, KEY_4, KEY_7,
KEY_2, KEY_5, 0,
KEY_3, KEY_6, 0,
};
struct jz_kbd {
unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)];
struct input_dev *input;
char phys[32];
spinlock_t lock;
struct timer_list timer;
unsigned int suspended;
unsigned long suspend_jiffies;
};
static struct jz_kbd g_jz_kbd;
static inline void jz_scan_kbd(unsigned short *s)
{
int i;
if (!s)
return;
for (i = 0; i < KB_COLS; i++) {
__gpio_as_input(85); /* row */
__gpio_as_input(87); /* row */
__gpio_as_input(91); /* row */
__gpio_as_input(60); /* col */
__gpio_as_input(61); /* col */
__gpio_as_input(62); /* col */
__gpio_clear_pin(col[i]);
__gpio_as_output(col[i]);
udelay(1000);
s[i]=(__gpio_get_pin(60) << 0) | (__gpio_get_pin(61) << 1) |
(__gpio_get_pin(62) << 2);
}
}
static void jz_kbd_scankeyboard(struct jz_kbd *kbd_data)
{
unsigned int row,col;
unsigned long flags;
unsigned int num_pressed;
if (kbd_data->suspended)
return;
spin_lock_irqsave(&kbd_data->lock, flags);
num_pressed = 0;
jz_scan_kbd(s0);
/* look for key if pressed down on not, col & row */
if (s0[0] == 7 && s0[1] == 7 && s0[2] == 7) {
if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) {
/* up */
input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0);
input_sync(kbd_data->input);
}
precol = prerow = -1;
s1[0] = s1[1] = s1[2] = 7;
spin_unlock_irqrestore(&kbd_data->lock, flags);
return;
}
if (s0[0] == 6 && s0[1] == 7 && s0[2] == 7) {
row = 0;//K7
col = 2;
goto find_row_col;
}
if (s0[0] == 7 && s0[1] == 3 && s0[2] == 7) {
row = 2;//k6
col = 1;
goto find_row_col;
}
if (s0[0] == 7 && s0[1] == 5 && s0[2] == 7) {
row = 1;//k5
col = 1;
goto find_row_col;
}
if (s0[0] == 7 && s0[1] == 6 && s0[2] == 7) {
row = 0;//k4
col = 1;
goto find_row_col;
}
if (s0[0] == 7 && s0[1] == 7 && s0[2] == 3) {
row = 2;//k3
col = 0;
goto find_row_col;
}
if (s0[0] == 7 && s0[1] == 7 && s0[2] == 5) {
row = 1;//k2
col = 0;
goto find_row_col;
}
if (s0[0] == 7 && s0[1] == 7 && s0[2] == 6) {
row = 0;//k1
col = 0;
goto find_row_col;
}
/* 2 or 3 buttons are pressed */
s0[0] = s0[1] = s0[2] = 7;
s1[0] = s1[1] = s1[2] = 7;
prerow = precol = -1;
spin_unlock_irqrestore(&kbd_data->lock, flags);
return;
find_row_col:
if (s1[0] == 7 && s1[1] == 7 && s1[2] == 7) {
/* down */
input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
input_sync(kbd_data->input);
s1[0] = s0[0];
s1[1] = s0[1];
s1[2] = s0[2];
precol = col;
prerow = row;
spin_unlock_irqrestore(&kbd_data->lock, flags);
return;
}
if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) {
/* is the same as the preview key */
if (s0[0] == s1[0] && s0[1] == s1[1] && s0[2] == s1[2]) {
input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
input_sync(kbd_data->input);
s1[0] = s0[0];
s1[1] = s0[1];
s1[2] = s0[2];
precol = col;
prerow = row;
spin_unlock_irqrestore(&kbd_data->lock, flags);
return;
} else {
/* the preview key is up and other key is down */
if (s0[0] != s1[0] || s0[1] != s1[1] || s0[2] != s1[2]) {
input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0);
input_sync(kbd_data->input);
input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
input_sync(kbd_data->input);
s1[0] = s0[0];
s1[1] = s0[1];
s1[2] = s0[2];
precol = col;
prerow = row;
spin_unlock_irqrestore(&kbd_data->lock, flags);
return;
}
}
}
}
static void jz_kbd_timer_callback(unsigned long data)
{
jz_kbd_scankeyboard(&g_jz_kbd);
mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
}
#ifdef CONFIG_PM
static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state)
{
struct jz_kbd *jz_kbd = platform_get_drvdata(dev);
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");

View File

@@ -0,0 +1,246 @@
/*
* JZ Keypad ( 5 x 5 ) Driver
*
* Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc.
*
* Author: Jason <xwang@ingenic.cn> 20090210
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
//#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>
#include <asm/jzsoc.h>
#define KB_ROWS 5
#define KB_COLS 5
#define KB_COUNT 25
#define JZ_KEY_PRESSED 0x01
#define JZ_KEY_RELEASED 0x00
#define SCAN_INTERVAL 10 /* jiffies */
#define ROW_KEYBIT_MASK 0xFFE0
#define SET_GPIOS_AS_INPUT() \
do { \
unsigned short i; \
\
for (i = 0; i < KB_ROWS; i++) { \
__gpio_as_input(jz_row_gpios[i]); \
__gpio_as_input(jz_col_gpios[i]); \
} \
} while (0)
#define GET_ROW_GPIO_PINS() \
({ \
unsigned short _pins = 0, i; \
for (i = 0; \
i < KB_ROWS; \
_pins |= __gpio_get_pin(jz_row_gpios[i]) << i, i++) \
; \
_pins; \
})
#define CHECK_IF_KEY_PRESSED(s) \
({ \
unsigned short i; \
for (i = 0; i < KB_COLS && s[i] == 0x1F ; i++) \
; \
i != KB_ROWS; \
})
#define CLEAN_SCAN_RESULT(s) \
do { \
unsigned short i; \
for (i = 0; i < KB_COLS; s[i++] = 0x1F) \
; \
} while (0)
static const unsigned short jz_col_gpios[KB_ROWS] = {76, 75, 74, 73, 72};
static const unsigned short jz_row_gpios[KB_COLS] = {181, 182, 79, 78, 77};
static const unsigned int jz_kbd_keycode[KB_ROWS * KB_COLS] = {
KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
KEY_LEFTSHIFT, KEY_LEFTCTRL, KEY_LEFTALT, KEY_BACKSPACE, KEY_ENTER
};
static unsigned short jz_kbd_status[KB_ROWS * KB_COLS] = {0};
struct jz_kbd {
unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)];
struct input_dev *input;
char phys[32];
spinlock_t lock;
struct timer_list timer;
unsigned int suspended;
unsigned long suspend_jiffies;
};
static struct jz_kbd g_jz_kbd;
/* An element shows the scan result of a whole row. LSB --> column 0 */
static unsigned short scan_result[KB_ROWS];
/**
* Scan keypad by reading GPIO pins.
*/
static inline void jz_do_scan(unsigned short *s)
{
unsigned short i;
if (!s)
return ;
for (i = 0; i < KB_COLS; i++) {
SET_GPIOS_AS_INPUT();
__gpio_clear_pin(jz_col_gpios[i]);
__gpio_as_output(jz_col_gpios[i]);
udelay(1000);
s[i] = GET_ROW_GPIO_PINS();
}
}
/**
* Call scan function and handle 'GPIO event'(like key down, key up),
* and report it to upper layer of input subsystem ... if necessary
*/
static void jz_kbd_scan(struct jz_kbd *kbd_data)
{
unsigned short row, col;
unsigned long flags;
if (kbd_data->suspended)
return;
spin_lock_irqsave(&kbd_data->lock, flags);
jz_do_scan(scan_result);
/* handle gpio event */
for (row = 0; row < KB_ROWS; row++) {
for (col = 0; col < KB_COLS; col++) {
if ( !(scan_result[row] & 0x01) ) {
/* oh! a key pressed ... may be it is not news ...*/
input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
input_sync(kbd_data->input);
jz_kbd_status[row * KB_ROWS + col] = JZ_KEY_PRESSED;
} else {
/* if the key has been pressed ... release it */
if (jz_kbd_status[row * KB_ROWS + col]) {
input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 0);
input_sync(kbd_data->input);
jz_kbd_status[row * KB_ROWS + col] = JZ_KEY_RELEASED;
}
}
scan_result[row] >>= 1;
}
}
spin_unlock_irqrestore(&kbd_data->lock, flags);
return;
}
static void jz_kbd_timer_callback(unsigned long data)
{
jz_kbd_scan(&g_jz_kbd);
mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
}
static int __init jz_kbd_init(void)
{
struct input_dev *input_dev;
int i, error;
input_dev = input_allocate_device();
if (!input_dev)
return -ENOMEM;
strcpy(g_jz_kbd.phys, "input/kbd0");
spin_lock_init(&g_jz_kbd.lock);
g_jz_kbd.suspend_jiffies = jiffies;
g_jz_kbd.input = input_dev;
input_dev->name = "JZ 5x5 Keypad";
input_dev->phys = g_jz_kbd.phys;
input_dev->id.bustype = BUS_PARPORT;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN);
input_dev->keycode = g_jz_kbd.keycode;
input_dev->keycodesize = sizeof(unsigned int);
input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode);
memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode));
for ( i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++)
set_bit(g_jz_kbd.keycode[i], input_dev->keybit);
init_timer(&g_jz_kbd.timer);
g_jz_kbd.timer.function = jz_kbd_timer_callback;
g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd;
mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
input_set_drvdata(input_dev, &g_jz_kbd);
error = input_register_device(input_dev);
if (error) {
pr_err("gpio-keys: Unable to register input device, "
"error: %d\n", error);
}
printk("input: JZ 5x5 Keypad Registered.\n");
return 0;
}
static void __exit jz_kbd_exit(void)
{
del_timer_sync(&g_jz_kbd.timer);
SET_GPIOS_AS_INPUT();
input_unregister_device(g_jz_kbd.input);
}
module_init(jz_kbd_init);
module_exit(jz_kbd_exit);
MODULE_AUTHOR("Jason <xwang@ingenic.cn>");
MODULE_DESCRIPTION("JZ 5x5 keypad driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,789 @@
/*
* JZ Touch Screen Driver
*
* Copyright (c) 2005 - 2009 Ingenic Semiconductor Inc.
*
* Author: Jason <xwang@ingenic.cn> 20090219
* Regen <lhhuang@ingenic.cn> 20090324 add adkey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <asm/irq.h>
#include <asm/gpio.h>
#include <asm/jzsoc.h>
#define TS_NAME "jz-ts"
#define KEY_SCAN_INTERVAL 5
#define TS_SCAN_INTERVAL 0
/* from qwerty.kl of android */
#define DPAD_CENTER 232
#define DPAD_DOWN 108
#define DPAD_UP 103
#define DPAD_LEFT 105
#define DPAD_RIGHT 106
/* TS event status */
#define PENUP 0x00
#define PENDOWN 0x01
/* Sample times in one sample process */
#define SAMPLE_TIMES 3
/* Min pressure value. If less than it, filt the point.
* Mask it if it is not useful for you
*/
//#define MIN_PRESSURE 0x100
/* Max delta x distance between current point and last point. */
#define MAX_DELTA_X_OF_2_POINTS 200
/* Max delta x distance between current point and last point. */
#define MAX_DELTA_Y_OF_2_POINTS 120
/* Max delta between points in one sample process
* Verify method :
* (diff value / min value) * 100 <= MAX_DELTA_OF_SAMPLING
*/
#define MAX_DELTA_OF_SAMPLING 20
#define DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a)))
#define MIN(a,b) (((a)<(b))?(a):(b))
/*
* TS deriver
*/
struct jz_ts_t {
int pendown_irq; // IRQ of pendown interrupt
int pen_is_down; // 1 = pen is down, 0 = pen is up
int irq_enabled;
struct timer_list acq_timer; // Timer for triggering acquisitions
#ifdef CONFIG_JZ_ADKEY
struct timer_list key_timer; // for adkey
int active_low; // for adkey's interrupt pin
#endif
wait_queue_head_t wait; // read wait queue
spinlock_t lock;
/* Following 4 members use to pass arguments from u-boot to tell us the ts data.
* But in Android we do not use them.
*/
/*
int minx, miny, maxx, maxy;
*/
int first_read;
char phys[32];
struct input_dev *input_dev;
};
/*
* TS Event type
*/
struct ts_event {
u16 status;
u16 x;
u16 y;
u16 pressure;
u16 pad;
};
#ifdef CONFIG_JZ_ADKEY
struct ad_keys_button {
int code; /* input event code */
int val; /* the ad value of the key */
int fuzz; /* the error(+-fuzz) allowed of the ad value of the key */
};
static struct ad_keys_button ad_buttons[] = {
{
.code = DPAD_LEFT,
.val = DPAD_LEFT_LEVEL,
.fuzz = 40,
},
{
.code = DPAD_DOWN,
.val = DPAD_DOWN_LEVEL,
.fuzz = 40,
},
{
.code = DPAD_UP,
.val = DPAD_UP_LEVEL,
.fuzz = 40,
},
{
.code = DPAD_CENTER,
.val = DPAD_CENTER_LEVEL,
.fuzz = 40,
},
{
.code = DPAD_RIGHT,
.val = DPAD_RIGHT_LEVEL,
.fuzz = 40,
},
};
#define KEY_NUM (sizeof(ad_buttons) / sizeof(struct ad_keys_button))
#endif
/************************************************************************/
/* SAR ADC OPS */
/************************************************************************/
typedef struct datasource {
u16 xbuf;
u16 ybuf;
u16 zbuf;
}datasource_t;
static datasource_t data_s;
static unsigned int p;
static DECLARE_WAIT_QUEUE_HEAD (sadc_wait_queue);
static int first_time = 0;
//static unsigned long last_x, last_y, last_p;
static unsigned int old_x, old_y;
extern unsigned int (*codec_read_battery)(void);
#if 0
static void reg_debug(void)
{
printk("\t####CTRL####################################################\n");
printk("\tPEND %s, ", REG_SADC_CTRL & SADC_CTRL_PENDM ? "masked" : "enabled");
printk("PENU %s, ", REG_SADC_CTRL & SADC_CTRL_PENUM ? "masked" : "enabled");
printk("TSRDY %s\n", REG_SADC_CTRL & SADC_CTRL_TSRDYM ? "masked" : "enabled");
printk("\t----STATE---------------------------------------------------\n");
printk("\tIRQ actived: %s, %s, %s\n",
REG_SADC_STATE & SADC_STATE_PEND ? "pen down" : " ",
REG_SADC_STATE & SADC_STATE_PENU ? "pen up " : " ",
REG_SADC_STATE & SADC_STATE_TSRDY ? "sample " : " ");
printk("\t############################################################\n");
}
#endif
/*
* set adc clock to 24MHz/div. A/D works at freq between 500KHz to 8MHz.
*/
static void sadc_init_clock(int div)
{
if (div < 2) div = 2;
if (div > 23) div = 23;
#if defined(CONFIG_SOC_JZ4740)
REG_SADC_CFG &= ~SADC_CFG_CLKDIV_MASK;
REG_SADC_CFG |= (div - 1) << SADC_CFG_CLKDIV_BIT;
#endif
#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_MASK;
REG_SADC_ADCLK |= (div - 1) << SADC_ADCLK_CLKDIV_BIT;
REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_BIT;
REG_SADC_ADCLK |= 39 << SADC_ADCLK_CLKDIV_10_BIT; /* if div ==3,here is 39 */
#endif
}
static inline void sadc_start_sadcin(void)
{
REG_SADC_ENA |= SADC_ENA_SADCINEN;
}
static void sadc_start_pbat(void)
{
if (CFG_PBAT_DIV == 1)
REG_SADC_CFG |= SADC_CFG_PBAT_HIGH; /* full baterry voltage >= 2.5V */
else
REG_SADC_CFG |= SADC_CFG_PBAT_LOW; /* full baterry voltage < 2.5V */
REG_SADC_ENA |= SADC_ENA_PBATEN; /* Enable pbat adc */
}
static inline void ts_enable_pendown_irq(void)
{
REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
}
static inline void ts_enable_penup_irq(void)
{
REG_SADC_CTRL &= ~SADC_CTRL_PENUM;
}
static inline void ts_disable_pendown_irq(void)
{
REG_SADC_CTRL |= SADC_CTRL_PENDM;
}
static inline void ts_disable_penup_irq(void)
{
REG_SADC_CTRL |= SADC_CTRL_PENUM;
}
static inline void sadc_enable_ts(void)
{
REG_SADC_ENA |= SADC_ENA_TSEN;
}
static inline void sadc_disable_ts(void)
{
REG_SADC_ENA &= ~SADC_ENA_TSEN;
}
static inline void sadc_start_ts(void)
{
REG_SADC_SAMETIME = 10; /* about 0.1 ms,you can change it */
REG_SADC_WAITTIME = 2; /* about 0.02 ms,you can change it */
REG_SADC_CFG &= ~(SADC_CFG_TS_DMA | SADC_CFG_XYZ_MASK | SADC_CFG_SNUM_MASK);
REG_SADC_CFG |= (SADC_CFG_EXIN | SADC_CFG_XYZ | SADC_CFG_SNUM_3);
REG_SADC_CTRL |= (SADC_CTRL_TSRDYM | SADC_CTRL_PBATRDYM | SADC_CTRL_PENUM |SADC_CTRL_SRDYM);
ts_enable_pendown_irq();
sadc_enable_ts();
}
/**
* Read the battery voltage
*/
unsigned int jz_read_battery(void)
{
unsigned int v;
unsigned int timeout = 0x3fff;
u16 pbat;
if(!(REG_SADC_STATE & SADC_STATE_PBATRDY) ==1)
sadc_start_pbat();
while(!(REG_SADC_STATE & SADC_STATE_PBATRDY) && --timeout)
;
pbat = REG_SADC_BATDAT;
v = pbat & 0x0fff;
REG_SADC_STATE = SADC_STATE_PBATRDY;
return v;
}
#define TSMAXX 3920
#define TSMAXY 3700
#define TSMINX 150
#define TSMINY 270
#define SCREEN_MAXX 479
#define SCREEN_MAXY 271
static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x )
{
/* Now we don't need u-boot to tell us the ts data. */
/*
if (ts->minx)
{
if (x < ts->minx) x = ts->minx;
if (x > ts->maxx) x = ts->maxx;
return (x - ts->minx) * SCREEN_MAXX / (ts->maxx - ts->minx);
}
else
{
*/
if (x < TSMINX) x = TSMINX;
if (x > TSMAXX) x = TSMAXX;
return (x - TSMINX) * SCREEN_MAXX / (TSMAXX - TSMINX);
/*
}
*/
}
static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y)
{
/* Now we don't need u-boot to tell us the ts data. */
/*
if (ts->miny)
{
if (y < ts->miny) y = ts->miny;
if (y > ts->maxy) y = ts->maxy;
return (ts->maxy - y) * SCREEN_MAXY / (ts->maxy - ts->miny);
}
else
{
*/
if (y < TSMINY) y = TSMINY;
if (y > TSMAXY) y = TSMAXY;
return (TSMAXY - y) * SCREEN_MAXY / (TSMAXY - TSMINY);
/*
}
*/
}
static inline void ts_data_ready(void)
{
REG_SADC_CTRL |= SADC_CTRL_TSRDYM;
}
static int adc_read(struct jz_ts_t *ts)
{
struct datasource *ds = &data_s;
u32 xybuf,z;
while (!(REG_SADC_STATE & SADC_STATE_TSRDY)) {
REG_SADC_CTRL &= ~SADC_CTRL_TSRDYM;
}
xybuf = REG_SADC_TSDAT;
ds->xbuf = (xybuf>>16) & 0x0fff;
ds->ybuf = (xybuf)& 0x0fff;
z = REG_SADC_TSDAT;
ds->zbuf = z& 0x0fff;
REG_SADC_STATE &= ~SADC_STATE_TSRDY;
return 0;
}
/*
* Acquire raw pen coodinate data and compute touch screen
* pressure resistance. Hold spinlock when calling.
*/
int adc_acquire_event(struct jz_ts_t *ts, struct ts_event *event)
{
unsigned int x_raw[SAMPLE_TIMES], y_raw[SAMPLE_TIMES], p_raw[SAMPLE_TIMES];
int i;
unsigned int avl_x, avl_y, avl_p, diff_x, diff_y;
struct datasource *ds = &data_s;
avl_x = avl_y = avl_p = 0;
for (i = 0; i < SAMPLE_TIMES; i++) {
if (adc_read(ts)) {
goto _INVALID_POINT;
}
x_raw[i] = ds->ybuf;
y_raw[i] = ds->xbuf;
p_raw[i] = ds->zbuf;
#ifdef MIN_PRESSURE
if (p_raw[i] < MIN_PRESSURE) {
goto _INVALID_POINT;
}
#endif
avl_x += x_raw[i];
avl_y += y_raw[i];
avl_p += p_raw[i];
#if 0
printk("x_raw = %u , y_raw = %u , z_raw = %u\n",x_raw[i],y_raw[i],p_raw[i]);
#endif
}
avl_x /= SAMPLE_TIMES;
avl_y /= SAMPLE_TIMES;
avl_p /= SAMPLE_TIMES;
/* Verify delta data. */
for (i = 1; i < SAMPLE_TIMES; i++)
{
if ( ((DIFF(x_raw[i],x_raw[i-1]) / MIN(x_raw[i],x_raw[i-1])) * 100) > MAX_DELTA_OF_SAMPLING )
goto _INVALID_POINT;
if ( ((DIFF(y_raw[i],y_raw[i-1]) / MIN(y_raw[i],y_raw[i-1])) * 100) > MAX_DELTA_OF_SAMPLING )
goto _INVALID_POINT;
if ( ((DIFF(p_raw[i],p_raw[i-1]) / MIN(p_raw[i],p_raw[i-1])) * 100) > MAX_DELTA_OF_SAMPLING )
goto _INVALID_POINT;
}
/* Compare with last point. */
if (ts->first_read) {
ts->first_read = 0;
old_x = avl_x;
old_y = avl_y;
}
diff_x = DIFF(old_x, avl_x);
diff_y = DIFF(old_y, avl_y);
if (diff_x >= MAX_DELTA_X_OF_2_POINTS || diff_y >= MAX_DELTA_Y_OF_2_POINTS)
goto _INVALID_POINT;
old_x = avl_x;
old_y = avl_y;
/* Android need it ... transform the raw value to screen coordinate. */
event->x = transform_to_screen_x(ts, avl_x);
event->y = transform_to_screen_y(ts, avl_y);
event->pressure = (u16)avl_p;
event->status = PENDOWN;
return 1;
_INVALID_POINT:
return 0;
}
/*
* Interrupt handler
*/
void ts_irq_callback(void)
{
u32 state;
state = REG_SADC_STATE;
if (!(REG_SADC_CTRL&SADC_CTRL_PENDM)&&(REG_SADC_STATE & SADC_STATE_PEND)) {
REG_SADC_STATE = SADC_STATE_PEND;
REG_SADC_STATE = SADC_STATE_PENU;
REG_SADC_CTRL |= SADC_CTRL_PENDM;
REG_SADC_CTRL &= ~SADC_CTRL_PENUM;
p = 1;
}
if (!(REG_SADC_CTRL&SADC_CTRL_PENUM)&&(REG_SADC_STATE & SADC_STATE_PENU)) {
REG_SADC_STATE = SADC_STATE_PENU;
REG_SADC_CTRL |= SADC_CTRL_PENUM;
REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
p = 0;
}
first_time = 1; // first time to acquire sample
}
static inline int PenIsDown(void)
{
return p;
}
#ifdef CONFIG_JZ_ADKEY
/**
* Read the battery voltage
*/
static unsigned int read_sadcin(void)
{
unsigned int v;
unsigned int timeout = 0x3ff;
u16 val;
if(!(REG_SADC_STATE & SADC_STATE_SRDY))
sadc_start_sadcin();
while(!(REG_SADC_STATE & SADC_STATE_SRDY) && --timeout)
;
val = REG_SADC_SADDAT;
v = val & 0x0fff;
REG_SADC_STATE = SADC_STATE_SRDY;
return v;
}
static unsigned int key_scan(int ad_val)
{
int i;
for(i = 0; i<KEY_NUM; i++) {
if((ad_buttons[i].val + ad_buttons[i].fuzz >= ad_val) &&
(ad_val >=ad_buttons[i].val - ad_buttons[i].fuzz)) {
return ad_buttons[i].code;
}
}
return -1;
}
static void key_timer_callback(unsigned long data)
{
struct jz_ts_t *ts = (struct jz_ts_t *)data;
int state;
int active_low = ts->active_low;
int ad_val, code;
static int old_code;
spin_lock(&ts->lock);
state = __gpio_get_pin(GPIO_ADKEY_INT);
ad_val = read_sadcin();
if (active_low) {
if (state == 0) {
/* press down */
code = key_scan(ad_val);
old_code = code;
input_report_key(ts->input_dev, code, 1);
input_sync(ts->input_dev);
mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL);
} else {
/* up */
input_report_key(ts->input_dev, old_code, 0);
input_sync(ts->input_dev);
udelay(1000);
__gpio_as_irq_fall_edge(GPIO_ADKEY_INT);
}
} else {
if (state == 1) {
/* press down */
code = key_scan(ad_val);
old_code = code;
input_report_key(ts->input_dev, code, 1);
input_sync(ts->input_dev);
mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL);
} else {
/* up */
input_report_key(ts->input_dev, old_code, 0);
input_sync(ts->input_dev);
udelay(1000);
__gpio_as_irq_rise_edge(GPIO_ADKEY_INT);
}
}
spin_unlock(&ts->lock);
}
static irqreturn_t key_interrupt(int irq, void * dev_id)
{
struct jz_ts_t *ts = dev_id;
spin_lock(&ts->lock);
__gpio_ack_irq(GPIO_ADKEY_INT);
__gpio_as_input(GPIO_ADKEY_INT);
sadc_start_sadcin();
mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL);
spin_unlock(&ts->lock);
return IRQ_HANDLED;
}
#endif
/************************************************************************/
/* Touch Screen module */
/************************************************************************/
static int pen_is_down = 0;
static irqreturn_t pendown_interrupt(int irq, void * dev_id)
{
struct jz_ts_t *ts = dev_id;
spin_lock_irq(&ts->lock);
if (ts->irq_enabled)
ts->irq_enabled = 0;
else
ts->irq_enabled = 1;
if (pen_is_down)
pen_is_down = 0;
else
pen_is_down = 1;
/* callback routine to clear irq status */
ts_irq_callback();
if ( (pen_is_down == 0)){
del_timer(&ts->acq_timer);
ts->first_read = 0;
input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
/* Android need it ... */
input_report_key(ts->input_dev, BTN_TOUCH, 0);
input_sync(ts->input_dev);
} else { // pen_is_down == 1
ts->acq_timer.expires = jiffies + TS_SCAN_INTERVAL;
del_timer(&ts->acq_timer);
ts->first_read = 1;
add_timer(&ts->acq_timer);
}
spin_unlock_irq(&ts->lock);
return IRQ_HANDLED;
}
/*
* Raw X,Y,pressure acquisition timer function. It gets scheduled
* only while pen is down. Its duration between calls is the polling
* rate.
*/
static void
jz_acq_timer(unsigned long data)
{
struct jz_ts_t *ts = (struct jz_ts_t *)data;
struct ts_event event;
int pen_was_down = ts->pen_is_down;
spin_lock_irq(&ts->lock);
if (PenIsDown()) {
ts->pen_is_down = 1;
if (adc_acquire_event(ts, &event)) {// check event is valid or not?
input_report_abs(ts->input_dev, ABS_X, event.x);
input_report_abs(ts->input_dev, ABS_Y, event.y);
input_report_abs(ts->input_dev, ABS_PRESSURE, event.pressure);
/* Android need it ... */
input_report_key(ts->input_dev, BTN_TOUCH, 1);
input_sync(ts->input_dev);
}
// schedule next acquire
ts->acq_timer.expires = jiffies + TS_SCAN_INTERVAL;
del_timer(&ts->acq_timer);
add_timer(&ts->acq_timer);
} else {
if (!ts->irq_enabled) {
ts->irq_enabled = 1;
}
ts->pen_is_down = 0;
if (pen_was_down) {
input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
/* Android need it ... */
input_report_key(ts->input_dev, BTN_TOUCH, 0);
input_sync(ts->input_dev);
}
}
spin_unlock_irq(&ts->lock);
}
static struct jz_ts_t *jz_ts;
static int __init jz_ts_init(void)
{
struct input_dev *input_dev;
struct jz_ts_t *ts;
int error;
ts = jz_ts = kzalloc(sizeof(struct jz_ts_t), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev)
return -ENOMEM;
input_dev->name = "qwerty"; /* Set to 'qwerty' to load /system/usr/keychars/qwerty.kcm.bin by Android */
input_dev->phys = ts->phys;
/*
old:
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
*/
/* For Android */
set_bit(EV_ABS, input_dev->evbit);
set_bit(ABS_X, input_dev->absbit);
set_bit(ABS_Y, input_dev->absbit);
set_bit(ABS_PRESSURE, input_dev->absbit);
set_bit(EV_KEY, input_dev->evbit);
set_bit(BTN_TOUCH, input_dev->keybit);
#ifdef CONFIG_JZ_ADKEY
set_bit(DPAD_CENTER, input_dev->keybit);
set_bit(DPAD_DOWN, input_dev->keybit);
set_bit(DPAD_UP, input_dev->keybit);
set_bit(DPAD_LEFT, input_dev->keybit);
set_bit(DPAD_RIGHT, input_dev->keybit);
#endif
input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAXX, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAXY, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
input_set_drvdata(input_dev, ts);
error = input_register_device(input_dev);
strcpy(ts->phys, "input/ts0");
spin_lock_init(&ts->lock);
ts->input_dev = input_dev;
// Init ts acquisition timer function
init_timer(&ts->acq_timer);
ts->acq_timer.function = jz_acq_timer;
ts->acq_timer.data = (unsigned long)ts;
ts->irq_enabled = 1;
if (error) {
printk("Input device register failed !\n");
goto err_free_dev;
}
sadc_init_clock(6);
ts_disable_pendown_irq();
ts_disable_penup_irq();
error = request_irq(IRQ_SADC, pendown_interrupt, IRQF_DISABLED, TS_NAME, ts);
if (error) {
pr_err("unable to get PenDown IRQ %d", IRQ_SADC);
goto err_free_irq;
}
#ifdef CONFIG_JZ_ADKEY
// Init key acquisition timer function
init_timer(&ts->key_timer);
ts->key_timer.function = key_timer_callback;
ts->key_timer.data = (unsigned long)ts;
ts->active_low = ACTIVE_LOW_ADKEY;
error = request_irq(IRQ_GPIO_0 + GPIO_ADKEY_INT, key_interrupt, IRQF_DISABLED, TS_NAME, ts);
if (error) {
pr_err("unable to get AD KEY IRQ %d", IRQ_GPIO_0 + GPIO_ADKEY_INT);
goto err_free_irq;
}
__gpio_disable_pull(GPIO_ADKEY_INT);
if(ts->active_low)
__gpio_as_irq_fall_edge(GPIO_ADKEY_INT);
else
__gpio_as_irq_rise_edge(GPIO_ADKEY_INT);
#endif
sadc_start_ts();
printk("input: JZ Touch Screen registered.\n");
return 0;
err_free_irq:
free_irq(IRQ_SADC, ts);
#ifdef CONFIG_JZ_ADKEY
free_irq(IRQ_GPIO_0 + GPIO_ADKEY_INT, ts);
#endif
err_free_dev:
input_free_device(ts->input_dev);
kfree(ts);
return 0;
}
static void __exit jz_ts_exit(void)
{
free_irq(IRQ_SADC, jz_ts);
input_unregister_device(jz_ts->input_dev);
ts_disable_pendown_irq();
ts_disable_penup_irq();
sadc_disable_ts();
}
module_init(jz_ts_init);
module_exit(jz_ts_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("JZ TouchScreen Driver");
MODULE_AUTHOR("Jason <xwang@ingenic.com>");

View File

@@ -0,0 +1,748 @@
/*
* linux/drivers/misc/tcsm.c
*
* Virtual device driver with tricky appoach to manage TCSM
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/wakelock.h>
#include <linux/platform_device.h>
#include <linux/major.h>
#include <linux/version.h>
#include <asm/cacheflush.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/thread_info.h>
#include <asm/uaccess.h>
#include <asm/jzsoc.h>
#include "jz_cim.h"
#include "jz_sensor.h"
MODULE_AUTHOR("Lemon Liu<zyliu@ingenic.cn>");
MODULE_DESCRIPTION("Ingenic Camera driver");
MODULE_LICENSE("GPL");
//#define CIM_DEBUG
#undef CIM_DEBUG
#ifdef CIM_DEBUG
#define dprintk(x...) printk(x)
#else
#define dprintk(x...)
#endif
#define CIM_NAME "cim"
/*
* CIM DMA descriptor
*/
struct cim_desc {
u32 nextdesc; /* Physical address of next desc */
u32 framebuf; /* Physical address of frame buffer */
u32 frameid; /* Frame ID */
u32 dmacmd; /* DMA command */
};
/*
* CIM device structure
*/
struct cim_device {
cim_config_t cim_cfg;
preview_param_t view_par;
picture_param_t pic_par;
unsigned char *mem_base;
unsigned char *frm_buf; /*current trans buffer pointer*/
unsigned char *jpeg_buf; /* buf for jpeg data */
unsigned int mem_size;
wait_queue_head_t wait_queue;
};
static struct cim_device jz_cim_info = {
#ifdef CONFIG_OV3640
.cim_cfg = {
.cfg = CIM_CFG_PACK_4 | CIM_CFG_DSM_GCM | CIM_CFG_VSP | CIM_CFG_PCP
| CIM_CFG_BYPASS | CIM_CFG_DMA_BURST_INCR8 | CIM_CTRL_FAST_MODE,
.ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_4,
.mclk = 24000000,
},
#elif defined(CONFIG_OV2640)
.cim_cfg = {
.cfg = CIM_CFG_PACK_4 | CIM_CFG_DSM_GCM | CIM_CFG_VSP | CIM_CFG_BYPASS,
.ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_4,
.mclk = 24000000,
},
#elif defined(CONFIG_OV9650)
.cim_cfg = {
.cfg = CIM_CFG_PACK_4 | CIM_CFG_DSM_GCM | CIM_CFG_VSP | CIM_CFG_BYPASS,
.ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_4,
.mclk = 24000000,
},
#else /* CONFIG-SENSOR*/
#error "Define Sensor first..."
#endif
.view_par = {320, 240, 16, "yuv422"},
.pic_par = {640, 480, 16, "yuv422",},
};
static int cim_inited = 0;
static int jpeg_reading_flag;
static int cim_tran_buf_id; /*cim dma current transfer buffer ID*/
static int data_ready_buf_id; /*data ready for yuv convert buffer ID*/
static struct cim_desc cim_frame_desc[CIM_BUF_NUM] __attribute__ ((aligned (16)));
static struct cim_desc cim_jpeg_desc __attribute__ ((aligned (16)));
static struct cim_desc cim_test_jpeg_desc __attribute__ ((aligned (16)));
static struct cim_device *jz_cim = &jz_cim_info;
/*==========================================================================
* CIM Module operations
*========================================================================*/
/*
* Init CIM module
*/
static void cim_print_regs(void)
{
printk("REG_CIM_CFG \t= \t0x%08x\n", REG_CIM_CFG);
printk("REG_CIM_CTRL \t= \t0x%08x\n", REG_CIM_CTRL);
printk("REG_CIM_STATE \t= \t0x%08x\n", REG_CIM_STATE);
printk("REG_CIM_IID \t= \t0x%08x\n", REG_CIM_IID);
printk("REG_CIM_DA \t= \t0x%08x\n", REG_CIM_DA);
printk("REG_CIM_FA \t= \t0x%08x\n", REG_CIM_FA);
printk("REG_CIM_FID \t= \t0x%08x\n", REG_CIM_FID);
printk("REG_CIM_CMD \t= \t0x%08x\n", REG_CIM_CMD);
printk("REG_CIM_SIZE \t= \t0x%08x\n", REG_CIM_SIZE);
printk("REG_CIM_OFFSET \t= \t0x%08x\n", REG_CIM_OFFSET);
}
static void cim_config(cim_config_t *c)
{
REG_CIM_CFG = c->cfg;
REG_CIM_CTRL = c->ctrl;
REG_CIM_SIZE = c->size;
REG_CIM_OFFSET = c->offs;
#ifndef CIM_EXTCLK
/* Set the master clock output, If use pll clock, enable it */
__cim_set_master_clk(__cpm_get_hclk(), c->mclk);
#endif
/* Enable sof, eof and stop interrupts*/
__cim_enable_eof_intr();
// __cim_enable_stop_intr();
#if defined(CONFIG_SOC_JZ4750)
__cim_enable_rxfifo_overflow_intr();
#endif
}
/*
* CIM start/stop operations
*/
#if 0
static int cim_start_dma(void)
{
if (start_inited == 0) {
__cim_disable();
__cim_set_da(virt_to_phys(jz_cim->frame_desc));
__cim_clear_state(); // clear state register
__cim_reset_rxfifo(); // resetting rxfifo
__cim_unreset_rxfifo();
start_inited = 1;
__cim_enable_dma(); // enable dma
__cim_enable();
}
interruptible_sleep_on(&jz_cim->wait_queue);
frm_buf = (unsigned char *)cim_frame_desc[data_ready_buf_id].framebuf;
return 0;
}
#endif
inline static int get_ready_buf_id(void)
{
interruptible_sleep_on(&jz_cim->wait_queue);
return data_ready_buf_id;
}
inline void cim_start(void)
{
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
cim_tran_buf_id = 0;
data_ready_buf_id = 0;
__cim_disable();
__cim_set_da(virt_to_phys(&cim_frame_desc[cim_tran_buf_id]));
__cim_clear_state(); // clear state register
__cim_reset_rxfifo(); // resetting rxfifo
__cim_unreset_rxfifo();
__cim_enable_dma(); // enable dma
__cim_enable();
}
inline static void cim_stop(void)
{
__cim_disable();
__cim_disable_dma();
__cim_clear_state();
}
static int cim_device_init(void)
{
cim_config(&jz_cim->cim_cfg);
__sensor_gpio_init();
return 0;
}
static int cim_snapshot(int mode)
{
int i;
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
jpeg_reading_flag = 1;
for(i = 0; i < INVALID_PIC_BUF; i++) {
__cim_disable();
__cim_set_da(virt_to_phys((&cim_test_jpeg_desc)));
__cim_clear_state(); // clear state register
__cim_reset_rxfifo(); // resetting rxfifo
__cim_unreset_rxfifo();
__cim_enable_dma(); // enable dma
__cim_enable();
interruptible_sleep_on(&jz_cim->wait_queue);
}
__cim_disable();
__cim_set_da(virt_to_phys(&cim_jpeg_desc));
__cim_clear_state(); // clear state register
__cim_reset_rxfifo(); // resetting rxfifo
__cim_unreset_rxfifo();
__cim_enable_dma(); // enable dma
__cim_enable();
interruptible_sleep_on(&jz_cim->wait_queue);
jpeg_reading_flag = 0;
return 0;
}
/*==========================================================================
* Framebuffer allocation and destroy
*========================================================================*/
static struct cim_desc *init_cim_desc_list(void * base)
{
int i;
unsigned char *p_buf;
struct cim_desc *p_desc;
struct cim_desc *desc_list_head __attribute__ ((aligned (16)));
struct cim_desc *desc_list_tail __attribute__ ((aligned (16)));
int frmsize = (((jz_cim->view_par.width * jz_cim->view_par.height
* jz_cim->view_par.bpp + 7) >> 3) + 3) >> 2; /* word aligned */
desc_list_head = desc_list_tail = NULL;
for (i = 0; i < CIM_BUF_NUM; i++) {
p_desc = &cim_frame_desc[i];
p_buf = (void*)((((unsigned int)base + (MAX_PRE_SIZE * i)) >> 3) << 3);
if (desc_list_head == NULL) {
dprintk("Page_list_head\n");
desc_list_head = p_desc;
} else
desc_list_tail->nextdesc = virt_to_phys(p_desc);
jz_cim->view_par.framebuf[i] = virt_to_phys(p_buf);
desc_list_tail = p_desc;
desc_list_tail->framebuf = virt_to_phys(p_buf);
dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf);
dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail));
desc_list_tail->frameid = i;
desc_list_tail->dmacmd = frmsize;
#if defined(CONFIG_SOC_JZ4750)
desc_list_tail->dmacmd |= CIM_CMD_EOFINT;
#else
desc_list_tail->dmacmd |= (CIM_CMD_EOFINT | CIM_CMD_OFRCV);
#endif
dprintk("framedesc\t= 0x%08x\n",(unsigned int)virt_to_phys(desc_list_tail));
dprintk("framebuf \t= 0x%08x\n", (unsigned int)desc_list_tail->framebuf);
dprintk("frameid \t= 0x%08x\n", (unsigned int)desc_list_tail->frameid);
dprintk("dmacmd \t= 0x%08x\n", (unsigned int)desc_list_tail->dmacmd);
dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
}
desc_list_tail->nextdesc = virt_to_phys(desc_list_head);
for (i = 0; i < CIM_BUF_NUM; i++)
dma_cache_wback((unsigned long)(&cim_frame_desc[i]), sizeof(struct cim_desc));
/* prepare the jpeg descriptor */
p_buf = (void*)((((unsigned int)base + (MAX_PRE_SIZE * CIM_BUF_NUM)) >> 3) << 3);
cim_test_jpeg_desc.framebuf = (unsigned int)virt_to_phys(p_buf);
cim_test_jpeg_desc.nextdesc = (unsigned int)virt_to_phys(NULL);
cim_test_jpeg_desc.frameid = 0xf0;
cim_test_jpeg_desc.dmacmd = (4 >> 2) | CIM_CMD_EOFINT | CIM_CMD_STOP;
dma_cache_wback_inv((unsigned long)&cim_test_jpeg_desc, sizeof(struct cim_desc));
jz_cim->pic_par.framebuf[0] = virt_to_phys(p_buf);
cim_jpeg_desc.framebuf = (unsigned int)virt_to_phys(p_buf);
cim_jpeg_desc.nextdesc = (unsigned int)virt_to_phys(NULL);
cim_jpeg_desc.frameid = 0xff;
frmsize = (((jz_cim->pic_par.width * jz_cim->pic_par.height
* 16) >> 3) + 3) >> 2; /* word aligned */
if (strcmp(jz_cim->pic_par.format, "jpeg") == 0) {
if (frmsize > (MAX_PICTURE_SIZE >> 2))
cim_jpeg_desc.dmacmd = (MAX_PICTURE_SIZE >> 2);
else
cim_jpeg_desc.dmacmd = frmsize;
}
else/* if ((strcmp(jz_cim->pic_par.format, "yuv422") == 0) ||
(strcmp(jz_cim->pic_par.format, "rgb565") == 0)) */
cim_jpeg_desc.dmacmd = frmsize;
cim_jpeg_desc.frameid = 0xff;
cim_jpeg_desc.dmacmd |= (CIM_CMD_EOFINT | CIM_CMD_STOP);
dma_cache_wback_inv((unsigned long)&cim_jpeg_desc, sizeof(struct cim_desc));
return 0;
}
static int cim_fb_alloc(void)
{
#ifndef USE_DEFAULT_MEM
int page_order;
#endif
/* Alloc max preview frame for chang preview size */
/* Total memsize = preview size + picture size */
jz_cim->mem_size = MAX_PRE_SIZE * CIM_BUF_NUM + MAX_PICTURE_SIZE;
#ifndef USE_DEFAULT_MEM
/* If no default memory, Alloc memory here */
page_order = get_order(jz_cim->mem_size);
jz_cim->mem_base = (unsigned char *)__get_free_pages(GFP_KERNEL, page_order);
if (jz_cim->mem_base == NULL)
return -ENOMEM;
#endif
/* Descriptor list for cim DMA */
init_cim_desc_list(jz_cim->mem_base);
return 0;
}
static void cim_fb_destroy(void)
{
#if 0
int pages;
struct cim_desc *jz_frame_desc, *p_desc;
__cim_disable_dma();
__cim_disable();
dprintk("jz_cim->frame_desc = %x\n", (u32)jz_cim->frame_desc);
if (jz_cim->frame_desc == NULL) {
printk("Original memory is NULL\n");
return;
}
jz_frame_desc = jz_cim->frame_desc;
// dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4);
p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
pages = jz_frame_desc->pagenum;
dprintk("page_order = %d\n", pages);
free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages);
kfree(jz_frame_desc);
jz_frame_desc = p_desc;
jz_cim->frame_desc = NULL;
start_init = 1;
#endif
}
/*==========================================================================
* Interrupt handler
*========================================================================*/
static irqreturn_t cim_irq_handler(int irq, void *dev_id)
{
u32 state = REG_CIM_STATE;
/* dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE);
dprintk("IRQ:REG_CIM_CTRL = %x\n", REG_CIM_CTRL);
dprintk("REG_CIM_IID \t= \t0x%08x\n", REG_CIM_IID);
dprintk("REG_CIM_FID \t= \t0x%08x\n", REG_CIM_FID);
*/
if (state & CIM_STATE_DMA_EOF) {
if (jpeg_reading_flag != 1) {
data_ready_buf_id = REG_CIM_IID;
cim_tran_buf_id = REG_CIM_FID;
wake_up_interruptible(&jz_cim->wait_queue);
// printk("preview sleep \n");
REG_CIM_STATE &= ~CIM_STATE_DMA_EOF;
return IRQ_HANDLED;
}
else {
cim_stop();
printk("wake_up_interruptible\n");
wake_up_interruptible(&jz_cim->wait_queue);
REG_CIM_STATE = 0;
}
}
#if defined(CONFIG_SOC_JZ4750)
if (state & CIM_STATE_RXF_OF) {
printk("OverFlow interrupt!\n");
__cim_disable();
REG_CIM_STATE = 0;
__cim_reset_rxfifo(); // resetting rxfifo
__cim_unreset_rxfifo();
__cim_enable_dma(); // enable dma
__cim_enable();
return IRQ_HANDLED;
}
#endif
/* clear status flags*/
REG_CIM_STATE = 0;
return IRQ_HANDLED;
}
/*==========================================================================
* File operations
*========================================================================*/
static int cim_open(struct inode *inode, struct file *filp);
static int cim_release(struct inode *inode, struct file *filp);
static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l);
static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l);
static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int cim_mmap(struct file *file, struct vm_area_struct *vma);
static struct file_operations cim_fops =
{
open: cim_open,
release: cim_release,
read: cim_read,
write: cim_write,
ioctl: cim_ioctl,
mmap: cim_mmap,
};
static int cim_open(struct inode *inode, struct file *filp)
{
if (cim_inited == 0) {
cim_device_init();
}
/* allocate frame buffers */
cim_inited = 1;
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
try_module_get(THIS_MODULE);
return 0;
}
static int cim_release(struct inode *inode, struct file *filp)
{
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
cim_fb_destroy();
cim_stop();
module_put(THIS_MODULE);
return 0;
}
static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l)
{
unsigned long off = *l;
if ((size + off) > jz_cim->mem_size)
size = jz_cim->mem_size;
memcpy(buf, jz_cim->mem_base + off, size);
return size;
}
static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l)
{
printk("cim error: write is not implemented\n");
return -1;
}
/**************************
* IOCTL Handlers *
**************************/
/*
* If use default mem, app need trans a mem_base to cim though "IOCTL_SET_MEM".(only once)
* Else driver will alloc memory by itself. See cim_fb_alloc() for detail.
*
* Then "IOCTL_SET_CIM_CONFIG" and "IOCTL_SET_PREVIEW_PARAM" will be call to set preview parametes.
* Now, call IOCTL_START_CIM to start data tranfer.
* When Take a picture,
*
*/
static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
switch (cmd) {
case IOCTL_SET_I2C_ADDR:
if (copy_from_user(&i2c_addr, (void *)arg, 4))
return -EFAULT;
break;
case IOCTL_SET_I2C_CLK:
if (copy_from_user(&i2c_clk, (void *)arg, 4))
return -EFAULT;
break;
case IOCTL_WRITE_I2C_REG:
{
unsigned char regval[2];
if (copy_from_user(regval, (void *)arg, 2))
return -EFAULT;
sensor_write_reg(regval[0], regval[1]);
break;
}
case IOCTL_READ_I2C_REG:
{
unsigned char reg, val;
if (copy_from_user(&reg, (void *)arg, 1))
return -EFAULT;
val = sensor_read_reg(reg);
if (copy_to_user((void *)(arg + 1), &val, 1))
return -EFAULT;
break;
}
case IOCTL_WRITE_I2C_REG16:
{
unsigned short regval[2];
if (copy_from_user(regval, (void *)arg, 4))
return -EFAULT;
sensor_write_reg16(regval[0], (unsigned char)regval[1]);
break;
}
case IOCTL_READ_I2C_REG16:
{
unsigned short reg, val;
if (copy_from_user(&reg, (void *)arg, 2))
return -EFAULT;
val = sensor_read_reg16(reg);
if (copy_to_user((void *)(arg + 1), &val, 2))
return -EFAULT;
break;
}
#ifdef USE_DEFAULT_MEM
case IOCTL_SET_MEM:
jz_cim->mem_base = (unsigned char *)arg;
cim_fb_alloc();
break;
#endif
case IOCTL_START_CIM:
cim_start();
break;
case IOCTL_STOP_CIM:
cim_stop();
return 0;
case IOCTL_GET_CIM_CONFIG:
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
return copy_to_user((void *)argp, (void *)&jz_cim->cim_cfg,
sizeof(cim_config_t)) ? -EFAULT : 0;
break;
case IOCTL_SET_CIM_CONFIG:
if (copy_from_user((void *)&jz_cim->cim_cfg, (void *)arg,
sizeof(cim_config_t)))
return -EFAULT;
cim_config(&jz_cim->cim_cfg);
break;
case IOCTL_GET_PREVIEW_PARAM:
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
return copy_to_user(argp, &jz_cim->view_par, sizeof(preview_param_t)) ? -EFAULT : 0;
break;
case IOCTL_SET_PREVIEW_PARAM:
{
int i, framesize, wpf; /* words per frame */
preview_param_t p;
if (copy_from_user((void *)&p, (void *)arg, sizeof(preview_param_t)))
return -EFAULT;
framesize = (p.width * p.height * p.bpp + 7) >> 3;
if (framesize > MAX_PRE_SIZE){
printk("ERROR! Preview size is too large!\n");
return -EINVAL;
}
jz_cim->view_par.width = p.width;
jz_cim->view_par.height = p.height;
jz_cim->view_par.bpp = p.bpp;
wpf = (framesize +3) >> 2 ;
for (i = 0; i < CIM_BUF_NUM; i++) {
cim_frame_desc[i].dmacmd &= ~CIM_CMD_LEN_MASK;
cim_frame_desc[i].dmacmd |= wpf;
dma_cache_wback((unsigned long)(&cim_frame_desc[i]), sizeof(struct cim_desc));
}
break;
}
case IOCTL_GET_PICTURE_PARAM:
return copy_to_user(argp, &jz_cim->pic_par, sizeof(picture_param_t)) ? -EFAULT : 0;
break;
case IOCTL_SET_PICTURE_PARAM:
{
int framesize, wpf; /* words per frame */
picture_param_t p;
if (copy_from_user((void *)&p, (void *)arg, sizeof(picture_param_t)))
return -EFAULT;
framesize = (p.width * p.height * 16 + 7) >> 3;
jz_cim->pic_par.width = p.width;
jz_cim->pic_par.height = p.height;
wpf = (framesize + 3) >> 2 ;
cim_jpeg_desc.dmacmd &= ~CIM_CMD_LEN_MASK;
cim_jpeg_desc.dmacmd |= wpf;
dma_cache_wback((unsigned long)(&cim_jpeg_desc), sizeof(struct cim_desc));
break;
}
case IOCTL_PRINT_REGS:
cim_print_regs();
break;
case IOCTL_TAKE_PICTURE:
cim_snapshot(0);
break;
case IOCTL_GET_CURRENT_BUF_ID:
{
int id;
id = get_ready_buf_id();
return copy_to_user(argp, &id, 4) ? -EFAULT : 0;
}
break;
default:
printk("Not supported command: 0x%x\n", cmd);
return -EINVAL;
break;
}
return 0;
}
/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
static int cim_mmap(struct file *file, struct vm_area_struct *vma)
{
unsigned long start;
unsigned long off;
u32 len;
dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
off = vma->vm_pgoff << PAGE_SHIFT;
/* frame buffer memory */
start = virt_to_phys(jz_cim->mem_base);
len = PAGE_ALIGN((start & ~PAGE_MASK) + ((unsigned long)jz_cim->mem_size));
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len) {
printk("Error: vma is larger than memory length\n");
return -EINVAL;
}
off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */
#if defined(CONFIG_MIPS32)
pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */
#endif
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) {
return -EAGAIN;
}
return 0;
}
static struct miscdevice cim_dev = {
CIM_MINOR,
"cim",
&cim_fops
};
/*
* Module init and exit
*/
static int __init cim_init(void)
{
int ret;
/* GPIO init for cim pins and i2c SDA & SCL */
__gpio_as_cim();
__gpio_as_i2c();
/* waitqueue */
init_waitqueue_head(&jz_cim->wait_queue);
#ifndef USE_DEFAULT_MEM
/* Alloc memory for cim DMA*/
printk("Alloc memory for cim DMA\n");
ret = cim_fb_alloc();
if (ret) {
printk("No mem: Alloc memory for cim DMA\n");
return ret;
}
#endif
/* request interrupt for cim */
if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, CIM_NAME, jz_cim))) {
printk(KERN_ERR "request_irq return error, ret=%d\n", ret);
cim_fb_destroy();
printk(KERN_ERR "CIM could not get IRQ\n");
return ret;
}
/* Register as a misc device */
ret = misc_register(&cim_dev);
if (ret < 0) {
return ret;
}
printk("Virtual Driver of JZ CIM registered\n");
return 0;
}
static void __exit cim_exit(void)
{
misc_deregister(&cim_dev);
}
module_init(cim_init);
module_exit(cim_exit);

View File

@@ -0,0 +1,104 @@
/*
* linux/drivers/misc/jz_cim.h -- Ingenic Jz4750 On-Chip CIM driver
*
* Copyright (C) 2005-2008, Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __JZ_CIM_H__
#define __JZ_CIM_H__
/* use ext clock as mclk */
#define CIM_EXTCLK 24000000
/* If use default 16M mem, enable it*/
//#define USE_DEFAULT_MEM
/* Camera Preview buffer number */
#define CIM_BUF_NUM 3
#define INVALID_PIC_BUF 0
//#define IMEM_MAX_ORDER 12 /* max 2^12 * 4096 = 16MB */
/*
* Define the Max Image Size CIM Support
*/
#define MAX_IMAGE_WIDTH 4096
#define MAX_IMAGE_HEIGHT 4096
#define MAX_PRE_WIDTH 640
#define MAX_PRE_HEIGHT 480
#define MAX_IMAGE_BPP 16
#define MAX_PRE_SIZE (MAX_PRE_WIDTH * MAX_PRE_HEIGHT * MAX_IMAGE_BPP >> 3)
#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP >> 3)
/*
* IOCTL_XXX commands
*/
#define IOCTL_SET_I2C_ADDR 0x0
#define IOCTL_SET_I2C_CLK 0x1
#define IOCTL_WRITE_I2C_REG 0x2
#define IOCTL_READ_I2C_REG 0x3
#define IOCTL_WRITE_I2C_REG16 0x4
#define IOCTL_READ_I2C_REG16 0x5
#define IOCTL_SET_MEM 0x6
#define IOCTL_START_CIM 0x7 // arg type: void
#define IOCTL_STOP_CIM 0x8 // arg type: void
#define IOCTL_GET_PREVIEW_PARAM 0x9 // arg type: preview param *
#define IOCTL_SET_PREVIEW_PARAM 0xA // arg type: preview param *
#define IOCTL_GET_PICTURE_PARAM 0xB // arg type: img_param_t *
#define IOCTL_SET_PICTURE_PARAM 0xC // arg type: img_param_t *
#define IOCTL_GET_CIM_CONFIG 0xD // arg type: cim_config_t *
#define IOCTL_SET_CIM_CONFIG 0xE // arg type: cim_config_t *
#define IOCTL_PRINT_REGS 0xF // NULL
#define IOCTL_TAKE_PICTURE 0x10
#define IOCTL_GET_CURRENT_BUF_ID 0x11
/* gpio init */
#if defined(CONFIG_JZ4750_APUS) || defined(CONFIG_JZ4750D_FUWA1) /* board pavo */
#define GPIO_CAMERA_RST (32*4+8) /* CIM_MCLK as reset */
#else
#error "driver/misc/jz_cim.h, please define camera for your board."
#endif
/* preview-format=rgb565|yuv422 */
typedef struct{
unsigned int width;
unsigned int height;
unsigned int bpp;
char format[20];
unsigned int framebuf[CIM_BUF_NUM];
} preview_param_t;
/* picture-format=yuv422|jpeg */
typedef struct{
unsigned int width;
unsigned int height;
unsigned int bpp;
// const char *format;
char format[20];
unsigned int framebuf[CIM_BUF_NUM];
} picture_param_t;
typedef struct{
unsigned int cfg;
unsigned int ctrl;
unsigned int mclk;
unsigned int size;
unsigned int offs;
} cim_config_t;
struct jz_camera_device_platform_data {
int gpio_reset;
void (*config_gpio_on) (void);
void (*config_gpio_off)(void);
};
#endif /*__JZ_CIM_H__*/

View File

@@ -0,0 +1,92 @@
/*
* linux/drivers/misc/jz_sensor.c
*
* Virtual device driver with tricky appoach to manage TCSM
*
* Copyright (C) 2006 Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/wakelock.h>
#include <linux/platform_device.h>
#include <linux/major.h>
#include <linux/version.h>
#include <asm/cacheflush.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/thread_info.h>
#include <asm/uaccess.h>
#include <asm/jzsoc.h>
#include "jz_cim.h"
#include "jz_sensor.h"
unsigned int i2c_addr = 0x60;
unsigned int i2c_clk = 100000;
/* I2C ops to init senser */
void sensor_write_reg(unsigned char reg, unsigned char val)
{
i2c_open();
i2c_setclk(i2c_clk);
i2c_write((i2c_addr >> 1), &val, reg, 1);
i2c_close();
}
int sensor_write_reg16(unsigned short reg, unsigned char val)
{
int ret;
i2c_open();
i2c_setclk(i2c_clk);
ret = i2c_write_16(i2c_addr >> 1, &val, reg, 1);
i2c_close();
return ret;
}
unsigned char sensor_read_reg(unsigned char reg)
{
unsigned char val;
i2c_open();
i2c_setclk(i2c_clk);
i2c_read((i2c_addr >> 1), &val, reg, 1);
i2c_close();
return val;
}
/*
* Get sensor register through i2c bus
*/
unsigned char sensor_read_reg16(unsigned short reg)
{
unsigned char val;
i2c_open();
i2c_setclk(i2c_clk);
i2c_read_16(i2c_addr >> 1, &val, reg, 1);
i2c_close();
return val;
}

View File

@@ -0,0 +1,94 @@
/*
* linux/drivers/misc/jz_cim.h -- Ingenic Jz4750 On-Chip CIM driver
*
* Copyright (C) 2005-2008, Ingenic Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __JZ_SENSOR_H__
#define __JZ_SENSOR_H__
#include "jz_cim.h"
#define IN_YUV422 1 /*Sensor output YUV422*/
/*
* Define the Max Image Size Sensor Support, Should less than CIM MAX
*/
#if defined(CONFIG_OV3640)
#define MAX_SENSOR_WIDTH 2048
#define MAX_SENSOR_HEIGHT 1536
#define MAX_SENSOR_BPP 16
#define SENSOR_PRE_WIDTH 320
#define SENSOR_PRE_HEIGHT 240
#elif defined(CONFIG_OV2640)
#define MAX_SENSOR_WIDTH 1600
#define MAX_SENSOR_HEIGHT 1200
#define MAX_SENSOR_BPP 16
#define SENSOR_PRE_WIDTH 320
#define SENSOR_PRE_HEIGHT 240
#elif defined(CONFIG_OV9650)
#define MAX_SENSOR_WIDTH 1280
#define MAX_SENSOR_HEIGHT 1024
#define MAX_SENSOR_BPP 16
#define SENSOR_PRE_WIDTH 320
#define SENSOR_PRE_HEIGHT 240
#else
#define MAX_SENSOR_WIDTH 1280
#define MAX_SENSOR_HEIGHT 1024
#define MAX_SENSOR_BPP 16
#define SENSOR_PRE_WIDTH 320
#define SENSOR_PRE_HEIGHT 240
#endif
#if defined(CONFIG_OV3640) || defined(CONFIG_OV2640)
//#define JPEG_OUTPUT_SUPPORT
#endif
#if defined(JPEG_OUTPUT_SUPPORT)
#define MAX_PICTURE_SIZE (6*1024*1024) /* for 2048*1536*2 */
#else
#define MAX_PICTURE_SIZE (MAX_SENSOR_WIDTH * MAX_SENSOR_HEIGHT * MAX_IMAGE_BPP >> 3)
#endif
#if defined(CONFIG_OV9650) || defined(CONFIG_OV2640)
#define __sensor_gpio_init() \
do {\
__gpio_as_output(GPIO_CAMERA_RST); \
__gpio_set_pin(GPIO_CAMERA_RST); \
mdelay(50); \
__gpio_clear_pin(GPIO_CAMERA_RST);\
} while(0)
#elif defined(CONFIG_OV3640)
#define __sensor_gpio_init() \
do {\
__gpio_as_output(GPIO_CAMERA_RST); \
__gpio_clear_pin(GPIO_CAMERA_RST);\
mdelay(50); \
__gpio_set_pin(GPIO_CAMERA_RST); \
} while(0)
#endif
extern unsigned int i2c_addr;
extern unsigned int i2c_clk;
/* I2C APP */
extern int i2c_write_16(unsigned char device, unsigned char *buf, unsigned short address, int count);
extern int i2c_read_16(unsigned char device, unsigned char *buf, unsigned short address, int count);
extern void sensor_write_reg(unsigned char reg, unsigned char val);
extern int sensor_write_reg16(unsigned short reg, unsigned char val);
extern unsigned char sensor_read_reg(unsigned char reg);
extern unsigned char sensor_read_reg16(unsigned short reg);
#endif

Some files were not shown because too many files have changed in this diff Show More