提交 e9d52234 编写于 作者: L Linus Torvalds
README for MIPS AU1XXX IDE driver - Released 2005-07-15
ABOUT
-----
This file describes the 'drivers/ide/mips/au1xxx-ide.c', related files and the
services they provide.
If you are short in patience and just want to know how to add your hard disc to
the white or black list, go to the 'ADD NEW HARD DISC TO WHITE OR BLACK LIST'
section.
LICENSE
-------
Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions
This program is free software; you can redistribute it and/or modify it under
the terms of the 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.
Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
Interface and Linux Device Driver" Application Note.
FILES, CONFIGS AND COMPATABILITY
--------------------------------
Two files are introduced:
a) 'include/asm-mips/mach-au1x00/au1xxx_ide.h'
containes : struct _auide_hwif
struct drive_list_entry dma_white_list
struct drive_list_entry dma_black_list
timing parameters for PIO mode 0/1/2/3/4
timing parameters for MWDMA 0/1/2
b) 'drivers/ide/mips/au1xxx-ide.c'
contains the functionality of the AU1XXX IDE driver
Four configs variables are introduced:
CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - enable the PIO+DBDMA mode
CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - enable the MWDMA mode
CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON - set Burstable FIFO in DBDMA
controler
CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ - maximum transfer size
per descriptor
If MWDMA is enabled and the connected hard disc is not on the white list, the
kernel switches to a "safe mwdma mode" at boot time. In this mode the IDE
performance is substantial slower then in full speed mwdma. In this case
please add your hard disc to the white list (follow instruction from 'ADD NEW
HARD DISC TO WHITE OR BLACK LIST' section).
SUPPORTED IDE MODES
-------------------
The AU1XXX IDE driver supported all PIO modes - PIO mode 0/1/2/3/4 - and all
MWDMA modes - MWDMA 0/1/2 -. There is no support for SWDMA and UDMA mode.
To change the PIO mode use the program hdparm with option -p, e.g.
'hdparm -p0 [device]' for PIO mode 0. To enable the MWDMA mode use the option
-X, e.g. 'hdparm -X32 [device]' for MWDMA mode 0.
PERFORMANCE CONFIGURATIONS
--------------------------
If the used system doesn't need USB support enable the following kernel configs:
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
CONFIG_IDE_GENERIC=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_BLK_DEV_IDE_AU1XXX=y
CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y
CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON=y
CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ=128
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_AUTO=y
If the used system need the USB support enable the following kernel configs for
high IDE to USB throughput.
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDE_GENERIC=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_IDEDMA_PCI=y
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_BLK_DEV_IDE_AU1XXX=y
CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y
CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ=128
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_AUTO=y
ADD NEW HARD DISC TO WHITE OR BLACK LIST
----------------------------------------
Step 1 : detect the model name of your hard disc
a) connect your hard disc to the AU1XXX
b) boot your kernel and get the hard disc model.
Example boot log:
--snipped--
Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
Au1xxx IDE(builtin) configured for MWDMA2
Probing IDE interface ide0...
hda: Maxtor 6E040L0, ATA DISK drive
ide0 at 0xac800000-0xac800007,0xac8001c0 on irq 64
hda: max request size: 64KiB
hda: 80293248 sectors (41110 MB) w/2048KiB Cache, CHS=65535/16/63, (U)DMA
--snipped--
In this example 'Maxtor 6E040L0'.
Step 2 : edit 'include/asm-mips/mach-au1x00/au1xxx_ide.h'
Add your hard disc to the dma_white_list or dma_black_list structur.
Step 3 : Recompile the kernel
Enable MWDMA support in the kernel configuration. Recompile the kernel and
reboot.
Step 4 : Tests
If you have add a hard disc to the white list, please run some stress tests
for verification.
ACKNOWLEDGMENTS
---------------
These drivers wouldn't have been done without the base of kernel 2.4.x AU1XXX
IDE driver from AMD.
Additional input also from:
Matthias Lenk <matthias.lenk@amd.com>
Happy hacking!
Enrico Walther <enrico.walther@amd.com>
......@@ -1643,7 +1643,7 @@ S: Maintained
MIPS
P: Ralf Baechle
M: ralf@linux-mips.org
W: http://oss.sgi.com/mips/mips-howto.html
W: http://www.linux-mips.org/
L: linux-mips@linux-mips.org
S: Maintained
......
此差异已折叠。
......@@ -52,6 +52,21 @@ ifdef CONFIG_CROSSCOMPILE
CROSS_COMPILE := $(tool-prefix)
endif
CHECKFLAGS-y += -D__linux__ -D__mips__ \
-D_ABIO32=1 \
-D_ABIN32=2 \
-D_ABI64=3
CHECKFLAGS-$(CONFIG_32BIT) += -D_MIPS_SIM=_ABIO32 \
-D_MIPS_SZLONG=32 \
-D__PTRDIFF_TYPE__=int
CHECKFLAGS-$(CONFIG_64BIT) += -m64 -D_MIPS_SIM=_ABI64 \
-D_MIPS_SZLONG=64 \
-D__PTRDIFF_TYPE__="long int"
CHECKFLAGS-$(CONFIG_CPU_BIG_ENDIAN) += -D__MIPSEB__
CHECKFLAGS-$(CONFIG_CPU_LITTLE_ENDIAN) += -D__MIPSEL__
CHECKFLAGS = $(CHECKFLAGS-y)
ifdef CONFIG_BUILD_ELF64
gas-abi = 64
ld-emul = $(64bit-emul)
......@@ -79,9 +94,18 @@ endif
cflags-y += -I $(TOPDIR)/include/asm/gcc
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
cflags-y += $(call cc-option, -finline-limit=100000)
LDFLAGS_vmlinux += -G 0 -static -n
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
MODFLAGS += -mlong-calls
#
# We explicitly add the endianness specifier if needed, this allows
# to compile kernels with a toolchain for the other endianness. We
# carefully avoid to add it redundantly because gcc 3.3/3.4 complains
# when fed the toolchain default!
#
cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB)
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL)
cflags-$(CONFIG_SB1XXX_CORELIS) += -mno-sched-prolog -fno-omit-frame-pointer
#
......@@ -167,14 +191,22 @@ cflags-$(CONFIG_CPU_TX49XX) += \
$(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \
-Wa,--trap
cflags-$(CONFIG_CPU_MIPS32) += \
cflags-$(CONFIG_CPU_MIPS32_R1) += \
$(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \
-Wa,--trap
cflags-$(CONFIG_CPU_MIPS64) += \
cflags-$(CONFIG_CPU_MIPS32_R2) += \
$(call set_gccflags,mips32r2,mips32r2,r4600,mips3,mips2) \
-Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R1) += \
$(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \
-Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R2) += \
$(call set_gccflags,mips64r2,mips64r2,r4600,mips3,mips2) \
-Wa,--trap
cflags-$(CONFIG_CPU_R5000) += \
$(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \
-Wa,--trap
......@@ -196,6 +228,7 @@ cflags-$(CONFIG_CPU_RM9000) += \
$(call set_gccflags,rm9000,mips4,r5000,mips4,mips2) \
-Wa,--trap
cflags-$(CONFIG_CPU_SB1) += \
$(call set_gccflags,sb1,mips64,r5000,mips4,mips2) \
-Wa,--trap
......@@ -265,6 +298,13 @@ libs-$(CONFIG_MIPS_PB1550) += arch/mips/au1000/pb1550/
cflags-$(CONFIG_MIPS_PB1550) += -Iinclude/asm-mips/mach-pb1x00
load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000
#
# AMD Alchemy Pb1200 eval board
#
libs-$(CONFIG_MIPS_PB1200) += arch/mips/au1000/pb1200/
cflags-$(CONFIG_MIPS_PB1200) += -Iinclude/asm-mips/mach-pb1x00
load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000
#
# AMD Alchemy Db1000 eval board
#
......@@ -293,6 +333,13 @@ libs-$(CONFIG_MIPS_DB1550) += arch/mips/au1000/db1x00/
cflags-$(CONFIG_MIPS_DB1550) += -Iinclude/asm-mips/mach-db1x00
load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000
#
# AMD Alchemy Db1200 eval board
#
libs-$(CONFIG_MIPS_DB1200) += arch/mips/au1000/pb1200/
cflags-$(CONFIG_MIPS_DB1200) += -Iinclude/asm-mips/mach-db1x00
load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000
#
# AMD Alchemy Bosporus eval board
#
......@@ -323,6 +370,7 @@ load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000
# Cobalt Server
#
core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/
cflags-$(CONFIG_MIPS_COBALT) += -Iinclude/asm-mips/cobalt
load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000
#
......@@ -388,6 +436,13 @@ load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/
load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000
#
# MIPS SIM
#
core-$(CONFIG_MIPS_SIM) += arch/mips/mips-boards/sim/
cflags-$(CONFIG_MIPS_SIM) += -Iinclude/asm-mips/mach-sim
load-$(CONFIG_MIPS_SIM) += 0x80100000
#
# Momentum Ocelot board
#
......@@ -513,6 +568,19 @@ load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
#
load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
#
# Common Philips PNX8550
#
core-$(CONFIG_SOC_PNX8550) += arch/mips/philips/pnx8550/common/
cflags-$(CONFIG_SOC_PNX8550) += -Iinclude/asm-mips/mach-pnx8550
#
# Philips PNX8550 JBS board
#
libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/
#cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550
load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
#
# SGI IP22 (Indy/Indigo2)
#
......@@ -582,10 +650,20 @@ load-$(CONFIG_SGI_IP32) += 0xffffffff80004000
# removed (as happens, even if they have __initcall/module_init)
#
core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/sb1250/
cflags-$(CONFIG_SIBYTE_BCM112X) += -Iinclude/asm-mips/mach-sibyte
cflags-$(CONFIG_SIBYTE_BCM112X) += -Iinclude/asm-mips/mach-sibyte \
-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/sb1250/
cflags-$(CONFIG_SIBYTE_SB1250) += -Iinclude/asm-mips/mach-sibyte
cflags-$(CONFIG_SIBYTE_SB1250) += -Iinclude/asm-mips/mach-sibyte \
-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/bcm1480/
cflags-$(CONFIG_SIBYTE_BCM1x55) += -Iinclude/asm-mips/mach-sibyte \
-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/bcm1480/
cflags-$(CONFIG_SIBYTE_BCM1x80) += -Iinclude/asm-mips/mach-sibyte \
-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
#
# Sibyte BCM91120x (Carmel) board
......@@ -593,6 +671,7 @@ cflags-$(CONFIG_SIBYTE_SB1250) += -Iinclude/asm-mips/mach-sibyte
# Sibyte BCM91125C (CRhone) board
# Sibyte BCM91125E (Rhone) board
# Sibyte SWARM board
# Sibyte BCM91x80 (BigSur) board
#
libs-$(CONFIG_SIBYTE_CARMEL) += arch/mips/sibyte/swarm/
load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000
......@@ -606,6 +685,8 @@ libs-$(CONFIG_SIBYTE_SENTOSA) += arch/mips/sibyte/swarm/
load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000
libs-$(CONFIG_SIBYTE_SWARM) += arch/mips/sibyte/swarm/
load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
libs-$(CONFIG_SIBYTE_BIGSUR) += arch/mips/sibyte/swarm/
load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
#
# SNI RM200 PCI
......@@ -629,6 +710,13 @@ core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/tx4927/toshiba_rbtx4927/
core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/tx4927/common/
load-$(CONFIG_TOSHIBA_RBTX4927) += 0xffffffff80020000
#
# Toshiba RBTX4938 board
#
core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/tx4938/toshiba_rbtx4938/
core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/tx4938/common/
load-$(CONFIG_TOSHIBA_RBTX4938) += 0xffffffff80100000
cflags-y += -Iinclude/asm-mips/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/
......@@ -701,10 +789,29 @@ ifdef CONFIG_BOOT_ELF64
all: $(vmlinux-64)
endif
ifdef CONFIG_MIPS_ATLAS
all: vmlinux.srec
endif
ifdef CONFIG_MIPS_MALTA
all: vmlinux.srec
endif
ifdef CONFIG_MIPS_SEAD
all: vmlinux.srec
endif
ifdef CONFIG_QEMU
all: vmlinux.bin
endif
ifdef CONFIG_SNI_RM200_PCI
all: vmlinux.ecoff
endif
vmlinux.bin: $(vmlinux-32)
+@$(call makeboot,$@)
vmlinux.ecoff vmlinux.rm200: $(vmlinux-32)
+@$(call makeboot,$@)
......@@ -720,7 +827,6 @@ archclean:
@$(MAKE) $(clean)=arch/mips/boot
@$(MAKE) $(clean)=arch/mips/lasat
CLEAN_FILES += vmlinux.32 \
vmlinux.64 \
vmlinux.ecoff
......@@ -3,7 +3,7 @@
#
lib-y += cmdline.o env.o file.o identify.o init.o \
misc.o time.o tree.o
misc.o salone.o time.o tree.o
lib-$(CONFIG_ARC_MEMORY) += memory.o
lib-$(CONFIG_ARC_CONSOLE) += arc_con.o
......
......@@ -44,6 +44,11 @@ static struct smatch mach_table[] = {
MACH_GROUP_SGI,
MACH_SGI_IP28,
PROM_FLAG_ARCS
}, { "SGI-IP30",
"SGI Octane",
MACH_GROUP_SGI,
MACH_SGI_IP30,
PROM_FLAG_ARCS
}, { "SGI-IP32",
"SGI O2",
MACH_GROUP_SGI,
......
......@@ -8,7 +8,7 @@
obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \
au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
sleeper.o cputable.o dma.o dbdma.o
sleeper.o cputable.o dma.o dbdma.o gpio.o
obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
obj-$(CONFIG_KGDB) += dbg_io.o
......
......@@ -173,14 +173,14 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
{ AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1550_TOY_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
{ AU1550_RTC_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
{ AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0},
{ AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 },
{ AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
......@@ -201,14 +201,14 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = {
{ AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0},
{ AU1200_TOY_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
{ AU1200_RTC_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
{ AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
{ AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0},
{ AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 },
{ AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
......
......@@ -37,7 +37,8 @@ struct cpu_spec cpu_specs[] = {
{ 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 },
{ 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
{ 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
{ 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 },
{ 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
{ 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
{ 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
};
......
......@@ -29,6 +29,7 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
......@@ -38,10 +39,12 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/system.h>
#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
/*
......@@ -61,37 +64,10 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
*/
#define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1))
static volatile dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
static int dbdma_initialized;
static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
static int dbdma_initialized=0;
static void au1xxx_dbdma_init(void);
typedef struct dbdma_device_table {
u32 dev_id;
u32 dev_flags;
u32 dev_tsize;
u32 dev_devwidth;
u32 dev_physaddr; /* If FIFO */
u32 dev_intlevel;
u32 dev_intpolarity;
} dbdev_tab_t;
typedef struct dbdma_chan_config {
u32 chan_flags;
u32 chan_index;
dbdev_tab_t *chan_src;
dbdev_tab_t *chan_dest;
au1x_dma_chan_t *chan_ptr;
au1x_ddma_desc_t *chan_desc_base;
au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr;
void *chan_callparam;
void (*chan_callback)(int, void *, struct pt_regs *);
} chan_tab_t;
#define DEV_FLAGS_INUSE (1 << 0)
#define DEV_FLAGS_ANYUSE (1 << 1)
#define DEV_FLAGS_OUT (1 << 2)
#define DEV_FLAGS_IN (1 << 3)
static dbdev_tab_t dbdev_tab[] = {
#ifdef CONFIG_SOC_AU1550
/* UARTS */
......@@ -157,25 +133,25 @@ static dbdev_tab_t dbdev_tab[] = {
{ DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 },
{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 },
{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 },
{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 },
{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 },
{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 },
{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 },
{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x11a0001c, 0, 0 },
{ DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 },
{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 },
{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x11b0001c, 0, 0 },
{ DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 },
{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 },
{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 },
{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
......@@ -184,6 +160,24 @@ static dbdev_tab_t dbdev_tab[] = {
{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
/* Provide 16 user definable device types */
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0 },
};
#define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t))
......@@ -203,6 +197,36 @@ find_dbdev_id (u32 id)
return NULL;
}
void * au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp)
{
return phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
}
EXPORT_SYMBOL(au1xxx_ddma_get_nextptr_virt);
u32
au1xxx_ddma_add_device(dbdev_tab_t *dev)
{
u32 ret = 0;
dbdev_tab_t *p=NULL;
static u16 new_id=0x1000;
p = find_dbdev_id(0);
if ( NULL != p )
{
memcpy(p, dev, sizeof(dbdev_tab_t));
p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
ret = p->dev_id;
new_id++;
#if 0
printk("add_device: id:%x flags:%x padd:%x\n",
p->dev_id, p->dev_flags, p->dev_physaddr );
#endif
}
return ret;
}
EXPORT_SYMBOL(au1xxx_ddma_add_device);
/* Allocate a channel and return a non-zero descriptor if successful.
*/
u32
......@@ -215,7 +239,7 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
int i;
dbdev_tab_t *stp, *dtp;
chan_tab_t *ctp;
volatile au1x_dma_chan_t *cp;
au1x_dma_chan_t *cp;
/* We do the intialization on the first channel allocation.
* We have to wait because of the interrupt handler initialization
......@@ -225,9 +249,6 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
au1xxx_dbdma_init();
dbdma_initialized = 1;
if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS))
return 0;
if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
if ((dtp = find_dbdev_id(destid)) == NULL) return 0;
......@@ -271,7 +292,6 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
*/
ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
chan_tab_ptr[i] = ctp;
ctp->chan_index = chan = i;
break;
}
}
......@@ -279,10 +299,11 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
if (ctp != NULL) {
memset(ctp, 0, sizeof(chan_tab_t));
ctp->chan_index = chan = i;
dcp = DDMA_CHANNEL_BASE;
dcp += (0x0100 * chan);
ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
cp = (volatile au1x_dma_chan_t *)dcp;
cp = (au1x_dma_chan_t *)dcp;
ctp->chan_src = stp;
ctp->chan_dest = dtp;
ctp->chan_callback = callback;
......@@ -299,6 +320,9 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
i |= DDMA_CFG_DED;
if (dtp->dev_intpolarity)
i |= DDMA_CFG_DP;
if ((stp->dev_flags & DEV_FLAGS_SYNC) ||
(dtp->dev_flags & DEV_FLAGS_SYNC))
i |= DDMA_CFG_SYNC;
cp->ddma_cfg = i;
au_sync();
......@@ -309,14 +333,14 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
rv = (u32)(&chan_tab_ptr[chan]);
}
else {
/* Release devices.
*/
/* Release devices */
stp->dev_flags &= ~DEV_FLAGS_INUSE;
dtp->dev_flags &= ~DEV_FLAGS_INUSE;
}
}
return rv;
}
EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc);
/* Set the device width if source or destination is a FIFO.
* Should be 8, 16, or 32 bits.
......@@ -344,6 +368,7 @@ au1xxx_dbdma_set_devwidth(u32 chanid, int bits)
return rv;
}
EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth);
/* Allocate a descriptor ring, initializing as much as possible.
*/
......@@ -370,7 +395,8 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
* and if we try that first we are likely to not waste larger
* slabs of memory.
*/
desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t),
GFP_KERNEL|GFP_DMA);
if (desc_base == 0)
return 0;
......@@ -381,7 +407,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
kfree((const void *)desc_base);
i = entries * sizeof(au1x_ddma_desc_t);
i += (sizeof(au1x_ddma_desc_t) - 1);
if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0)
if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0)
return 0;
desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
......@@ -403,7 +429,13 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
cmd0 |= DSCR_CMD0_SID(srcid);
cmd0 |= DSCR_CMD0_DID(destid);
cmd0 |= DSCR_CMD0_IE | DSCR_CMD0_CV;
cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_CURRENT);
cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_NOCHANGE);
/* is it mem to mem transfer? */
if(((DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_THROTTLE) || (DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_ALWAYS)) &&
((DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_THROTTLE) || (DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_ALWAYS))) {
cmd0 |= DSCR_CMD0_MEM;
}
switch (stp->dev_devwidth) {
case 8:
......@@ -461,9 +493,14 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
/* If source input is fifo, set static address.
*/
if (stp->dev_flags & DEV_FLAGS_IN) {
src0 = stp->dev_physaddr;
if ( stp->dev_flags & DEV_FLAGS_BURSTABLE )
src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST);
else
src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);
}
if (stp->dev_physaddr)
src0 = stp->dev_physaddr;
/* Set up dest1. For now, assume no stride and increment.
* A channel attribute update can change this later.
......@@ -487,10 +524,18 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
/* If destination output is fifo, set static address.
*/
if (dtp->dev_flags & DEV_FLAGS_OUT) {
dest0 = dtp->dev_physaddr;
if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE )
dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST);
else
dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);
}
if (dtp->dev_physaddr)
dest0 = dtp->dev_physaddr;
#if 0
printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 );
#endif
for (i=0; i<entries; i++) {
dp->dscr_cmd0 = cmd0;
dp->dscr_cmd1 = cmd1;
......@@ -499,6 +544,8 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
dp->dscr_dest0 = dest0;
dp->dscr_dest1 = dest1;
dp->dscr_stat = 0;
dp->sw_context = 0;
dp->sw_status = 0;
dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));
dp++;
}
......@@ -511,13 +558,14 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
return (u32)(ctp->chan_desc_base);
}
EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);
/* Put a source buffer into the DMA ring.
* This updates the source pointer and byte count. Normally used
* for memory to fifo transfers.
*/
u32
au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
{
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
......@@ -544,8 +592,24 @@ au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
*/
dp->dscr_source0 = virt_to_phys(buf);
dp->dscr_cmd1 = nbytes;
dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
ctp->chan_ptr->ddma_dbell = 0xffffffff; /* Make it go */
/* Check flags */
if (flags & DDMA_FLAGS_IE)
dp->dscr_cmd0 |= DSCR_CMD0_IE;
if (flags & DDMA_FLAGS_NOIE)
dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
/*
* There is an errata on the Au1200/Au1550 parts that could result
* in "stale" data being DMA'd. It has to do with the snoop logic on
* the dache eviction buffer. NONCOHERENT_IO is on by default for
* these parts. If it is fixedin the future, these dma_cache_inv will
* just be nothing more than empty macros. See io.h.
* */
dma_cache_wback_inv((unsigned long)buf, nbytes);
dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
au_sync();
dma_cache_wback_inv((unsigned long)dp, sizeof(dp));
ctp->chan_ptr->ddma_dbell = 0;
/* Get next descriptor pointer.
*/
......@@ -555,13 +619,14 @@ au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
*/
return nbytes;
}
EXPORT_SYMBOL(_au1xxx_dbdma_put_source);
/* Put a destination buffer into the DMA ring.
* This updates the destination pointer and byte count. Normally used
* to place an empty buffer into the ring for fifo to memory transfers.
*/
u32
au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
{
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
......@@ -583,11 +648,33 @@ au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
if (dp->dscr_cmd0 & DSCR_CMD0_V)
return 0;
/* Load up buffer address and byte count.
*/
/* Load up buffer address and byte count */
/* Check flags */
if (flags & DDMA_FLAGS_IE)
dp->dscr_cmd0 |= DSCR_CMD0_IE;
if (flags & DDMA_FLAGS_NOIE)
dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
dp->dscr_dest0 = virt_to_phys(buf);
dp->dscr_cmd1 = nbytes;
#if 0
printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0,
dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 );
#endif
/*
* There is an errata on the Au1200/Au1550 parts that could result in
* "stale" data being DMA'd. It has to do with the snoop logic on the
* dache eviction buffer. NONCOHERENT_IO is on by default for these
* parts. If it is fixedin the future, these dma_cache_inv will just
* be nothing more than empty macros. See io.h.
* */
dma_cache_inv((unsigned long)buf,nbytes);
dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
au_sync();
dma_cache_wback_inv((unsigned long)dp, sizeof(dp));
ctp->chan_ptr->ddma_dbell = 0;
/* Get next descriptor pointer.
*/
......@@ -597,6 +684,7 @@ au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
*/
return nbytes;
}
EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);
/* Get a destination buffer into the DMA ring.
* Normally used to get a full buffer from the ring during fifo
......@@ -646,7 +734,7 @@ void
au1xxx_dbdma_stop(u32 chanid)
{
chan_tab_t *ctp;
volatile au1x_dma_chan_t *cp;
au1x_dma_chan_t *cp;
int halt_timeout = 0;
ctp = *((chan_tab_t **)chanid);
......@@ -666,6 +754,7 @@ au1xxx_dbdma_stop(u32 chanid)
cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);
au_sync();
}
EXPORT_SYMBOL(au1xxx_dbdma_stop);
/* Start using the current descriptor pointer. If the dbdma encounters
* a not valid descriptor, it will stop. In this case, we can just
......@@ -675,17 +764,17 @@ void
au1xxx_dbdma_start(u32 chanid)
{
chan_tab_t *ctp;
volatile au1x_dma_chan_t *cp;
au1x_dma_chan_t *cp;
ctp = *((chan_tab_t **)chanid);
cp = ctp->chan_ptr;
cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */
au_sync();
cp->ddma_dbell = 0xffffffff; /* Make it go */
cp->ddma_dbell = 0;
au_sync();
}
EXPORT_SYMBOL(au1xxx_dbdma_start);
void
au1xxx_dbdma_reset(u32 chanid)
......@@ -704,15 +793,21 @@ au1xxx_dbdma_reset(u32 chanid)
do {
dp->dscr_cmd0 &= ~DSCR_CMD0_V;
/* reset our SW status -- this is used to determine
* if a descriptor is in use by upper level SW. Since
* posting can reset 'V' bit.
*/
dp->sw_status = 0;
dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
} while (dp != ctp->chan_desc_base);
}
EXPORT_SYMBOL(au1xxx_dbdma_reset);
u32
au1xxx_get_dma_residue(u32 chanid)
{
chan_tab_t *ctp;
volatile au1x_dma_chan_t *cp;
au1x_dma_chan_t *cp;
u32 rv;
ctp = *((chan_tab_t **)chanid);
......@@ -738,8 +833,7 @@ au1xxx_dbdma_chan_free(u32 chanid)
au1xxx_dbdma_stop(chanid);
if (ctp->chan_desc_base != NULL)
kfree(ctp->chan_desc_base);
kfree((void *)ctp->chan_desc_base);
stp->dev_flags &= ~DEV_FLAGS_INUSE;
dtp->dev_flags &= ~DEV_FLAGS_INUSE;
......@@ -747,15 +841,16 @@ au1xxx_dbdma_chan_free(u32 chanid)
kfree(ctp);
}
EXPORT_SYMBOL(au1xxx_dbdma_chan_free);
static irqreturn_t
dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
u32 intstat;
u32 chan_index;
u32 intstat;
u32 chan_index;
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
volatile au1x_dma_chan_t *cp;
au1x_dma_chan_t *cp;
intstat = dbdma_gptr->ddma_intstat;
au_sync();
......@@ -774,19 +869,27 @@ dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
(ctp->chan_callback)(irq, ctp->chan_callparam, regs);
ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
return IRQ_HANDLED;
return IRQ_RETVAL(1);
}
static void
au1xxx_dbdma_init(void)
static void au1xxx_dbdma_init(void)
{
int irq_nr;
dbdma_gptr->ddma_config = 0;
dbdma_gptr->ddma_throttle = 0;
dbdma_gptr->ddma_inten = 0xffff;
au_sync();
if (request_irq(AU1550_DDMA_INT, dbdma_interrupt, SA_INTERRUPT,
#if defined(CONFIG_SOC_AU1550)
irq_nr = AU1550_DDMA_INT;
#elif defined(CONFIG_SOC_AU1200)
irq_nr = AU1200_DDMA_INT;
#else
#error Unknown Au1x00 SOC
#endif
if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT,
"Au1xxx dbdma", (void *)dbdma_gptr))
printk("Can't get 1550 dbdma irq");
}
......@@ -797,7 +900,8 @@ au1xxx_dbdma_dump(u32 chanid)
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
dbdev_tab_t *stp, *dtp;
volatile au1x_dma_chan_t *cp;
au1x_dma_chan_t *cp;
u32 i = 0;
ctp = *((chan_tab_t **)chanid);
stp = ctp->chan_src;
......@@ -822,15 +926,64 @@ au1xxx_dbdma_dump(u32 chanid)
dp = ctp->chan_desc_base;
do {
printk("dp %08x, cmd0 %08x, cmd1 %08x\n",
(u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
printk("src0 %08x, src1 %08x, dest0 %08x\n",
dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0);
printk("dest1 %08x, stat %08x, nxtptr %08x\n",
dp->dscr_dest1, dp->dscr_stat, dp->dscr_nxtptr);
printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n",
i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n",
dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
printk("stat %08x, nxtptr %08x\n",
dp->dscr_stat, dp->dscr_nxtptr);
dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
} while (dp != ctp->chan_desc_base);
}
/* Put a descriptor into the DMA ring.
* This updates the source/destination pointers and byte count.
*/
u32
au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr )
{
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
u32 nbytes=0;
/* I guess we could check this to be within the
* range of the table......
*/
ctp = *((chan_tab_t **)chanid);
/* We should have multiple callers for a particular channel,
* an interrupt doesn't affect this pointer nor the descriptor,
* so no locking should be needed.
*/
dp = ctp->put_ptr;
/* If the descriptor is valid, we are way ahead of the DMA
* engine, so just return an error condition.
*/
if (dp->dscr_cmd0 & DSCR_CMD0_V)
return 0;
/* Load up buffer addresses and byte count.
*/
dp->dscr_dest0 = dscr->dscr_dest0;
dp->dscr_source0 = dscr->dscr_source0;
dp->dscr_dest1 = dscr->dscr_dest1;
dp->dscr_source1 = dscr->dscr_source1;
dp->dscr_cmd1 = dscr->dscr_cmd1;
nbytes = dscr->dscr_cmd1;
/* Allow the caller to specifiy if an interrupt is generated */
dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;
ctp->chan_ptr->ddma_dbell = 0;
/* Get next descriptor pointer.
*/
ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
/* return something not zero.
*/
return nbytes;
}
#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
......@@ -39,7 +39,6 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1000_dma.h>
......
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the 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/config.h>
#include <linux/module.h>
#include <au1000.h>
#include <au1xxx_gpio.h>
#define gpio1 sys
#if !defined(CONFIG_SOC_AU1000)
static AU1X00_GPIO2 * const gpio2 = (AU1X00_GPIO2 *)GPIO2_BASE;
#define GPIO2_OUTPUT_ENABLE_MASK 0x00010000
int au1xxx_gpio2_read(int signal)
{
signal -= 200;
/* gpio2->dir &= ~(0x01 << signal); //Set GPIO to input */
return ((gpio2->pinstate >> signal) & 0x01);
}
void au1xxx_gpio2_write(int signal, int value)
{
signal -= 200;
gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << signal) |
(value << signal);
}
void au1xxx_gpio2_tristate(int signal)
{
signal -= 200;
gpio2->dir &= ~(0x01 << signal); /* Set GPIO to input */
}
#endif
int au1xxx_gpio1_read(int signal)
{
/* gpio1->trioutclr |= (0x01 << signal); */
return ((gpio1->pinstaterd >> signal) & 0x01);
}
void au1xxx_gpio1_write(int signal, int value)
{
if(value)
gpio1->outputset = (0x01 << signal);
else
gpio1->outputclr = (0x01 << signal); /* Output a Zero */
}
void au1xxx_gpio1_tristate(int signal)
{
gpio1->trioutclr = (0x01 << signal); /* Tristate signal */
}
int au1xxx_gpio_read(int signal)
{
if(signal >= 200)
#if defined(CONFIG_SOC_AU1000)
return 0;
#else
return au1xxx_gpio2_read(signal);
#endif
else
return au1xxx_gpio1_read(signal);
}
void au1xxx_gpio_write(int signal, int value)
{
if(signal >= 200)
#if defined(CONFIG_SOC_AU1000)
;
#else
au1xxx_gpio2_write(signal, value);
#endif
else
au1xxx_gpio1_write(signal, value);
}
void au1xxx_gpio_tristate(int signal)
{
if(signal >= 200)
#if defined(CONFIG_SOC_AU1000)
;
#else
au1xxx_gpio2_tristate(signal);
#endif
else
au1xxx_gpio1_tristate(signal);
}
void au1xxx_gpio1_set_inputs(void)
{
gpio1->pininputen = 0;
}
EXPORT_SYMBOL(au1xxx_gpio1_set_inputs);
EXPORT_SYMBOL(au1xxx_gpio_tristate);
EXPORT_SYMBOL(au1xxx_gpio_write);
EXPORT_SYMBOL(au1xxx_gpio_read);
......@@ -83,7 +83,7 @@ inline void local_disable_irq(unsigned int irq_nr);
void (*board_init_irq)(void);
#ifdef CONFIG_PM
extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
#endif
static DEFINE_SPINLOCK(irq_lock);
......@@ -253,52 +253,72 @@ void restore_local_and_enable(int controller, unsigned long mask)
static struct hw_interrupt_type rise_edge_irq_type = {
"Au1000 Rise Edge",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_rise_edge_irq,
end_irq,
NULL
.typename = "Au1000 Rise Edge",
.startup = startup_irq,
.shutdown = shutdown_irq,
.enable = local_enable_irq,
.disable = local_disable_irq,
.ack = mask_and_ack_rise_edge_irq,
.end = end_irq,
};
static struct hw_interrupt_type fall_edge_irq_type = {
"Au1000 Fall Edge",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_fall_edge_irq,
end_irq,
NULL
.typename = "Au1000 Fall Edge",
.startup = startup_irq,
.shutdown = shutdown_irq,
.enable = local_enable_irq,
.disable = local_disable_irq,
.ack = mask_and_ack_fall_edge_irq,
.end = end_irq,
};
static struct hw_interrupt_type either_edge_irq_type = {
"Au1000 Rise or Fall Edge",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_either_edge_irq,
end_irq,
NULL
.typename = "Au1000 Rise or Fall Edge",
.startup = startup_irq,
.shutdown = shutdown_irq,
.enable = local_enable_irq,
.disable = local_disable_irq,
.ack = mask_and_ack_either_edge_irq,
.end = end_irq,
};
static struct hw_interrupt_type level_irq_type = {
"Au1000 Level",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_level_irq,
end_irq,
NULL
.typename = "Au1000 Level",
.startup = startup_irq,
.shutdown = shutdown_irq,
.enable = local_enable_irq,
.disable = local_disable_irq,
.ack = mask_and_ack_level_irq,
.end = end_irq,
};
#ifdef CONFIG_PM
void startup_match20_interrupt(void)
void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *))
{
struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT];
static struct irqaction action;
memset(&action, 0, sizeof(struct irqaction));
/* This is a big problem.... since we didn't use request_irq
* when kernel/irq.c calls probe_irq_xxx this interrupt will
* be probed for usage. This will end up disabling the device :(
* Give it a bogus "action" pointer -- this will keep it from
* getting auto-probed!
*
* By setting the status to match that of request_irq() we
* can avoid it. --cgray
*/
action.dev_id = handler;
action.flags = SA_INTERRUPT;
cpus_clear(action.mask);
action.name = "Au1xxx TOY";
action.handler = handler;
action.next = NULL;
desc->action = &action;
desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
local_enable_irq(AU1000_TOY_MATCH2_INT);
}
#endif
......@@ -426,7 +446,6 @@ void __init arch_init_irq(void)
extern int au1xxx_ic0_nr_irqs;
cp0_status = read_c0_status();
memset(irq_desc, 0, sizeof(irq_desc));
set_except_vector(0, au1000_IRQ);
/* Initialize interrupt controllers to a safe state.
......@@ -492,7 +511,7 @@ void intc0_req0_irqdispatch(struct pt_regs *regs)
intc0_req0 |= au_readl(IC0_REQ0INT);
if (!intc0_req0) return;
#ifdef AU1000_USB_DEV_REQ_INT
/*
* Because of the tight timing of SETUP token to reply
* transactions, the USB devices-side packet complete
......@@ -503,7 +522,7 @@ void intc0_req0_irqdispatch(struct pt_regs *regs)
do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
return;
}
#endif
irq = au_ffs(intc0_req0) - 1;
intc0_req0 &= ~(1<<irq);
do_IRQ(irq, regs);
......@@ -521,17 +540,7 @@ void intc0_req1_irqdispatch(struct pt_regs *regs)
irq = au_ffs(intc0_req1) - 1;
intc0_req1 &= ~(1<<irq);
#ifdef CONFIG_PM
if (irq == AU1000_TOY_MATCH2_INT) {
mask_and_ack_rise_edge_irq(irq);
counter0_irq(irq, NULL, regs);
local_enable_irq(irq);
}
else
#endif
{
do_IRQ(irq, regs);
}
do_IRQ(irq, regs);
}
......
......@@ -7,13 +7,15 @@
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/config.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx.h>
/* OHCI (USB full speed host controller) */
static struct resource au1xxx_usb_ohci_resources[] = {
[0] = {
.start = USB_OHCI_BASE,
......@@ -41,8 +43,252 @@ static struct platform_device au1xxx_usb_ohci_device = {
.resource = au1xxx_usb_ohci_resources,
};
/*** AU1100 LCD controller ***/
#ifdef CONFIG_FB_AU1100
static struct resource au1100_lcd_resources[] = {
[0] = {
.start = LCD_PHYS_ADDR,
.end = LCD_PHYS_ADDR + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1100_LCD_INT,
.end = AU1100_LCD_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 au1100_lcd_dmamask = ~(u32)0;
static struct platform_device au1100_lcd_device = {
.name = "au1100-lcd",
.id = 0,
.dev = {
.dma_mask = &au1100_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1100_lcd_resources),
.resource = au1100_lcd_resources,
};
#endif
#ifdef CONFIG_SOC_AU1200
/* EHCI (USB high speed host controller) */
static struct resource au1xxx_usb_ehci_resources[] = {
[0] = {
.start = USB_EHCI_BASE,
.end = USB_EHCI_BASE + USB_EHCI_LEN - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1000_USB_HOST_INT,
.end = AU1000_USB_HOST_INT,
.flags = IORESOURCE_IRQ,
},
};
static u64 ehci_dmamask = ~(u32)0;
static struct platform_device au1xxx_usb_ehci_device = {
.name = "au1xxx-ehci",
.id = 0,
.dev = {
.dma_mask = &ehci_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1xxx_usb_ehci_resources),
.resource = au1xxx_usb_ehci_resources,
};
/* Au1200 UDC (USB gadget controller) */
static struct resource au1xxx_usb_gdt_resources[] = {
[0] = {
.start = USB_UDC_BASE,
.end = USB_UDC_BASE + USB_UDC_LEN - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_USB_INT,
.end = AU1200_USB_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct resource au1xxx_mmc_resources[] = {
[0] = {
.start = SD0_PHYS_ADDR,
.end = SD0_PHYS_ADDR + 0x40,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = SD1_PHYS_ADDR,
.end = SD1_PHYS_ADDR + 0x40,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = AU1200_SD_INT,
.end = AU1200_SD_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 udc_dmamask = ~(u32)0;
static struct platform_device au1xxx_usb_gdt_device = {
.name = "au1xxx-udc",
.id = 0,
.dev = {
.dma_mask = &udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1xxx_usb_gdt_resources),
.resource = au1xxx_usb_gdt_resources,
};
/* Au1200 UOC (USB OTG controller) */
static struct resource au1xxx_usb_otg_resources[] = {
[0] = {
.start = USB_UOC_BASE,
.end = USB_UOC_BASE + USB_UOC_LEN - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_USB_INT,
.end = AU1200_USB_INT,
.flags = IORESOURCE_IRQ,
},
};
static u64 uoc_dmamask = ~(u32)0;
static struct platform_device au1xxx_usb_otg_device = {
.name = "au1xxx-uoc",
.id = 0,
.dev = {
.dma_mask = &uoc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1xxx_usb_otg_resources),
.resource = au1xxx_usb_otg_resources,
};
static struct resource au1200_lcd_resources[] = {
[0] = {
.start = LCD_PHYS_ADDR,
.end = LCD_PHYS_ADDR + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_LCD_INT,
.end = AU1200_LCD_INT,
.flags = IORESOURCE_IRQ,
}
};
static struct resource au1200_ide0_resources[] = {
[0] = {
.start = AU1XXX_ATA_PHYS_ADDR,
.end = AU1XXX_ATA_PHYS_ADDR + AU1XXX_ATA_PHYS_LEN,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1XXX_ATA_INT,
.end = AU1XXX_ATA_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 au1200_lcd_dmamask = ~(u32)0;
static struct platform_device au1200_lcd_device = {
.name = "au1200-lcd",
.id = 0,
.dev = {
.dma_mask = &au1200_lcd_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1200_lcd_resources),
.resource = au1200_lcd_resources,
};
static u64 ide0_dmamask = ~(u32)0;
static struct platform_device au1200_ide0_device = {
.name = "au1200-ide",
.id = 0,
.dev = {
.dma_mask = &ide0_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1200_ide0_resources),
.resource = au1200_ide0_resources,
};
static u64 au1xxx_mmc_dmamask = ~(u32)0;
static struct platform_device au1xxx_mmc_device = {
.name = "au1xxx-mmc",
.id = 0,
.dev = {
.dma_mask = &au1xxx_mmc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(au1xxx_mmc_resources),
.resource = au1xxx_mmc_resources,
};
#endif /* #ifdef CONFIG_SOC_AU1200 */
static struct platform_device au1x00_pcmcia_device = {
.name = "au1x00-pcmcia",
.id = 0,
};
#ifdef CONFIG_MIPS_DB1200
static struct resource smc91x_resources[] = {
[0] = {
.name = "smc91x-regs",
.start = AU1XXX_SMC91111_PHYS_ADDR,
.end = AU1XXX_SMC91111_PHYS_ADDR + 0xfffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1XXX_SMC91111_IRQ,
.end = AU1XXX_SMC91111_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device smc91x_device = {
.name = "smc91x",
.id = -1,
.num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources,
};
#endif
static struct platform_device *au1xxx_platform_devices[] __initdata = {
&au1xxx_usb_ohci_device,
&au1x00_pcmcia_device,
#ifdef CONFIG_FB_AU1100
&au1100_lcd_device,
#endif
#ifdef CONFIG_SOC_AU1200
#if 0 /* fixme */
&au1xxx_usb_ehci_device,
#endif
&au1xxx_usb_gdt_device,
&au1xxx_usb_otg_device,
&au1200_lcd_device,
&au1200_ide0_device,
&au1xxx_mmc_device,
#endif
#ifdef CONFIG_MIPS_DB1200
&smc91x_device,
#endif
};
int au1xxx_platform_init(void)
......
......@@ -34,11 +34,13 @@
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/jiffies.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_PM
......@@ -50,7 +52,7 @@
# define DPRINTK(fmt, args...)
#endif
static void calibrate_delay(void);
static void au1000_calibrate_delay(void);
extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
......@@ -260,7 +262,7 @@ int au_sleep(void)
}
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len)
void __user *buffer, size_t * len, loff_t *ppos)
{
int retval = 0;
#ifdef SLEEP_TEST_TIMEOUT
......@@ -294,10 +296,9 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
}
static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len)
void __user *buffer, size_t * len, loff_t *ppos)
{
int retval = 0;
void au1k_wait(void);
if (!write) {
*len = 0;
......@@ -306,7 +307,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
if (retval)
return retval;
suspend_mode = 1;
au1k_wait();
retval = pm_send_all(PM_RESUME, (void *) 0);
}
return retval;
......@@ -314,7 +315,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len)
void __user *buffer, size_t * len, loff_t *ppos)
{
int retval = 0, i;
unsigned long val, pll;
......@@ -409,14 +410,14 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
/* We don't want _any_ interrupts other than
* match20. Otherwise our calibrate_delay()
* match20. Otherwise our au1000_calibrate_delay()
* calculation will be off, potentially a lot.
*/
intc0_mask = save_local_and_disable(0);
intc1_mask = save_local_and_disable(1);
local_enable_irq(AU1000_TOY_MATCH2_INT);
spin_unlock_irqrestore(&pm_lock, flags);
calibrate_delay();
au1000_calibrate_delay();
restore_local_and_enable(0, intc0_mask);
restore_local_and_enable(1, intc1_mask);
return retval;
......@@ -456,7 +457,7 @@ __initcall(pm_init);
better than 1% */
#define LPS_PREC 8
static void calibrate_delay(void)
static void au1000_calibrate_delay(void)
{
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
......
......@@ -75,7 +75,8 @@ void prom_init_cmdline(void)
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
*cp = '\0';
if (prom_argc > 1)
*cp = '\0';
}
......
......@@ -39,7 +39,6 @@
#define TIMEOUT 0xffffff
#define SLOW_DOWN
static const char digits[16] = "0123456789abcdef";
static volatile unsigned long * const com1 = (unsigned long *)SERIAL_BASE;
......@@ -54,7 +53,7 @@ static inline void slow_down(void)
#endif
void
putch(const unsigned char c)
prom_putchar(const unsigned char c)
{
unsigned char ch;
int i = 0;
......@@ -69,77 +68,3 @@ putch(const unsigned char c)
} while (0 == (ch & TX_BUSY));
com1[SER_DATA] = c;
}
void
puts(unsigned char *cp)
{
unsigned char ch;
int i = 0;
while (*cp) {
do {
ch = com1[SER_CMD];
slow_down();
i++;
if (i>TIMEOUT) {
break;
}
} while (0 == (ch & TX_BUSY));
com1[SER_DATA] = *cp++;
}
putch('\r');
putch('\n');
}
void
fputs(const char *cp)
{
unsigned char ch;
int i = 0;
while (*cp) {
do {
ch = com1[SER_CMD];
slow_down();
i++;
if (i>TIMEOUT) {
break;
}
} while (0 == (ch & TX_BUSY));
com1[SER_DATA] = *cp++;
}
}
void
put64(uint64_t ul)
{
int cnt;
unsigned ch;
cnt = 16; /* 16 nibbles in a 64 bit long */
putch('0');
putch('x');
do {
cnt--;
ch = (unsigned char)(ul >> cnt * 4) & 0x0F;
putch(digits[ch]);
} while (cnt > 0);
}
void
put32(unsigned u)
{
int cnt;
unsigned ch;
cnt = 8; /* 8 nibbles in a 32 bit long */
putch('0');
putch('x');
do {
cnt--;
ch = (unsigned char)(u >> cnt * 4) & 0x0F;
putch(digits[ch]);
} while (cnt > 0);
}
......@@ -32,6 +32,7 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
......@@ -57,7 +58,7 @@ extern void au1xxx_time_init(void);
extern void au1xxx_timer_setup(struct irqaction *irq);
extern void set_cpuspec(void);
static int __init au1x00_setup(void)
void __init plat_setup(void)
{
struct cpu_spec *sp;
char *argptr;
......@@ -106,8 +107,6 @@ static int __init au1x00_setup(void)
/*strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");*/
#ifdef CONFIG_MIPS_HYDROGEN3
strcat(argptr, " video=au1100fb:panel:Hydrogen_3_NEC_panel_320x240,nohwcursor");
#else
strcat(argptr, " video=au1100fb:panel:s10,nohwcursor");
#endif
}
#endif
......@@ -153,15 +152,11 @@ static int __init au1x00_setup(void)
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
au_writel(0, SYS_TOYTRIM);
return 0;
}
early_initcall(au1x00_setup);
#if defined(CONFIG_64BIT_PHYS_ADDR)
/* This routine should be valid for all Au1x based boards */
phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size)
phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)
{
u32 start, end;
......@@ -192,4 +187,5 @@ phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size)
/* default nop */
return phys_addr;
}
EXPORT_SYMBOL(__fixup_bigphys_addr);
#endif
......@@ -50,7 +50,6 @@
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
extern void startup_match20_interrupt(void);
extern void do_softirq(void);
extern volatile unsigned long wall_jiffies;
unsigned long missed_heart_beats = 0;
......@@ -58,14 +57,17 @@ unsigned long missed_heart_beats = 0;
static unsigned long r4k_offset; /* Amount to increment compare reg each time */
static unsigned long r4k_cur; /* What counter should be at next timer irq */
int no_au1xxx_32khz;
void (*au1k_wait_ptr)(void);
extern int allow_au1k_wait; /* default off for CP0 Counter */
/* Cycle counter value at the previous timer interrupt.. */
static unsigned int timerhi = 0, timerlo = 0;
#ifdef CONFIG_PM
#define MATCH20_INC 328
extern void startup_match20_interrupt(void);
#if HZ < 100 || HZ > 1000
#error "unsupported HZ value! Must be in [100,1000]"
#endif
#define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */
extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *));
static unsigned long last_pc0, last_match20;
#endif
......@@ -117,17 +119,16 @@ void mips_timer_interrupt(struct pt_regs *regs)
}
#ifdef CONFIG_PM
void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long pc0;
int time_elapsed;
static int jiffie_drift = 0;
kstat.irqs[0][irq]++;
if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
/* should never happen! */
printk(KERN_WARNING "counter 0 w status eror\n");
return;
printk(KERN_WARNING "counter 0 w status error\n");
return IRQ_NONE;
}
pc0 = au_readl(SYS_TOYREAD);
......@@ -164,6 +165,8 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
update_process_times(user_mode(regs));
#endif
}
return IRQ_HANDLED;
}
/* When we wakeup from sleep, we have to "catch up" on all of the
......@@ -388,7 +391,6 @@ void au1xxx_timer_setup(struct irqaction *irq)
{
unsigned int est_freq;
extern unsigned long (*do_gettimeoffset)(void);
extern void au1k_wait(void);
printk("calculating r4koff... ");
r4k_offset = cal_r4koff();
......@@ -441,18 +443,18 @@ void au1xxx_timer_setup(struct irqaction *irq)
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
/* setup match20 to interrupt once every 10ms */
/* setup match20 to interrupt once every HZ */
last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
startup_match20_interrupt();
startup_match20_interrupt(counter0_irq);
do_gettimeoffset = do_fast_pm_gettimeoffset;
/* We can use the real 'wait' instruction.
*/
au1k_wait_ptr = au1k_wait;
allow_au1k_wait = 1;
}
#else
......
......@@ -1005,11 +1005,11 @@ process_ep0_receive (struct usb_dev* dev)
#endif
dev->ep0_stage = SETUP_STAGE;
break;
}
}
spin_unlock(&ep0->lock);
// we're done processing the packet, free it
kfree(pkt);
// we're done processing the packet, free it
kfree(pkt);
}
......@@ -1072,8 +1072,7 @@ dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs)
clear_dma_done1(ep0->indma);
pkt = send_packet_complete(ep0);
if (pkt)
kfree(pkt);
kfree(pkt);
}
/*
......@@ -1302,8 +1301,7 @@ usbdev_exit(void)
endpoint_flush(ep);
}
if (usbdev.full_conf_desc)
kfree(usbdev.full_conf_desc);
kfree(usbdev.full_conf_desc);
}
int
......
......@@ -35,7 +35,6 @@
#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
int prom_argc;
char **prom_argv, **prom_envp;
......
......@@ -48,6 +48,38 @@
#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_MIPS_DB1500
char irq_tab_alchemy[][5] __initdata = {
[12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - HPT371 */
[13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */
};
#endif
#ifdef CONFIG_MIPS_BOSPORUS
char irq_tab_alchemy[][5] __initdata = {
[11] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 11 - miniPCI */
[12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - SN1741 */
[13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */
};
#endif
#ifdef CONFIG_MIPS_MIRAGE
char irq_tab_alchemy[][5] __initdata = {
[11] = { -1, INTD, INTX, INTX, INTX}, /* IDSEL 11 - SMI VGX */
[12] = { -1, INTX, INTX, INTC, INTX}, /* IDSEL 12 - PNX1300 */
[13] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 13 - miniPCI */
};
#endif
#ifdef CONFIG_MIPS_DB1550
char irq_tab_alchemy[][5] __initdata = {
[11] = { -1, INTC, INTX, INTX, INTX}, /* IDSEL 11 - on-board HPT371 */
[12] = { -1, INTB, INTC, INTD, INTA}, /* IDSEL 12 - PCI slot 2 (left) */
[13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot 1 (right) */
};
#endif
au1xxx_irq_map_t au1xxx_irq_map[] = {
#ifndef CONFIG_MIPS_MIRAGE
......
......@@ -102,15 +102,15 @@ static struct {
} mirage_ts_cal =
{
#if 0
xscale: 84,
xtrans: -157,
yscale: 66,
ytrans: -150,
.xscale = 84,
.xtrans = -157,
.yscale = 66,
.ytrans = -150,
#else
xscale: 84,
xtrans: -150,
yscale: 66,
ytrans: -146,
.xscale = 84,
.xtrans = -150,
.yscale = 66,
.ytrans = -146,
#endif
};
......
......@@ -37,7 +37,6 @@
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
int prom_argc;
char **prom_argv, **prom_envp;
......
......@@ -33,7 +33,6 @@
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
......
......@@ -47,6 +47,17 @@
#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
char irq_tab_alchemy[][5] __initdata = {
[0] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 00 - AdapterA-Slot0 (top) */
[1] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
[2] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 02 - AdapterB-Slot0 (top) */
[3] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
[4] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 04 - AdapterC-Slot0 (top) */
[5] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
[6] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 06 - AdapterD-Slot0 (top) */
[7] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
};
au1xxx_irq_map_t au1xxx_irq_map[] = {
{ AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0},
{ AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 },
......
......@@ -65,5 +65,4 @@ void __init prom_init(void)
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
return 0;
}
#
# Makefile for the Alchemy Semiconductor PB1200 board.
#
lib-y := init.o board_setup.o irqmap.o
/*
*
* BRIEF MODULE DESCRIPTION
* Alchemy Pb1200/Db1200 board setup.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the 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/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/mc146818rtc.h>
#include <linux/delay.h>
#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
#include <linux/ide.h>
#endif
#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/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#ifdef CONFIG_MIPS_PB1200
#include <asm/mach-pb1x00/pb1200.h>
#endif
#ifdef CONFIG_MIPS_DB1200
#include <asm/mach-db1x00/db1200.h>
#define PB1200_ETH_INT DB1200_ETH_INT
#define PB1200_IDE_INT DB1200_IDE_INT
#endif
extern void _board_init_irq(void);
extern void (*board_init_irq)(void);
void board_reset (void)
{
bcsr->resets = 0;
bcsr->system = 0;
}
void __init board_setup(void)
{
char *argptr = NULL;
u32 pin_func;
#if 0
/* Enable PSC1 SYNC for AC97. Normaly done in audio driver,
* but it is board specific code, so put it here.
*/
pin_func = au_readl(SYS_PINFUNC);
au_sync();
pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
au_writel(pin_func, SYS_PINFUNC);
au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */
au_sync();
#endif
#if defined(CONFIG_I2C_AU1550)
{
u32 freq0, clksrc;
/* Select SMBUS in CPLD */
bcsr->resets &= ~(BCSR_RESETS_PCS0MUX);
pin_func = au_readl(SYS_PINFUNC);
au_sync();
pin_func &= ~(3<<17 | 1<<4);
/* Set GPIOs correctly */
pin_func |= 2<<17;
au_writel(pin_func, SYS_PINFUNC);
au_sync();
/* The i2c driver depends on 50Mhz clock */
freq0 = au_readl(SYS_FREQCTRL0);
au_sync();
freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1);
freq0 |= (3<<SYS_FC_FRDIV1_BIT);
/* 396Mhz / (3+1)*2 == 49.5Mhz */
au_writel(freq0, SYS_FREQCTRL0);
au_sync();
freq0 |= SYS_FC_FE1;
au_writel(freq0, SYS_FREQCTRL0);
au_sync();
clksrc = au_readl(SYS_CLKSRC);
au_sync();
clksrc &= ~0x01f00000;
/* bit 22 is EXTCLK0 for PSC0 */
clksrc |= (0x3 << 22);
au_writel(clksrc, SYS_CLKSRC);
au_sync();
}
#endif
#ifdef CONFIG_FB_AU1200
argptr = prom_getcmdline();
#ifdef CONFIG_MIPS_PB1200
strcat(argptr, " video=au1200fb:panel:bs");
#endif
#ifdef CONFIG_MIPS_DB1200
strcat(argptr, " video=au1200fb:panel:bs");
#endif
#endif
/* The Pb1200 development board uses external MUX for PSC0 to
support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
*/
#if defined(CONFIG_AU1XXX_PSC_SPI) && defined(CONFIG_I2C_AU1550)
#error I2C and SPI are mutually exclusive. Both are physically connected to PSC0.\
Refer to Pb1200/Db1200 documentation.
#elif defined( CONFIG_AU1XXX_PSC_SPI )
bcsr->resets |= BCSR_RESETS_PCS0MUX;
/*Hard Coding Value to enable Temp Sensors [bit 14] Value for SOC Au1200. Pls refer documentation*/
bcsr->resets =0x900f;
#elif defined( CONFIG_I2C_AU1550 )
bcsr->resets &= (~BCSR_RESETS_PCS0MUX);
#endif
au_sync();
#ifdef CONFIG_MIPS_PB1200
printk("AMD Alchemy Pb1200 Board\n");
#endif
#ifdef CONFIG_MIPS_DB1200
printk("AMD Alchemy Db1200 Board\n");
#endif
/* Setup Pb1200 External Interrupt Controller */
{
extern void (*board_init_irq)(void);
extern void _board_init_irq(void);
board_init_irq = _board_init_irq;
}
}
int
board_au1200fb_panel (void)
{
BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
int p;
p = bcsr->switches;
p >>= 8;
p &= 0x0F;
return p;
}
int
board_au1200fb_panel_init (void)
{
/* Apply power */
BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
bcsr->board |= (BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
/*printk("board_au1200fb_panel_init()\n"); */
return 0;
}
int
board_au1200fb_panel_shutdown (void)
{
/* Remove power */
BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
/*printk("board_au1200fb_panel_shutdown()\n"); */
return 0;
}
/*
*
* BRIEF MODULE DESCRIPTION
* PB1200 board setup
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS 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/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
int prom_argc;
char **prom_argv, **prom_envp;
extern void __init prom_init_cmdline(void);
extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
return "Alchemy Pb1200";
}
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_machgroup = MACH_GROUP_ALCHEMY;
mips_machtype = MACH_PB1200;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x08000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
/*
* BRIEF MODULE DESCRIPTION
* Au1xxx irq map table
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the 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/config.h>
#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 <asm/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
#ifdef CONFIG_MIPS_PB1200
#include <asm/mach-pb1x00/pb1200.h>
#endif
#ifdef CONFIG_MIPS_DB1200
#include <asm/mach-db1x00/db1200.h>
#define PB1200_INT_BEGIN DB1200_INT_BEGIN
#define PB1200_INT_END DB1200_INT_END
#endif
au1xxx_irq_map_t au1xxx_irq_map[] = {
{ AU1000_GPIO_7, INTC_INT_LOW_LEVEL, 0 }, // This is exteranl interrupt cascade
};
int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
/*
* Support for External interrupts on the PbAu1200 Development platform.
*/
static volatile int pb1200_cascade_en=0;
irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs)
{
unsigned short bisr = bcsr->int_status;
int extirq_nr = 0;
/* Clear all the edge interrupts. This has no effect on level */
bcsr->int_status = bisr;
for( ; bisr; bisr &= (bisr-1) )
{
extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr);
/* Ack and dispatch IRQ */
do_IRQ(extirq_nr,regs);
}
return IRQ_RETVAL(1);
}
inline void pb1200_enable_irq(unsigned int irq_nr)
{
bcsr->intset_mask = 1<<(irq_nr - PB1200_INT_BEGIN);
bcsr->intset = 1<<(irq_nr - PB1200_INT_BEGIN);
}
inline void pb1200_disable_irq(unsigned int irq_nr)
{
bcsr->intclr_mask = 1<<(irq_nr - PB1200_INT_BEGIN);
bcsr->intclr = 1<<(irq_nr - PB1200_INT_BEGIN);
}
static unsigned int pb1200_startup_irq( unsigned int irq_nr )
{
if (++pb1200_cascade_en == 1)
{
request_irq(AU1000_GPIO_7, &pb1200_cascade_handler,
0, "Pb1200 Cascade", (void *)&pb1200_cascade_handler );
#ifdef CONFIG_MIPS_PB1200
/* We have a problem with CPLD rev3. Enable a workaround */
if( ((bcsr->whoami & BCSR_WHOAMI_CPLD)>>4) <= 3)
{
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("Pb1200 must be at CPLD rev4. Please have Pb1200\n");
printk("updated to latest revision. This software will not\n");
printk("work on anything less than CPLD rev4\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
printk("\nWARNING!!!\n");
while(1);
}
#endif
}
pb1200_enable_irq(irq_nr);
return 0;
}
static void pb1200_shutdown_irq( unsigned int irq_nr )
{
pb1200_disable_irq(irq_nr);
if (--pb1200_cascade_en == 0)
{
free_irq(AU1000_GPIO_7,&pb1200_cascade_handler );
}
return;
}
static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr)
{
pb1200_disable_irq( irq_nr );
}
static void pb1200_end_irq(unsigned int irq_nr)
{
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
pb1200_enable_irq(irq_nr);
}
}
static struct hw_interrupt_type external_irq_type =
{
#ifdef CONFIG_MIPS_PB1200
"Pb1200 Ext",
#endif
#ifdef CONFIG_MIPS_DB1200
"Db1200 Ext",
#endif
pb1200_startup_irq,
pb1200_shutdown_irq,
pb1200_enable_irq,
pb1200_disable_irq,
pb1200_mask_and_ack_irq,
pb1200_end_irq,
NULL
};
void _board_init_irq(void)
{
int irq_nr;
for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
{
irq_desc[irq_nr].handler = &external_irq_type;
pb1200_disable_irq(irq_nr);
}
/* GPIO_7 can not be hooked here, so it is hooked upon first
request of any source attached to the cascade */
}
......@@ -47,6 +47,11 @@
#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
char irq_tab_alchemy[][5] __initdata = {
[12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - HPT370 */
[13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */
};
au1xxx_irq_map_t au1xxx_irq_map[] = {
{ AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0},
{ AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 },
......
......@@ -47,6 +47,11 @@
#include <asm/system.h>
#include <asm/mach-au1x00/au1000.h>
char irq_tab_alchemy[][5] __initdata = {
[12] = { -1, INTB, INTC, INTD, INTA}, /* IDSEL 12 - PCI slot 2 (left) */
[13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot 1 (right) */
};
au1xxx_irq_map_t au1xxx_irq_map[] = {
{ AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 },
{ AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 },
......
......@@ -33,6 +33,9 @@ vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX)
$(obj)/elf2ecoff: $(obj)/elf2ecoff.c
$(HOSTCC) -o $@ $^
vmlinux.bin: $(VMLINUX)
$(OBJCOPY) -O binary $(strip-flags) $(VMLINUX) $(obj)/vmlinux.bin
vmlinux.srec: $(VMLINUX)
$(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $(obj)/vmlinux.srec
......@@ -45,5 +48,6 @@ archhelp:
clean-files += addinitrd \
elf2ecoff \
vmlinux.bin \
vmlinux.ecoff \
vmlinux.srec
......@@ -2,6 +2,6 @@
# Makefile for the Cobalt micro systems family specific parts of the kernel
#
obj-y := irq.o int-handler.o reset.o setup.o promcon.o
obj-y := irq.o int-handler.o reset.o setup.o
EXTRA_AFLAGS := $(CFLAGS)
......@@ -18,8 +18,8 @@
SAVE_ALL
CLI
la ra, ret_from_irq
move a1, sp
PTR_LA ra, ret_from_irq
move a0, sp
j cobalt_irq
END(cobalt_handle_int)
......@@ -10,6 +10,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
......@@ -25,8 +27,8 @@ extern void cobalt_handle_int(void);
* the CPU interrupt lines, and ones that come in on the via chip. The CPU
* mappings are:
*
* 16, - Software interrupt 0 (unused) IE_SW0
* 17 - Software interrupt 1 (unused) IE_SW0
* 16 - Software interrupt 0 (unused) IE_SW0
* 17 - Software interrupt 1 (unused) IE_SW1
* 18 - Galileo chip (timer) IE_IRQ0
* 19 - Tulip 0 + NCR SCSI IE_IRQ1
* 20 - Tulip 1 IE_IRQ2
......@@ -42,61 +44,94 @@ extern void cobalt_handle_int(void);
* 15 - IDE1
*/
asmlinkage void cobalt_irq(struct pt_regs *regs)
static inline void galileo_irq(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & CAUSEF_IP2) { /* int 18 */
unsigned long irq_src = GALILEO_INL(GT_INTRCAUSE_OFS);
/* Check for timer irq ... */
if (irq_src & GALILEO_T0EXP) {
/* Clear the int line */
GALILEO_OUTL(0, GT_INTRCAUSE_OFS);
do_IRQ(COBALT_TIMER_IRQ, regs);
}
return;
}
unsigned int mask, pending, devfn;
if (pending & CAUSEF_IP6) { /* int 22 */
int irq = i8259_irq();
mask = GALILEO_INL(GT_INTRMASK_OFS);
pending = GALILEO_INL(GT_INTRCAUSE_OFS) & mask;
if (irq >= 0)
do_IRQ(irq, regs);
return;
}
if (pending & GALILEO_INTR_T0EXP) {
if (pending & CAUSEF_IP3) { /* int 19 */
do_IRQ(COBALT_ETH0_IRQ, regs);
return;
}
GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS);
do_IRQ(COBALT_GALILEO_IRQ, regs);
if (pending & CAUSEF_IP4) { /* int 20 */
do_IRQ(COBALT_ETH1_IRQ, regs);
return;
}
} else if (pending & GALILEO_INTR_RETRY_CTR) {
if (pending & CAUSEF_IP5) { /* int 21 */
do_IRQ(COBALT_SERIAL_IRQ, regs);
return;
}
devfn = GALILEO_INL(GT_PCI0_CFGADDR_OFS) >> 8;
GALILEO_OUTL(~GALILEO_INTR_RETRY_CTR, GT_INTRCAUSE_OFS);
printk(KERN_WARNING "Galileo: PCI retry count exceeded (%02x.%u)\n",
PCI_SLOT(devfn), PCI_FUNC(devfn));
} else {
if (pending & CAUSEF_IP7) { /* int 23 */
do_IRQ(COBALT_QUBE_SLOT_IRQ, regs);
return;
GALILEO_OUTL(mask & ~pending, GT_INTRMASK_OFS);
printk(KERN_WARNING "Galileo: masking unexpected interrupt %08x\n", pending);
}
}
static inline void via_pic_irq(struct pt_regs *regs)
{
int irq;
irq = i8259_irq();
if (irq >= 0)
do_IRQ(irq, regs);
}
asmlinkage void cobalt_irq(struct pt_regs *regs)
{
unsigned pending;
pending = read_c0_status() & read_c0_cause();
if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */
galileo_irq(regs);
else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */
via_pic_irq(regs);
else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */
do_IRQ(COBALT_CPU_IRQ + 3, regs);
else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */
do_IRQ(COBALT_CPU_IRQ + 4, regs);
else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */
do_IRQ(COBALT_CPU_IRQ + 5, regs);
else if (pending & CAUSEF_IP7) /* IRQ 23 */
do_IRQ(COBALT_CPU_IRQ + 7, regs);
}
static struct irqaction irq_via = {
no_action, 0, { { 0, } }, "cascade", NULL, NULL
};
void __init arch_init_irq(void)
{
/*
* Mask all Galileo interrupts. The Galileo
* handler is set in cobalt_timer_setup()
*/
GALILEO_OUTL(0, GT_INTRMASK_OFS);
set_except_vector(0, cobalt_handle_int);
init_i8259_irqs(); /* 0 ... 15 */
mips_cpu_irq_init(16); /* 16 ... 23 */
mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */
/*
* Mask all cpu interrupts
* (except IE4, we already masked those at VIA level)
*/
change_c0_status(ST0_IM, IE_IRQ4);
setup_irq(COBALT_VIA_IRQ, &irq_via);
}
/*
* PROM console for Cobalt Raq2
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
* Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
*
*/
#include <linux/init.h>
#include <linux/console.h>
#include <linux/kdev_t.h>
#include <linux/serial_reg.h>
#include <asm/delay.h>
#include <asm/serial.h>
#include <asm/io.h>
static unsigned long port = 0xc800000;
static __inline__ void ns16550_cons_put_char(char ch, unsigned long ioaddr)
{
char lsr;
do {
lsr = inb(ioaddr + UART_LSR);
} while ((lsr & (UART_LSR_TEMT | UART_LSR_THRE)) != (UART_LSR_TEMT | UART_LSR_THRE));
outb(ch, ioaddr + UART_TX);
}
static __inline__ char ns16550_cons_get_char(unsigned long ioaddr)
{
while ((inb(ioaddr + UART_LSR) & UART_LSR_DR) == 0)
udelay(1);
return inb(ioaddr + UART_RX);
}
void ns16550_console_write(struct console *co, const char *s, unsigned count)
{
char lsr, ier;
unsigned i;
ier = inb(port + UART_IER);
outb(0x00, port + UART_IER);
for (i=0; i < count; i++, s++) {
if(*s == '\n')
ns16550_cons_put_char('\r', port);
ns16550_cons_put_char(*s, port);
}
do {
lsr = inb(port + UART_LSR);
} while ((lsr & (UART_LSR_TEMT | UART_LSR_THRE)) != (UART_LSR_TEMT | UART_LSR_THRE));
outb(ier, port + UART_IER);
}
char getDebugChar(void)
{
return ns16550_cons_get_char(port);
}
void putDebugChar(char kgdb_char)
{
ns16550_cons_put_char(kgdb_char, port);
}
static struct console ns16550_console = {
.name = "prom",
.setup = NULL,
.write = ns16550_console_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
static int __init ns16550_setup_console(void)
{
register_console(&ns16550_console);
return 0;
}
console_initcall(ns16550_setup_console);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
config DDB5477_BUS_FREQUENCY
int "bus frequency (in kHZ, 0 for auto-detect)"
depends on DDB5477
default 0
......@@ -209,14 +209,13 @@ static void nile4_irq_end(unsigned int irq) {
#define nile4_irq_shutdown nile4_disable_irq
static hw_irq_controller nile4_irq_controller = {
"nile4",
nile4_irq_startup,
nile4_irq_shutdown,
nile4_enable_irq,
nile4_disable_irq,
nile4_ack_irq,
nile4_irq_end,
NULL
.typename = "nile4",
.startup = nile4_irq_startup,
.shutdown = nile4_irq_shutdown,
.enable = nile4_enable_irq,
.disable = nile4_disable_irq,
.ack = nile4_ack_irq,
.end = nile4_irq_end,
};
void nile4_irq_setup(u32 base) {
......
......@@ -85,7 +85,7 @@ static void __init ddb_time_init(void)
static void __init ddb5074_setup(void)
void __init plat_setup(void)
{
set_io_port_base(NILE4_PCI_IO_BASE);
isa_slot_offset = NILE4_PCI_MEM_BASE;
......@@ -106,8 +106,6 @@ static void __init ddb5074_setup(void)
panic_timeout = 180;
}
early_initcall(ddb5074_setup);
#define USE_NILE4_SERIAL 0
#if USE_NILE4_SERIAL
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册