diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/mips')
658 files changed, 138221 insertions, 0 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig new file mode 100644 index 00000000000..5e666aad881 --- /dev/null +++ b/arch/mips/Kconfig @@ -0,0 +1,1658 @@ +config MIPS + bool + default y + # Horrible source of confusion. Die, die, die ... + select EMBEDDED + +config MIPS64 + bool "64-bit kernel" + help + Select this option if you want to build a 64-bit kernel. You should + only select this option if you have hardware that actually has a + 64-bit processor and if your application will actually benefit from + 64-bit processing, otherwise say N. You must say Y for kernels for + SGI IP27 (Origin 200 and 2000) and SGI IP32 (O2). If in doubt say N. + +config 64BIT + def_bool MIPS64 + +config MIPS32 + bool + depends on MIPS64 = 'n' + default y + +mainmenu "Linux/MIPS Kernel Configuration" + +source "init/Kconfig" + +menu "Machine selection" + +config MACH_JAZZ + bool "Support for the Jazz family of machines" + select ARC + select ARC32 + select GENERIC_ISA_DMA + select I8259 + select ISA + help + This a family of machines based on the MIPS R4030 chipset which was + used by several vendors to build RISC/os and Windows NT workstations. + Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and + Olivetti M700-10 workstations. + +config ACER_PICA_61 + bool "Support for Acer PICA 1 chipset (EXPERIMENTAL)" + depends on MACH_JAZZ && EXPERIMENTAL + select DMA_NONCOHERENT + help + This is a machine with a R4400 133/150 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux on + the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + <http://www.linux-mips.org/>. + +config MIPS_MAGNUM_4000 + bool "Support for MIPS Magnum 4000" + depends on MACH_JAZZ + select DMA_NONCOHERENT + help + This is a machine with a R4000 100 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux on + the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + <http://www.linux-mips.org/>. + +config OLIVETTI_M700 + bool "Support for Olivetti M700-10" + depends on MACH_JAZZ + select DMA_NONCOHERENT + help + This is a machine with a R4000 100 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux on + the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + <http://www.linux-mips.org/>. + +config MACH_VR41XX + bool "Support for NEC VR41XX-based machines" + +config NEC_CMBVR4133 + bool "Support for NEC CMB-VR4133" + depends on MACH_VR41XX + select CPU_VR41XX + select DMA_NONCOHERENT + select IRQ_CPU + select HW_HAS_PCI + select PCI_VR41XX + +config ROCKHOPPER + bool "Support for Rockhopper baseboard" + depends on NEC_CMBVR4133 + select I8259 + select HAVE_STD_PC_SERIAL_PORT + +config CASIO_E55 + bool "Support for CASIO CASSIOPEIA E-10/15/55/65" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select IRQ_CPU + select ISA + +config IBM_WORKPAD + bool "Support for IBM WorkPad z50" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select IRQ_CPU + select ISA + +config TANBAC_TB0226 + bool "Support for TANBAC TB0226 (Mbase)" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + help + The TANBAC TB0226 (Mbase) is a MIPS-based platform manufactured by TANBAC. + Please refer to <http://www.tanbac.co.jp/> about Mbase. + +config TANBAC_TB0229 + bool "Support for TANBAC TB0229 (VR4131DIMM)" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + help + The TANBAC TB0229 (VR4131DIMM) is a MIPS-based platform manufactured by TANBAC. + Please refer to <http://www.tanbac.co.jp/> about VR4131DIMM. + +config VICTOR_MPC30X + bool "Support for Victor MP-C303/304" + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + depends on MACH_VR41XX + +config ZAO_CAPCELLA + bool "Support for ZAO Networks Capcella" + depends on MACH_VR41XX + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + +config PCI_VR41XX + bool "Add PCI control unit support of NEC VR4100 series" + depends on MACH_VR41XX && PCI + +config VRC4171 + tristate "Add NEC VRC4171 companion chip support" + depends on MACH_VR41XX && ISA + ---help--- + The NEC VRC4171/4171A is a companion chip for NEC VR4111/VR4121. + +config VRC4173 + tristate "Add NEC VRC4173 companion chip support" + depends on MACH_VR41XX && PCI_VR41XX + ---help--- + The NEC VRC4173 is a companion chip for NEC VR4122/VR4131. + +config TOSHIBA_JMR3927 + bool "Support for Toshiba JMR-TX3927 board" + depends on MIPS32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select SWAP_IO_SPACE + +config MIPS_COBALT + bool "Support for Cobalt Server (EXPERIMENTAL)" + depends on EXPERIMENTAL + select DMA_NONCOHERENT + select HW_HAS_PCI + select I8259 + select IRQ_CPU + +config MACH_DECSTATION + bool "Support for DECstations" + select BOOT_ELF32 + select DMA_NONCOHERENT + select IRQ_CPU + depends on MIPS32 || EXPERIMENTAL + ---help--- + This enables support for DEC's MIPS based workstations. For details + see the Linux/MIPS FAQ on <http://www.linux-mips.org/> and the + DECstation porting pages on <http://decstation.unix-ag.org/>. + + If you have one of the following DECstation Models you definitely + want to choose R4xx0 for the CPU Type: + + DECstation 5000/50 + DECstation 5000/150 + DECstation 5000/260 + DECsystem 5900/260 + + otherwise choose R3000. + +config MIPS_EV64120 + bool "Support for Galileo EV64120 Evaluation board (EXPERIMENTAL)" + depends on EXPERIMENTAL + select DMA_NONCOHERENT + select HW_HAS_PCI + select MIPS_GT64120 + help + This is an evaluation board based on the Galileo GT-64120 + single-chip system controller that contains a MIPS R5000 compatible + core running at 75/100MHz. Their website is located at + <http://www.marvell.com/>. Say Y here if you wish to build a + kernel for this platform. + +config EVB_PCI1 + bool "Enable Second PCI (PCI1)" + depends on MIPS_EV64120 + +config MIPS_EV96100 + bool "Support for Galileo EV96100 Evaluation board (EXPERIMENTAL)" + depends on EXPERIMENTAL + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select MIPS_GT96100 + select RM7000_CPU_SCACHE + select SWAP_IO_SPACE + help + This is an evaluation board based on the Galileo GT-96100 LAN/WAN + communications controllers containing a MIPS R5000 compatible core + running at 83MHz. Their website is <http://www.marvell.com/>. Say Y + here if you wish to build a kernel for this platform. + +config MIPS_IVR + bool "Support for Globespan IVR board" + select DMA_NONCOHERENT + select HW_HAS_PCI + help + This is an evaluation board built by Globespan to showcase thir + iVR (Internet Video Recorder) design. It utilizes a QED RM5231 + R5000 MIPS core. More information can be found out their website + located at <http://www.globespan.net/>. Say Y here if you wish to + build a kernel for this platform. + +config LASAT + bool "Support for LASAT Networks platforms" + select DMA_NONCOHERENT + select HW_HAS_PCI + select MIPS_GT64120 + select R5000_CPU_SCACHE + +config PICVUE + tristate "PICVUE LCD display driver" + depends on LASAT + +config PICVUE_PROC + tristate "PICVUE LCD display driver /proc interface" + depends on PICVUE + +config DS1603 + bool "DS1603 RTC driver" + depends on LASAT + +config LASAT_SYSCTL + bool "LASAT sysctl interface" + depends on LASAT + +config MIPS_ITE8172 + bool "Support for ITE 8172G board" + select DMA_NONCOHERENT + select HW_HAS_PCI + help + Ths is an evaluation board made by ITE <http://www.ite.com.tw/> + with ATX form factor that utilizes a MIPS R5000 to work with its + ITE8172G companion internet appliance chip. The MIPS core can be + either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build + a kernel for this platform. + +config IT8172_REVC + bool "Support for older IT8172 (Rev C)" + depends on MIPS_ITE8172 + help + Say Y here to support the older, Revision C version of the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the + board at <http://www.mvista.com/partners/semiconductor/ite.html>. + +config MIPS_ATLAS + bool "Support for MIPS Atlas board" + select BOOT_ELF32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select MIPS_GT64120 + select SWAP_IO_SPACE + help + This enables support for the QED R5231-based MIPS Atlas evaluation + board. + +config MIPS_MALTA + bool "Support for MIPS Malta board" + select BOOT_ELF32 + select HAVE_STD_PC_SERIAL_PORT + select DMA_NONCOHERENT + select GENERIC_ISA_DMA + select HW_HAS_PCI + select I8259 + select MIPS_GT64120 + select SWAP_IO_SPACE + help + This enables support for the VR5000-based MIPS Malta evaluation + board. + +config MIPS_SEAD + bool "Support for MIPS SEAD board (EXPERIMENTAL)" + depends on EXPERIMENTAL + select IRQ_CPU + select DMA_NONCOHERENT + +config MOMENCO_OCELOT + bool "Support for Momentum Ocelot board" + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_CPU_RM7K + select MIPS_GT64120 + select RM7000_CPU_SCACHE + select SWAP_IO_SPACE + help + The Ocelot is a MIPS-based Single Board Computer (SBC) made by + Momentum Computer <http://www.momenco.com/>. + +config MOMENCO_OCELOT_G + bool "Support for Momentum Ocelot-G board" + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_CPU_RM7K + select PCI_MARVELL + select RM7000_CPU_SCACHE + select SWAP_IO_SPACE + help + The Ocelot is a MIPS-based Single Board Computer (SBC) made by + Momentum Computer <http://www.momenco.com/>. + +config MOMENCO_OCELOT_C + bool "Support for Momentum Ocelot-C board" + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_MV64340 + select PCI_MARVELL + select RM7000_CPU_SCACHE + select SWAP_IO_SPACE + help + The Ocelot is a MIPS-based Single Board Computer (SBC) made by + Momentum Computer <http://www.momenco.com/>. + +config MOMENCO_OCELOT_3 + bool "Support for Momentum Ocelot-3 board" + select BOOT_ELF32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_CPU_RM7K + select IRQ_MV64340 + select PCI_MARVELL + select RM7000_CPU_SCACHE + select SWAP_IO_SPACE + help + The Ocelot-3 is based off Discovery III System Controller and + PMC-Sierra Rm79000 core. + +config MOMENCO_JAGUAR_ATX + bool "Support for Momentum Jaguar board" + select BOOT_ELF32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_CPU_RM7K + select IRQ_MV64340 + select LIMITED_DMA + select PCI_MARVELL + select RM7000_CPU_SCACHE + select SWAP_IO_SPACE + help + The Jaguar ATX is a MIPS-based Single Board Computer (SBC) made by + Momentum Computer <http://www.momenco.com/>. + +config JAGUAR_DMALOW + bool "Low DMA Mode" + depends on MOMENCO_JAGUAR_ATX + help + Select to Y if jump JP5 is set on your board, N otherwise. Normally + the jumper is set, so if you feel unsafe, just say Y. + +config PMC_YOSEMITE + bool "Support for PMC-Sierra Yosemite eval board" + select DMA_COHERENT + select HW_HAS_PCI + select IRQ_CPU + select IRQ_CPU_RM7K + select IRQ_CPU_RM9K + select SWAP_IO_SPACE + help + Yosemite is an evaluation board for the RM9000x2 processor + manufactured by PMC-Sierra + +config HYPERTRANSPORT + bool "Hypertransport Support for PMC-Sierra Yosemite" + depends on PMC_YOSEMITE + +config DDB5074 + bool "Support for NEC DDB Vrc-5074 (EXPERIMENTAL)" + depends on EXPERIMENTAL + select DMA_NONCOHERENT + select HAVE_STD_PC_SERIAL_PORT + select HW_HAS_PCI + select IRQ_CPU + select I8259 + select ISA + help + This enables support for the VR5000-based NEC DDB Vrc-5074 + evaluation board. + +config DDB5476 + bool "Support for NEC DDB Vrc-5476" + select DMA_NONCOHERENT + select HAVE_STD_PC_SERIAL_PORT + select HW_HAS_PCI + select IRQ_CPU + select I8259 + select ISA + help + This enables support for the R5432-based NEC DDB Vrc-5476 + evaluation board. + + Features : kernel debugging, serial terminal, NFS root fs, on-board + ether port USB, AC97, PCI, PCI VGA card & framebuffer console, + IDE controller, PS2 keyboard, PS2 mouse, etc. + +config DDB5477 + bool "Support for NEC DDB Vrc-5477" + select DMA_NONCOHERENT + select HW_HAS_PCI + select I8259 + select IRQ_CPU + help + This enables support for the R5432-based NEC DDB Vrc-5477, + or Rockhopper/SolutionGear boards with R5432/R5500 CPUs. + + Features : kernel debugging, serial terminal, NFS root fs, on-board + ether port USB, AC97, PCI, etc. + +config DDB5477_BUS_FREQUENCY + int "bus frequency (in kHZ, 0 for auto-detect)" + depends on DDB5477 + default 0 + +config NEC_OSPREY + bool "Support for NEC Osprey board" + select DMA_NONCOHERENT + select IRQ_CPU + +config SGI_IP22 + bool "Support for SGI IP22 (Indy/Indigo2)" + select ARC + select ARC32 + select BOOT_ELF32 + select DMA_NONCOHERENT + select IP22_CPU_SCACHE + select IRQ_CPU + select SWAP_IO_SPACE + help + This are the SGI Indy, Challenge S and Indigo2, as well as certain + OEM variants like the Tandem CMN B006S. To compile a Linux kernel + that runs on these, say Y here. + +config SGI_IP27 + bool "Support for SGI IP27 (Origin200/2000)" + depends on MIPS64 + select ARC + select ARC64 + select DMA_IP27 + select HW_HAS_PCI + select PCI_DOMAINS + help + This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics + workstations. To compile a Linux kernel that runs on these, say Y + here. + +#config SGI_SN0_XXL +# bool "IP27 XXL" +# depends on SGI_IP27 +# This options adds support for userspace processes upto 16TB size. +# Normally the limit is just .5TB. + +config SGI_SN0_N_MODE + bool "IP27 N-Mode" + depends on SGI_IP27 + help + The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be + configured in either N-Modes which allows for more nodes or M-Mode + which allows for more memory. Your system is most probably + running in M-Mode, so you should say N here. + +config DISCONTIGMEM + bool + default y if SGI_IP27 + help + Say Y to upport efficient handling of discontiguous physical memory, + for architectures which are either NUMA (Non-Uniform Memory Access) + or have huge holes in the physical address space for other reasons. + See <file:Documentation/vm/numa> for more. + +config NUMA + bool "NUMA Support" + depends on SGI_IP27 + help + Say Y to compile the kernel to support NUMA (Non-Uniform Memory + Access). This option is for configuring high-end multiprocessor + server machines. If in doubt, say N. + +config MAPPED_KERNEL + bool "Mapped kernel support" + depends on SGI_IP27 + help + Change the way a Linux kernel is loaded into memory on a MIPS64 + machine. This is required in order to support text replication and + NUMA. If you need to understand it, read the source code. + +config REPLICATE_KTEXT + bool "Kernel text replication support" + depends on SGI_IP27 + help + Say Y here to enable replicating the kernel text across multiple + nodes in a NUMA cluster. This trades memory for speed. + +config REPLICATE_EXHANDLERS + bool "Exception handler replication support" + depends on SGI_IP27 + help + Say Y here to enable replicating the kernel exception handlers + across multiple nodes in a NUMA cluster. This trades memory for + speed. + +config SGI_IP32 + bool "Support for SGI IP32 (O2) (EXPERIMENTAL)" + depends on MIPS64 && EXPERIMENTAL + select ARC + select ARC32 + select BOOT_ELF32 + select OWN_DMA + select DMA_IP32 + select DMA_NONCOHERENT + select HW_HAS_PCI + select R5000_CPU_SCACHE + select RM7000_CPU_SCACHE + help + If you want this kernel to run on SGI O2 workstation, say Y here. + +config SOC_AU1X00 + depends on MIPS32 + bool "Support for AMD/Alchemy Au1X00 SOCs" + +choice + prompt "Au1X00 SOC Type" + depends on SOC_AU1X00 + help + Say Y here to enable support for one of three AMD/Alchemy + SOCs. For additional documentation see www.amd.com. + +config SOC_AU1000 + bool "SOC_AU1000" +config SOC_AU1100 + bool "SOC_AU1100" +config SOC_AU1500 + bool "SOC_AU1500" +config SOC_AU1550 + bool "SOC_AU1550" + +endchoice + +choice + prompt "AMD/Alchemy Au1x00 board support" + depends on SOC_AU1X00 + help + These are evaluation boards built by AMD/Alchemy to + showcase their Au1X00 Internet Edge Processors. The SOC design + is based on the MIPS32 architecture running at 266/400/500MHz + with many integrated peripherals. Further information can be + found at their website, <http://www.amd.com/>. Say Y here if you + wish to build a kernel for this platform. + +config MIPS_PB1000 + bool "PB1000 board" + depends on SOC_AU1000 + select DMA_NONCOHERENT + select HW_HAS_PCI + select SWAP_IO_SPACE + +config MIPS_PB1100 + bool "PB1100 board" + depends on SOC_AU1100 + select DMA_NONCOHERENT + select HW_HAS_PCI + select SWAP_IO_SPACE + +config MIPS_PB1500 + bool "PB1500 board" + depends on SOC_AU1500 + select DMA_COHERENT + select HW_HAS_PCI + +config MIPS_PB1550 + bool "PB1550 board" + depends on SOC_AU1550 + select DMA_COHERENT + select HW_HAS_PCI + select MIPS_DISABLE_OBSOLETE_IDE + +config MIPS_DB1000 + bool "DB1000 board" + depends on SOC_AU1000 + select DMA_NONCOHERENT + select HW_HAS_PCI + +config MIPS_DB1100 + bool "DB1100 board" + depends on SOC_AU1100 + select DMA_NONCOHERENT + +config MIPS_DB1500 + bool "DB1500 board" + depends on SOC_AU1500 + select DMA_COHERENT + select HW_HAS_PCI + select MIPS_DISABLE_OBSOLETE_IDE + +config MIPS_DB1550 + bool "DB1550 board" + depends on SOC_AU1550 + select HW_HAS_PCI + select DMA_COHERENT + select MIPS_DISABLE_OBSOLETE_IDE + +config MIPS_BOSPORUS + bool "Bosporus board" + depends on SOC_AU1500 + select DMA_NONCOHERENT + +config MIPS_MIRAGE + bool "Mirage board" + depends on SOC_AU1500 + select DMA_NONCOHERENT + +config MIPS_XXS1500 + bool "MyCable XXS1500 board" + depends on SOC_AU1500 + select DMA_NONCOHERENT + +config MIPS_MTX1 + bool "4G Systems MTX-1 board" + depends on SOC_AU1500 + select HW_HAS_PCI + select DMA_NONCOHERENT + +endchoice + +config SIBYTE_SB1xxx_SOC + bool "Support for Broadcom BCM1xxx SOCs (EXPERIMENTAL)" + depends on EXPERIMENTAL + select BOOT_ELF32 + select DMA_COHERENT + select SWAP_IO_SPACE + +choice + prompt "BCM1xxx SOC-based board" + depends on SIBYTE_SB1xxx_SOC + default SIBYTE_SWARM + help + Enable support for boards based on the SiByte line of SOCs + from Broadcom. There are configurations for the known + evaluation boards, or you can choose "Other" and add your + own board support code. + +config SIBYTE_SWARM + bool "BCM91250A-SWARM" + select SIBYTE_SB1250 + +config SIBYTE_SENTOSA + bool "BCM91250E-Sentosa" + select SIBYTE_SB1250 + +config SIBYTE_RHONE + bool "BCM91125E-Rhone" + select SIBYTE_BCM1125H + +config SIBYTE_CARMEL + bool "BCM91120x-Carmel" + select SIBYTE_BCM1120 + +config SIBYTE_PTSWARM + bool "BCM91250PT-PTSWARM" + select SIBYTE_SB1250 + +config SIBYTE_LITTLESUR + bool "BCM91250C2-LittleSur" + select SIBYTE_SB1250 + +config SIBYTE_CRHINE + bool "BCM91120C-CRhine" + select SIBYTE_BCM1120 + +config SIBYTE_CRHONE + bool "BCM91125C-CRhone" + select SIBYTE_BCM1125 + +config SIBYTE_UNKNOWN + bool "Other" + +endchoice + +config SIBYTE_BOARD + bool + depends on SIBYTE_SB1xxx_SOC && !SIBYTE_UNKNOWN + default y + +choice + prompt "BCM1xxx SOC Type" + depends on SIBYTE_UNKNOWN + default SIBYTE_UNK_BCM1250 + help + Since you haven't chosen a known evaluation board from + Broadcom, you must explicitly pick the SOC this kernel is + targetted for. + +config SIBYTE_UNK_BCM1250 + bool "BCM1250" + select SIBYTE_SB1250 + +config SIBYTE_UNK_BCM1120 + bool "BCM1120" + select SIBYTE_BCM1120 + +config SIBYTE_UNK_BCM1125 + bool "BCM1125" + select SIBYTE_BCM1125 + +config SIBYTE_UNK_BCM1125H + bool "BCM1125H" + select SIBYTE_BCM1125H + +endchoice + +config SIBYTE_SB1250 + bool + select HW_HAS_PCI + +config SIBYTE_BCM1120 + bool + select SIBYTE_BCM112X + +config SIBYTE_BCM1125 + bool + select HW_HAS_PCI + select SIBYTE_BCM112X + +config SIBYTE_BCM1125H + bool + select HW_HAS_PCI + select SIBYTE_BCM112X + +config SIBYTE_BCM112X + bool + +choice + prompt "SiByte SOC Stepping" + depends on SIBYTE_SB1xxx_SOC + +config CPU_SB1_PASS_1 + bool "1250 Pass1" + depends on SIBYTE_SB1250 + select CPU_HAS_PREFETCH + +config CPU_SB1_PASS_2_1250 + bool "1250 An" + depends on SIBYTE_SB1250 + select CPU_SB1_PASS_2 + help + Also called BCM1250 Pass 2 + +config CPU_SB1_PASS_2_2 + bool "1250 Bn" + depends on SIBYTE_SB1250 + select CPU_HAS_PREFETCH + help + Also called BCM1250 Pass 2.2 + +config CPU_SB1_PASS_4 + bool "1250 Cn" + depends on SIBYTE_SB1250 + select CPU_HAS_PREFETCH + help + Also called BCM1250 Pass 3 + +config CPU_SB1_PASS_2_112x + bool "112x Hybrid" + depends on SIBYTE_BCM112X + select CPU_SB1_PASS_2 + +config CPU_SB1_PASS_3 + bool "112x An" + depends on SIBYTE_BCM112X + select CPU_HAS_PREFETCH + +endchoice + +config CPU_SB1_PASS_2 + bool + +config SIBYTE_HAS_LDT + bool + depends on PCI && (SIBYTE_SB1250 || SIBYTE_BCM1125H) + default y + +config SIMULATION + bool "Running under simulation" + depends on SIBYTE_SB1xxx_SOC + help + Build a kernel suitable for running under the GDB simulator. + Primarily adjusts the kernel's notion of time. + +config SIBYTE_CFE + bool "Booting from CFE" + depends on SIBYTE_SB1xxx_SOC + help + Make use of the CFE API for enumerating available memory, + controlling secondary CPUs, and possibly console output. + +config SIBYTE_CFE_CONSOLE + bool "Use firmware console" + depends on SIBYTE_CFE + help + Use the CFE API's console write routines during boot. Other console + options (VT console, sb1250 duart console, etc.) should not be + configured. + +config SIBYTE_STANDALONE + bool + depends on SIBYTE_SB1xxx_SOC && !SIBYTE_CFE + default y + +config SIBYTE_STANDALONE_RAM_SIZE + int "Memory size (in megabytes)" + depends on SIBYTE_STANDALONE + default "32" + +config SIBYTE_BUS_WATCHER + bool "Support for Bus Watcher statistics" + depends on SIBYTE_SB1xxx_SOC + help + Handle and keep statistics on the bus error interrupts (COR_ECC, + BAD_ECC, IO_BUS). + +config SIBYTE_BW_TRACE + bool "Capture bus trace before bus error" + depends on SIBYTE_BUS_WATCHER + help + Run a continuous bus trace, dumping the raw data as soon as + a ZBbus error is detected. Cannot work if ZBbus profiling + is turned on, and also will interfere with JTAG-based trace + buffer activity. Raw buffer data is dumped to console, and + must be processed off-line. + +config SIBYTE_SB1250_PROF + bool "Support for SB1/SOC profiling - SB1/SCD perf counters" + depends on SIBYTE_SB1xxx_SOC + +config SIBYTE_TBPROF + bool "Support for ZBbus profiling" + depends on SIBYTE_SB1xxx_SOC + +config SNI_RM200_PCI + bool "Support for SNI RM200 PCI" + select ARC + select ARC32 + select BOOT_ELF32 + select DMA_NONCOHERENT + select GENERIC_ISA_DMA + select HAVE_STD_PC_SERIAL_PORT + select HW_HAS_PCI + select I8259 + select ISA + help + The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens + Nixdorf Informationssysteme (SNI), parent company of Pyramid + Technology and now in turn merged with Fujitsu. Say Y here to + support this machine type. + +config TOSHIBA_RBTX4927 + bool "Support for Toshiba TBTX49[23]7 board" + depends on MIPS32 + select DMA_NONCOHERENT + select HAS_TXX9_SERIAL + select HW_HAS_PCI + select I8259 + select ISA + select SWAP_IO_SPACE + help + This Toshiba board is based on the TX4927 processor. Say Y here to + support this machine type + +config TOSHIBA_FPCIB0 + bool "FPCIB0 Backplane Support" + depends on TOSHIBA_RBTX4927 + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + +config GENERIC_CALIBRATE_DELAY + bool + default y + +config HAVE_DEC_LOCK + bool + default y + +# +# Select some configuration options automatically based on user selections. +# +config ARC + bool + depends on SNI_RM200_PCI || SGI_IP32 || SGI_IP27 || SGI_IP22 || MIPS_MAGNUM_4000 || OLIVETTI_M700 || ACER_PICA_61 + default y + +config DMA_COHERENT + bool + +config DMA_IP27 + bool + +config DMA_NONCOHERENT + bool + +config EARLY_PRINTK + bool + depends on MACH_DECSTATION + default y + +config GENERIC_ISA_DMA + bool + depends on SNI_RM200_PCI || MIPS_MAGNUM_4000 || OLIVETTI_M700 || ACER_PICA_61 || MIPS_MALTA + default y + +config I8259 + bool + depends on SNI_RM200_PCI || DDB5477 || DDB5476 || DDB5074 || MACH_JAZZ || MIPS_MALTA || MIPS_COBALT + default y + +config LIMITED_DMA + bool + select HIGHMEM + +config MIPS_BONITO64 + bool + depends on MIPS_ATLAS || MIPS_MALTA + default y + +config MIPS_MSC + bool + depends on MIPS_ATLAS || MIPS_MALTA + default y + +config MIPS_NILE4 + bool + depends on LASAT + default y + +config MIPS_DISABLE_OBSOLETE_IDE + bool + +config CPU_LITTLE_ENDIAN + bool "Generate little endian code" + default y if ACER_PICA_61 || CASIO_E55 || DDB5074 || DDB5476 || DDB5477 || MACH_DECSTATION || IBM_WORKPAD || LASAT || MIPS_COBALT || MIPS_ITE8172 || MIPS_IVR || SOC_AU1X00 || NEC_OSPREY || OLIVETTI_M700 || SNI_RM200_PCI || VICTOR_MPC30X || ZAO_CAPCELLA + default n if MIPS_EV64120 || MIPS_EV96100 || MOMENCO_OCELOT || MOMENCO_OCELOT_G || SGI_IP22 || SGI_IP27 || SGI_IP32 || TOSHIBA_JMR3927 + help + Some MIPS machines can be configured for either little or big endian + byte order. These modes require different kernels. Say Y if your + machine is little endian, N if it's a big endian machine. + +config IRQ_CPU + bool + +config IRQ_CPU_RM7K + bool + +config IRQ_MV64340 + bool + +config DDB5XXX_COMMON + bool + depends on DDB5074 || DDB5476 || DDB5477 + default y + +config MIPS_BOARDS_GEN + bool + depends on MIPS_ATLAS || MIPS_MALTA || MIPS_SEAD + default y + +config MIPS_GT64111 + bool + depends on MIPS_COBALT + default y + +config MIPS_GT64120 + bool + depends on MIPS_EV64120 || MIPS_EV96100 || LASAT || MIPS_ATLAS || MIPS_MALTA || MOMENCO_OCELOT + default y + +config MIPS_TX3927 + bool + depends on TOSHIBA_JMR3927 + select HAS_TXX9_SERIAL + default y + +config PCI_MARVELL + bool + +config ITE_BOARD_GEN + bool + depends on MIPS_IVR || MIPS_ITE8172 + default y + +config SWAP_IO_SPACE + bool + +# +# Unfortunately not all GT64120 systems run the chip at the same clock. +# As the user for the clock rate and try to minimize the available options. +# +choice + prompt "Galileo Chip Clock" + #default SYSCLK_83 if MIPS_EV64120 + depends on MIPS_EV64120 || MOMENCO_OCELOT || MOMENCO_OCELOT_G + default SYSCLK_83 if MIPS_EV64120 + default SYSCLK_100 if MOMENCO_OCELOT || MOMENCO_OCELOT_G + +config SYSCLK_75 + bool "75" if MIPS_EV64120 + +config SYSCLK_83 + bool "83.3" if MIPS_EV64120 + +config SYSCLK_100 + bool "100" if MIPS_EV64120 || MOMENCO_OCELOT || MOMENCO_OCELOT_G + +endchoice + +config AU1X00_USB_DEVICE + bool + depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000 + default n + +config MIPS_GT96100 + bool + depends on MIPS_EV96100 + default y + help + Say Y here to support the Galileo Technology GT96100 communications + controller card. There is a web page at <http://www.galileot.com/>. + +config IT8172_CIR + bool + depends on MIPS_ITE8172 || MIPS_IVR + default y + +config IT8712 + bool + depends on MIPS_ITE8172 + default y + +config BOOT_ELF32 + bool + depends on MACH_DECSTATION || MIPS_ATLAS || MIPS_MALTA || MOMENCO_JAGUAR_ATX || MOMENCO_OCELOT_3 || SIBYTE_SB1xxx_SOC || SGI_IP32 || SGI_IP22 || SNI_RM200_PCI + default y + +config MIPS_L1_CACHE_SHIFT + int + default "4" if MACH_DECSTATION + default "7" if SGI_IP27 + default "5" + +config ARC32 + bool + depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP22 || SGI_IP32 + default y + +config FB + bool + depends on MIPS_MAGNUM_4000 || OLIVETTI_M700 + default y + ---help--- + The frame buffer device provides an abstraction for the graphics + hardware. It represents the frame buffer of some video hardware and + allows application software to access the graphics hardware through + a well-defined interface, so the software doesn't need to know + anything about the low-level (hardware register) stuff. + + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + + The device is accessed through special device nodes, usually located + in the /dev directory, i.e. /dev/fb*. + + You need an utility program called fbset to make full use of frame + buffer devices. Please read <file:Documentation/fb/framebuffer.txt> + and the Framebuffer-HOWTO at <http://www.tldp.org/docs.html#howto> + for more information. + + Say Y here and to the driver for your graphics board below if you + are compiling a kernel for a non-x86 architecture. + + If you are compiling for the x86 architecture, you can say Y if you + want to play with it, but it is not essential. Please note that + running graphical applications that directly touch the hardware + (e.g. an accelerated X server) and that are not frame buffer + device-aware may cause unexpected results. If unsure, say N. + +config HAVE_STD_PC_SERIAL_PORT + bool + +config VR4181 + bool + depends on NEC_OSPREY + default y + +config ARC_CONSOLE + bool "ARC console support" + depends on SGI_IP22 || SNI_RM200_PCI + +config ARC_MEMORY + bool + depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP32 + default y + +config ARC_PROMLIB + bool + depends on MACH_JAZZ || SNI_RM200_PCI || SGI_IP22 || SGI_IP32 + default y + +config ARC64 + bool + depends on SGI_IP27 + default y + +config BOOT_ELF64 + bool + depends on SGI_IP27 + default y + +#config MAPPED_PCI_IO y +# bool +# depends on SGI_IP27 +# default y + +config QL_ISP_A64 + bool + depends on SGI_IP27 + default y + +config TOSHIBA_BOARDS + bool + depends on TOSHIBA_JMR3927 || TOSHIBA_RBTX4927 + default y + +endmenu + +menu "CPU selection" + +choice + prompt "CPU type" + default CPU_R4X00 + +config CPU_MIPS32 + bool "MIPS32" + +config CPU_MIPS64 + bool "MIPS64" + +config CPU_R3000 + bool "R3000" + depends on MIPS32 + help + Please make sure to pick the right CPU type. Linux/MIPS is not + designed to be generic, i.e. Kernels compiled for R3000 CPUs will + *not* work on R4000 machines and vice versa. However, since most + of the supported machines have an R4000 (or similar) CPU, R4x00 + might be a safe bet. If the resulting kernel does not work, + try to recompile with R3000. + +config CPU_TX39XX + bool "R39XX" + depends on MIPS32 + +config CPU_VR41XX + bool "R41xx" + help + The options selects support for the NEC VR41xx series of processors. + Only choose this option if you have one of these processors as a + kernel built with this option will not run on any other type of + processor or vice versa. + +config CPU_R4300 + bool "R4300" + help + MIPS Technologies R4300-series processors. + +config CPU_R4X00 + bool "R4x00" + help + MIPS Technologies R4000-series processors other than 4300, including + the R4000, R4400, R4600, and 4700. + +config CPU_TX49XX + bool "R49XX" + +config CPU_R5000 + bool "R5000" + help + MIPS Technologies R5000-series processors other than the Nevada. + +config CPU_R5432 + bool "R5432" + +config CPU_R6000 + bool "R6000" + depends on MIPS32 && EXPERIMENTAL + help + MIPS Technologies R6000 and R6000A series processors. Note these + processors are extremly rare and the support for them is incomplete. + +config CPU_NEVADA + bool "RM52xx" + help + QED / PMC-Sierra RM52xx-series ("Nevada") processors. + +config CPU_R8000 + bool "R8000" + depends on MIPS64 && EXPERIMENTAL + help + MIPS Technologies R8000 processors. Note these processors are + uncommon and the support for them is incomplete. + +config CPU_R10000 + bool "R10000" + help + MIPS Technologies R10000-series processors. + +config CPU_RM7000 + bool "RM7000" + +config CPU_RM9000 + bool "RM9000" + +config CPU_SB1 + bool "SB1" + +endchoice + +choice + prompt "Kernel page size" + default PAGE_SIZE_4KB + +config PAGE_SIZE_4KB + bool "4kB" + help + This option select the standard 4kB Linux page size. On some + R3000-family processors this is the only available page size. Using + 4kB page size will minimize memory consumption and is therefore + recommended for low memory systems. + +config PAGE_SIZE_8KB + bool "8kB" + depends on EXPERIMENTAL && CPU_R8000 + help + Using 8kB page size will result in higher performance kernel at + the price of higher memory consumption. This option is available + only on the R8000 processor. Not that at the time of this writing + this option is still high experimental; there are also issues with + compatibility of user applications. + +config PAGE_SIZE_16KB + bool "16kB" + depends on EXPERIMENTAL && !CPU_R3000 && !CPU_TX39XX + help + Using 16kB page size will result in higher performance kernel at + the price of higher memory consumption. This option is available on + all non-R3000 family processor. Not that at the time of this + writing this option is still high experimental; there are also + issues with compatibility of user applications. + +config PAGE_SIZE_64KB + bool "64kB" + depends on EXPERIMENTAL && !CPU_R3000 && !CPU_TX39XX + help + Using 64kB page size will result in higher performance kernel at + the price of higher memory consumption. This option is available on + all non-R3000 family processor. Not that at the time of this + writing this option is still high experimental; there are also + issues with compatibility of user applications. + +endchoice + +config BOARD_SCACHE + bool + +config IP22_CPU_SCACHE + bool + select BOARD_SCACHE + +config R5000_CPU_SCACHE + bool + select BOARD_SCACHE + +config RM7000_CPU_SCACHE + bool + select BOARD_SCACHE + +config SIBYTE_DMA_PAGEOPS + bool "Use DMA to clear/copy pages" + depends on CPU_SB1 + help + Instead of using the CPU to zero and copy pages, use a Data Mover + channel. These DMA channels are otherwise unused by the standard + SiByte Linux port. Seems to give a small performance benefit. + +config CPU_HAS_PREFETCH + bool "Enable prefetches" if CPU_SB1 && !CPU_SB1_PASS_2 + default y if CPU_MIPS32 || CPU_MIPS64 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 + +config VTAG_ICACHE + bool "Support for Virtual Tagged I-cache" if CPU_MIPS64 || CPU_MIPS32 + default y if CPU_SB1 + +config SB1_PASS_1_WORKAROUNDS + bool + depends on CPU_SB1_PASS_1 + default y + +config SB1_PASS_2_WORKAROUNDS + bool + depends on CPU_SB1 && (CPU_SB1_PASS_2_2 || CPU_SB1_PASS_2) + default y + +config SB1_PASS_2_1_WORKAROUNDS + bool + depends on CPU_SB1 && CPU_SB1_PASS_2 + default y + +config 64BIT_PHYS_ADDR + bool "Support for 64-bit physical address space" + depends on (CPU_R4X00 || CPU_R5000 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 || CPU_SB1 || CPU_MIPS32 || CPU_MIPS64) && MIPS32 + +config CPU_ADVANCED + bool "Override CPU Options" + depends on MIPS32 + help + Saying yes here allows you to select support for various features + your CPU may or may not have. Most people should say N here. + +config CPU_HAS_LLSC + bool "ll/sc Instructions available" if CPU_ADVANCED + default y if !CPU_ADVANCED && !CPU_R3000 && !CPU_VR41XX && !CPU_TX39XX + help + MIPS R4000 series and later provide the Load Linked (ll) + and Store Conditional (sc) instructions. More information is + available at <http://www.go-ecs.com/mips/miptek1.htm>. + + Say Y here if your CPU has the ll and sc instructions. Say Y here + for better performance, N if you don't know. You must say Y here + for multiprocessor machines. + +config CPU_HAS_LLDSCD + bool "lld/scd Instructions available" if CPU_ADVANCED + default y if !CPU_ADVANCED && !CPU_R3000 && !CPU_VR41XX && !CPU_TX39XX && !CPU_MIPS32 + help + Say Y here if your CPU has the lld and scd instructions, the 64-bit + equivalents of ll and sc. Say Y here for better performance, N if + you don't know. You must say Y here for multiprocessor machines. + +config CPU_HAS_WB + bool "Writeback Buffer available" if CPU_ADVANCED + default y if !CPU_ADVANCED && CPU_R3000 && MACH_DECSTATION + help + Say N here for slightly better performance. You must say Y here for + machines which require flushing of write buffers in software. Saying + Y is the safe option; N may result in kernel malfunction and crashes. + +config CPU_HAS_SYNC + bool + depends on !CPU_R3000 + default y + +# +# - Highmem only makes sense for the 32-bit kernel. +# - The current highmem code will only work properly on physically indexed +# caches such as R3000, SB1, R7000 or those that look like they're virtually +# indexed such as R4000/R4400 SC and MC versions or R10000. So for the +# moment we protect the user and offer the highmem option only on machines +# where it's known to be safe. This will not offer highmem on a few systems +# such as MIPS32 and MIPS64 CPUs which may have virtual and physically +# indexed CPUs but we're playing safe. +# - We should not offer highmem for system of which we already know that they +# don't have memory configurations that could gain from highmem support in +# the kernel because they don't support configurations with RAM at physical +# addresses > 0x20000000. +# +config HIGHMEM + bool "High Memory Support" + depends on MIPS32 && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX) + +config SMP + bool "Multi-Processing support" + depends on CPU_RM9000 || (SIBYTE_SB1250 && !SIBYTE_STANDALONE) || SGI_IP27 + ---help--- + This enables support for systems with more than one CPU. If you have + a system with only one CPU, like most personal computers, say N. If + you have a system with more than one CPU, say Y. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on many, but not all, + singleprocessor machines. On a singleprocessor machine, the kernel + will run faster if you say N here. + + People using multiprocessor machines who say Y here should also say + Y to "Enhanced Real Time Clock Support", below. + + See also the <file:Documentation/smp.txt> and the SMP-HOWTO + available at <http://www.tldp.org/docs.html#howto>. + + If you don't know what to do here, say N. + +config NR_CPUS + int "Maximum number of CPUs (2-64)" + range 2 64 + depends on SMP + default "64" if SGI_IP27 + default "2" + help + This allows you to specify the maximum number of CPUs which this + kernel will support. The maximum supported value is 32 for 32-bit + kernel and 64 for 64-bit kernels; the minimum value which makes + sense is 2. + + This is purely to save memory - each supported CPU adds + approximately eight kilobytes to the kernel image. + +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + +config RTC_DS1742 + bool "DS1742 BRAM/RTC support" + depends on TOSHIBA_JMR3927 || TOSHIBA_RBTX4927 + +config MIPS_INSANE_LARGE + bool "Support for large 64-bit configurations" + depends on CPU_R10000 && MIPS64 + help + MIPS R10000 does support a 44 bit / 16TB address space as opposed to + previous 64-bit processors which only supported 40 bit / 1TB. If you + need processes of more than 1TB virtual address space, say Y here. + This will result in additional memory usage, so it is not + recommended for normal users. + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +endmenu + +menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)" + +config HW_HAS_PCI + bool + +config PCI + bool "Support for PCI controller" + depends on HW_HAS_PCI + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. Other bus systems are ISA, EISA, or VESA. If you have PCI, + say Y, otherwise N. + + The PCI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, contains valuable + information about which PCI hardware does work under Linux and which + doesn't. + +config PCI_DOMAINS + bool + depends on PCI + +source "drivers/pci/Kconfig" + +# +# ISA support is now enabled via select. Too many systems still have the one +# or other ISA chip on the board that users don't know about so don't expect +# users to choose the right thing ... +# +config ISA + bool + +config EISA + bool "EISA support" + depends on SGI_IP22 || SNI_RM200_PCI + select ISA + ---help--- + The Extended Industry Standard Architecture (EISA) bus was + developed as an open alternative to the IBM MicroChannel bus. + + The EISA bus provided some of the features of the IBM MicroChannel + bus while maintaining backward compatibility with cards made for + the older ISA bus. The EISA bus saw limited use between 1988 and + 1995 when it was made obsolete by the PCI bus. + + Say Y here if you are building a kernel for an EISA-based machine. + + Otherwise, say N. + +source "drivers/eisa/Kconfig" + +config TC + bool "TURBOchannel support" + depends on MACH_DECSTATION + help + TurboChannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS + processors. Documentation on writing device drivers for TurboChannel + is available at: + <http://www.cs.arizona.edu/computer.help/policy/DIGITAL_unix/AA-PS3HD-TET1_html/TITLE.html>. + +#config ACCESSBUS +# bool "Access.Bus support" +# depends on TC + +config MMU + bool + default y + +config MCA + bool + +config SBUS + bool + +source "drivers/pcmcia/Kconfig" + +source "drivers/pci/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +config TRAD_SIGNALS + bool + default y if MIPS32 + +config BUILD_ELF64 + bool "Use 64-bit ELF format for building" + depends on MIPS64 + help + A 64-bit kernel is usually built using the 64-bit ELF binary object + format as it's one that allows arbitrary 64-bit constructs. For + kernels that are loaded within the KSEG compatibility segments the + 32-bit ELF format can optionally be used resulting in a somewhat + smaller binary, but this option is not explicitly supported by the + toolchain and since binutils 2.14 it does not even work at all. + + Say Y to use the 64-bit format or N to use the 32-bit one. + + If unsure say Y. + +config BINFMT_IRIX + bool "Include IRIX binary compatibility" + depends on !CPU_LITTLE_ENDIAN && MIPS32 && BROKEN + +config MIPS32_COMPAT + bool "Kernel support for Linux/MIPS 32-bit binary compatibility" + depends on MIPS64 + help + Select this option if you want Linux/MIPS 32-bit binary + compatibility. Since all software available for Linux/MIPS is + currently 32-bit you should say Y here. + +config COMPAT + bool + depends on MIPS32_COMPAT + default y + +config MIPS32_O32 + bool "Kernel support for o32 binaries" + depends on MIPS32_COMPAT + help + Select this option if you want to run o32 binaries. These are pure + 32-bit binaries as used by the 32-bit Linux/MIPS port. Most of + existing binaries are in this format. + + If unsure, say Y. + +config MIPS32_N32 + bool "Kernel support for n32 binaries" + depends on MIPS32_COMPAT + help + Select this option if you want to run n32 binaries. These are + 64-bit binaries using 32-bit quantities for addressing and certain + data that would normally be 64-bit. They are used in special + cases. + + If unsure, say N. + +config BINFMT_ELF32 + bool + default y if MIPS32_O32 || MIPS32_N32 + +config PM + bool "Power Management support (EXPERIMENTAL)" + depends on EXPERIMENTAL && MACH_AU1X00 + +endmenu + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/mips/Kconfig.debug" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + +# +# Use the generic interrupt handling code in kernel/irq/: +# +config GENERIC_HARDIRQS + bool + default y + +config GENERIC_IRQ_PROBE + bool + default y diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug new file mode 100644 index 00000000000..d3c5cc3b9c9 --- /dev/null +++ b/arch/mips/Kconfig.debug @@ -0,0 +1,76 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config CROSSCOMPILE + bool "Are you using a crosscompiler" + help + Say Y here if you are compiling the kernel on a different + architecture than the one it is intended to run on. + +config CMDLINE + string "Default kernel command string" + default "" + help + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + other cases you can specify kernel args so that you don't have + to set them up in board prom initialization routines. + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +config KGDB + bool "Remote GDB kernel debugging" + depends on DEBUG_KERNEL + select DEBUG_INFO + help + If you say Y here, it will be possible to remotely debug the MIPS + kernel using gdb. This enlarges your kernel image disk size by + several megabytes and requires a machine with more than 16 MB, + better 32 MB RAM to avoid excessive linking time. This is only + useful for kernel hackers. If unsure, say N. + +config GDB_CONSOLE + bool "Console output to GDB" + depends on KGDB + help + If you are using GDB for remote debugging over a serial port and + would like kernel messages to be formatted into GDB $O packets so + that GDB prints them as program output, say 'Y'. + +config SB1XXX_CORELIS + bool "Corelis Debugger" + depends on SIBYTE_SB1xxx_SOC + select DEBUG_INFO + help + Select compile flags that produce code that can be processed by the + Corelis mksym utility and UDB Emulator. + +config RUNTIME_DEBUG + bool "Enable run-time debugging" + depends on DEBUG_KERNEL + help + If you say Y here, some debugging macros will do run-time checking. + If you say N here, those macros will mostly turn to no-ops. See + include/asm-mips/debug.h for debuging macros. + If unsure, say N. + +config MIPS_UNCACHED + bool "Run uncached" + depends on DEBUG_KERNEL && !SMP && !SGI_IP27 + help + If you say Y here there kernel will disable all CPU caches. This will + reduce the system's performance dramatically but can help finding + otherwise hard to track bugs. It can also useful if you're doing + hardware debugging with a logic analyzer and need to see all traffic + on the bus. + +endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile new file mode 100644 index 00000000000..bc1c44274a5 --- /dev/null +++ b/arch/mips/Makefile @@ -0,0 +1,767 @@ +# +# 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) 1994, 95, 96, 2003 by Ralf Baechle +# DECStation modifications by Paul M. Antoine, 1996 +# Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" cleaning up for this architecture. +# + +as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ + -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \ + else echo "$(2)"; fi ;) + +cflags-y := + +# +# Select the object file format to substitute into the linker script. +# +ifdef CONFIG_CPU_LITTLE_ENDIAN +32bit-tool-prefix = mipsel-linux- +64bit-tool-prefix = mips64el-linux- +32bit-bfd = elf32-tradlittlemips +64bit-bfd = elf64-tradlittlemips +32bit-emul = elf32ltsmip +64bit-emul = elf64ltsmip +else +32bit-tool-prefix = mips-linux- +64bit-tool-prefix = mips64-linux- +32bit-bfd = elf32-tradbigmips +64bit-bfd = elf64-tradbigmips +32bit-emul = elf32btsmip +64bit-emul = elf64btsmip +endif + +ifdef CONFIG_MIPS32 +gcc-abi = 32 +tool-prefix = $(32bit-tool-prefix) +UTS_MACHINE := mips +endif +ifdef CONFIG_MIPS64 +gcc-abi = 64 +tool-prefix = $(64bit-tool-prefix) +UTS_MACHINE := mips64 +endif + +ifdef CONFIG_CROSSCOMPILE +CROSS_COMPILE := $(tool-prefix) +endif + +ifdef CONFIG_BUILD_ELF64 +gas-abi = 64 +ld-emul = $(64bit-emul) +vmlinux-32 = vmlinux.32 +vmlinux-64 = vmlinux +else +gas-abi = 32 +ld-emul = $(32bit-emul) +vmlinux-32 = vmlinux +vmlinux-64 = vmlinux.64 + +cflags-$(CONFIG_MIPS64) += $(call cc-option,-mno-explicit-relocs) +endif + +# +# GCC uses -G 0 -mabicalls -fpic as default. We don't want PIC in the kernel +# code since it only slows down the whole thing. At some point we might make +# use of global pointer optimizations but their use of $28 conflicts with +# the current pointer optimization. +# +# The DECStation requires an ECOFF kernel for remote booting, other MIPS +# machines may also. Since BFD is incredibly buggy with respect to +# crossformat linking we rely on the elf2ecoff tool for format conversion. +# +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 +MODFLAGS += -mlong-calls + +cflags-$(CONFIG_SB1XXX_CORELIS) += -mno-sched-prolog -fno-omit-frame-pointer + +# +# Use: $(call set_gccflags,<cpu0>,<isa0>,<cpu1>,<isa1>,<isa2>) +# +# <cpu0>,<isa0> -- preferred CPU and ISA designations (may require +# recent tools) +# <cpu1>,<isa1> -- fallback CPU and ISA designations (have to work +# with up to the oldest supported tools) +# <isa2> -- an ISA designation used as an ABI selector for +# gcc versions that do not support "-mabi=32" +# (depending on the CPU type, either "mips1" or +# "mips2") +# +set_gccflags = $(shell \ +while :; do \ + cpu=$(1); isa=-$(2); \ + for gcc_opt in -march= -mcpu=; do \ + $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \ + -xc /dev/null > /dev/null 2>&1 && \ + break 2; \ + done; \ + cpu=$(3); isa=-$(4); \ + for gcc_opt in -march= -mcpu=; do \ + $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \ + -xc /dev/null > /dev/null 2>&1 && \ + break 2; \ + done; \ + break; \ +done; \ +gcc_abi=-mabi=$(gcc-abi); gcc_cpu=$$cpu; \ +if $(CC) $$gcc_abi -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then \ + gcc_isa=$$isa; \ +else \ + gcc_abi=; gcc_isa=-$(5); \ +fi; \ +gas_abi=-Wa,-$(gcc-abi); gas_cpu=$$cpu; gas_isa=-Wa,$$isa; \ +while :; do \ + for gas_opt in -Wa,-march= -Wa,-mcpu=; do \ + $(CC) $$gas_abi $$gas_opt$$cpu $$gas_isa -Wa,-Z -c \ + -o /dev/null -xassembler /dev/null > /dev/null 2>&1 && \ + break 2; \ + done; \ + gas_abi=; gas_opt=; gas_cpu=; gas_isa=; \ + break; \ +done; \ +if test "$(gcc-abi)" != "$(gas-abi)"; then \ + gas_abi="-Wa,-$(gas-abi) -Wa,-mgp$(gcc-abi)"; \ +fi; \ +if test "$$gcc_opt" = -march= && test -n "$$gcc_abi"; then \ + $(CC) $$gcc_abi $$gcc_opt$$gcc_cpu -S -o /dev/null \ + -xc /dev/null > /dev/null 2>&1 && \ + gcc_isa=; \ +fi; \ +echo $$gcc_abi $$gcc_opt$$gcc_cpu $$gcc_isa $$gas_abi $$gas_opt$$gas_cpu $$gas_isa) + +# +# CPU-dependent compiler/assembler options for optimization. +# +cflags-$(CONFIG_CPU_R3000) += \ + $(call set_gccflags,r3000,mips1,r3000,mips1,mips1) + +cflags-$(CONFIG_CPU_TX39XX) += \ + $(call set_gccflags,r3900,mips1,r3000,mips1,mips1) + +cflags-$(CONFIG_CPU_R6000) += \ + $(call set_gccflags,r6000,mips2,r6000,mips2,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_R4300) += \ + $(call set_gccflags,r4300,mips3,r4300,mips3,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_VR41XX) += \ + $(call set_gccflags,r4100,mips3,r4600,mips3,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_R4X00) += \ + $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_TX49XX) += \ + $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_MIPS32) += \ + $(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_MIPS64) += \ + $(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_R5000) += \ + $(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_R5432) += \ + $(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_NEVADA) += \ + $(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \ + -Wa,--trap +# $(call cc-option,-mmad) + +cflags-$(CONFIG_CPU_RM7000) += \ + $(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \ + -Wa,--trap + +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 + +cflags-$(CONFIG_CPU_R8000) += \ + $(call set_gccflags,r8000,mips4,r8000,mips4,mips2) \ + -Wa,--trap + +cflags-$(CONFIG_CPU_R10000) += \ + $(call set_gccflags,r10000,mips4,r8000,mips4,mips2) \ + -Wa,--trap + +ifdef CONFIG_CPU_SB1 +ifdef CONFIG_SB1_PASS_1_WORKAROUNDS +MODFLAGS += -msb1-pass1-workarounds +endif +endif + +# +# Firmware support +# +libs-$(CONFIG_ARC) += arch/mips/arc/ +libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/ + +# +# Board-dependent options and extra files +# + +# +# Acer PICA 61, Mips Magnum 4000 and Olivetti M700. +# +core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/ +cflags-$(CONFIG_MACH_JAZZ) += -Iinclude/asm-mips/mach-jazz +load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000 + +# +# Common Alchemy Au1x00 stuff +# +core-$(CONFIG_SOC_AU1X00) += arch/mips/au1000/common/ +cflags-$(CONFIG_SOC_AU1X00) += -Iinclude/asm-mips/mach-au1x00 + +# +# AMD Alchemy Pb1000 eval board +# +libs-$(CONFIG_MIPS_PB1000) += arch/mips/au1000/pb1000/ +cflags-$(CONFIG_MIPS_PB1000) += -Iinclude/asm-mips/mach-pb1x00 +load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000 + +# +# AMD Alchemy Pb1100 eval board +# +libs-$(CONFIG_MIPS_PB1100) += arch/mips/au1000/pb1100/ +cflags-$(CONFIG_MIPS_PB1100) += -Iinclude/asm-mips/mach-pb1x00 +load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000 + +# +# AMD Alchemy Pb1500 eval board +# +libs-$(CONFIG_MIPS_PB1500) += arch/mips/au1000/pb1500/ +cflags-$(CONFIG_MIPS_PB1500) += -Iinclude/asm-mips/mach-pb1x00 +load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000 + +# +# AMD Alchemy Pb1550 eval board +# +libs-$(CONFIG_MIPS_PB1550) += arch/mips/au1000/pb1550/ +cflags-$(CONFIG_MIPS_PB1550) += -Iinclude/asm-mips/mach-pb1x00 +load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000 + +# +# AMD Alchemy Db1000 eval board +# +libs-$(CONFIG_MIPS_DB1000) += arch/mips/au1000/db1x00/ +cflags-$(CONFIG_MIPS_DB1000) += -Iinclude/asm-mips/mach-db1x00 +load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000 + +# +# AMD Alchemy Db1100 eval board +# +libs-$(CONFIG_MIPS_DB1100) += arch/mips/au1000/db1x00/ +cflags-$(CONFIG_MIPS_DB1100) += -Iinclude/asm-mips/mach-db1x00 +load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000 + +# +# AMD Alchemy Db1500 eval board +# +libs-$(CONFIG_MIPS_DB1500) += arch/mips/au1000/db1x00/ +cflags-$(CONFIG_MIPS_DB1500) += -Iinclude/asm-mips/mach-db1x00 +load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000 + +# +# AMD Alchemy Db1550 eval board +# +libs-$(CONFIG_MIPS_DB1550) += arch/mips/au1000/db1x00/ +cflags-$(CONFIG_MIPS_DB1550) += -Iinclude/asm-mips/mach-db1x00 +load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000 + +# +# AMD Alchemy Bosporus eval board +# +libs-$(CONFIG_MIPS_BOSPORUS) += arch/mips/au1000/db1x00/ +cflags-$(CONFIG_MIPS_BOSPORUS) += -Iinclude/asm-mips/mach-db1x00 +load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000 + +# +# AMD Alchemy Mirage eval board +# +libs-$(CONFIG_MIPS_MIRAGE) += arch/mips/au1000/db1x00/ +cflags-$(CONFIG_MIPS_MIRAGE) += -Iinclude/asm-mips/mach-db1x00 +load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000 + +# +# 4G-Systems eval board +# +libs-$(CONFIG_MIPS_MTX1) += arch/mips/au1000/mtx-1/ +load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000 + +# +# MyCable eval board +# +libs-$(CONFIG_MIPS_XXS1500) += arch/mips/au1000/xxs1500/ +load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000 + +# +# Cobalt Server +# +core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/ +load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000 + +# +# DECstation family +# +core-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/ +cflags-$(CONFIG_MACH_DECSTATION)+= -Iinclude/asm-mips/mach-dec +libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/ +load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000 +CLEAN_FILES += drivers/tc/lk201-map.c + +# +# Galileo EV64120 Board +# +core-$(CONFIG_MIPS_EV64120) += arch/mips/gt64120/ev64120/ +core-$(CONFIG_MIPS_EV64120) += arch/mips/gt64120/common/ +cflags-$(CONFIG_MIPS_EV64120) += -Iinclude/asm-mips/mach-ev64120 +load-$(CONFIG_MIPS_EV64120) += 0xffffffff80100000 + +# +# Galileo EV96100 Board +# +core-$(CONFIG_MIPS_EV96100) += arch/mips/galileo-boards/ev96100/ +cflags-$(CONFIG_MIPS_EV96100) += -Iinclude/asm-mips/mach-ev96100 +load-$(CONFIG_MIPS_EV96100) += 0xffffffff80100000 + +# +# Globespan IVR eval board with QED 5231 CPU +# +core-$(CONFIG_ITE_BOARD_GEN) += arch/mips/ite-boards/generic/ +core-$(CONFIG_MIPS_IVR) += arch/mips/ite-boards/ivr/ +load-$(CONFIG_MIPS_IVR) += 0xffffffff80100000 + +# +# ITE 8172 eval board with QED 5231 CPU +# +core-$(CONFIG_MIPS_ITE8172) += arch/mips/ite-boards/qed-4n-s01b/ +load-$(CONFIG_MIPS_ITE8172) += 0xffffffff80100000 + +# +# For all MIPS, Inc. eval boards +# +core-$(CONFIG_MIPS_BOARDS_GEN) += arch/mips/mips-boards/generic/ + +# +# MIPS Atlas board +# +core-$(CONFIG_MIPS_ATLAS) += arch/mips/mips-boards/atlas/ +cflags-$(CONFIG_MIPS_ATLAS) += -Iinclude/asm-mips/mach-atlas +cflags-$(CONFIG_MIPS_ATLAS) += -Iinclude/asm-mips/mach-mips +load-$(CONFIG_MIPS_ATLAS) += 0xffffffff80100000 + +# +# MIPS Malta board +# +core-$(CONFIG_MIPS_MALTA) += arch/mips/mips-boards/malta/ +cflags-$(CONFIG_MIPS_MALTA) += -Iinclude/asm-mips/mach-mips +load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000 + +# +# MIPS SEAD board +# +core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/ +load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000 + +# +# Momentum Ocelot board +# +# The Ocelot setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +# +core-$(CONFIG_MOMENCO_OCELOT) += arch/mips/gt64120/common/ \ + arch/mips/gt64120/momenco_ocelot/ +cflags-$(CONFIG_MOMENCO_OCELOT) += -Iinclude/asm-mips/mach-ocelot +load-$(CONFIG_MOMENCO_OCELOT) += 0xffffffff80100000 + +# +# Momentum Ocelot-G board +# +# The Ocelot-G setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +# +core-$(CONFIG_MOMENCO_OCELOT_G) += arch/mips/momentum/ocelot_g/ +load-$(CONFIG_MOMENCO_OCELOT_G) += 0xffffffff80100000 + +# +# Momentum Ocelot-C and -CS boards +# +# The Ocelot-C[S] setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +core-$(CONFIG_MOMENCO_OCELOT_C) += arch/mips/momentum/ocelot_c/ +load-$(CONFIG_MOMENCO_OCELOT_C) += 0xffffffff80100000 + +# +# PMC-Sierra Yosemite +# +core-$(CONFIG_PMC_YOSEMITE) += arch/mips/pmc-sierra/yosemite/ +cflags-$(CONFIG_PMC_YOSEMITE) += -Iinclude/asm-mips/mach-yosemite +load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000 + +# +# Momentum Ocelot-3 +# +core-$(CONFIG_MOMENCO_OCELOT_3) += arch/mips/momentum/ocelot_3/ +cflags-$(CONFIG_MOMENCO_OCELOT_3) += -Iinclude/asm-mips/mach-ocelot3 +load-$(CONFIG_MOMENCO_OCELOT_3) += 0xffffffff80100000 + +# +# Momentum Jaguar ATX +# +core-$(CONFIG_MOMENCO_JAGUAR_ATX) += arch/mips/momentum/jaguar_atx/ +cflags-$(CONFIG_MOMENCO_JAGUAR_ATX) += -Iinclude/asm-mips/mach-ja +#ifdef CONFIG_JAGUAR_DMALOW +#load-$(CONFIG_MOMENCO_JAGUAR_ATX) += 0xffffffff88000000 +#else +load-$(CONFIG_MOMENCO_JAGUAR_ATX) += 0xffffffff80100000 +#endif + +# +# NEC DDB +# +core-$(CONFIG_DDB5XXX_COMMON) += arch/mips/ddb5xxx/common/ + +# +# NEC DDB Vrc-5074 +# +core-$(CONFIG_DDB5074) += arch/mips/ddb5xxx/ddb5074/ +load-$(CONFIG_DDB5074) += 0xffffffff80080000 + +# +# NEC DDB Vrc-5476 +# +core-$(CONFIG_DDB5476) += arch/mips/ddb5xxx/ddb5476/ +load-$(CONFIG_DDB5476) += 0xffffffff80080000 + +# +# NEC DDB Vrc-5477 +# +core-$(CONFIG_DDB5477) += arch/mips/ddb5xxx/ddb5477/ +load-$(CONFIG_DDB5477) += 0xffffffff80100000 + +core-$(CONFIG_LASAT) += arch/mips/lasat/ +cflags-$(CONFIG_LASAT) += -Iinclude/asm-mips/mach-lasat +load-$(CONFIG_LASAT) += 0xffffffff80000000 + +# +# NEC Osprey (vr4181) board +# +core-$(CONFIG_NEC_OSPREY) += arch/mips/vr4181/common/ \ + arch/mips/vr4181/osprey/ +load-$(CONFIG_NEC_OSPREY) += 0xffffffff80002000 + +# +# Common VR41xx +# +core-$(CONFIG_MACH_VR41XX) += arch/mips/vr41xx/common/ +cflags-$(CONFIG_MACH_VR41XX) += -Iinclude/asm-mips/mach-vr41xx + +# +# NEC VR4133 +# +core-$(CONFIG_NEC_CMBVR4133) += arch/mips/vr41xx/nec-cmbvr4133/ +load-$(CONFIG_NEC_CMBVR4133) += 0xffffffff80100000 + +# +# ZAO Networks Capcella (VR4131) +# +core-$(CONFIG_ZAO_CAPCELLA) += arch/mips/vr41xx/zao-capcella/ +load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000 + +# +# Victor MP-C303/304 (VR4122) +# +core-$(CONFIG_VICTOR_MPC30X) += arch/mips/vr41xx/victor-mpc30x/ +load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000 + +# +# IBM WorkPad z50 (VR4121) +# +core-$(CONFIG_IBM_WORKPAD) += arch/mips/vr41xx/ibm-workpad/ +load-$(CONFIG_IBM_WORKPAD) += 0xffffffff80004000 + +# +# CASIO CASSIPEIA E-55/65 (VR4111) +# +core-$(CONFIG_CASIO_E55) += arch/mips/vr41xx/casio-e55/ +load-$(CONFIG_CASIO_E55) += 0xffffffff80004000 + +# +# TANBAC TB0226 Mbase (VR4131) +# +core-$(CONFIG_TANBAC_TB0226) += arch/mips/vr41xx/tanbac-tb0226/ +load-$(CONFIG_TANBAC_TB0226) += 0xffffffff80000000 + +# +# TANBAC TB0229 VR4131DIMM (VR4131) +# +core-$(CONFIG_TANBAC_TB0229) += arch/mips/vr41xx/tanbac-tb0229/ +load-$(CONFIG_TANBAC_TB0229) += 0xffffffff80000000 + +# +# SGI IP22 (Indy/Indigo2) +# +# Set the load address to >= 0xffffffff88069000 if you want to leave space for +# symmon, 0xffffffff80002000 for production kernels. Note that the value must +# be aligned to a multiple of the kernel stack size or the handling of the +# current variable will break so for 64-bit kernels we have to raise the start +# address by 8kb. +# +core-$(CONFIG_SGI_IP22) += arch/mips/sgi-ip22/ +cflags-$(CONFIG_SGI_IP22) += -Iinclude/asm-mips/mach-ip22 +ifdef CONFIG_MIPS32 +load-$(CONFIG_SGI_IP22) += 0xffffffff88002000 +endif +ifdef CONFIG_MIPS64 +load-$(CONFIG_SGI_IP22) += 0xffffffff88004000 +endif + +# +# SGI-IP27 (Origin200/2000) +# +# Set the load address to >= 0xc000000000300000 if you want to leave space for +# symmon, 0xc00000000001c000 for production kernels. Note that the value must +# be 16kb aligned or the handling of the current variable will break. +# +ifdef CONFIG_SGI_IP27 +core-$(CONFIG_SGI_IP27) += arch/mips/sgi-ip27/ +cflags-$(CONFIG_SGI_IP27) += -Iinclude/asm-mips/mach-ip27 +ifdef CONFIG_BUILD_ELF64 +ifdef CONFIG_MAPPED_KERNEL +load-$(CONFIG_SGI_IP27) += 0xc00000004001c000 +OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000 +dataoffset-$(CONFIG_SGI_IP27) += 0x01000000 +else +load-$(CONFIG_SGI_IP27) += 0xa80000000001c000 +OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000 +endif +else +ifdef CONFIG_MAPPED_KERNEL +load-$(CONFIG_SGI_IP27) += 0xffffffffc001c000 +OBJCOPYFLAGS := --change-addresses=0xc000000080000000 +dataoffset-$(CONFIG_SGI_IP27) += 0x01000000 +else +load-$(CONFIG_SGI_IP27) += 0xffffffff8001c000 +OBJCOPYFLAGS := --change-addresses=0xa800000080000000 +endif +endif +endif + +# +# SGI-IP32 (O2) +# +# Set the load address to >= 80069000 if you want to leave space for symmon, +# 0xffffffff80004000 for production kernels. Note that the value must be aligned to +# a multiple of the kernel stack size or the handling of the current variable +# will break. +# +core-$(CONFIG_SGI_IP32) += arch/mips/sgi-ip32/ +cflags-$(CONFIG_SGI_IP32) += -Iinclude/asm-mips/mach-ip32 +load-$(CONFIG_SGI_IP32) += 0xffffffff80004000 + +# +# Sibyte SB1250 SOC +# +# This is a LIB so that it links at the end, and initcalls are later +# the sequence; but it is built as an object so that modules don't get +# 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 + +core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/sb1250/ +cflags-$(CONFIG_SIBYTE_SB1250) += -Iinclude/asm-mips/mach-sibyte + +# +# Sibyte BCM91120x (Carmel) board +# Sibyte BCM91120C (CRhine) board +# Sibyte BCM91125C (CRhone) board +# Sibyte BCM91125E (Rhone) board +# Sibyte SWARM board +# +libs-$(CONFIG_SIBYTE_CARMEL) += arch/mips/sibyte/swarm/ +load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000 +libs-$(CONFIG_SIBYTE_CRHINE) += arch/mips/sibyte/swarm/ +load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000 +libs-$(CONFIG_SIBYTE_CRHONE) += arch/mips/sibyte/swarm/ +load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000 +libs-$(CONFIG_SIBYTE_RHONE) += arch/mips/sibyte/swarm/ +load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000 +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 + +# +# SNI RM200 PCI +# +core-$(CONFIG_SNI_RM200_PCI) += arch/mips/sni/ +cflags-$(CONFIG_SNI_RM200_PCI) += -Iinclude/asm-mips/mach-rm200 +load-$(CONFIG_SNI_RM200_PCI) += 0xffffffff80600000 + +# +# Toshiba JMR-TX3927 board +# +core-$(CONFIG_TOSHIBA_JMR3927) += arch/mips/jmr3927/rbhma3100/ \ + arch/mips/jmr3927/common/ +load-$(CONFIG_TOSHIBA_JMR3927) += 0xffffffff80050000 + +# +# Toshiba RBTX4927 board or +# Toshiba RBTX4937 board +# +core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/tx4927/toshiba_rbtx4927/ +core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/tx4927/common/ +load-$(CONFIG_TOSHIBA_RBTX4927) += 0xffffffff80020000 + +cflags-y += -Iinclude/asm-mips/mach-generic +drivers-$(CONFIG_PCI) += arch/mips/pci/ + +ifdef CONFIG_MIPS32 +ifdef CONFIG_CPU_LITTLE_ENDIAN +JIFFIES = jiffies_64 +else +JIFFIES = jiffies_64 + 4 +endif +else +JIFFIES = jiffies_64 +endif + +AFLAGS += $(cflags-y) +CFLAGS += $(cflags-y) + +LDFLAGS += -m $(ld-emul) + +OBJCOPYFLAGS += --remove-section=.reginfo + +# +# Choosing incompatible machines durings configuration will result in +# error messages during linking. Select a default linkscript if +# none has been choosen above. +# + +CPPFLAGS_vmlinux.lds := \ + $(CFLAGS) \ + -D"LOADADDR=$(load-y)" \ + -D"JIFFIES=$(JIFFIES)" \ + -D"DATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)" + +head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o + +libs-y += arch/mips/lib/ +libs-$(CONFIG_MIPS32) += arch/mips/lib-32/ +libs-$(CONFIG_MIPS64) += arch/mips/lib-64/ + +core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/ + +drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/ + +ifdef CONFIG_LASAT +rom.bin rom.sw: vmlinux + $(call descend,arch/mips/lasat/image,$@) +endif + +# +# Some machines like the Indy need 32-bit ELF binaries for booting purposes. +# Other need ECOFF, so we build a 32-bit ELF binary for them which we then +# convert to ECOFF using elf2ecoff. +# +vmlinux.32: vmlinux + $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ + +# +# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit +# ELF files from 32-bit files by conversion. +# +vmlinux.64: vmlinux + $(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@ + +makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1) + +ifdef CONFIG_BOOT_ELF32 +all: $(vmlinux-32) +endif + +ifdef CONFIG_BOOT_ELF64 +all: $(vmlinux-64) +endif + +ifdef CONFIG_SNI_RM200_PCI +all: vmlinux.ecoff +endif + +vmlinux.ecoff vmlinux.rm200: $(vmlinux-32) + +@$(call makeboot,$@) + +vmlinux.srec: $(vmlinux-32) + +@$(call makeboot,$@) + +CLEAN_FILES += vmlinux.ecoff \ + vmlinux.srec \ + vmlinux.rm200.tmp \ + vmlinux.rm200 + +archclean: + @$(MAKE) $(clean)=arch/mips/boot + @$(MAKE) $(clean)=arch/mips/lasat + +# Generate <asm/offset.h +# +# The default rule is suffering from funny problems on MIPS so we using our +# own ... +# +# --------------------------------------------------------------------------- + +define filechk_gen-asm-offset.h + (set -e; \ + echo "#ifndef _ASM_OFFSET_H"; \ + echo "#define _ASM_OFFSET_H"; \ + echo "/*"; \ + echo " * DO NOT MODIFY."; \ + echo " *"; \ + echo " * This file was generated by arch/$(ARCH)/Makefile"; \ + echo " *"; \ + echo " */"; \ + echo ""; \ + sed -ne "/^@@@/s///p"; \ + echo "#endif /* _ASM_OFFSET_H */" ) +endef + +prepare: include/asm-$(ARCH)/offset.h + +arch/$(ARCH)/kernel/offset.s: include/asm include/linux/version.h \ + include/config/MARKER + +include/asm-$(ARCH)/offset.h: arch/$(ARCH)/kernel/offset.s + $(call filechk,gen-asm-offset.h) + +CLEAN_FILES += include/asm-$(ARCH)/offset.h.tmp \ + include/asm-$(ARCH)/offset.h \ + vmlinux.32 \ + vmlinux.64 \ + vmlinux.ecoff diff --git a/arch/mips/arc/Makefile b/arch/mips/arc/Makefile new file mode 100644 index 00000000000..e8424932e1a --- /dev/null +++ b/arch/mips/arc/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the ARC prom monitor library routines under Linux. +# + +lib-y += cmdline.o env.o file.o identify.o init.o \ + misc.o time.o tree.o + +lib-$(CONFIG_ARC_MEMORY) += memory.o +lib-$(CONFIG_ARC_CONSOLE) += arc_con.o +lib-$(CONFIG_ARC_PROMLIB) += promlib.o diff --git a/arch/mips/arc/arc_con.c b/arch/mips/arc/arc_con.c new file mode 100644 index 00000000000..51785a6a732 --- /dev/null +++ b/arch/mips/arc/arc_con.c @@ -0,0 +1,50 @@ +/* + * Wrap-around code for a console using the + * ARC io-routines. + * + * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 2001 Ralf Baechle + * Copyright (c) 2002 Thiemo Seufer + */ +#include <linux/tty.h> +#include <linux/major.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/fs.h> +#include <asm/sgialib.h> + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + /* Do each character */ + while (count--) { + if (*s == '\n') + prom_putchar('\r'); + prom_putchar(*s++); + } +} + +static int __init prom_console_setup(struct console *co, char *options) +{ + return !(prom_flags & PROM_FLAG_USE_AS_CONSOLE); +} + +static struct console arc_cons = { + .name = "arc", + .write = prom_console_write, + .setup = prom_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* + * Register console. + */ + +static int __init arc_console_init(void) +{ + register_console(&arc_cons); + + return 0; +} +console_initcall(arc_console_init); diff --git a/arch/mips/arc/cmdline.c b/arch/mips/arc/cmdline.c new file mode 100644 index 00000000000..fd604ef2882 --- /dev/null +++ b/arch/mips/arc/cmdline.c @@ -0,0 +1,108 @@ +/* + * 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. + * + * cmdline.c: Kernel command line creation using ARCS argc/argv. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> + +#include <asm/sgialib.h> +#include <asm/bootinfo.h> + +#undef DEBUG_CMDLINE + +char * __init prom_getcmdline(void) +{ + return arcs_cmdline; +} + +static char *ignored[] = { + "ConsoleIn=", + "ConsoleOut=", + "SystemPartition=", + "OSLoader=", + "OSLoadPartition=", + "OSLoadFilename=", + "OSLoadOptions=" +}; + +static char *used_arc[][2] = { + { "OSLoadPartition=", "root=" }, + { "OSLoadOptions=", "" } +}; + +static char * __init move_firmware_args(char* cp) +{ + char *s; + int actr, i; + + actr = 1; /* Always ignore argv[0] */ + + while (actr < prom_argc) { + for(i = 0; i < ARRAY_SIZE(used_arc); i++) { + int len = strlen(used_arc[i][0]); + + if (!strncmp(prom_argv(actr), used_arc[i][0], len)) { + /* Ok, we want it. First append the replacement... */ + strcat(cp, used_arc[i][1]); + cp += strlen(used_arc[i][1]); + /* ... and now the argument */ + s = strstr(prom_argv(actr), "="); + if (s) { + s++; + strcpy(cp, s); + cp += strlen(s); + } + *cp++ = ' '; + break; + } + } + actr++; + } + + return cp; +} + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr, i; + + actr = 1; /* Always ignore argv[0] */ + + cp = arcs_cmdline; + /* + * Move ARC variables to the beginning to make sure they can be + * overridden by later arguments. + */ + cp = move_firmware_args(cp); + + while (actr < prom_argc) { + for (i = 0; i < ARRAY_SIZE(ignored); i++) { + int len = strlen(ignored[i]); + + if (!strncmp(prom_argv(actr), ignored[i], len)) + goto pic_cont; + } + /* Ok, we want it. */ + strcpy(cp, prom_argv(actr)); + cp += strlen(prom_argv(actr)); + *cp++ = ' '; + + pic_cont: + actr++; + } + + if (cp != arcs_cmdline) /* get rid of trailing space */ + --cp; + *cp = '\0'; + +#ifdef DEBUG_CMDLINE + printk(KERN_DEBUG "prom cmdline: %s\n", arcs_cmdline); +#endif +} diff --git a/arch/mips/arc/console.c b/arch/mips/arc/console.c new file mode 100644 index 00000000000..6a9d144512c --- /dev/null +++ b/arch/mips/arc/console.c @@ -0,0 +1,63 @@ +/* + * 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) 1996 David S. Miller (dm@sgi.com) + * Compability with board caches, Ulf Carlsson + */ +#include <linux/kernel.h> +#include <asm/sgialib.h> +#include <asm/bcache.h> + +/* + * IP22 boardcache is not compatible with board caches. Thus we disable it + * during romvec action. Since r4xx0.c is always compiled and linked with your + * kernel, this shouldn't cause any harm regardless what MIPS processor you + * have. + * + * The ARC write and read functions seem to interfere with the serial lines + * in some way. You should be careful with them. + */ + +void prom_putchar(char c) +{ + ULONG cnt; + CHAR it = c; + + bc_disable(); + ArcWrite(1, &it, 1, &cnt); + bc_enable(); +} + +char prom_getchar(void) +{ + ULONG cnt; + CHAR c; + + bc_disable(); + ArcRead(0, &c, 1, &cnt); + bc_enable(); + + return c; +} + +void prom_printf(char *fmt, ...) +{ + va_list args; + char ppbuf[1024]; + char *bptr; + + va_start(args, fmt); + vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while (*bptr != 0) { + if (*bptr == '\n') + prom_putchar('\r'); + + prom_putchar(*bptr++); + } + va_end(args); +} diff --git a/arch/mips/arc/env.c b/arch/mips/arc/env.c new file mode 100644 index 00000000000..e521a6e010a --- /dev/null +++ b/arch/mips/arc/env.c @@ -0,0 +1,27 @@ +/* + * 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. + * + * env.c: ARCS environment variable routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> + +#include <asm/arc/types.h> +#include <asm/sgialib.h> + +PCHAR __init +ArcGetEnvironmentVariable(CHAR *name) +{ + return (CHAR *) ARC_CALL1(get_evar, name); +} + +LONG __init +ArcSetEnvironmentVariable(PCHAR name, PCHAR value) +{ + return ARC_CALL2(set_evar, name, value); +} diff --git a/arch/mips/arc/file.c b/arch/mips/arc/file.c new file mode 100644 index 00000000000..a43425b3c83 --- /dev/null +++ b/arch/mips/arc/file.c @@ -0,0 +1,75 @@ +/* + * 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. + * + * ARC firmware interface. + * + * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include <linux/init.h> + +#include <asm/arc/types.h> +#include <asm/sgialib.h> + +LONG __init +ArcGetDirectoryEntry(ULONG FileID, struct linux_vdirent *Buffer, + ULONG N, ULONG *Count) +{ + return ARC_CALL4(get_vdirent, FileID, Buffer, N, Count); +} + +LONG __init +ArcOpen(CHAR *Path, enum linux_omode OpenMode, ULONG *FileID) +{ + return ARC_CALL3(open, Path, OpenMode, FileID); +} + +LONG __init +ArcClose(ULONG FileID) +{ + return ARC_CALL1(close, FileID); +} + +LONG __init +ArcRead(ULONG FileID, VOID *Buffer, ULONG N, ULONG *Count) +{ + return ARC_CALL4(read, FileID, Buffer, N, Count); +} + +LONG __init +ArcGetReadStatus(ULONG FileID) +{ + return ARC_CALL1(get_rstatus, FileID); +} + +LONG __init +ArcWrite(ULONG FileID, PVOID Buffer, ULONG N, PULONG Count) +{ + return ARC_CALL4(write, FileID, Buffer, N, Count); +} + +LONG __init +ArcSeek(ULONG FileID, struct linux_bigint *Position, enum linux_seekmode SeekMode) +{ + return ARC_CALL3(seek, FileID, Position, SeekMode); +} + +LONG __init +ArcMount(char *name, enum linux_mountops op) +{ + return ARC_CALL2(mount, name, op); +} + +LONG __init +ArcGetFileInformation(ULONG FileID, struct linux_finfo *Information) +{ + return ARC_CALL2(get_finfo, FileID, Information); +} + +LONG __init ArcSetFileInformation(ULONG FileID, ULONG AttributeFlags, + ULONG AttributeMask) +{ + return ARC_CALL3(set_finfo, FileID, AttributeFlags, AttributeMask); +} diff --git a/arch/mips/arc/identify.c b/arch/mips/arc/identify.c new file mode 100644 index 00000000000..0dd7a345eb7 --- /dev/null +++ b/arch/mips/arc/identify.c @@ -0,0 +1,119 @@ +/* + * 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. + * + * identify.c: identify machine by looking up system identifier + * + * Copyright (C) 1998 Thomas Bogendoerfer + * + * This code is based on arch/mips/sgi/kernel/system.c, which is + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/string.h> + +#include <asm/sgialib.h> +#include <asm/bootinfo.h> + +struct smatch { + char *arcname; + char *liname; + int group; + int type; + int flags; +}; + +static struct smatch mach_table[] = { + { "SGI-IP22", + "SGI Indy", + MACH_GROUP_SGI, + MACH_SGI_IP22, + PROM_FLAG_ARCS + }, { "SGI-IP27", + "SGI Origin", + MACH_GROUP_SGI, + MACH_SGI_IP27, + PROM_FLAG_ARCS + }, { "SGI-IP28", + "SGI IP28", + MACH_GROUP_SGI, + MACH_SGI_IP28, + PROM_FLAG_ARCS + }, { "SGI-IP32", + "SGI O2", + MACH_GROUP_SGI, + MACH_SGI_IP32, + PROM_FLAG_ARCS + }, { "Microsoft-Jazz", + "Jazz MIPS_Magnum_4000", + MACH_GROUP_JAZZ, + MACH_MIPS_MAGNUM_4000, + 0 + }, { "PICA-61", + "Jazz Acer_PICA_61", + MACH_GROUP_JAZZ, + MACH_ACER_PICA_61, + 0 + }, { "RM200PCI", + "SNI RM200_PCI", + MACH_GROUP_SNI_RM, + MACH_SNI_RM200_PCI, + PROM_FLAG_DONT_FREE_TEMP + } +}; + +int prom_flags; + +static struct smatch * __init string_to_mach(const char *s) +{ + int i; + + for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) { + if (!strcmp(s, mach_table[i].arcname)) + return &mach_table[i]; + } + + panic("Yeee, could not determine architecture type <%s>", s); +} + +char *system_type; + +const char *get_system_type(void) +{ + return system_type; +} + +void __init prom_identify_arch(void) +{ + pcomponent *p; + struct smatch *mach; + const char *iname; + + /* + * The root component tells us what machine architecture we have here. + */ + p = ArcGetChild(PROM_NULL_COMPONENT); + if (p == NULL) { +#ifdef CONFIG_SGI_IP27 + /* IP27 PROM misbehaves, seems to not implement ARC + GetChild(). So we just assume it's an IP27. */ + iname = "SGI-IP27"; +#else + iname = "Unknown"; +#endif + } else + iname = (char *) (long) p->iname; + + printk("ARCH: %s\n", iname); + mach = string_to_mach(iname); + system_type = mach->liname; + + mips_machgroup = mach->group; + mips_machtype = mach->type; + prom_flags = mach->flags; +} diff --git a/arch/mips/arc/init.c b/arch/mips/arc/init.c new file mode 100644 index 00000000000..76ab505ca69 --- /dev/null +++ b/arch/mips/arc/init.c @@ -0,0 +1,48 @@ +/* + * 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. + * + * PROM library initialisation code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include <linux/init.h> +#include <linux/kernel.h> + +#include <asm/bootinfo.h> +#include <asm/sgialib.h> + +#undef DEBUG_PROM_INIT + +/* Master romvec interface. */ +struct linux_romvec *romvec; +int prom_argc; +LONG *_prom_argv, *_prom_envp; + +void __init prom_init(void) +{ + PSYSTEM_PARAMETER_BLOCK pb = PROMBLOCK; + romvec = ROMVECTOR; + prom_argc = fw_arg0; + _prom_argv = (LONG *) fw_arg1; + _prom_envp = (LONG *) fw_arg2; + + if (pb->magic != 0x53435241) { + prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); + while(1) + ; + } + + prom_init_cmdline(); + prom_identify_arch(); + printk(KERN_INFO "PROMLIB: ARC firmware Version %d Revision %d\n", + pb->ver, pb->rev); + prom_meminit(); + +#ifdef DEBUG_PROM_INIT + prom_printf("Press a key to reboot\n"); + prom_getchar(); + ArcEnterInteractiveMode(); +#endif +} diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c new file mode 100644 index 00000000000..958d2eb7886 --- /dev/null +++ b/arch/mips/arc/memory.c @@ -0,0 +1,170 @@ +/* + * memory.c: PROM library functions for acquiring/using memory descriptors + * given to us from the ARCS firmware. + * + * Copyright (C) 1996 by David S. Miller + * Copyright (C) 1999, 2000, 2001 by Ralf Baechle + * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. + * + * PROM library functions for acquiring/using memory descriptors given to us + * from the ARCS firmware. This is only used when CONFIG_ARC_MEMORY is set + * because on some machines like SGI IP27 the ARC memory configuration data + * completly bogus and alternate easier to use mechanisms are available. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/bootmem.h> +#include <linux/swap.h> + +#include <asm/sgialib.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/bootinfo.h> + +#undef DEBUG + +/* + * For ARC firmware memory functions the unit of meassuring memory is always + * a 4k page of memory + */ +#define ARC_PAGE_SHIFT 12 + +struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) +{ + return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); +} + +#ifdef DEBUG /* convenient for debugging */ +static char *arcs_mtypes[8] = { + "Exception Block", + "ARCS Romvec Page", + "Free/Contig RAM", + "Generic Free RAM", + "Bad Memory", + "Standalone Program Pages", + "ARCS Temp Storage Area", + "ARCS Permanent Storage Area" +}; + +static char *arc_mtypes[8] = { + "Exception Block", + "SystemParameterBlock", + "FreeMemory", + "Bad Memory", + "LoadedProgram", + "FirmwareTemporary", + "FirmwarePermanent", + "FreeContiguous" +}; +#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] \ + : arc_mtypes[a.arc] +#endif + +static inline int memtype_classify_arcs (union linux_memtypes type) +{ + switch (type.arcs) { + case arcs_fcontig: + case arcs_free: + return BOOT_MEM_RAM; + case arcs_atmp: + return BOOT_MEM_ROM_DATA; + case arcs_eblock: + case arcs_rvpage: + case arcs_bmem: + case arcs_prog: + case arcs_aperm: + return BOOT_MEM_RESERVED; + default: + BUG(); + } + while(1); /* Nuke warning. */ +} + +static inline int memtype_classify_arc (union linux_memtypes type) +{ + switch (type.arc) { + case arc_free: + case arc_fcontig: + return BOOT_MEM_RAM; + case arc_atmp: + return BOOT_MEM_ROM_DATA; + case arc_eblock: + case arc_rvpage: + case arc_bmem: + case arc_prog: + case arc_aperm: + return BOOT_MEM_RESERVED; + default: + BUG(); + } + while(1); /* Nuke warning. */ +} + +static int __init prom_memtype_classify (union linux_memtypes type) +{ + if (prom_flags & PROM_FLAG_ARCS) /* SGI is ``different'' ... */ + return memtype_classify_arcs(type); + + return memtype_classify_arc(type); +} + +void __init prom_meminit(void) +{ + struct linux_mdesc *p; + +#ifdef DEBUG + int i = 0; + + prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); + p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); + while(p) { + prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", + i, p, p->base, p->pages, mtypes(p->type)); + p = ArcGetMemoryDescriptor(p); + i++; + } +#endif + + p = PROM_NULL_MDESC; + while ((p = ArcGetMemoryDescriptor(p))) { + unsigned long base, size; + long type; + + base = p->base << ARC_PAGE_SHIFT; + size = p->pages << ARC_PAGE_SHIFT; + type = prom_memtype_classify(p->type); + + add_memory_region(base, size, type); + } +} + +unsigned long __init prom_free_prom_memory(void) +{ + unsigned long freed = 0; + unsigned long addr; + int i; + + if (prom_flags & PROM_FLAG_DONT_FREE_TEMP) + return 0; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) + continue; + + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(__va(addr))); + set_page_count(virt_to_page(__va(addr)), 1); + free_page((unsigned long)__va(addr)); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10); + + return freed; +} diff --git a/arch/mips/arc/misc.c b/arch/mips/arc/misc.c new file mode 100644 index 00000000000..84867de2202 --- /dev/null +++ b/arch/mips/arc/misc.c @@ -0,0 +1,108 @@ +/* + * 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. + * + * Miscellaneous ARCS PROM routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> + +#include <asm/bcache.h> + +#include <asm/arc/types.h> +#include <asm/sgialib.h> +#include <asm/bootinfo.h> +#include <asm/system.h> + +extern void *sgiwd93_host; +extern void reset_wd33c93(void *instance); + +VOID +ArcHalt(VOID) +{ + bc_disable(); + local_irq_disable(); +#ifdef CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(halt); +never: goto never; +} + +VOID +ArcPowerDown(VOID) +{ + bc_disable(); + local_irq_disable(); +#ifdef CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(pdown); +never: goto never; +} + +/* XXX is this a soft reset basically? XXX */ +VOID +ArcRestart(VOID) +{ + bc_disable(); + local_irq_disable(); +#ifdef CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(restart); +never: goto never; +} + +VOID +ArcReboot(VOID) +{ + bc_disable(); + local_irq_disable(); +#ifdef CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(reboot); +never: goto never; +} + +VOID +ArcEnterInteractiveMode(VOID) +{ + bc_disable(); + local_irq_disable(); +#ifdef CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(imode); +never: goto never; +} + +LONG +ArcSaveConfiguration(VOID) +{ + return ARC_CALL0(cfg_save); +} + +struct linux_sysid * +ArcGetSystemId(VOID) +{ + return (struct linux_sysid *) ARC_CALL0(get_sysid); +} + +VOID __init +ArcFlushAllCaches(VOID) +{ + ARC_CALL0(cache_flush); +} + +DISPLAY_STATUS * __init ArcGetDisplayStatus(ULONG FileID) +{ + return (DISPLAY_STATUS *) ARC_CALL1(GetDisplayStatus, FileID); +} diff --git a/arch/mips/arc/promlib.c b/arch/mips/arc/promlib.c new file mode 100644 index 00000000000..c508c00dbb6 --- /dev/null +++ b/arch/mips/arc/promlib.c @@ -0,0 +1,43 @@ +/* + * 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) 1996 David S. Miller (dm@sgi.com) + * Compability with board caches, Ulf Carlsson + */ +#include <linux/kernel.h> +#include <asm/sgialib.h> +#include <asm/bcache.h> + +/* + * IP22 boardcache is not compatible with board caches. Thus we disable it + * during romvec action. Since r4xx0.c is always compiled and linked with your + * kernel, this shouldn't cause any harm regardless what MIPS processor you + * have. + * + * The ARC write and read functions seem to interfere with the serial lines + * in some way. You should be careful with them. + */ + +void prom_putchar(char c) +{ + ULONG cnt; + CHAR it = c; + + bc_disable(); + ArcWrite(1, &it, 1, &cnt); + bc_enable(); +} + +char prom_getchar(void) +{ + ULONG cnt; + CHAR c; + + bc_disable(); + ArcRead(0, &c, 1, &cnt); + bc_enable(); + + return c; +} diff --git a/arch/mips/arc/salone.c b/arch/mips/arc/salone.c new file mode 100644 index 00000000000..e6afb64723d --- /dev/null +++ b/arch/mips/arc/salone.c @@ -0,0 +1,24 @@ +/* + * Routines to load into memory and execute stand-along program images using + * ARCS PROM firmware. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include <linux/init.h> +#include <asm/sgialib.h> + +LONG __init ArcLoad(CHAR *Path, ULONG TopAddr, ULONG *ExecAddr, ULONG *LowAddr) +{ + return ARC_CALL4(load, Path, TopAddr, ExecAddr, LowAddr); +} + +LONG __init ArcInvoke(ULONG ExecAddr, ULONG StackAddr, ULONG Argc, CHAR *Argv[], + CHAR *Envp[]) +{ + return ARC_CALL5(invoke, ExecAddr, StackAddr, Argc, Argv, Envp); +} + +LONG __init ArcExecute(CHAR *Path, LONG Argc, CHAR *Argv[], CHAR *Envp[]) +{ + return ARC_CALL4(exec, Path, Argc, Argv, Envp); +} diff --git a/arch/mips/arc/time.c b/arch/mips/arc/time.c new file mode 100644 index 00000000000..299ff2c5c0b --- /dev/null +++ b/arch/mips/arc/time.c @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Extracting time information from ARCS prom. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include <linux/init.h> + +#include <asm/arc/types.h> +#include <asm/sgialib.h> + +struct linux_tinfo * __init +ArcGetTime(VOID) +{ + return (struct linux_tinfo *) ARC_CALL0(get_tinfo); +} + +ULONG __init +ArcGetRelativeTime(VOID) +{ + return ARC_CALL0(get_rtime); +} diff --git a/arch/mips/arc/tree.c b/arch/mips/arc/tree.c new file mode 100644 index 00000000000..2aedd4f5283 --- /dev/null +++ b/arch/mips/arc/tree.c @@ -0,0 +1,127 @@ +/* + * 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. + * + * PROM component device tree code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include <linux/init.h> +#include <asm/arc/types.h> +#include <asm/sgialib.h> + +#undef DEBUG_PROM_TREE + +pcomponent * __init +ArcGetPeer(pcomponent *Current) +{ + if (Current == PROM_NULL_COMPONENT) + return PROM_NULL_COMPONENT; + + return (pcomponent *) ARC_CALL1(next_component, Current); +} + +pcomponent * __init +ArcGetChild(pcomponent *Current) +{ + return (pcomponent *) ARC_CALL1(child_component, Current); +} + +pcomponent * __init +ArcGetParent(pcomponent *Current) +{ + if (Current == PROM_NULL_COMPONENT) + return PROM_NULL_COMPONENT; + + return (pcomponent *) ARC_CALL1(parent_component, Current); +} + +LONG __init +ArcGetConfigurationData(VOID *Buffer, pcomponent *Current) +{ + return ARC_CALL2(component_data, Buffer, Current); +} + +pcomponent * __init +ArcAddChild(pcomponent *Current, pcomponent *Template, VOID *ConfigurationData) +{ + return (pcomponent *) + ARC_CALL3(child_add, Current, Template, ConfigurationData); +} + +LONG __init +ArcDeleteComponent(pcomponent *ComponentToDelete) +{ + return ARC_CALL1(comp_del, ComponentToDelete); +} + +pcomponent * __init +ArcGetComponent(CHAR *Path) +{ + return (pcomponent *)ARC_CALL1(component_by_path, Path); +} + +#ifdef DEBUG_PROM_TREE + +static char *classes[] = { + "system", "processor", "cache", "adapter", "controller", "peripheral", + "memory" +}; + +static char *types[] = { + "arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", + "sccache", "memdev", "eisa adapter", "tc adapter", "scsi adapter", + "dti adapter", "multi-func adapter", "disk controller", + "tp controller", "cdrom controller", "worm controller", + "serial controller", "net controller", "display controller", + "parallel controller", "pointer controller", "keyboard controller", + "audio controller", "misc controller", "disk peripheral", + "floppy peripheral", "tp peripheral", "modem peripheral", + "monitor peripheral", "printer peripheral", "pointer peripheral", + "keyboard peripheral", "terminal peripheral", "line peripheral", + "net peripheral", "misc peripheral", "anonymous" +}; + +static char *iflags[] = { + "bogus", "read only", "removable", "console in", "console out", + "input", "output" +}; + +static void __init +dump_component(pcomponent *p) +{ + prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>", + p, classes[p->class], types[p->type], + iflags[p->iflags], p->vers, p->rev); + prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n", + p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname); +} + +static void __init +traverse(pcomponent *p, int op) +{ + dump_component(p); + if(ArcGetChild(p)) + traverse(ArcGetChild(p), 1); + if(ArcGetPeer(p) && op) + traverse(ArcGetPeer(p), 1); +} + +void __init +prom_testtree(void) +{ + pcomponent *p; + + p = ArcGetChild(PROM_NULL_COMPONENT); + dump_component(p); + p = ArcGetChild(p); + while(p) { + dump_component(p); + p = ArcGetPeer(p); + } +} + +#endif /* DEBUG_PROM_TREE */ diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile new file mode 100644 index 00000000000..594b75e5e08 --- /dev/null +++ b/arch/mips/au1000/common/Makefile @@ -0,0 +1,15 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Au1000 CPU, generic files. +# + +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 + +obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o +obj-$(CONFIG_KGDB) += dbg_io.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/mips/au1000/common/au1xxx_irqmap.c b/arch/mips/au1000/common/au1xxx_irqmap.c new file mode 100644 index 00000000000..8a0f39f67c5 --- /dev/null +++ b/arch/mips/au1000/common/au1xxx_irqmap.c @@ -0,0 +1,224 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx processor specific IRQ tables + * + * Copyright 2004 Embedded Edge, LLC + * dan@embeddededge.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/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 <linux/bitops.h> + +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/mach-au1x00/au1000.h> + +/* The IC0 interrupt table. This is processor, rather than + * board dependent, so no reason to keep this info in the board + * dependent files. + * + * Careful if you change match 2 request! + * The interrupt handler is called directly from the low level dispatch code. + */ +au1xxx_irq_map_t au1xxx_ic0_map[] = { + +#if defined(CONFIG_SOC_AU1000) + { AU1000_UART0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_UART1_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_UART2_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_UART3_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_SSI0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_SSI1_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+1, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+2, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+3, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+4, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+5, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+6, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+7, INTC_INT_HIGH_LEVEL, 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 }, + { AU1000_IRDA_TX_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_IRDA_RX_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, + { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 }, + +#elif defined(CONFIG_SOC_AU1500) + + { AU1500_UART0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_PCI_INTA, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_PCI_INTB, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_UART3_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_PCI_INTC, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_PCI_INTD, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+1, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+2, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+3, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+4, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+5, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+6, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+7, INTC_INT_HIGH_LEVEL, 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 }, + { AU1000_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, + { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1500_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1500_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 }, + +#elif defined(CONFIG_SOC_AU1100) + + { AU1100_UART0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1100_UART1_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1100_SD_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1100_UART3_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_SSI0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_SSI1_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+1, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+2, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+3, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+4, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+5, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+6, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_DMA_INT_BASE+7, INTC_INT_HIGH_LEVEL, 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 }, + { AU1000_IRDA_TX_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_IRDA_RX_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, + { AU1000_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_ACSYNC_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1100_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + /*{ AU1000_GPIO215_208_INT, INTC_INT_HIGH_LEVEL, 0},*/ + { AU1100_LCD_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1000_AC97C_INT, INTC_INT_RISE_EDGE, 0 }, + +#elif defined(CONFIG_SOC_AU1550) + + { AU1550_UART0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1550_PCI_INTA, INTC_INT_LOW_LEVEL, 0 }, + { AU1550_PCI_INTB, INTC_INT_LOW_LEVEL, 0 }, + { AU1550_DDMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1550_CRYPTO_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1550_PCI_INTC, INTC_INT_LOW_LEVEL, 0 }, + { AU1550_PCI_INTD, INTC_INT_LOW_LEVEL, 0 }, + { AU1550_PCI_RST_INT, INTC_INT_LOW_LEVEL, 0 }, + { AU1550_UART1_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1550_UART3_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1550_PSC0_INT, INTC_INT_HIGH_LEVEL, 0}, + { 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 }, + { 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 }, + { AU1550_USB_HOST_INT, INTC_INT_LOW_LEVEL, 0 }, + { AU1550_MAC0_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1550_MAC1_DMA_INT, INTC_INT_HIGH_LEVEL, 0}, + +#elif defined(CONFIG_SOC_AU1200) + + { AU1200_UART0_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1200_SWT_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1200_SD_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1200_DDMA_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1200_MAE_BE_INT, INTC_INT_HIGH_LEVEL, 0 }, + { AU1200_UART1_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1200_MAE_FE_INT, INTC_INT_HIGH_LEVEL, 0 }, + { AU1200_PSC0_INT, INTC_INT_HIGH_LEVEL, 0}, + { 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 }, + { AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0}, + { AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 }, + { AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0}, + { AU1200_MAE_BOTH_INT, INTC_INT_HIGH_LEVEL, 0}, + +#else +#error "Error: Unknown Alchemy SOC" +#endif + +}; + +int au1xxx_ic0_nr_irqs = sizeof(au1xxx_ic0_map)/sizeof(au1xxx_irq_map_t); + diff --git a/arch/mips/au1000/common/clocks.c b/arch/mips/au1000/common/clocks.c new file mode 100644 index 00000000000..3ce6cace0eb --- /dev/null +++ b/arch/mips/au1000/common/clocks.c @@ -0,0 +1,96 @@ +/* + * BRIEF MODULE DESCRIPTION + * Simple Au1000 clocks routines. + * + * 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/module.h> +#include <asm/mach-au1x00/au1000.h> + +static unsigned int au1x00_clock; // Hz +static unsigned int lcd_clock; // KHz +static unsigned long uart_baud_base; + +/* + * Set the au1000_clock + */ +void set_au1x00_speed(unsigned int new_freq) +{ + au1x00_clock = new_freq; +} + +unsigned int get_au1x00_speed(void) +{ + return au1x00_clock; +} + + + +/* + * The UART baud base is not known at compile time ... if + * we want to be able to use the same code on different + * speed CPUs. + */ +unsigned long get_au1x00_uart_baud_base(void) +{ + return uart_baud_base; +} + +void set_au1x00_uart_baud_base(unsigned long new_baud_base) +{ + uart_baud_base = new_baud_base; +} + +/* + * Calculate the Au1x00's LCD clock based on the current + * cpu clock and the system bus clock, and try to keep it + * below 40 MHz (the Pb1000 board can lock-up if the LCD + * clock is over 40 MHz). + */ +void set_au1x00_lcd_clock(void) +{ + unsigned int static_cfg0; + unsigned int sys_busclk = + (get_au1x00_speed()/1000) / + ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2); + + static_cfg0 = au_readl(MEM_STCFG0); + + if (static_cfg0 & (1<<11)) + lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */ + else + lcd_clock = sys_busclk / 4; + + if (lcd_clock > 50000) /* Epson MAX */ + printk("warning: LCD clock too high (%d KHz)\n", lcd_clock); +} + +unsigned int get_au1x00_lcd_clock(void) +{ + return lcd_clock; +} + +EXPORT_SYMBOL(get_au1x00_lcd_clock); diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c new file mode 100644 index 00000000000..f5521dfccfd --- /dev/null +++ b/arch/mips/au1000/common/cputable.c @@ -0,0 +1,55 @@ +/* + * arch/mips/au1000/common/cputable.c + * + * Copyright (C) 2004 Dan Malek (dan@embeddededge.com) + * Copied from PowerPC and updated for Alchemy Au1xxx processors. + * + * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * 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/string.h> +#include <linux/sched.h> +#include <linux/threads.h> +#include <linux/init.h> +#include <asm/mach-au1x00/au1000.h> + +struct cpu_spec* cur_cpu_spec[NR_CPUS]; + +/* With some thought, we can probably use the mask to reduce the + * size of the table. + */ +struct cpu_spec cpu_specs[] = { + { 0xffffffff, 0x00030100, "Au1000 DA", 1, 0 }, + { 0xffffffff, 0x00030201, "Au1000 HA", 1, 0 }, + { 0xffffffff, 0x00030202, "Au1000 HB", 1, 0 }, + { 0xffffffff, 0x00030203, "Au1000 HC", 1, 1 }, + { 0xffffffff, 0x00030204, "Au1000 HD", 1, 1 }, + { 0xffffffff, 0x01030200, "Au1500 AB", 1, 1 }, + { 0xffffffff, 0x01030201, "Au1500 AC", 0, 1 }, + { 0xffffffff, 0x01030202, "Au1500 AD", 0, 1 }, + { 0xffffffff, 0x02030200, "Au1100 AB", 1, 1 }, + { 0xffffffff, 0x02030201, "Au1100 BA", 1, 1 }, + { 0xffffffff, 0x02030202, "Au1100 BC", 1, 1 }, + { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 }, + { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 }, + { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 }, + { 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 }, + { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 }, +}; + +void +set_cpuspec(void) +{ + struct cpu_spec *sp; + u32 prid; + + prid = read_c0_prid(); + sp = cpu_specs; + while ((prid & sp->prid_mask) != sp->prid_value) + sp++; + cur_cpu_spec[0] = sp; +} diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c new file mode 100644 index 00000000000..adfc3172aac --- /dev/null +++ b/arch/mips/au1000/common/dbdma.c @@ -0,0 +1,836 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * The Descriptor Based DMA channel manager that first appeared + * on the Au1550. I started with dma.c, but I think all that is + * left is this initial comment :-) + * + * Copyright 2004 Embedded Edge, LLC + * dan@embeddededge.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/config.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.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) + +/* + * The Descriptor Based DMA supports up to 16 channels. + * + * There are 32 devices defined. We keep an internal structure + * of devices using these channels, along with additional + * information. + * + * We allocate the descriptors and allow access to them through various + * functions. The drivers allocate the data buffers and assign them + * to the descriptors. + */ +static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock); + +/* I couldn't find a macro that did this...... +*/ +#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 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 */ + { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, + { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, + { DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 }, + { DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 }, + + /* EXT DMA */ + { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 }, + + /* USB DEV */ + { DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 }, + { DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 }, + { DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 }, + { DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 }, + { DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 }, + { DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 }, + + /* PSC 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 }, + + /* PSC 1 */ + { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, + { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, + + /* PSC 2 */ + { DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 }, + { DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 }, + + /* PSC 3 */ + { DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 }, + { DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 }, + + { DSCR_CMD0_PCI_WRITE, 0, 0, 0, 0x00000000, 0, 0 }, /* PCI */ + { DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 }, /* NAND */ + + /* MAC 0 */ + { DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, + + /* MAC 1 */ + { DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, + +#endif /* CONFIG_SOC_AU1550 */ + +#ifdef CONFIG_SOC_AU1200 + { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, + { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, + { DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 }, + { DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x11200000, 0, 0 }, + + { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, + + { DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + { 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_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 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_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_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_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + + { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + +#endif // CONFIG_SOC_AU1200 + + { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +}; + +#define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t)) + +static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS]; + +static dbdev_tab_t * +find_dbdev_id (u32 id) +{ + int i; + dbdev_tab_t *p; + for (i = 0; i < DBDEV_TAB_SIZE; ++i) { + p = &dbdev_tab[i]; + if (p->dev_id == id) + return p; + } + return NULL; +} + +/* Allocate a channel and return a non-zero descriptor if successful. +*/ +u32 +au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, + void (*callback)(int, void *, struct pt_regs *), void *callparam) +{ + unsigned long flags; + u32 used, chan, rv; + u32 dcp; + int i; + dbdev_tab_t *stp, *dtp; + chan_tab_t *ctp; + volatile au1x_dma_chan_t *cp; + + /* We do the intialization on the first channel allocation. + * We have to wait because of the interrupt handler initialization + * which can't be done successfully during board set up. + */ + if (!dbdma_initialized) + 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; + + used = 0; + rv = 0; + + /* Check to see if we can get both channels. + */ + spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); + if (!(stp->dev_flags & DEV_FLAGS_INUSE) || + (stp->dev_flags & DEV_FLAGS_ANYUSE)) { + /* Got source */ + stp->dev_flags |= DEV_FLAGS_INUSE; + if (!(dtp->dev_flags & DEV_FLAGS_INUSE) || + (dtp->dev_flags & DEV_FLAGS_ANYUSE)) { + /* Got destination */ + dtp->dev_flags |= DEV_FLAGS_INUSE; + } + else { + /* Can't get dest. Release src. + */ + stp->dev_flags &= ~DEV_FLAGS_INUSE; + used++; + } + } + else { + used++; + } + spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); + + if (!used) { + /* Let's see if we can allocate a channel for it. + */ + ctp = NULL; + chan = 0; + spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); + for (i=0; i<NUM_DBDMA_CHANS; i++) { + if (chan_tab_ptr[i] == NULL) { + /* If kmalloc fails, it is caught below same + * as a channel not available. + */ + ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL); + chan_tab_ptr[i] = ctp; + ctp->chan_index = chan = i; + break; + } + } + spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); + + if (ctp != NULL) { + memset(ctp, 0, sizeof(chan_tab_t)); + dcp = DDMA_CHANNEL_BASE; + dcp += (0x0100 * chan); + ctp->chan_ptr = (au1x_dma_chan_t *)dcp; + cp = (volatile au1x_dma_chan_t *)dcp; + ctp->chan_src = stp; + ctp->chan_dest = dtp; + ctp->chan_callback = callback; + ctp->chan_callparam = callparam; + + /* Initialize channel configuration. + */ + i = 0; + if (stp->dev_intlevel) + i |= DDMA_CFG_SED; + if (stp->dev_intpolarity) + i |= DDMA_CFG_SP; + if (dtp->dev_intlevel) + i |= DDMA_CFG_DED; + if (dtp->dev_intpolarity) + i |= DDMA_CFG_DP; + cp->ddma_cfg = i; + au_sync(); + + /* Return a non-zero value that can be used to + * find the channel information in subsequent + * operations. + */ + rv = (u32)(&chan_tab_ptr[chan]); + } + else { + /* Release devices. + */ + stp->dev_flags &= ~DEV_FLAGS_INUSE; + dtp->dev_flags &= ~DEV_FLAGS_INUSE; + } + } + return rv; +} + +/* Set the device width if source or destination is a FIFO. + * Should be 8, 16, or 32 bits. + */ +u32 +au1xxx_dbdma_set_devwidth(u32 chanid, int bits) +{ + u32 rv; + chan_tab_t *ctp; + dbdev_tab_t *stp, *dtp; + + ctp = *((chan_tab_t **)chanid); + stp = ctp->chan_src; + dtp = ctp->chan_dest; + rv = 0; + + if (stp->dev_flags & DEV_FLAGS_IN) { /* Source in fifo */ + rv = stp->dev_devwidth; + stp->dev_devwidth = bits; + } + if (dtp->dev_flags & DEV_FLAGS_OUT) { /* Destination out fifo */ + rv = dtp->dev_devwidth; + dtp->dev_devwidth = bits; + } + + return rv; +} + +/* Allocate a descriptor ring, initializing as much as possible. +*/ +u32 +au1xxx_dbdma_ring_alloc(u32 chanid, int entries) +{ + int i; + u32 desc_base, srcid, destid; + u32 cmd0, cmd1, src1, dest1; + u32 src0, dest0; + chan_tab_t *ctp; + dbdev_tab_t *stp, *dtp; + au1x_ddma_desc_t *dp; + + /* I guess we could check this to be within the + * range of the table...... + */ + ctp = *((chan_tab_t **)chanid); + stp = ctp->chan_src; + dtp = ctp->chan_dest; + + /* The descriptors must be 32-byte aligned. There is a + * possibility the allocation will give us such an address, + * 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); + if (desc_base == 0) + return 0; + + if (desc_base & 0x1f) { + /* Lost....do it again, allocate extra, and round + * the address base. + */ + 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) + return 0; + + desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); + } + dp = (au1x_ddma_desc_t *)desc_base; + + /* Keep track of the base descriptor. + */ + ctp->chan_desc_base = dp; + + /* Initialize the rings with as much information as we know. + */ + srcid = stp->dev_id; + destid = dtp->dev_id; + + cmd0 = cmd1 = src1 = dest1 = 0; + src0 = dest0 = 0; + + 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); + + switch (stp->dev_devwidth) { + case 8: + cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_BYTE); + break; + case 16: + cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_HALFWORD); + break; + case 32: + default: + cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_WORD); + break; + } + + switch (dtp->dev_devwidth) { + case 8: + cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_BYTE); + break; + case 16: + cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_HALFWORD); + break; + case 32: + default: + cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_WORD); + break; + } + + /* If the device is marked as an in/out FIFO, ensure it is + * set non-coherent. + */ + if (stp->dev_flags & DEV_FLAGS_IN) + cmd0 |= DSCR_CMD0_SN; /* Source in fifo */ + if (dtp->dev_flags & DEV_FLAGS_OUT) + cmd0 |= DSCR_CMD0_DN; /* Destination out fifo */ + + /* Set up source1. For now, assume no stride and increment. + * A channel attribute update can change this later. + */ + switch (stp->dev_tsize) { + case 1: + src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE1); + break; + case 2: + src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE2); + break; + case 4: + src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE4); + break; + case 8: + default: + src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE8); + break; + } + + /* If source input is fifo, set static address. + */ + if (stp->dev_flags & DEV_FLAGS_IN) { + src0 = stp->dev_physaddr; + src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC); + } + + /* Set up dest1. For now, assume no stride and increment. + * A channel attribute update can change this later. + */ + switch (dtp->dev_tsize) { + case 1: + dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE1); + break; + case 2: + dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE2); + break; + case 4: + dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE4); + break; + case 8: + default: + dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE8); + break; + } + + /* If destination output is fifo, set static address. + */ + if (dtp->dev_flags & DEV_FLAGS_OUT) { + dest0 = dtp->dev_physaddr; + dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC); + } + + for (i=0; i<entries; i++) { + dp->dscr_cmd0 = cmd0; + dp->dscr_cmd1 = cmd1; + dp->dscr_source0 = src0; + dp->dscr_source1 = src1; + dp->dscr_dest0 = dest0; + dp->dscr_dest1 = dest1; + dp->dscr_stat = 0; + dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1)); + dp++; + } + + /* Make last descrptor point to the first. + */ + dp--; + dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(ctp->chan_desc_base)); + ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base; + + return (u32)(ctp->chan_desc_base); +} + +/* 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) +{ + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + /* 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 address and byte count. + */ + 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 */ + + /* Get next descriptor pointer. + */ + ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + + /* return something not zero. + */ + return nbytes; +} + +/* 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) +{ + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + /* 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 address and byte count. + */ + dp->dscr_dest0 = virt_to_phys(buf); + dp->dscr_cmd1 = nbytes; + dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ + + /* Get next descriptor pointer. + */ + ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + + /* return something not zero. + */ + return nbytes; +} + +/* Get a destination buffer into the DMA ring. + * Normally used to get a full buffer from the ring during fifo + * to memory transfers. This does not set the valid bit, you will + * have to put another destination buffer to keep the DMA going. + */ +u32 +au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes) +{ + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + u32 rv; + + /* 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->get_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; + + /* Return buffer address and byte count. + */ + *buf = (void *)(phys_to_virt(dp->dscr_dest0)); + *nbytes = dp->dscr_cmd1; + rv = dp->dscr_stat; + + /* Get next descriptor pointer. + */ + ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + + /* return something not zero. + */ + return rv; +} + +void +au1xxx_dbdma_stop(u32 chanid) +{ + chan_tab_t *ctp; + volatile au1x_dma_chan_t *cp; + int halt_timeout = 0; + + ctp = *((chan_tab_t **)chanid); + + cp = ctp->chan_ptr; + cp->ddma_cfg &= ~DDMA_CFG_EN; /* Disable channel */ + au_sync(); + while (!(cp->ddma_stat & DDMA_STAT_H)) { + udelay(1); + halt_timeout++; + if (halt_timeout > 100) { + printk("warning: DMA channel won't halt\n"); + break; + } + } + /* clear current desc valid and doorbell */ + cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V); + au_sync(); +} + +/* Start using the current descriptor pointer. If the dbdma encounters + * a not valid descriptor, it will stop. In this case, we can just + * continue by adding a buffer to the list and starting again. + */ +void +au1xxx_dbdma_start(u32 chanid) +{ + chan_tab_t *ctp; + volatile 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 */ + au_sync(); +} + +void +au1xxx_dbdma_reset(u32 chanid) +{ + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + au1xxx_dbdma_stop(chanid); + + ctp = *((chan_tab_t **)chanid); + ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base; + + /* Run through the descriptors and reset the valid indicator. + */ + dp = ctp->chan_desc_base; + + do { + dp->dscr_cmd0 &= ~DSCR_CMD0_V; + dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + } while (dp != ctp->chan_desc_base); +} + +u32 +au1xxx_get_dma_residue(u32 chanid) +{ + chan_tab_t *ctp; + volatile au1x_dma_chan_t *cp; + u32 rv; + + ctp = *((chan_tab_t **)chanid); + cp = ctp->chan_ptr; + + /* This is only valid if the channel is stopped. + */ + rv = cp->ddma_bytecnt; + au_sync(); + + return rv; +} + +void +au1xxx_dbdma_chan_free(u32 chanid) +{ + chan_tab_t *ctp; + dbdev_tab_t *stp, *dtp; + + ctp = *((chan_tab_t **)chanid); + stp = ctp->chan_src; + dtp = ctp->chan_dest; + + au1xxx_dbdma_stop(chanid); + + if (ctp->chan_desc_base != NULL) + kfree(ctp->chan_desc_base); + + stp->dev_flags &= ~DEV_FLAGS_INUSE; + dtp->dev_flags &= ~DEV_FLAGS_INUSE; + chan_tab_ptr[ctp->chan_index] = NULL; + + kfree(ctp); +} + +static irqreturn_t +dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 intstat; + u32 chan_index; + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + volatile au1x_dma_chan_t *cp; + + intstat = dbdma_gptr->ddma_intstat; + au_sync(); + chan_index = au_ffs(intstat) - 1; + + ctp = chan_tab_ptr[chan_index]; + cp = ctp->chan_ptr; + dp = ctp->cur_ptr; + + /* Reset interrupt. + */ + cp->ddma_irq = 0; + au_sync(); + + if (ctp->chan_callback) + (ctp->chan_callback)(irq, ctp->chan_callparam, regs); + + ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + + return IRQ_HANDLED; +} + +static void +au1xxx_dbdma_init(void) +{ + 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, + "Au1xxx dbdma", (void *)dbdma_gptr)) + printk("Can't get 1550 dbdma irq"); +} + +void +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; + + ctp = *((chan_tab_t **)chanid); + stp = ctp->chan_src; + dtp = ctp->chan_dest; + cp = ctp->chan_ptr; + + printk("Chan %x, stp %x (dev %d) dtp %x (dev %d) \n", + (u32)ctp, (u32)stp, stp - dbdev_tab, (u32)dtp, dtp - dbdev_tab); + printk("desc base %x, get %x, put %x, cur %x\n", + (u32)(ctp->chan_desc_base), (u32)(ctp->get_ptr), + (u32)(ctp->put_ptr), (u32)(ctp->cur_ptr)); + + printk("dbdma chan %x\n", (u32)cp); + printk("cfg %08x, desptr %08x, statptr %08x\n", + cp->ddma_cfg, cp->ddma_desptr, cp->ddma_statptr); + printk("dbell %08x, irq %08x, stat %08x, bytecnt %08x\n", + cp->ddma_dbell, cp->ddma_irq, cp->ddma_stat, cp->ddma_bytecnt); + + + /* Run through the descriptors + */ + 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); + dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + } while (dp != ctp->chan_desc_base); +} + +#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ + diff --git a/arch/mips/au1000/common/dbg_io.c b/arch/mips/au1000/common/dbg_io.c new file mode 100644 index 00000000000..7bc768e558d --- /dev/null +++ b/arch/mips/au1000/common/dbg_io.c @@ -0,0 +1,122 @@ + +#include <linux/config.h> +#include <asm/io.h> +#include <asm/mach-au1x00/au1000.h> + +#ifdef CONFIG_KGDB + +/* + * FIXME the user should be able to select the + * uart to be used for debugging. + */ +#define DEBUG_BASE UART_DEBUG_BASE +/**/ + +/* we need uint32 uint8 */ +/* #include "types.h" */ +typedef unsigned char uint8; +typedef unsigned int uint32; + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + + +#define UART_RX 0 /* Receive buffer */ +#define UART_TX 4 /* Transmit buffer */ +#define UART_IER 8 /* Interrupt Enable Register */ +#define UART_IIR 0xC /* Interrupt ID Register */ +#define UART_FCR 0x10 /* FIFO Control Register */ +#define UART_LCR 0x14 /* Line Control Register */ +#define UART_MCR 0x18 /* Modem Control Register */ +#define UART_LSR 0x1C /* Line Status Register */ +#define UART_MSR 0x20 /* Modem Status Register */ +#define UART_CLK 0x28 /* Baud Rat4e Clock Divider */ +#define UART_MOD_CNTRL 0x100 /* Module Control */ + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff) +#define UART16550_WRITE(y,z) (au_writel(z&0xff, DEBUG_BASE + y)) + +extern unsigned long get_au1x00_uart_baud_base(void); +extern unsigned long cal_r4koff(void); + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + + if (UART16550_READ(UART_MOD_CNTRL) != 0x3) { + UART16550_WRITE(UART_MOD_CNTRL, 3); + } + cal_r4koff(); + + /* disable interrupts */ + UART16550_WRITE(UART_IER, 0); + + /* set up baud rate */ + { + uint32 divisor; + + /* set divisor */ + divisor = get_au1x00_uart_baud_base() / baud; + UART16550_WRITE(UART_CLK, divisor & 0xffff); + } + + /* set data format */ + UART16550_WRITE(UART_LCR, (data | parity | stop)); +} + +static int remoteDebugInitialized = 0; + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_115200, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while((UART16550_READ(UART_LSR) & 0x1) == 0); + return UART16550_READ(UART_RX); +} + + +int putDebugChar(uint8 byte) +{ +// int i; + + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_115200, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while ((UART16550_READ(UART_LSR)&0x40) == 0); + UART16550_WRITE(UART_TX, byte); + //for (i=0;i<0xfff;i++); + + return 1; +} + +#endif diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c new file mode 100644 index 00000000000..372c33f1353 --- /dev/null +++ b/arch/mips/au1000/common/dma.c @@ -0,0 +1,243 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * A DMA channel allocator for Au1000. API is modeled loosely off of + * linux/kernel/dma.c. + * + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) + * + * 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 <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/module.h> +#include <asm/system.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1000_dma.h> + +#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1100) +/* + * A note on resource allocation: + * + * All drivers needing DMA channels, should allocate and release them + * through the public routines `request_dma()' and `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 request_dma. + */ + + +DEFINE_SPINLOCK(au1000_dma_spin_lock); + +struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = { + {.dev_id = -1,}, + {.dev_id = -1,}, + {.dev_id = -1,}, + {.dev_id = -1,}, + {.dev_id = -1,}, + {.dev_id = -1,}, + {.dev_id = -1,}, + {.dev_id = -1,} +}; +EXPORT_SYMBOL(au1000_dma_table); + +// Device FIFO addresses and default DMA modes +static const struct dma_dev { + unsigned int fifo_addr; + unsigned int dma_mode; +} dma_dev_table[DMA_NUM_DEV] = { + {UART0_ADDR + UART_TX, 0}, + {UART0_ADDR + UART_RX, 0}, + {0, 0}, + {0, 0}, + {AC97C_DATA, DMA_DW16 }, // coherent + {AC97C_DATA, DMA_DR | DMA_DW16 }, // coherent + {UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC}, + {UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC}, + {USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC}, + {USBD_EP0WR, DMA_DW8 | DMA_NC}, + {USBD_EP2WR, DMA_DW8 | DMA_NC}, + {USBD_EP3WR, DMA_DW8 | DMA_NC}, + {USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC}, + {USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC}, + {I2S_DATA, DMA_DW32 | DMA_NC}, + {I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC} +}; + +int au1000_dma_read_proc(char *buf, char **start, off_t fpos, + int length, int *eof, void *data) +{ + int i, len = 0; + struct dma_chan *chan; + + for (i = 0; i < NUM_AU1000_DMA_CHANNELS; 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; +} + +// Device FIFO addresses and default DMA modes - 2nd bank +static const struct dma_dev dma_dev_table_bank2[DMA_NUM_DEV_BANK2] = { + {SD0_XMIT_FIFO, DMA_DS | DMA_DW8}, // coherent + {SD0_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8}, // coherent + {SD1_XMIT_FIFO, DMA_DS | DMA_DW8}, // coherent + {SD1_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8} // coherent +}; + +void dump_au1000_dma_channel(unsigned int dmanr) +{ + struct dma_chan *chan; + + if (dmanr >= NUM_AU1000_DMA_CHANNELS) + return; + chan = &au1000_dma_table[dmanr]; + + printk(KERN_INFO "Au1000 DMA%d Register Dump:\n", dmanr); + printk(KERN_INFO " mode = 0x%08x\n", + au_readl(chan->io + DMA_MODE_SET)); + printk(KERN_INFO " addr = 0x%08x\n", + au_readl(chan->io + DMA_PERIPHERAL_ADDR)); + printk(KERN_INFO " start0 = 0x%08x\n", + au_readl(chan->io + DMA_BUFFER0_START)); + printk(KERN_INFO " start1 = 0x%08x\n", + au_readl(chan->io + DMA_BUFFER1_START)); + printk(KERN_INFO " count0 = 0x%08x\n", + au_readl(chan->io + DMA_BUFFER0_COUNT)); + printk(KERN_INFO " count1 = 0x%08x\n", + au_readl(chan->io + DMA_BUFFER1_COUNT)); +} + + +/* + * 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 request_au1000_dma(int dev_id, const char *dev_str, + irqreturn_t (*irqhandler)(int, void *, struct pt_regs *), + unsigned long irqflags, + void *irq_dev_id) +{ + struct dma_chan *chan; + const struct dma_dev *dev; + int i, ret; + +#if defined(CONFIG_SOC_AU1100) + if (dev_id < 0 || dev_id >= (DMA_NUM_DEV + DMA_NUM_DEV_BANK2)) + return -EINVAL; +#else + if (dev_id < 0 || dev_id >= DMA_NUM_DEV) + return -EINVAL; +#endif + + for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) { + if (au1000_dma_table[i].dev_id < 0) + break; + } + if (i == NUM_AU1000_DMA_CHANNELS) + return -ENODEV; + + chan = &au1000_dma_table[i]; + + if (dev_id >= DMA_NUM_DEV) { + dev_id -= DMA_NUM_DEV; + dev = &dma_dev_table_bank2[dev_id]; + } else { + dev = &dma_dev_table[dev_id]; + } + + if (irqhandler) { + chan->irq = AU1000_DMA_INT_BASE + i; + 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 = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN; + chan->dev_id = dev_id; + chan->dev_str = dev_str; + chan->fifo_addr = dev->fifo_addr; + chan->mode = dev->dma_mode; + + /* initialize the channel before returning */ + init_dma(i); + + return i; +} +EXPORT_SYMBOL(request_au1000_dma); + +void free_au1000_dma(unsigned int dmanr) +{ + struct 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; +} +EXPORT_SYMBOL(free_au1000_dma); + +#endif // AU1000 AU1500 AU1100 diff --git a/arch/mips/au1000/common/int-handler.S b/arch/mips/au1000/common/int-handler.S new file mode 100644 index 00000000000..1c4ca883321 --- /dev/null +++ b/arch/mips/au1000/common/int-handler.S @@ -0,0 +1,68 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: ppopov@mvista.com + * + * Interrupt dispatcher for Au1000 boards. + * + * 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/asm.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .text + .set macro + .set noat + .align 5 + +NESTED(au1000_IRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + + andi t0,0xff00 # isolate pending bits + beqz t0, 3f # spurious interrupt + + andi a0, t0, CAUSEF_IP7 + beq a0, zero, 1f + move a0, sp + jal mips_timer_interrupt + j ret_from_irq + +1: + andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0 + beq a0, zero, 2f + move a0,sp + jal intc0_req0_irqdispatch + j ret_from_irq +2: + andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1 + beq a0, zero, 3f + move a0,sp + jal intc0_req1_irqdispatch + j ret_from_irq +3: + andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0 + beq a0, zero, 4f + move a0,sp + jal intc1_req0_irqdispatch + j ret_from_irq +4: + andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1 + beq a0, zero, 5f + move a0, sp + jal intc1_req1_irqdispatch + j ret_from_irq + +5: + move a0, sp + j spurious_interrupt +END(au1000_IRQ) diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c new file mode 100644 index 00000000000..d1eb5a4a9a1 --- /dev/null +++ b/arch/mips/au1000/common/irq.c @@ -0,0 +1,654 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1000 interrupt routines. + * + * 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/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 <linux/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_PB1000 +#include <asm/mach-pb1x00/pb1000.h> +#endif + +#undef DEBUG_IRQ +#ifdef DEBUG_IRQ +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define EXT_INTC0_REQ0 2 /* IP 2 */ +#define EXT_INTC0_REQ1 3 /* IP 3 */ +#define EXT_INTC1_REQ0 4 /* IP 4 */ +#define EXT_INTC1_REQ1 5 /* IP 5 */ +#define MIPS_TIMER_IP 7 /* IP 7 */ + +extern asmlinkage void au1000_IRQ(void); +extern void set_debug_traps(void); +extern irq_cpustat_t irq_stat [NR_CPUS]; + +static void setup_local_irq(unsigned int irq, int type, int int_req); +static unsigned int startup_irq(unsigned int irq); +static void end_irq(unsigned int irq_nr); +static inline void mask_and_ack_level_irq(unsigned int irq_nr); +static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr); +static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr); +static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr); +inline void local_enable_irq(unsigned int irq_nr); +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); +#endif + +static DEFINE_SPINLOCK(irq_lock); + + +static unsigned int startup_irq(unsigned int irq_nr) +{ + local_enable_irq(irq_nr); + return 0; +} + + +static void shutdown_irq(unsigned int irq_nr) +{ + local_disable_irq(irq_nr); + return; +} + + +inline void local_enable_irq(unsigned int irq_nr) +{ + if (irq_nr > AU1000_LAST_INTC0_INT) { + au_writel(1<<(irq_nr-32), IC1_MASKSET); + au_writel(1<<(irq_nr-32), IC1_WAKESET); + } + else { + au_writel(1<<irq_nr, IC0_MASKSET); + au_writel(1<<irq_nr, IC0_WAKESET); + } + au_sync(); +} + + +inline void local_disable_irq(unsigned int irq_nr) +{ + if (irq_nr > AU1000_LAST_INTC0_INT) { + au_writel(1<<(irq_nr-32), IC1_MASKCLR); + au_writel(1<<(irq_nr-32), IC1_WAKECLR); + } + else { + au_writel(1<<irq_nr, IC0_MASKCLR); + au_writel(1<<irq_nr, IC0_WAKECLR); + } + au_sync(); +} + + +static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr) +{ + if (irq_nr > AU1000_LAST_INTC0_INT) { + au_writel(1<<(irq_nr-32), IC1_RISINGCLR); + au_writel(1<<(irq_nr-32), IC1_MASKCLR); + } + else { + au_writel(1<<irq_nr, IC0_RISINGCLR); + au_writel(1<<irq_nr, IC0_MASKCLR); + } + au_sync(); +} + + +static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr) +{ + if (irq_nr > AU1000_LAST_INTC0_INT) { + au_writel(1<<(irq_nr-32), IC1_FALLINGCLR); + au_writel(1<<(irq_nr-32), IC1_MASKCLR); + } + else { + au_writel(1<<irq_nr, IC0_FALLINGCLR); + au_writel(1<<irq_nr, IC0_MASKCLR); + } + au_sync(); +} + + +static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr) +{ + /* This may assume that we don't get interrupts from + * both edges at once, or if we do, that we don't care. + */ + if (irq_nr > AU1000_LAST_INTC0_INT) { + au_writel(1<<(irq_nr-32), IC1_FALLINGCLR); + au_writel(1<<(irq_nr-32), IC1_RISINGCLR); + au_writel(1<<(irq_nr-32), IC1_MASKCLR); + } + else { + au_writel(1<<irq_nr, IC0_FALLINGCLR); + au_writel(1<<irq_nr, IC0_RISINGCLR); + au_writel(1<<irq_nr, IC0_MASKCLR); + } + au_sync(); +} + + +static inline void mask_and_ack_level_irq(unsigned int irq_nr) +{ + + local_disable_irq(irq_nr); + au_sync(); +#if defined(CONFIG_MIPS_PB1000) + if (irq_nr == AU1000_GPIO_15) { + au_writel(0x8000, PB1000_MDR); /* ack int */ + au_sync(); + } +#endif + return; +} + + +static void end_irq(unsigned int irq_nr) +{ + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + local_enable_irq(irq_nr); + } +#if defined(CONFIG_MIPS_PB1000) + if (irq_nr == AU1000_GPIO_15) { + au_writel(0x4000, PB1000_MDR); /* enable int */ + au_sync(); + } +#endif +} + +unsigned long save_local_and_disable(int controller) +{ + int i; + unsigned long flags, mask; + + spin_lock_irqsave(&irq_lock, flags); + if (controller) { + mask = au_readl(IC1_MASKSET); + for (i=32; i<64; i++) { + local_disable_irq(i); + } + } + else { + mask = au_readl(IC0_MASKSET); + for (i=0; i<32; i++) { + local_disable_irq(i); + } + } + spin_unlock_irqrestore(&irq_lock, flags); + + return mask; +} + +void restore_local_and_enable(int controller, unsigned long mask) +{ + int i; + unsigned long flags, new_mask; + + spin_lock_irqsave(&irq_lock, flags); + for (i=0; i<32; i++) { + if (mask & (1<<i)) { + if (controller) + local_enable_irq(i+32); + else + local_enable_irq(i); + } + } + if (controller) + new_mask = au_readl(IC1_MASKSET); + else + new_mask = au_readl(IC0_MASKSET); + + spin_unlock_irqrestore(&irq_lock, flags); +} + + +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 +}; + +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 +}; + +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 +}; + +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 +}; + +#ifdef CONFIG_PM +void startup_match20_interrupt(void) +{ + local_enable_irq(AU1000_TOY_MATCH2_INT); +} +#endif + +static void setup_local_irq(unsigned int irq_nr, int type, int int_req) +{ + if (irq_nr > AU1000_MAX_INTR) return; + /* Config2[n], Config1[n], Config0[n] */ + if (irq_nr > AU1000_LAST_INTC0_INT) { + switch (type) { + case INTC_INT_RISE_EDGE: /* 0:0:1 */ + au_writel(1<<(irq_nr-32), IC1_CFG2CLR); + au_writel(1<<(irq_nr-32), IC1_CFG1CLR); + au_writel(1<<(irq_nr-32), IC1_CFG0SET); + irq_desc[irq_nr].handler = &rise_edge_irq_type; + break; + case INTC_INT_FALL_EDGE: /* 0:1:0 */ + au_writel(1<<(irq_nr-32), IC1_CFG2CLR); + au_writel(1<<(irq_nr-32), IC1_CFG1SET); + au_writel(1<<(irq_nr-32), IC1_CFG0CLR); + irq_desc[irq_nr].handler = &fall_edge_irq_type; + break; + case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ + au_writel(1<<(irq_nr-32), IC1_CFG2CLR); + au_writel(1<<(irq_nr-32), IC1_CFG1SET); + au_writel(1<<(irq_nr-32), IC1_CFG0SET); + irq_desc[irq_nr].handler = &either_edge_irq_type; + break; + case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ + au_writel(1<<(irq_nr-32), IC1_CFG2SET); + au_writel(1<<(irq_nr-32), IC1_CFG1CLR); + au_writel(1<<(irq_nr-32), IC1_CFG0SET); + irq_desc[irq_nr].handler = &level_irq_type; + break; + case INTC_INT_LOW_LEVEL: /* 1:1:0 */ + au_writel(1<<(irq_nr-32), IC1_CFG2SET); + au_writel(1<<(irq_nr-32), IC1_CFG1SET); + au_writel(1<<(irq_nr-32), IC1_CFG0CLR); + irq_desc[irq_nr].handler = &level_irq_type; + break; + case INTC_INT_DISABLED: /* 0:0:0 */ + au_writel(1<<(irq_nr-32), IC1_CFG0CLR); + au_writel(1<<(irq_nr-32), IC1_CFG1CLR); + au_writel(1<<(irq_nr-32), IC1_CFG2CLR); + break; + default: /* disable the interrupt */ + printk("unexpected int type %d (irq %d)\n", type, irq_nr); + au_writel(1<<(irq_nr-32), IC1_CFG0CLR); + au_writel(1<<(irq_nr-32), IC1_CFG1CLR); + au_writel(1<<(irq_nr-32), IC1_CFG2CLR); + return; + } + if (int_req) /* assign to interrupt request 1 */ + au_writel(1<<(irq_nr-32), IC1_ASSIGNCLR); + else /* assign to interrupt request 0 */ + au_writel(1<<(irq_nr-32), IC1_ASSIGNSET); + au_writel(1<<(irq_nr-32), IC1_SRCSET); + au_writel(1<<(irq_nr-32), IC1_MASKCLR); + au_writel(1<<(irq_nr-32), IC1_WAKECLR); + } + else { + switch (type) { + case INTC_INT_RISE_EDGE: /* 0:0:1 */ + au_writel(1<<irq_nr, IC0_CFG2CLR); + au_writel(1<<irq_nr, IC0_CFG1CLR); + au_writel(1<<irq_nr, IC0_CFG0SET); + irq_desc[irq_nr].handler = &rise_edge_irq_type; + break; + case INTC_INT_FALL_EDGE: /* 0:1:0 */ + au_writel(1<<irq_nr, IC0_CFG2CLR); + au_writel(1<<irq_nr, IC0_CFG1SET); + au_writel(1<<irq_nr, IC0_CFG0CLR); + irq_desc[irq_nr].handler = &fall_edge_irq_type; + break; + case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ + au_writel(1<<irq_nr, IC0_CFG2CLR); + au_writel(1<<irq_nr, IC0_CFG1SET); + au_writel(1<<irq_nr, IC0_CFG0SET); + irq_desc[irq_nr].handler = &either_edge_irq_type; + break; + case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ + au_writel(1<<irq_nr, IC0_CFG2SET); + au_writel(1<<irq_nr, IC0_CFG1CLR); + au_writel(1<<irq_nr, IC0_CFG0SET); + irq_desc[irq_nr].handler = &level_irq_type; + break; + case INTC_INT_LOW_LEVEL: /* 1:1:0 */ + au_writel(1<<irq_nr, IC0_CFG2SET); + au_writel(1<<irq_nr, IC0_CFG1SET); + au_writel(1<<irq_nr, IC0_CFG0CLR); + irq_desc[irq_nr].handler = &level_irq_type; + break; + case INTC_INT_DISABLED: /* 0:0:0 */ + au_writel(1<<irq_nr, IC0_CFG0CLR); + au_writel(1<<irq_nr, IC0_CFG1CLR); + au_writel(1<<irq_nr, IC0_CFG2CLR); + break; + default: /* disable the interrupt */ + printk("unexpected int type %d (irq %d)\n", type, irq_nr); + au_writel(1<<irq_nr, IC0_CFG0CLR); + au_writel(1<<irq_nr, IC0_CFG1CLR); + au_writel(1<<irq_nr, IC0_CFG2CLR); + return; + } + if (int_req) /* assign to interrupt request 1 */ + au_writel(1<<irq_nr, IC0_ASSIGNCLR); + else /* assign to interrupt request 0 */ + au_writel(1<<irq_nr, IC0_ASSIGNSET); + au_writel(1<<irq_nr, IC0_SRCSET); + au_writel(1<<irq_nr, IC0_MASKCLR); + au_writel(1<<irq_nr, IC0_WAKECLR); + } + au_sync(); +} + + +void __init arch_init_irq(void) +{ + int i; + unsigned long cp0_status; + au1xxx_irq_map_t *imp; + extern au1xxx_irq_map_t au1xxx_irq_map[]; + extern au1xxx_irq_map_t au1xxx_ic0_map[]; + extern int au1xxx_nr_irqs; + 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. + */ + au_writel(0xffffffff, IC0_CFG0CLR); + au_writel(0xffffffff, IC0_CFG1CLR); + au_writel(0xffffffff, IC0_CFG2CLR); + au_writel(0xffffffff, IC0_MASKCLR); + au_writel(0xffffffff, IC0_ASSIGNSET); + au_writel(0xffffffff, IC0_WAKECLR); + au_writel(0xffffffff, IC0_SRCSET); + au_writel(0xffffffff, IC0_FALLINGCLR); + au_writel(0xffffffff, IC0_RISINGCLR); + au_writel(0x00000000, IC0_TESTBIT); + + au_writel(0xffffffff, IC1_CFG0CLR); + au_writel(0xffffffff, IC1_CFG1CLR); + au_writel(0xffffffff, IC1_CFG2CLR); + au_writel(0xffffffff, IC1_MASKCLR); + au_writel(0xffffffff, IC1_ASSIGNSET); + au_writel(0xffffffff, IC1_WAKECLR); + au_writel(0xffffffff, IC1_SRCSET); + au_writel(0xffffffff, IC1_FALLINGCLR); + au_writel(0xffffffff, IC1_RISINGCLR); + au_writel(0x00000000, IC1_TESTBIT); + + /* Initialize IC0, which is fixed per processor. + */ + imp = au1xxx_ic0_map; + for (i=0; i<au1xxx_ic0_nr_irqs; i++) { + setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); + imp++; + } + + /* Now set up the irq mapping for the board. + */ + imp = au1xxx_irq_map; + for (i=0; i<au1xxx_nr_irqs; i++) { + setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); + imp++; + } + + set_c0_status(ALLINTS); + + /* Board specific IRQ initialization. + */ + if (board_init_irq) + (*board_init_irq)(); +} + + +/* + * Interrupts are nested. Even if an interrupt handler is registered + * as "fast", we might get another interrupt before we return from + * intcX_reqX_irqdispatch(). + */ + +void intc0_req0_irqdispatch(struct pt_regs *regs) +{ + int irq = 0; + static unsigned long intc0_req0 = 0; + + intc0_req0 |= au_readl(IC0_REQ0INT); + + if (!intc0_req0) return; + + /* + * Because of the tight timing of SETUP token to reply + * transactions, the USB devices-side packet complete + * interrupt needs the highest priority. + */ + if ((intc0_req0 & (1<<AU1000_USB_DEV_REQ_INT))) { + intc0_req0 &= ~(1<<AU1000_USB_DEV_REQ_INT); + do_IRQ(AU1000_USB_DEV_REQ_INT, regs); + return; + } + + irq = au_ffs(intc0_req0) - 1; + intc0_req0 &= ~(1<<irq); + do_IRQ(irq, regs); +} + + +void intc0_req1_irqdispatch(struct pt_regs *regs) +{ + int irq = 0; + static unsigned long intc0_req1 = 0; + + intc0_req1 |= au_readl(IC0_REQ1INT); + + if (!intc0_req1) return; + + 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); + } +} + + +/* + * Interrupt Controller 1: + * interrupts 32 - 63 + */ +void intc1_req0_irqdispatch(struct pt_regs *regs) +{ + int irq = 0; + static unsigned long intc1_req0 = 0; + + intc1_req0 |= au_readl(IC1_REQ0INT); + + if (!intc1_req0) return; + + irq = au_ffs(intc1_req0) - 1; + intc1_req0 &= ~(1<<irq); + irq += 32; + do_IRQ(irq, regs); +} + + +void intc1_req1_irqdispatch(struct pt_regs *regs) +{ + int irq = 0; + static unsigned long intc1_req1 = 0; + + intc1_req1 |= au_readl(IC1_REQ1INT); + + if (!intc1_req1) return; + + irq = au_ffs(intc1_req1) - 1; + intc1_req1 &= ~(1<<irq); + irq += 32; + do_IRQ(irq, regs); +} + +#ifdef CONFIG_PM + +/* Save/restore the interrupt controller state. + * Called from the save/restore core registers as part of the + * au_sleep function in power.c.....maybe I should just pm_register() + * them instead? + */ +static uint sleep_intctl_config0[2]; +static uint sleep_intctl_config1[2]; +static uint sleep_intctl_config2[2]; +static uint sleep_intctl_src[2]; +static uint sleep_intctl_assign[2]; +static uint sleep_intctl_wake[2]; +static uint sleep_intctl_mask[2]; + +void +save_au1xxx_intctl(void) +{ + sleep_intctl_config0[0] = au_readl(IC0_CFG0RD); + sleep_intctl_config1[0] = au_readl(IC0_CFG1RD); + sleep_intctl_config2[0] = au_readl(IC0_CFG2RD); + sleep_intctl_src[0] = au_readl(IC0_SRCRD); + sleep_intctl_assign[0] = au_readl(IC0_ASSIGNRD); + sleep_intctl_wake[0] = au_readl(IC0_WAKERD); + sleep_intctl_mask[0] = au_readl(IC0_MASKRD); + + sleep_intctl_config0[1] = au_readl(IC1_CFG0RD); + sleep_intctl_config1[1] = au_readl(IC1_CFG1RD); + sleep_intctl_config2[1] = au_readl(IC1_CFG2RD); + sleep_intctl_src[1] = au_readl(IC1_SRCRD); + sleep_intctl_assign[1] = au_readl(IC1_ASSIGNRD); + sleep_intctl_wake[1] = au_readl(IC1_WAKERD); + sleep_intctl_mask[1] = au_readl(IC1_MASKRD); +} + +/* For most restore operations, we clear the entire register and + * then set the bits we found during the save. + */ +void +restore_au1xxx_intctl(void) +{ + au_writel(0xffffffff, IC0_MASKCLR); au_sync(); + + au_writel(0xffffffff, IC0_CFG0CLR); au_sync(); + au_writel(sleep_intctl_config0[0], IC0_CFG0SET); au_sync(); + au_writel(0xffffffff, IC0_CFG1CLR); au_sync(); + au_writel(sleep_intctl_config1[0], IC0_CFG1SET); au_sync(); + au_writel(0xffffffff, IC0_CFG2CLR); au_sync(); + au_writel(sleep_intctl_config2[0], IC0_CFG2SET); au_sync(); + au_writel(0xffffffff, IC0_SRCCLR); au_sync(); + au_writel(sleep_intctl_src[0], IC0_SRCSET); au_sync(); + au_writel(0xffffffff, IC0_ASSIGNCLR); au_sync(); + au_writel(sleep_intctl_assign[0], IC0_ASSIGNSET); au_sync(); + au_writel(0xffffffff, IC0_WAKECLR); au_sync(); + au_writel(sleep_intctl_wake[0], IC0_WAKESET); au_sync(); + au_writel(0xffffffff, IC0_RISINGCLR); au_sync(); + au_writel(0xffffffff, IC0_FALLINGCLR); au_sync(); + au_writel(0x00000000, IC0_TESTBIT); au_sync(); + + au_writel(0xffffffff, IC1_MASKCLR); au_sync(); + + au_writel(0xffffffff, IC1_CFG0CLR); au_sync(); + au_writel(sleep_intctl_config0[1], IC1_CFG0SET); au_sync(); + au_writel(0xffffffff, IC1_CFG1CLR); au_sync(); + au_writel(sleep_intctl_config1[1], IC1_CFG1SET); au_sync(); + au_writel(0xffffffff, IC1_CFG2CLR); au_sync(); + au_writel(sleep_intctl_config2[1], IC1_CFG2SET); au_sync(); + au_writel(0xffffffff, IC1_SRCCLR); au_sync(); + au_writel(sleep_intctl_src[1], IC1_SRCSET); au_sync(); + au_writel(0xffffffff, IC1_ASSIGNCLR); au_sync(); + au_writel(sleep_intctl_assign[1], IC1_ASSIGNSET); au_sync(); + au_writel(0xffffffff, IC1_WAKECLR); au_sync(); + au_writel(sleep_intctl_wake[1], IC1_WAKESET); au_sync(); + au_writel(0xffffffff, IC1_RISINGCLR); au_sync(); + au_writel(0xffffffff, IC1_FALLINGCLR); au_sync(); + au_writel(0x00000000, IC1_TESTBIT); au_sync(); + + au_writel(sleep_intctl_mask[1], IC1_MASKSET); au_sync(); + + au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync(); +} +#endif /* CONFIG_PM */ diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c new file mode 100644 index 00000000000..533721eef6a --- /dev/null +++ b/arch/mips/au1000/common/pci.c @@ -0,0 +1,97 @@ +/* + * BRIEF MODULE DESCRIPTION + * Alchemy/AMD Au1x00 pci support. + * + * Copyright 2001,2002,2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) + * + * Support for all devices (greater than 16) added by David Gathright. + * + * 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/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mach-au1x00/au1000.h> + +/* TBD */ +static struct resource pci_io_resource = { + "pci IO space", + (u32)PCI_IO_START, + (u32)PCI_IO_END, + IORESOURCE_IO +}; + +static struct resource pci_mem_resource = { + "pci memory space", + (u32)PCI_MEM_START, + (u32)PCI_MEM_END, + IORESOURCE_MEM +}; + +extern struct pci_ops au1x_pci_ops; + +static struct pci_controller au1x_controller = { + .pci_ops = &au1x_pci_ops, + .io_resource = &pci_io_resource, + .mem_resource = &pci_mem_resource, +}; + +#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) +static unsigned long virt_io_addr; +#endif + +static int __init au1x_pci_setup(void) +{ +#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) + virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, + Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1); + + if (!virt_io_addr) { + printk(KERN_ERR "Unable to ioremap pci space\n"); + return 1; + } + +#ifdef CONFIG_DMA_NONCOHERENT + /* + * Set the NC bit in controller for Au1500 pre-AC silicon + */ + u32 prid = read_c0_prid(); + if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { + au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG); + printk("Non-coherent PCI accesses enabled\n"); + } +#endif + + set_io_port_base(virt_io_addr); +#endif + + register_pci_controller(&au1x_controller); + return 0; +} + +arch_initcall(au1x_pci_setup); diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c new file mode 100644 index 00000000000..0776b2db564 --- /dev/null +++ b/arch/mips/au1000/common/platform.c @@ -0,0 +1,53 @@ +/* + * Platform device support for Au1x00 SoCs. + * + * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/resource.h> + +#include <asm/mach-au1x00/au1000.h> + +static struct resource au1xxx_usb_ohci_resources[] = { + [0] = { + .start = USB_OHCI_BASE, + .end = USB_OHCI_BASE + USB_OHCI_LEN, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1000_USB_HOST_INT, + .end = AU1000_USB_HOST_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +/* The dmamask must be set for OHCI to work */ +static u64 ohci_dmamask = ~(u32)0; + +static struct platform_device au1xxx_usb_ohci_device = { + .name = "au1xxx-ohci", + .id = 0, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1xxx_usb_ohci_resources), + .resource = au1xxx_usb_ohci_resources, +}; + +static struct platform_device *au1xxx_platform_devices[] __initdata = { + &au1xxx_usb_ohci_device, +}; + +int au1xxx_platform_init(void) +{ + return platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); +} + +arch_initcall(au1xxx_platform_init); diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c new file mode 100644 index 00000000000..c40daccbb5b --- /dev/null +++ b/arch/mips/au1000/common/power.c @@ -0,0 +1,493 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1000 Power Management routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * Some of the routines are right out of init/main.c, whose + * copyrights apply here. + * + * 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/pm.h> +#include <linux/slab.h> +#include <linux/sysctl.h> + +#include <asm/string.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/mach-au1x00/au1000.h> + +#ifdef CONFIG_PM + +#define DEBUG 1 +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +static void calibrate_delay(void); + +extern void set_au1x00_speed(unsigned int new_freq); +extern unsigned int get_au1x00_speed(void); +extern unsigned long get_au1x00_uart_baud_base(void); +extern void set_au1x00_uart_baud_base(unsigned long new_baud_base); +extern unsigned long save_local_and_disable(int controller); +extern void restore_local_and_enable(int controller, unsigned long mask); +extern void local_enable_irq(unsigned int irq_nr); + +/* Quick acpi hack. This will have to change! */ +#define CTL_ACPI 9999 +#define ACPI_S1_SLP_TYP 19 +#define ACPI_SLEEP 21 + + +static DEFINE_SPINLOCK(pm_lock); + +/* We need to save/restore a bunch of core registers that are + * either volatile or reset to some state across a processor sleep. + * If reading a register doesn't provide a proper result for a + * later restore, we have to provide a function for loading that + * register and save a copy. + * + * We only have to save/restore registers that aren't otherwise + * done as part of a driver pm_* function. + */ +static uint sleep_aux_pll_cntrl; +static uint sleep_cpu_pll_cntrl; +static uint sleep_pin_function; +static uint sleep_uart0_inten; +static uint sleep_uart0_fifoctl; +static uint sleep_uart0_linectl; +static uint sleep_uart0_clkdiv; +static uint sleep_uart0_enable; +static uint sleep_usbhost_enable; +static uint sleep_usbdev_enable; +static uint sleep_static_memctlr[4][3]; + +/* Define this to cause the value you write to /proc/sys/pm/sleep to + * set the TOY timer for the amount of time you want to sleep. + * This is done mainly for testing, but may be useful in other cases. + * The value is number of 32KHz ticks to sleep. + */ +#define SLEEP_TEST_TIMEOUT 1 +#ifdef SLEEP_TEST_TIMEOUT +static int sleep_ticks; +void wakeup_counter0_set(int ticks); +#endif + +static void +save_core_regs(void) +{ + extern void save_au1xxx_intctl(void); + extern void pm_eth0_shutdown(void); + + /* Do the serial ports.....these really should be a pm_* + * registered function by the driver......but of course the + * standard serial driver doesn't understand our Au1xxx + * unique registers. + */ + sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER); + sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR); + sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); + sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); + sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); + + /* Shutdown USB host/device. + */ + sleep_usbhost_enable = au_readl(USB_HOST_CONFIG); + + /* There appears to be some undocumented reset register.... + */ + au_writel(0, 0xb0100004); au_sync(); + au_writel(0, USB_HOST_CONFIG); au_sync(); + + sleep_usbdev_enable = au_readl(USBD_ENABLE); + au_writel(0, USBD_ENABLE); au_sync(); + + /* Save interrupt controller state. + */ + save_au1xxx_intctl(); + + /* Clocks and PLLs. + */ + sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL); + + /* We don't really need to do this one, but unless we + * write it again it won't have a valid value if we + * happen to read it. + */ + sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL); + + sleep_pin_function = au_readl(SYS_PINFUNC); + + /* Save the static memory controller configuration. + */ + sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); + sleep_static_memctlr[0][1] = au_readl(MEM_STTIME0); + sleep_static_memctlr[0][2] = au_readl(MEM_STADDR0); + sleep_static_memctlr[1][0] = au_readl(MEM_STCFG1); + sleep_static_memctlr[1][1] = au_readl(MEM_STTIME1); + sleep_static_memctlr[1][2] = au_readl(MEM_STADDR1); + sleep_static_memctlr[2][0] = au_readl(MEM_STCFG2); + sleep_static_memctlr[2][1] = au_readl(MEM_STTIME2); + sleep_static_memctlr[2][2] = au_readl(MEM_STADDR2); + sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); + sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); + sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); +} + +static void +restore_core_regs(void) +{ + extern void restore_au1xxx_intctl(void); + extern void wakeup_counter0_adjust(void); + + au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); + au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync(); + au_writel(sleep_pin_function, SYS_PINFUNC); au_sync(); + + /* Restore the static memory controller configuration. + */ + au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); + au_writel(sleep_static_memctlr[0][1], MEM_STTIME0); + au_writel(sleep_static_memctlr[0][2], MEM_STADDR0); + au_writel(sleep_static_memctlr[1][0], MEM_STCFG1); + au_writel(sleep_static_memctlr[1][1], MEM_STTIME1); + au_writel(sleep_static_memctlr[1][2], MEM_STADDR1); + au_writel(sleep_static_memctlr[2][0], MEM_STCFG2); + au_writel(sleep_static_memctlr[2][1], MEM_STTIME2); + au_writel(sleep_static_memctlr[2][2], MEM_STADDR2); + au_writel(sleep_static_memctlr[3][0], MEM_STCFG3); + au_writel(sleep_static_memctlr[3][1], MEM_STTIME3); + au_writel(sleep_static_memctlr[3][2], MEM_STADDR3); + + /* Enable the UART if it was enabled before sleep. + * I guess I should define module control bits........ + */ + if (sleep_uart0_enable & 0x02) { + au_writel(0, UART0_ADDR + UART_MOD_CNTRL); au_sync(); + au_writel(1, UART0_ADDR + UART_MOD_CNTRL); au_sync(); + au_writel(3, UART0_ADDR + UART_MOD_CNTRL); au_sync(); + au_writel(sleep_uart0_inten, UART0_ADDR + UART_IER); au_sync(); + au_writel(sleep_uart0_fifoctl, UART0_ADDR + UART_FCR); au_sync(); + au_writel(sleep_uart0_linectl, UART0_ADDR + UART_LCR); au_sync(); + au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync(); + } + + restore_au1xxx_intctl(); + wakeup_counter0_adjust(); +} + +unsigned long suspend_mode; + +void wakeup_from_suspend(void) +{ + suspend_mode = 0; +} + +int au_sleep(void) +{ + unsigned long wakeup, flags; + extern void save_and_sleep(void); + + spin_lock_irqsave(&pm_lock,flags); + + save_core_regs(); + + flush_cache_all(); + + /** The code below is all system dependent and we should probably + ** have a function call out of here to set this up. You need + ** to configure the GPIO or timer interrupts that will bring + ** you out of sleep. + ** For testing, the TOY counter wakeup is useful. + **/ + +#if 0 + au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD); + + /* gpio 6 can cause a wake up event */ + wakeup = au_readl(SYS_WAKEMSK); + wakeup &= ~(1 << 8); /* turn off match20 wakeup */ + wakeup |= 1 << 6; /* turn on gpio 6 wakeup */ +#else + /* For testing, allow match20 to wake us up. + */ +#ifdef SLEEP_TEST_TIMEOUT + wakeup_counter0_set(sleep_ticks); +#endif + wakeup = 1 << 8; /* turn on match20 wakeup */ + wakeup = 0; +#endif + au_writel(1, SYS_WAKESRC); /* clear cause */ + au_sync(); + au_writel(wakeup, SYS_WAKEMSK); + au_sync(); + + save_and_sleep(); + + /* after a wakeup, the cpu vectors back to 0x1fc00000 so + * it's up to the boot code to get us back here. + */ + restore_core_regs(); + spin_unlock_irqrestore(&pm_lock, flags); + return 0; +} + +static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, + void *buffer, size_t * len) +{ + int retval = 0; +#ifdef SLEEP_TEST_TIMEOUT +#define TMPBUFLEN2 16 + char buf[TMPBUFLEN2], *p; +#endif + + if (!write) { + *len = 0; + } else { +#ifdef SLEEP_TEST_TIMEOUT + if (*len > TMPBUFLEN2 - 1) { + return -EFAULT; + } + if (copy_from_user(buf, buffer, *len)) { + return -EFAULT; + } + buf[*len] = 0; + p = buf; + sleep_ticks = simple_strtoul(p, &p, 0); +#endif + retval = pm_send_all(PM_SUSPEND, (void *) 2); + + if (retval) + return retval; + + au_sleep(); + retval = pm_send_all(PM_RESUME, (void *) 0); + } + return retval; +} + +static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, + void *buffer, size_t * len) +{ + int retval = 0; + void au1k_wait(void); + + if (!write) { + *len = 0; + } else { + retval = pm_send_all(PM_SUSPEND, (void *) 2); + if (retval) + return retval; + suspend_mode = 1; + au1k_wait(); + retval = pm_send_all(PM_RESUME, (void *) 0); + } + return retval; +} + + +static int pm_do_freq(ctl_table * ctl, int write, struct file *file, + void *buffer, size_t * len) +{ + int retval = 0, i; + unsigned long val, pll; +#define TMPBUFLEN 64 +#define MAX_CPU_FREQ 396 + char buf[TMPBUFLEN], *p; + unsigned long flags, intc0_mask, intc1_mask; + unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk, + old_refresh; + unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; + + spin_lock_irqsave(&pm_lock, flags); + if (!write) { + *len = 0; + } else { + /* Parse the new frequency */ + if (*len > TMPBUFLEN - 1) { + spin_unlock_irqrestore(&pm_lock, flags); + return -EFAULT; + } + if (copy_from_user(buf, buffer, *len)) { + spin_unlock_irqrestore(&pm_lock, flags); + return -EFAULT; + } + buf[*len] = 0; + p = buf; + val = simple_strtoul(p, &p, 0); + if (val > MAX_CPU_FREQ) { + spin_unlock_irqrestore(&pm_lock, flags); + return -EFAULT; + } + + pll = val / 12; + if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ + /* revisit this for higher speed cpus */ + spin_unlock_irqrestore(&pm_lock, flags); + return -EFAULT; + } + + old_baud_base = get_au1x00_uart_baud_base(); + old_cpu_freq = get_au1x00_speed(); + + new_cpu_freq = pll * 12 * 1000000; + new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); + set_au1x00_speed(new_cpu_freq); + set_au1x00_uart_baud_base(new_baud_base); + + old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff; + new_refresh = + ((old_refresh * new_cpu_freq) / + old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff); + + au_writel(pll, SYS_CPUPLL); + au_sync_delay(1); + au_writel(new_refresh, MEM_SDREFCFG); + au_sync_delay(1); + + for (i = 0; i < 4; i++) { + if (au_readl + (UART_BASE + UART_MOD_CNTRL + + i * 0x00100000) == 3) { + old_clk = + au_readl(UART_BASE + UART_CLK + + i * 0x00100000); + // baud_rate = baud_base/clk + baud_rate = old_baud_base / old_clk; + /* we won't get an exact baud rate and the error + * could be significant enough that our new + * calculation will result in a clock that will + * give us a baud rate that's too far off from + * what we really want. + */ + if (baud_rate > 100000) + baud_rate = 115200; + else if (baud_rate > 50000) + baud_rate = 57600; + else if (baud_rate > 30000) + baud_rate = 38400; + else if (baud_rate > 17000) + baud_rate = 19200; + else + (baud_rate = 9600); + // new_clk = new_baud_base/baud_rate + new_clk = new_baud_base / baud_rate; + au_writel(new_clk, + UART_BASE + UART_CLK + + i * 0x00100000); + au_sync_delay(10); + } + } + } + + + /* We don't want _any_ interrupts other than + * match20. Otherwise our 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(); + restore_local_and_enable(0, intc0_mask); + restore_local_and_enable(1, intc1_mask); + return retval; +} + + +static struct ctl_table pm_table[] = { + {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend}, + {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep}, + {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq}, + {0} +}; + +static struct ctl_table pm_dir_table[] = { + {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, + {0} +}; + +/* + * Initialize power interface + */ +static int __init pm_init(void) +{ + register_sysctl_table(pm_dir_table, 1); + return 0; +} + +__initcall(pm_init); + + +/* + * This is right out of init/main.c + */ + +/* This is the number of bits of precision for the loops_per_jiffy. Each + bit takes on average 1.5/HZ seconds. This (like the original) is a little + better than 1% */ +#define LPS_PREC 8 + +static void calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + loops_per_jiffy = (1 << 12); + + while (loops_per_jiffy <<= 1) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */ ; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_jiffy); + ticks = jiffies - ticks; + if (ticks) + break; + } + +/* Do a binary approximation to get loops_per_jiffy set to equal one clock + (up to lps_precision bits) */ + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; + while (lps_precision-- && (loopbit >>= 1)) { + loops_per_jiffy |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_jiffy); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_jiffy &= ~loopbit; + } +} +#endif /* CONFIG_PM */ diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c new file mode 100644 index 00000000000..22e5a85af4d --- /dev/null +++ b/arch/mips/au1000/common/prom.c @@ -0,0 +1,162 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PROM library initialisation code, assuming a version of + * pmon is the boot code. + * + * Copyright 2000,2001 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> + +/* #define DEBUG_CMDLINE */ + +extern int prom_argc; +extern char **prom_argv, **prom_envp; + +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; + + +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; + *cp = '\0'; + +} + + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + * Environment variables are stored in the form of "memsize=64". + */ + + t_env_var *env = (t_env_var *)prom_envp; + int i; + + i = strlen(envname); + + while(env->name) { + if(strncmp(envname, env->name, i) == 0) { + return(env->name + strlen(envname) + 1); + } + env++; + } + 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; +} + +unsigned long __init prom_free_prom_memory(void) +{ + return 0; +} + +EXPORT_SYMBOL(prom_getcmdline); +EXPORT_SYMBOL(get_ethernet_addr); +EXPORT_SYMBOL(str2eaddr); diff --git a/arch/mips/au1000/common/puts.c b/arch/mips/au1000/common/puts.c new file mode 100644 index 00000000000..c2ae4624b77 --- /dev/null +++ b/arch/mips/au1000/common/puts.c @@ -0,0 +1,145 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Low level uart routines to directly access a 16550 uart. + * + * 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/types.h> +#include <asm/mach-au1x00/au1000.h> + +#define SERIAL_BASE UART_BASE +#define SER_CMD 0x7 +#define SER_DATA 0x1 +#define TX_BUSY 0x20 + +#define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; +static volatile unsigned long * const com1 = (unsigned long *)SERIAL_BASE; + + +#ifdef SLOW_DOWN +static inline void slow_down(void) +{ + int k; + for (k=0; k<10000; k++); +} +#else +#define slow_down() +#endif + +void +putch(const unsigned char c) +{ + unsigned char ch; + int i = 0; + + do { + ch = com1[SER_CMD]; + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } 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); +} diff --git a/arch/mips/au1000/common/reset.c b/arch/mips/au1000/common/reset.c new file mode 100644 index 00000000000..65b84db800e --- /dev/null +++ b/arch/mips/au1000/common/reset.c @@ -0,0 +1,195 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Au1000 reset routines. + * + * 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/config.h> +#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/mach-au1x00/au1000.h> + +extern int au_sleep(void); +extern void (*flush_cache_all)(void); + +void au1000_restart(char *command) +{ + /* Set all integrated peripherals to disabled states */ + extern void board_reset (void); + u32 prid = read_c0_prid(); + + printk(KERN_NOTICE "\n** Resetting Integrated Peripherals\n"); + switch (prid & 0xFF000000) + { + case 0x00000000: /* Au1000 */ + au_writel(0x02, 0xb0000010); /* ac97_enable */ + au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */ + asm("sync"); + au_writel(0x00, 0xb017fffc); /* usbh_enable */ + au_writel(0x00, 0xb0200058); /* usbd_enable */ + au_writel(0x00, 0xb0300040); /* ir_enable */ + au_writel(0x00, 0xb4004104); /* mac dma */ + au_writel(0x00, 0xb4004114); /* mac dma */ + au_writel(0x00, 0xb4004124); /* mac dma */ + au_writel(0x00, 0xb4004134); /* mac dma */ + au_writel(0x00, 0xb0520000); /* macen0 */ + au_writel(0x00, 0xb0520004); /* macen1 */ + au_writel(0x00, 0xb1000008); /* i2s_enable */ + au_writel(0x00, 0xb1100100); /* uart0_enable */ + au_writel(0x00, 0xb1200100); /* uart1_enable */ + au_writel(0x00, 0xb1300100); /* uart2_enable */ + au_writel(0x00, 0xb1400100); /* uart3_enable */ + au_writel(0x02, 0xb1600100); /* ssi0_enable */ + au_writel(0x02, 0xb1680100); /* ssi1_enable */ + au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ + au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ + au_writel(0x00, 0xb1900028); /* sys_clksrc */ + au_writel(0x10, 0xb1900060); /* sys_cpupll */ + au_writel(0x00, 0xb1900064); /* sys_auxpll */ + au_writel(0x00, 0xb1900100); /* sys_pininputen */ + break; + case 0x01000000: /* Au1500 */ + au_writel(0x02, 0xb0000010); /* ac97_enable */ + au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */ + asm("sync"); + au_writel(0x00, 0xb017fffc); /* usbh_enable */ + au_writel(0x00, 0xb0200058); /* usbd_enable */ + au_writel(0x00, 0xb4004104); /* mac dma */ + au_writel(0x00, 0xb4004114); /* mac dma */ + au_writel(0x00, 0xb4004124); /* mac dma */ + au_writel(0x00, 0xb4004134); /* mac dma */ + au_writel(0x00, 0xb1520000); /* macen0 */ + au_writel(0x00, 0xb1520004); /* macen1 */ + au_writel(0x00, 0xb1100100); /* uart0_enable */ + au_writel(0x00, 0xb1400100); /* uart3_enable */ + au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ + au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ + au_writel(0x00, 0xb1900028); /* sys_clksrc */ + au_writel(0x10, 0xb1900060); /* sys_cpupll */ + au_writel(0x00, 0xb1900064); /* sys_auxpll */ + au_writel(0x00, 0xb1900100); /* sys_pininputen */ + break; + case 0x02000000: /* Au1100 */ + au_writel(0x02, 0xb0000010); /* ac97_enable */ + au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */ + asm("sync"); + au_writel(0x00, 0xb017fffc); /* usbh_enable */ + au_writel(0x00, 0xb0200058); /* usbd_enable */ + au_writel(0x00, 0xb0300040); /* ir_enable */ + au_writel(0x00, 0xb4004104); /* mac dma */ + au_writel(0x00, 0xb4004114); /* mac dma */ + au_writel(0x00, 0xb4004124); /* mac dma */ + au_writel(0x00, 0xb4004134); /* mac dma */ + au_writel(0x00, 0xb0520000); /* macen0 */ + au_writel(0x00, 0xb1000008); /* i2s_enable */ + au_writel(0x00, 0xb1100100); /* uart0_enable */ + au_writel(0x00, 0xb1200100); /* uart1_enable */ + au_writel(0x00, 0xb1400100); /* uart3_enable */ + au_writel(0x02, 0xb1600100); /* ssi0_enable */ + au_writel(0x02, 0xb1680100); /* ssi1_enable */ + au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ + au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ + au_writel(0x00, 0xb1900028); /* sys_clksrc */ + au_writel(0x10, 0xb1900060); /* sys_cpupll */ + au_writel(0x00, 0xb1900064); /* sys_auxpll */ + au_writel(0x00, 0xb1900100); /* sys_pininputen */ + break; + case 0x03000000: /* Au1550 */ + au_writel(0x00, 0xb1a00004); /* psc 0 */ + au_writel(0x00, 0xb1b00004); /* psc 1 */ + au_writel(0x00, 0xb0a00004); /* psc 2 */ + au_writel(0x00, 0xb0b00004); /* psc 3 */ + au_writel(0x00, 0xb017fffc); /* usbh_enable */ + au_writel(0x00, 0xb0200058); /* usbd_enable */ + au_writel(0x00, 0xb4004104); /* mac dma */ + au_writel(0x00, 0xb4004114); /* mac dma */ + au_writel(0x00, 0xb4004124); /* mac dma */ + au_writel(0x00, 0xb4004134); /* mac dma */ + au_writel(0x00, 0xb1520000); /* macen0 */ + au_writel(0x00, 0xb1520004); /* macen1 */ + au_writel(0x00, 0xb1100100); /* uart0_enable */ + au_writel(0x00, 0xb1200100); /* uart1_enable */ + au_writel(0x00, 0xb1400100); /* uart3_enable */ + au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */ + au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */ + au_writel(0x00, 0xb1900028); /* sys_clksrc */ + au_writel(0x10, 0xb1900060); /* sys_cpupll */ + au_writel(0x00, 0xb1900064); /* sys_auxpll */ + au_writel(0x00, 0xb1900100); /* sys_pininputen */ + break; + + default: + break; + } + + set_c0_status(ST0_BEV | ST0_ERL); + set_c0_config(CONF_CM_UNCACHED); + flush_cache_all(); + write_c0_wired(0); + + /* Give board a chance to do a hardware reset */ + board_reset(); + + /* Jump to the beggining in case board_reset() is empty */ + __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); +} + +void au1000_halt(void) +{ +#if defined(CONFIG_MIPS_PB1550) + /* power off system */ + printk("\n** Powering off Pb1550\n"); + au_writew(au_readw(0xAF00001C) | (3<<14), 0xAF00001C); + au_sync(); + while(1); /* should not get here */ +#endif + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); +#ifdef CONFIG_MIPS_MIRAGE + au_writel((1 << 26) | (1 << 10), GPIO2_OUTPUT); +#endif +#ifdef CONFIG_PM + au_sleep(); + + /* should not get here */ + printk(KERN_ERR "Unable to put cpu in sleep mode\n"); + while(1); +#else + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +#endif +} + +void au1000_power_off(void) +{ + au1000_halt(); +} diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c new file mode 100644 index 00000000000..dbc8b1bda96 --- /dev/null +++ b/arch/mips/au1000/common/setup.c @@ -0,0 +1,195 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * Updates to 2.6, Pete Popov, Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS 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/delay.h> +#include <linux/interrupt.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/mach-au1x00/au1000.h> +#include <asm/time.h> + +extern char * __init prom_getcmdline(void); +extern void __init board_setup(void); +extern void au1000_restart(char *); +extern void au1000_halt(void); +extern void au1000_power_off(void); +extern struct resource ioport_resource; +extern struct resource iomem_resource; +extern void (*board_time_init)(void); +extern void au1x_time_init(void); +extern void (*board_timer_setup)(struct irqaction *irq); +extern void au1x_timer_setup(struct irqaction *irq); +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) +{ + struct cpu_spec *sp; + char *argptr; + unsigned long prid, cpupll, bclk = 1; + + set_cpuspec(); + sp = cur_cpu_spec[0]; + + board_setup(); /* board specific setup */ + + prid = read_c0_prid(); + cpupll = (au_readl(0xB1900060) & 0x3F) * 12; + printk("(PRId %08lx) @ %ldMHZ\n", prid, cpupll); + + bclk = sp->cpu_bclk; + if (bclk) + { + /* Enable BCLK switching */ + bclk = au_readl(0xB190003C); + au_writel(bclk | 0x60, 0xB190003C); + printk("BCLK switching enabled!\n"); + } + + if (sp->cpu_od) { + /* Various early Au1000 Errata corrected by this */ + set_c0_config(1<<19); /* Set Config[OD] */ + } + else { + /* Clear to obtain best system bus performance */ + clear_c0_config(1<<19); /* Clear Config[OD] */ + } + + argptr = prom_getcmdline(); + +#ifdef CONFIG_SERIAL_AU1X00_CONSOLE + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS0,115200"); + } +#endif + +#ifdef CONFIG_FB_AU1100 + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + /* default panel */ + /*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 + +#ifdef CONFIG_FB_E1356 + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); +#ifdef CONFIG_MIPS_PB1000 + strcat(argptr, " video=e1356fb:system:pb1000,mmunalign:1"); +#else + strcat(argptr, " video=e1356fb:system:pb1500"); +#endif + } +#endif + +#ifdef CONFIG_FB_XPERT98 + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " video=atyfb:1024x768-8@70"); + } +#endif + +#if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000) + /* au1000 does not support vra, au1500 and au1100 do */ + strcat(argptr, " au1000_audio=vra"); + argptr = prom_getcmdline(); +#endif + _machine_restart = au1000_restart; + _machine_halt = au1000_halt; + _machine_power_off = au1000_power_off; + board_time_init = au1xxx_time_init; + board_timer_setup = au1xxx_timer_setup; + + /* IO/MEM resources. */ + set_io_port_base(0); + ioport_resource.start = IOPORT_RESOURCE_START; + ioport_resource.end = IOPORT_RESOURCE_END; + iomem_resource.start = IOMEM_RESOURCE_START; + iomem_resource.end = IOMEM_RESOURCE_END; + + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S); + au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL); + 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) +{ + u32 start, end; + + /* Don't fixup 36 bit addresses */ + if ((phys_addr >> 32) != 0) return phys_addr; + +#ifdef CONFIG_PCI + start = (u32)Au1500_PCI_MEM_START; + end = (u32)Au1500_PCI_MEM_END; + /* check for pci memory window */ + if ((phys_addr >= start) && ((phys_addr + size) < end)) { + return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START); + } +#endif + + /* All Au1x SOCs have a pcmcia controller */ + /* We setup our 32 bit pseudo addresses to be equal to the + * 36 bit addr >> 4, to make it easier to check the address + * and fix it. + * The Au1x socket 0 phys attribute address is 0xF 4000 0000. + * The pseudo address we use is 0xF400 0000. Any address over + * 0xF400 0000 is a pcmcia pseudo address. + */ + if ((phys_addr >= 0xF4000000) && (phys_addr < 0xFFFFFFFF)) { + return (phys_t)(phys_addr << 4); + } + + /* default nop */ + return phys_addr; +} +#endif diff --git a/arch/mips/au1000/common/sleeper.S b/arch/mips/au1000/common/sleeper.S new file mode 100644 index 00000000000..44dac3b0df3 --- /dev/null +++ b/arch/mips/au1000/common/sleeper.S @@ -0,0 +1,149 @@ +/* + * Copyright 2002 Embedded Edge, LLC + * Author: dan@embeddededge.com + * + * Sleep helper for Au1xxx sleep mode. + * + * 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/asm.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .text + .set macro + .set noat + .align 5 + +/* Save all of the processor general registers and go to sleep. + * A wakeup condition will get us back here to restore the registers. + */ +LEAF(save_and_sleep) + + subu sp, PT_SIZE + sw $1, PT_R1(sp) + sw $2, PT_R2(sp) + sw $3, PT_R3(sp) + sw $4, PT_R4(sp) + sw $5, PT_R5(sp) + sw $6, PT_R6(sp) + sw $7, PT_R7(sp) + sw $8, PT_R8(sp) + sw $9, PT_R9(sp) + sw $10, PT_R10(sp) + sw $11, PT_R11(sp) + sw $12, PT_R12(sp) + sw $13, PT_R13(sp) + sw $14, PT_R14(sp) + sw $15, PT_R15(sp) + sw $16, PT_R16(sp) + sw $17, PT_R17(sp) + sw $18, PT_R18(sp) + sw $19, PT_R19(sp) + sw $20, PT_R20(sp) + sw $21, PT_R21(sp) + sw $22, PT_R22(sp) + sw $23, PT_R23(sp) + sw $24, PT_R24(sp) + sw $25, PT_R25(sp) + sw $26, PT_R26(sp) + sw $27, PT_R27(sp) + sw $28, PT_R28(sp) + sw $29, PT_R29(sp) + sw $30, PT_R30(sp) + sw $31, PT_R31(sp) + mfc0 k0, CP0_STATUS + sw k0, 0x20(sp) + mfc0 k0, CP0_CONTEXT + sw k0, 0x1c(sp) + mfc0 k0, CP0_PAGEMASK + sw k0, 0x18(sp) + mfc0 k0, CP0_CONFIG + sw k0, 0x14(sp) + + /* Now set up the scratch registers so the boot rom will + * return to this point upon wakeup. + */ + la k0, 1f + lui k1, 0xb190 + ori k1, 0x18 + sw sp, 0(k1) + ori k1, 0x1c + sw k0, 0(k1) + +/* Put SDRAM into self refresh. Preload instructions into cache, + * issue a precharge, then auto refresh, then sleep commands to it. + */ + la t0, sdsleep + .set mips3 + cache 0x14, 0(t0) + cache 0x14, 32(t0) + cache 0x14, 64(t0) + cache 0x14, 96(t0) + .set mips0 + +sdsleep: + lui k0, 0xb400 + sw zero, 0x001c(k0) /* Precharge */ + sw zero, 0x0020(k0) /* Auto refresh */ + sw zero, 0x0030(k0) /* SDRAM sleep */ + sync + + lui k1, 0xb190 + sw zero, 0x0078(k1) /* get ready to sleep */ + sync + sw zero, 0x007c(k1) /* Put processor to sleep */ + sync + + /* This is where we return upon wakeup. + * Reload all of the registers and return. + */ +1: nop + lw k0, 0x20(sp) + mtc0 k0, CP0_STATUS + lw k0, 0x1c(sp) + mtc0 k0, CP0_CONTEXT + lw k0, 0x18(sp) + mtc0 k0, CP0_PAGEMASK + lw k0, 0x14(sp) + mtc0 k0, CP0_CONFIG + lw $1, PT_R1(sp) + lw $2, PT_R2(sp) + lw $3, PT_R3(sp) + lw $4, PT_R4(sp) + lw $5, PT_R5(sp) + lw $6, PT_R6(sp) + lw $7, PT_R7(sp) + lw $8, PT_R8(sp) + lw $9, PT_R9(sp) + lw $10, PT_R10(sp) + lw $11, PT_R11(sp) + lw $12, PT_R12(sp) + lw $13, PT_R13(sp) + lw $14, PT_R14(sp) + lw $15, PT_R15(sp) + lw $16, PT_R16(sp) + lw $17, PT_R17(sp) + lw $18, PT_R18(sp) + lw $19, PT_R19(sp) + lw $20, PT_R20(sp) + lw $21, PT_R21(sp) + lw $22, PT_R22(sp) + lw $23, PT_R23(sp) + lw $24, PT_R24(sp) + lw $25, PT_R25(sp) + lw $26, PT_R26(sp) + lw $27, PT_R27(sp) + lw $28, PT_R28(sp) + lw $29, PT_R29(sp) + lw $30, PT_R30(sp) + lw $31, PT_R31(sp) + addiu sp, PT_SIZE + + jr ra +END(save_and_sleep) diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c new file mode 100644 index 00000000000..fe418f1620c --- /dev/null +++ b/arch/mips/au1000/common/time.c @@ -0,0 +1,469 @@ +/* + * + * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com + * Copied and modified Carsten Langgaard's time.c + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * 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. + * + * ######################################################################## + * + * Setting up the clock on the MIPS boards. + * + * Update. Always configure the kernel with CONFIG_NEW_TIME_C. This + * will use the user interface gettimeofday() functions from the + * arch/mips/kernel/time.c, and we provide the clock interrupt processing + * and the timer offset compute functions. If CONFIG_PM is selected, + * we also ensure the 32KHz timer is available. -- Dan + */ + +#include <linux/types.h> +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/hardirq.h> + +#include <asm/compiler.h> +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/time.h> +#include <asm/div64.h> +#include <asm/mach-au1x00/au1000.h> + +#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; + +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); + +/* 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); +static unsigned long last_pc0, last_match20; +#endif + +static DEFINE_SPINLOCK(time_lock); + +static inline void ack_r4ktimer(unsigned long newval) +{ + write_c0_compare(newval); +} + +/* + * There are a lot of conceptually broken versions of the MIPS timer interrupt + * handler floating around. This one is rather different, but the algorithm + * is provably more robust. + */ +unsigned long wtimer; +void mips_timer_interrupt(struct pt_regs *regs) +{ + int irq = 63; + unsigned long count; + + irq_enter(); + kstat_this_cpu.irqs[irq]++; + + if (r4k_offset == 0) + goto null; + + do { + count = read_c0_count(); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + + kstat_this_cpu.irqs[irq]++; + do_timer(regs); +#ifndef CONFIG_SMP + update_process_times(user_mode(regs)); +#endif + r4k_cur += r4k_offset; + ack_r4ktimer(r4k_cur); + + } while (((unsigned long)read_c0_count() + - r4k_cur) < 0x7fffffff); + + irq_exit(); + return; + +null: + ack_r4ktimer(0); +} + +#ifdef CONFIG_PM +void 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; + } + + pc0 = au_readl(SYS_TOYREAD); + if (pc0 < last_match20) { + /* counter overflowed */ + time_elapsed = (0xffffffff - last_match20) + pc0; + } + else { + time_elapsed = pc0 - last_match20; + } + + while (time_elapsed > 0) { + do_timer(regs); +#ifndef CONFIG_SMP + update_process_times(user_mode(regs)); +#endif + time_elapsed -= MATCH20_INC; + last_match20 += MATCH20_INC; + jiffie_drift++; + } + + last_pc0 = pc0; + au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); + au_sync(); + + /* our counter ticks at 10.009765625 ms/tick, we we're running + * almost 10uS too slow per tick. + */ + + if (jiffie_drift >= 999) { + jiffie_drift -= 999; + do_timer(regs); /* increment jiffies by one */ +#ifndef CONFIG_SMP + update_process_times(user_mode(regs)); +#endif + } +} + +/* When we wakeup from sleep, we have to "catch up" on all of the + * timer ticks we have missed. + */ +void +wakeup_counter0_adjust(void) +{ + unsigned long pc0; + int time_elapsed; + + pc0 = au_readl(SYS_TOYREAD); + if (pc0 < last_match20) { + /* counter overflowed */ + time_elapsed = (0xffffffff - last_match20) + pc0; + } + else { + time_elapsed = pc0 - last_match20; + } + + while (time_elapsed > 0) { + time_elapsed -= MATCH20_INC; + last_match20 += MATCH20_INC; + } + + last_pc0 = pc0; + au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); + au_sync(); + +} + +/* This is just for debugging to set the timer for a sleep delay. +*/ +void +wakeup_counter0_set(int ticks) +{ + unsigned long pc0; + + pc0 = au_readl(SYS_TOYREAD); + last_pc0 = pc0; + au_writel(last_match20 + (MATCH20_INC * ticks), SYS_TOYMATCH2); + au_sync(); +} +#endif + +/* I haven't found anyone that doesn't use a 12 MHz source clock, + * but just in case..... + */ +#ifdef CONFIG_AU1000_SRC_CLK +#define AU1000_SRC_CLK CONFIG_AU1000_SRC_CLK +#else +#define AU1000_SRC_CLK 12000000 +#endif + +/* + * We read the real processor speed from the PLL. This is important + * because it is more accurate than computing it from the 32KHz + * counter, if it exists. If we don't have an accurate processor + * speed, all of the peripherals that derive their clocks based on + * this advertised speed will introduce error and sometimes not work + * properly. This function is futher convoluted to still allow configurations + * to do that in case they have really, really old silicon with a + * write-only PLL register, that we need the 32KHz when power management + * "wait" is enabled, and we need to detect if the 32KHz isn't present + * but requested......got it? :-) -- Dan + */ +unsigned long cal_r4koff(void) +{ + unsigned long count; + unsigned long cpu_speed; + unsigned long flags; + unsigned long counter; + + spin_lock_irqsave(&time_lock, flags); + + /* Power management cares if we don't have a 32KHz counter. + */ + no_au1xxx_32khz = 0; + counter = au_readl(SYS_COUNTER_CNTRL); + if (counter & SYS_CNTRL_E0) { + int trim_divide = 16; + + au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL); + + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); + /* RTC now ticks at 32.768/16 kHz */ + au_writel(trim_divide-1, SYS_RTCTRIM); + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); + + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); + au_writel (0, SYS_TOYWRITE); + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); + +#if defined(CONFIG_AU1000_USE32K) + { + unsigned long start, end; + + start = au_readl(SYS_RTCREAD); + start += 2; + /* wait for the beginning of a new tick + */ + while (au_readl(SYS_RTCREAD) < start); + + /* Start r4k counter. + */ + write_c0_count(0); + + /* Wait 0.5 seconds. + */ + end = start + (32768 / trim_divide)/2; + + while (end > au_readl(SYS_RTCREAD)); + + count = read_c0_count(); + cpu_speed = count * 2; + } +#else + cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * + AU1000_SRC_CLK; + count = cpu_speed / 2; +#endif + } + else { + /* The 32KHz oscillator isn't running, so assume there + * isn't one and grab the processor speed from the PLL. + * NOTE: some old silicon doesn't allow reading the PLL. + */ + cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK; + count = cpu_speed / 2; + no_au1xxx_32khz = 1; + } + mips_hpt_frequency = count; + // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) + set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); + spin_unlock_irqrestore(&time_lock, flags); + return (cpu_speed / HZ); +} + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) +#define USECS_PER_JIFFY_FRAC (0x100000000LL*1000000/HZ&0xffffffff) + +static unsigned long +div64_32(unsigned long v1, unsigned long v2, unsigned long v3) +{ + unsigned long r0; + do_div64_32(r0, v1, v2, v3); + return r0; +} + +static unsigned long do_fast_cp0_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + unsigned long r0; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies=0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient=0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (tmp && last_jiffies != tmp) { + last_jiffies = tmp; + if (last_jiffies != 0) { + r0 = div64_32(timerhi, timerlo, tmp); + quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0); + cached_quotient = quotient; + } + } + + /* Get last timer tick in absolute kernel time */ + count = read_c0_count(); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + : "=r" (res) + : "r" (count), "r" (quotient) + : "hi", "lo", GCC_REG_ACCUM); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + + return res; +} + +#ifdef CONFIG_PM +static unsigned long do_fast_pm_gettimeoffset(void) +{ + unsigned long pc0; + unsigned long offset; + + pc0 = au_readl(SYS_TOYREAD); + au_sync(); + offset = pc0 - last_pc0; + if (offset > 2*MATCH20_INC) { + printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n", + (unsigned)offset, (unsigned)last_pc0, + (unsigned)last_match20, (unsigned)pc0); + } + offset = (unsigned long)((offset * 305) / 10); + return offset; +} +#endif + +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(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + //est_freq = 2*r4k_offset*HZ; + est_freq = r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + set_au1x00_speed(est_freq); + set_au1x00_lcd_clock(); // program the LCD clock + + r4k_cur = (read_c0_count() + r4k_offset); + write_c0_compare(r4k_cur); + +#ifdef CONFIG_PM + /* + * setup counter 0, since it keeps ticking after a + * 'wait' instruction has been executed. The CP0 timer and + * counter 1 do NOT continue running after 'wait' + * + * It's too early to call request_irq() here, so we handle + * counter 0 interrupt as a special irq and it doesn't show + * up under /proc/interrupts. + * + * Check to ensure we really have a 32KHz oscillator before + * we do this. + */ + if (no_au1xxx_32khz) { + unsigned int c0_status; + + printk("WARNING: no 32KHz clock found.\n"); + do_gettimeoffset = do_fast_cp0_gettimeoffset; + + /* Ensure we get CPO_COUNTER interrupts. + */ + c0_status = read_c0_status(); + c0_status |= IE_IRQ5; + write_c0_status(c0_status); + } + else { + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); + au_writel(0, SYS_TOYWRITE); + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); + + au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK); + au_writel(~0, SYS_WAKESRC); + au_sync(); + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); + + /* setup match20 to interrupt once every 10ms */ + 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(); + + do_gettimeoffset = do_fast_pm_gettimeoffset; + + /* We can use the real 'wait' instruction. + */ + au1k_wait_ptr = au1k_wait; + } + +#else + /* We have to do this here instead of in timer_init because + * the generic code in arch/mips/kernel/time.c will write + * over our function pointer. + */ + do_gettimeoffset = do_fast_cp0_gettimeoffset; +#endif +} + +void __init au1xxx_time_init(void) +{ +} diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c new file mode 100644 index 00000000000..447a9a4612a --- /dev/null +++ b/arch/mips/au1000/common/usbdev.c @@ -0,0 +1,1557 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1000 USB Device-Side (device layer) + * + * Copyright 2001-2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@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/kernel.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/fcntl.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/smp_lock.h> +#define DEBUG +#include <linux/usb.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <asm/mipsregs.h> +#include <asm/au1000.h> +#include <asm/au1000_dma.h> +#include <asm/au1000_usbdev.h> + +#ifdef DEBUG +#undef VDEBUG +#ifdef VDEBUG +#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg) +#else +#define vdbg(fmt, arg...) do {} while (0) +#endif +#else +#define vdbg(fmt, arg...) do {} while (0) +#endif + +#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL) + +#define EP_FIFO_DEPTH 8 + +typedef enum { + SETUP_STAGE = 0, + DATA_STAGE, + STATUS_STAGE +} ep0_stage_t; + +typedef struct { + int read_fifo; + int write_fifo; + int ctrl_stat; + int read_fifo_status; + int write_fifo_status; +} endpoint_reg_t; + +typedef struct { + usbdev_pkt_t *head; + usbdev_pkt_t *tail; + int count; +} pkt_list_t; + +typedef struct { + int active; + struct usb_endpoint_descriptor *desc; + endpoint_reg_t *reg; + /* Only one of these are used, unless this is the control ep */ + pkt_list_t inlist; + pkt_list_t outlist; + unsigned int indma, outdma; /* DMA channel numbers for IN, OUT */ + /* following are extracted from endpoint descriptor for easy access */ + int max_pkt_size; + int type; + int direction; + /* WE assign endpoint addresses! */ + int address; + spinlock_t lock; +} endpoint_t; + + +static struct usb_dev { + endpoint_t ep[6]; + ep0_stage_t ep0_stage; + + struct usb_device_descriptor * dev_desc; + struct usb_interface_descriptor* if_desc; + struct usb_config_descriptor * conf_desc; + u8 * full_conf_desc; + struct usb_string_descriptor * str_desc[6]; + + /* callback to function layer */ + void (*func_cb)(usbdev_cb_type_t type, unsigned long arg, + void *cb_data); + void* cb_data; + + usbdev_state_t state; // device state + int suspended; // suspended flag + int address; // device address + int interface; + int num_ep; + u8 alternate_setting; + u8 configuration; // configuration value + int remote_wakeup_en; +} usbdev; + + +static endpoint_reg_t ep_reg[] = { + // FIFO's 0 and 1 are EP0 default control + {USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT }, + {0}, + // FIFO 2 is EP2, IN + { -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT }, + // FIFO 3 is EP3, IN + { -1, USBD_EP3WR, USBD_EP3CS, -1, USBD_EP3WRSTAT }, + // FIFO 4 is EP4, OUT + {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP4RDSTAT, -1 }, + // FIFO 5 is EP5, OUT + {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1 } +}; + +static struct { + unsigned int id; + const char *str; +} ep_dma_id[] = { + { DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" }, + { DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" }, + { DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" }, + { DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" }, + { DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" }, + { DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" } +}; + +#define DIR_OUT 0 +#define DIR_IN (1<<3) + +#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL +#define BULK_EP USB_ENDPOINT_XFER_BULK + +static inline endpoint_t * +epaddr_to_ep(struct usb_dev* dev, int ep_addr) +{ + if (ep_addr >= 0 && ep_addr < 2) + return &dev->ep[0]; + if (ep_addr < 6) + return &dev->ep[ep_addr]; + return NULL; +} + +static const char* std_req_name[] = { + "GET_STATUS", + "CLEAR_FEATURE", + "RESERVED", + "SET_FEATURE", + "RESERVED", + "SET_ADDRESS", + "GET_DESCRIPTOR", + "SET_DESCRIPTOR", + "GET_CONFIGURATION", + "SET_CONFIGURATION", + "GET_INTERFACE", + "SET_INTERFACE", + "SYNCH_FRAME" +}; + +static inline const char* +get_std_req_name(int req) +{ + return (req >= 0 && req <= 12) ? std_req_name[req] : "UNKNOWN"; +} + +#if 0 +static void +dump_setup(struct usb_ctrlrequest* s) +{ + dbg("%s: requesttype=%d", __FUNCTION__, s->requesttype); + dbg("%s: request=%d %s", __FUNCTION__, s->request, + get_std_req_name(s->request)); + dbg("%s: value=0x%04x", __FUNCTION__, s->wValue); + dbg("%s: index=%d", __FUNCTION__, s->index); + dbg("%s: length=%d", __FUNCTION__, s->length); +} +#endif + +static inline usbdev_pkt_t * +alloc_packet(endpoint_t * ep, int data_size, void* data) +{ + usbdev_pkt_t* pkt = kmalloc(sizeof(usbdev_pkt_t) + data_size, + ALLOC_FLAGS); + if (!pkt) + return NULL; + pkt->ep_addr = ep->address; + pkt->size = data_size; + pkt->status = 0; + pkt->next = NULL; + if (data) + memcpy(pkt->payload, data, data_size); + + return pkt; +} + + +/* + * Link a packet to the tail of the enpoint's packet list. + * EP spinlock must be held when calling. + */ +static void +link_tail(endpoint_t * ep, pkt_list_t * list, usbdev_pkt_t * pkt) +{ + if (!list->tail) { + list->head = list->tail = pkt; + list->count = 1; + } else { + list->tail->next = pkt; + list->tail = pkt; + list->count++; + } +} + +/* + * Unlink and return a packet from the head of the given packet + * list. It is the responsibility of the caller to free the packet. + * EP spinlock must be held when calling. + */ +static usbdev_pkt_t * +unlink_head(pkt_list_t * list) +{ + usbdev_pkt_t *pkt; + + pkt = list->head; + if (!pkt || !list->count) { + return NULL; + } + + list->head = pkt->next; + if (!list->head) { + list->head = list->tail = NULL; + list->count = 0; + } else + list->count--; + + return pkt; +} + +/* + * Create and attach a new packet to the tail of the enpoint's + * packet list. EP spinlock must be held when calling. + */ +static usbdev_pkt_t * +add_packet(endpoint_t * ep, pkt_list_t * list, int size) +{ + usbdev_pkt_t *pkt = alloc_packet(ep, size, NULL); + if (!pkt) + return NULL; + + link_tail(ep, list, pkt); + return pkt; +} + + +/* + * Unlink and free a packet from the head of the enpoint's + * packet list. EP spinlock must be held when calling. + */ +static inline void +free_packet(pkt_list_t * list) +{ + kfree(unlink_head(list)); +} + +/* EP spinlock must be held when calling. */ +static inline void +flush_pkt_list(pkt_list_t * list) +{ + while (list->count) + free_packet(list); +} + +/* EP spinlock must be held when calling */ +static inline void +flush_write_fifo(endpoint_t * ep) +{ + if (ep->reg->write_fifo_status >= 0) { + au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | + USBDEV_FSTAT_OF, + ep->reg->write_fifo_status); + //udelay(100); + //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, + // ep->reg->write_fifo_status); + } +} + +/* EP spinlock must be held when calling */ +static inline void +flush_read_fifo(endpoint_t * ep) +{ + if (ep->reg->read_fifo_status >= 0) { + au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF | + USBDEV_FSTAT_OF, + ep->reg->read_fifo_status); + //udelay(100); + //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF, + // ep->reg->read_fifo_status); + } +} + + +/* EP spinlock must be held when calling. */ +static void +endpoint_flush(endpoint_t * ep) +{ + // First, flush all packets + flush_pkt_list(&ep->inlist); + flush_pkt_list(&ep->outlist); + + // Now flush the endpoint's h/w FIFO(s) + flush_write_fifo(ep); + flush_read_fifo(ep); +} + +/* EP spinlock must be held when calling. */ +static void +endpoint_stall(endpoint_t * ep) +{ + u32 cs; + + warn(__FUNCTION__); + + cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL; + au_writel(cs, ep->reg->ctrl_stat); +} + +/* EP spinlock must be held when calling. */ +static void +endpoint_unstall(endpoint_t * ep) +{ + u32 cs; + + warn(__FUNCTION__); + + cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL; + au_writel(cs, ep->reg->ctrl_stat); +} + +static void +endpoint_reset_datatoggle(endpoint_t * ep) +{ + // FIXME: is this possible? +} + + +/* EP spinlock must be held when calling. */ +static int +endpoint_fifo_read(endpoint_t * ep) +{ + int read_count = 0; + u8 *bufptr; + usbdev_pkt_t *pkt = ep->outlist.tail; + + if (!pkt) + return -EINVAL; + + bufptr = &pkt->payload[pkt->size]; + while (au_readl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) { + *bufptr++ = au_readl(ep->reg->read_fifo) & 0xff; + read_count++; + pkt->size++; + } + + return read_count; +} + +#if 0 +/* EP spinlock must be held when calling. */ +static int +endpoint_fifo_write(endpoint_t * ep, int index) +{ + int write_count = 0; + u8 *bufptr; + usbdev_pkt_t *pkt = ep->inlist.head; + + if (!pkt) + return -EINVAL; + + bufptr = &pkt->payload[index]; + while ((au_readl(ep->reg->write_fifo_status) & + USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) { + if (bufptr < pkt->payload + pkt->size) { + au_writel(*bufptr++, ep->reg->write_fifo); + write_count++; + } else { + break; + } + } + + return write_count; +} +#endif + +/* + * This routine is called to restart transmission of a packet. + * The endpoint's TSIZE must be set to the new packet's size, + * and DMA to the write FIFO needs to be restarted. + * EP spinlock must be held when calling. + */ +static void +kickstart_send_packet(endpoint_t * ep) +{ + u32 cs; + usbdev_pkt_t *pkt = ep->inlist.head; + + vdbg("%s: ep%d, pkt=%p", __FUNCTION__, ep->address, pkt); + + if (!pkt) { + err("%s: head=NULL! list->count=%d", __FUNCTION__, + ep->inlist.count); + return; + } + + dma_cache_wback_inv((unsigned long)pkt->payload, pkt->size); + + /* + * make sure FIFO is empty + */ + flush_write_fifo(ep); + + cs = au_readl(ep->reg->ctrl_stat) & USBDEV_CS_STALL; + cs |= (pkt->size << USBDEV_CS_TSIZE_BIT); + au_writel(cs, ep->reg->ctrl_stat); + + if (get_dma_active_buffer(ep->indma) == 1) { + set_dma_count1(ep->indma, pkt->size); + set_dma_addr1(ep->indma, virt_to_phys(pkt->payload)); + enable_dma_buffer1(ep->indma); // reenable + } else { + set_dma_count0(ep->indma, pkt->size); + set_dma_addr0(ep->indma, virt_to_phys(pkt->payload)); + enable_dma_buffer0(ep->indma); // reenable + } + if (dma_halted(ep->indma)) + start_dma(ep->indma); +} + + +/* + * This routine is called when a packet in the inlist has been + * completed. Frees the completed packet and starts sending the + * next. EP spinlock must be held when calling. + */ +static usbdev_pkt_t * +send_packet_complete(endpoint_t * ep) +{ + usbdev_pkt_t *pkt = unlink_head(&ep->inlist); + + if (pkt) { + pkt->status = + (au_readl(ep->reg->ctrl_stat) & USBDEV_CS_NAK) ? + PKT_STATUS_NAK : PKT_STATUS_ACK; + + vdbg("%s: ep%d, %s pkt=%p, list count=%d", __FUNCTION__, + ep->address, (pkt->status & PKT_STATUS_NAK) ? + "NAK" : "ACK", pkt, ep->inlist.count); + } + + /* + * The write fifo should already be drained if things are + * working right, but flush it anyway just in case. + */ + flush_write_fifo(ep); + + // begin transmitting next packet in the inlist + if (ep->inlist.count) { + kickstart_send_packet(ep); + } + + return pkt; +} + +/* + * Add a new packet to the tail of the given ep's packet + * inlist. The transmit complete interrupt frees packets from + * the head of this list. EP spinlock must be held when calling. + */ +static int +send_packet(struct usb_dev* dev, usbdev_pkt_t *pkt, int async) +{ + pkt_list_t *list; + endpoint_t* ep; + + if (!pkt || !(ep = epaddr_to_ep(dev, pkt->ep_addr))) + return -EINVAL; + + if (!pkt->size) + return 0; + + list = &ep->inlist; + + if (!async && list->count) { + halt_dma(ep->indma); + flush_pkt_list(list); + } + + link_tail(ep, list, pkt); + + vdbg("%s: ep%d, pkt=%p, size=%d, list count=%d", __FUNCTION__, + ep->address, pkt, pkt->size, list->count); + + if (list->count == 1) { + /* + * if the packet count is one, it means the list was empty, + * and no more data will go out this ep until we kick-start + * it again. + */ + kickstart_send_packet(ep); + } + + return pkt->size; +} + +/* + * This routine is called to restart reception of a packet. + * EP spinlock must be held when calling. + */ +static void +kickstart_receive_packet(endpoint_t * ep) +{ + usbdev_pkt_t *pkt; + + // get and link a new packet for next reception + if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) { + err("%s: could not alloc new packet", __FUNCTION__); + return; + } + + if (get_dma_active_buffer(ep->outdma) == 1) { + clear_dma_done1(ep->outdma); + set_dma_count1(ep->outdma, ep->max_pkt_size); + set_dma_count0(ep->outdma, 0); + set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload)); + enable_dma_buffer1(ep->outdma); // reenable + } else { + clear_dma_done0(ep->outdma); + set_dma_count0(ep->outdma, ep->max_pkt_size); + set_dma_count1(ep->outdma, 0); + set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload)); + enable_dma_buffer0(ep->outdma); // reenable + } + if (dma_halted(ep->outdma)) + start_dma(ep->outdma); +} + + +/* + * This routine is called when a packet in the outlist has been + * completed (received) and we need to prepare for a new packet + * to be received. Halts DMA and computes the packet size from the + * remaining DMA counter. Then prepares a new packet for reception + * and restarts DMA. FIXME: what if another packet comes in + * on top of the completed packet? Counter would be wrong. + * EP spinlock must be held when calling. + */ +static usbdev_pkt_t * +receive_packet_complete(endpoint_t * ep) +{ + usbdev_pkt_t *pkt = ep->outlist.tail; + u32 cs; + + halt_dma(ep->outdma); + + cs = au_readl(ep->reg->ctrl_stat); + + if (!pkt) + return NULL; + + pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma); + if (pkt->size) + dma_cache_inv((unsigned long)pkt->payload, pkt->size); + /* + * need to pull out any remaining bytes in the FIFO. + */ + endpoint_fifo_read(ep); + /* + * should be drained now, but flush anyway just in case. + */ + flush_read_fifo(ep); + + pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK; + if (ep->address == 0 && (cs & USBDEV_CS_SU)) + pkt->status |= PKT_STATUS_SU; + + vdbg("%s: ep%d, %s pkt=%p, size=%d", __FUNCTION__, + ep->address, (pkt->status & PKT_STATUS_NAK) ? + "NAK" : "ACK", pkt, pkt->size); + + kickstart_receive_packet(ep); + + return pkt; +} + + +/* + **************************************************************************** + * Here starts the standard device request handlers. They are + * all called by do_setup() via a table of function pointers. + **************************************************************************** + */ + +static ep0_stage_t +do_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + switch (setup->bRequestType) { + case 0x80: // Device + // FIXME: send device status + break; + case 0x81: // Interface + // FIXME: send interface status + break; + case 0x82: // End Point + // FIXME: send endpoint status + break; + default: + // Invalid Command + endpoint_stall(&dev->ep[0]); // Stall End Point 0 + break; + } + + return STATUS_STAGE; +} + +static ep0_stage_t +do_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + switch (setup->bRequestType) { + case 0x00: // Device + if ((le16_to_cpu(setup->wValue) & 0xff) == 1) + dev->remote_wakeup_en = 0; + else + endpoint_stall(&dev->ep[0]); + break; + case 0x02: // End Point + if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { + endpoint_t *ep = + epaddr_to_ep(dev, + le16_to_cpu(setup->wIndex) & 0xff); + + endpoint_unstall(ep); + endpoint_reset_datatoggle(ep); + } else + endpoint_stall(&dev->ep[0]); + break; + } + + return SETUP_STAGE; +} + +static ep0_stage_t +do_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + // Invalid request, stall End Point 0 + endpoint_stall(&dev->ep[0]); + return SETUP_STAGE; +} + +static ep0_stage_t +do_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + switch (setup->bRequestType) { + case 0x00: // Device + if ((le16_to_cpu(setup->wValue) & 0xff) == 1) + dev->remote_wakeup_en = 1; + else + endpoint_stall(&dev->ep[0]); + break; + case 0x02: // End Point + if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { + endpoint_t *ep = + epaddr_to_ep(dev, + le16_to_cpu(setup->wIndex) & 0xff); + + endpoint_stall(ep); + } else + endpoint_stall(&dev->ep[0]); + break; + } + + return SETUP_STAGE; +} + +static ep0_stage_t +do_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + int new_state = dev->state; + int new_addr = le16_to_cpu(setup->wValue); + + dbg("%s: our address=%d", __FUNCTION__, new_addr); + + if (new_addr > 127) { + // usb spec doesn't tell us what to do, so just go to + // default state + new_state = DEFAULT; + dev->address = 0; + } else if (dev->address != new_addr) { + dev->address = new_addr; + new_state = ADDRESS; + } + + if (dev->state != new_state) { + dev->state = new_state; + /* inform function layer of usbdev state change */ + dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); + } + + return SETUP_STAGE; +} + +static ep0_stage_t +do_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + int strnum, desc_len = le16_to_cpu(setup->wLength); + + switch (le16_to_cpu(setup->wValue) >> 8) { + case USB_DT_DEVICE: + // send device descriptor! + desc_len = desc_len > dev->dev_desc->bLength ? + dev->dev_desc->bLength : desc_len; + dbg("sending device desc, size=%d", desc_len); + send_packet(dev, alloc_packet(&dev->ep[0], desc_len, + dev->dev_desc), 0); + break; + case USB_DT_CONFIG: + // If the config descr index in low-byte of + // setup->wValue is valid, send config descr, + // otherwise stall ep0. + if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { + // send config descriptor! + if (desc_len <= USB_DT_CONFIG_SIZE) { + dbg("sending partial config desc, size=%d", + desc_len); + send_packet(dev, + alloc_packet(&dev->ep[0], + desc_len, + dev->conf_desc), + 0); + } else { + int len = le16_to_cpu(dev->conf_desc->wTotalLength); + dbg("sending whole config desc," + " size=%d, our size=%d", desc_len, len); + desc_len = desc_len > len ? len : desc_len; + send_packet(dev, + alloc_packet(&dev->ep[0], + desc_len, + dev->full_conf_desc), + 0); + } + } else + endpoint_stall(&dev->ep[0]); + break; + case USB_DT_STRING: + // If the string descr index in low-byte of setup->wValue + // is valid, send string descr, otherwise stall ep0. + strnum = le16_to_cpu(setup->wValue) & 0xff; + if (strnum >= 0 && strnum < 6) { + struct usb_string_descriptor *desc = + dev->str_desc[strnum]; + desc_len = desc_len > desc->bLength ? + desc->bLength : desc_len; + dbg("sending string desc %d", strnum); + send_packet(dev, + alloc_packet(&dev->ep[0], desc_len, + desc), 0); + } else + endpoint_stall(&dev->ep[0]); + break; + default: + // Invalid request + err("invalid get desc=%d, stalled", + le16_to_cpu(setup->wValue) >> 8); + endpoint_stall(&dev->ep[0]); // Stall endpoint 0 + break; + } + + return STATUS_STAGE; +} + +static ep0_stage_t +do_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + // TODO: implement + // there will be an OUT data stage (the descriptor to set) + return DATA_STAGE; +} + +static ep0_stage_t +do_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + // send dev->configuration + dbg("sending config"); + send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration), + 0); + return STATUS_STAGE; +} + +static ep0_stage_t +do_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + // set active config to low-byte of setup->wValue + dev->configuration = le16_to_cpu(setup->wValue) & 0xff; + dbg("set config, config=%d", dev->configuration); + if (!dev->configuration && dev->state > DEFAULT) { + dev->state = ADDRESS; + /* inform function layer of usbdev state change */ + dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); + } else if (dev->configuration == 1) { + dev->state = CONFIGURED; + /* inform function layer of usbdev state change */ + dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); + } else { + // FIXME: "respond with request error" - how? + } + + return SETUP_STAGE; +} + +static ep0_stage_t +do_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + // interface must be zero. + if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) { + // FIXME: respond with "request error". how? + } else if (dev->state == CONFIGURED) { + // send dev->alternate_setting + dbg("sending alt setting"); + send_packet(dev, alloc_packet(&dev->ep[0], 1, + &dev->alternate_setting), 0); + } + + return STATUS_STAGE; + +} + +static ep0_stage_t +do_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + if (dev->state == ADDRESS) { + // FIXME: respond with "request error". how? + } else if (dev->state == CONFIGURED) { + dev->interface = le16_to_cpu(setup->wIndex) & 0xff; + dev->alternate_setting = + le16_to_cpu(setup->wValue) & 0xff; + // interface and alternate_setting must be zero + if (dev->interface || dev->alternate_setting) { + // FIXME: respond with "request error". how? + } + } + + return SETUP_STAGE; +} + +static ep0_stage_t +do_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + // TODO + return SETUP_STAGE; +} + +typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev, + struct usb_ctrlrequest* setup); + + +/* Table of the standard device request handlers */ +static const req_method_t req_method[] = { + do_get_status, + do_clear_feature, + do_reserved, + do_set_feature, + do_reserved, + do_set_address, + do_get_descriptor, + do_set_descriptor, + do_get_configuration, + do_set_configuration, + do_get_interface, + do_set_interface, + do_synch_frame +}; + + +// SETUP packet request dispatcher +static void +do_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup) +{ + req_method_t m; + + dbg("%s: req %d %s", __FUNCTION__, setup->bRequestType, + get_std_req_name(setup->bRequestType)); + + if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD || + (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) { + err("%s: invalid requesttype 0x%02x", __FUNCTION__, + setup->bRequestType); + return; + } + + if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength) + dbg("%s: OUT phase! length=%d", __FUNCTION__, setup->wLength); + + if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t)) + m = req_method[setup->bRequestType]; + else + m = do_reserved; + + dev->ep0_stage = (*m)(dev, setup); +} + +/* + * A SETUP, DATA0, or DATA1 packet has been received + * on the default control endpoint's fifo. + */ +static void +process_ep0_receive (struct usb_dev* dev) +{ + endpoint_t *ep0 = &dev->ep[0]; + usbdev_pkt_t *pkt; + + spin_lock(&ep0->lock); + + // complete packet and prepare a new packet + pkt = receive_packet_complete(ep0); + if (!pkt) { + // FIXME: should put a warn/err here. + spin_unlock(&ep0->lock); + return; + } + + // unlink immediately from endpoint. + unlink_head(&ep0->outlist); + + // override current stage if h/w says it's a setup packet + if (pkt->status & PKT_STATUS_SU) + dev->ep0_stage = SETUP_STAGE; + + switch (dev->ep0_stage) { + case SETUP_STAGE: + vdbg("SU bit is %s in setup stage", + (pkt->status & PKT_STATUS_SU) ? "set" : "not set"); + + if (pkt->size == sizeof(struct usb_ctrlrequest)) { +#ifdef VDEBUG + if (pkt->status & PKT_STATUS_ACK) + vdbg("received SETUP"); + else + vdbg("received NAK SETUP"); +#endif + do_setup(dev, (struct usb_ctrlrequest*)pkt->payload); + } else + err("%s: wrong size SETUP received", __FUNCTION__); + break; + case DATA_STAGE: + /* + * this setup has an OUT data stage. Of the standard + * device requests, only set_descriptor has this stage, + * so this packet is that descriptor. TODO: drop it for + * now, set_descriptor not implemented. + * + * Need to place a byte in the write FIFO here, to prepare + * to send a zero-length DATA ack packet to the host in the + * STATUS stage. + */ + au_writel(0, ep0->reg->write_fifo); + dbg("received OUT stage DATAx on EP0, size=%d", pkt->size); + dev->ep0_stage = SETUP_STAGE; + break; + case STATUS_STAGE: + // this setup had an IN data stage, and host is ACK'ing + // the packet we sent during that stage. + if (pkt->size != 0) + warn("received non-zero ACK on EP0??"); +#ifdef VDEBUG + else + vdbg("received ACK on EP0"); +#endif + dev->ep0_stage = SETUP_STAGE; + break; + } + + spin_unlock(&ep0->lock); + // we're done processing the packet, free it + kfree(pkt); +} + + +/* + * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5) + */ +static void +process_ep_receive (struct usb_dev* dev, endpoint_t *ep) +{ + usbdev_pkt_t *pkt; + + spin_lock(&ep->lock); + pkt = receive_packet_complete(ep); + spin_unlock(&ep->lock); + + dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data); +} + + + +/* This ISR handles the receive complete and suspend events */ +static void +req_sus_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct usb_dev *dev = (struct usb_dev *) dev_id; + u32 status; + + status = au_readl(USBD_INTSTAT); + au_writel(status, USBD_INTSTAT); // ack'em + + if (status & (1<<0)) + process_ep0_receive(dev); + if (status & (1<<4)) + process_ep_receive(dev, &dev->ep[4]); + if (status & (1<<5)) + process_ep_receive(dev, &dev->ep[5]); +} + + +/* This ISR handles the DMA done events on EP0 */ +static void +dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct usb_dev *dev = (struct usb_dev *) dev_id; + usbdev_pkt_t* pkt; + endpoint_t *ep0 = &dev->ep[0]; + u32 cs0, buff_done; + + spin_lock(&ep0->lock); + cs0 = au_readl(ep0->reg->ctrl_stat); + + // first check packet transmit done + if ((buff_done = get_dma_buffer_done(ep0->indma)) != 0) { + // transmitted a DATAx packet during DATA stage + // on control endpoint 0 + // clear DMA done bit + if (buff_done & DMA_D0) + clear_dma_done0(ep0->indma); + if (buff_done & DMA_D1) + clear_dma_done1(ep0->indma); + + pkt = send_packet_complete(ep0); + if (pkt) + kfree(pkt); + } + + /* + * Now check packet receive done. Shouldn't get these, + * the receive packet complete intr should happen + * before the DMA done intr occurs. + */ + if ((buff_done = get_dma_buffer_done(ep0->outdma)) != 0) { + // clear DMA done bit + if (buff_done & DMA_D0) + clear_dma_done0(ep0->outdma); + if (buff_done & DMA_D1) + clear_dma_done1(ep0->outdma); + + //process_ep0_receive(dev); + } + + spin_unlock(&ep0->lock); +} + +/* This ISR handles the DMA done events on endpoints 2,3,4,5 */ +static void +dma_done_ep_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct usb_dev *dev = (struct usb_dev *) dev_id; + int i; + + for (i = 2; i < 6; i++) { + u32 buff_done; + usbdev_pkt_t* pkt; + endpoint_t *ep = &dev->ep[i]; + + if (!ep->active) continue; + + spin_lock(&ep->lock); + + if (ep->direction == USB_DIR_IN) { + buff_done = get_dma_buffer_done(ep->indma); + if (buff_done != 0) { + // transmitted a DATAx pkt on the IN ep + // clear DMA done bit + if (buff_done & DMA_D0) + clear_dma_done0(ep->indma); + if (buff_done & DMA_D1) + clear_dma_done1(ep->indma); + + pkt = send_packet_complete(ep); + + spin_unlock(&ep->lock); + dev->func_cb(CB_PKT_COMPLETE, + (unsigned long)pkt, + dev->cb_data); + spin_lock(&ep->lock); + } + } else { + /* + * Check packet receive done (OUT ep). Shouldn't get + * these, the rx packet complete intr should happen + * before the DMA done intr occurs. + */ + buff_done = get_dma_buffer_done(ep->outdma); + if (buff_done != 0) { + // received a DATAx pkt on the OUT ep + // clear DMA done bit + if (buff_done & DMA_D0) + clear_dma_done0(ep->outdma); + if (buff_done & DMA_D1) + clear_dma_done1(ep->outdma); + + //process_ep_receive(dev, ep); + } + } + + spin_unlock(&ep->lock); + } +} + + +/*************************************************************************** + * Here begins the external interface functions + *************************************************************************** + */ + +/* + * allocate a new packet + */ +int +usbdev_alloc_packet(int ep_addr, int data_size, usbdev_pkt_t** pkt) +{ + endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr); + usbdev_pkt_t* lpkt = NULL; + + if (!ep || !ep->active || ep->address < 2) + return -ENODEV; + if (data_size > ep->max_pkt_size) + return -EINVAL; + + lpkt = *pkt = alloc_packet(ep, data_size, NULL); + if (!lpkt) + return -ENOMEM; + return 0; +} + + +/* + * packet send + */ +int +usbdev_send_packet(int ep_addr, usbdev_pkt_t * pkt) +{ + unsigned long flags; + int count; + endpoint_t * ep; + + if (!pkt || !(ep = epaddr_to_ep(&usbdev, pkt->ep_addr)) || + !ep->active || ep->address < 2) + return -ENODEV; + if (ep->direction != USB_DIR_IN) + return -EINVAL; + + spin_lock_irqsave(&ep->lock, flags); + count = send_packet(&usbdev, pkt, 1); + spin_unlock_irqrestore(&ep->lock, flags); + + return count; +} + +/* + * packet receive + */ +int +usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt) +{ + unsigned long flags; + usbdev_pkt_t* lpkt = NULL; + endpoint_t *ep = epaddr_to_ep(&usbdev, ep_addr); + + if (!ep || !ep->active || ep->address < 2) + return -ENODEV; + if (ep->direction != USB_DIR_OUT) + return -EINVAL; + + spin_lock_irqsave(&ep->lock, flags); + if (ep->outlist.count > 1) + lpkt = unlink_head(&ep->outlist); + spin_unlock_irqrestore(&ep->lock, flags); + + if (!lpkt) { + /* no packet available */ + *pkt = NULL; + return -ENODATA; + } + + *pkt = lpkt; + + return lpkt->size; +} + + +/* + * return total queued byte count on the endpoint. + */ +int +usbdev_get_byte_count(int ep_addr) +{ + unsigned long flags; + pkt_list_t *list; + usbdev_pkt_t *scan; + int count = 0; + endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr); + + if (!ep || !ep->active || ep->address < 2) + return -ENODEV; + + if (ep->direction == USB_DIR_IN) { + list = &ep->inlist; + + spin_lock_irqsave(&ep->lock, flags); + for (scan = list->head; scan; scan = scan->next) + count += scan->size; + spin_unlock_irqrestore(&ep->lock, flags); + } else { + list = &ep->outlist; + + spin_lock_irqsave(&ep->lock, flags); + if (list->count > 1) { + for (scan = list->head; scan != list->tail; + scan = scan->next) + count += scan->size; + } + spin_unlock_irqrestore(&ep->lock, flags); + } + + return count; +} + + +void +usbdev_exit(void) +{ + endpoint_t *ep; + int i; + + au_writel(0, USBD_INTEN); // disable usb dev ints + au_writel(0, USBD_ENABLE); // disable usb dev + + free_irq(AU1000_USB_DEV_REQ_INT, &usbdev); + free_irq(AU1000_USB_DEV_SUS_INT, &usbdev); + + // free all control endpoint resources + ep = &usbdev.ep[0]; + free_au1000_dma(ep->indma); + free_au1000_dma(ep->outdma); + endpoint_flush(ep); + + // free ep resources + for (i = 2; i < 6; i++) { + ep = &usbdev.ep[i]; + if (!ep->active) continue; + + if (ep->direction == USB_DIR_IN) { + free_au1000_dma(ep->indma); + } else { + free_au1000_dma(ep->outdma); + } + endpoint_flush(ep); + } + + if (usbdev.full_conf_desc) + kfree(usbdev.full_conf_desc); +} + +int +usbdev_init(struct usb_device_descriptor* dev_desc, + struct usb_config_descriptor* config_desc, + struct usb_interface_descriptor* if_desc, + struct usb_endpoint_descriptor* ep_desc, + struct usb_string_descriptor* str_desc[], + void (*cb)(usbdev_cb_type_t, unsigned long, void *), + void* cb_data) +{ + endpoint_t *ep0; + int i, ret=0; + u8* fcd; + + if (dev_desc->bNumConfigurations > 1 || + config_desc->bNumInterfaces > 1 || + if_desc->bNumEndpoints > 4) { + err("Only one config, one i/f, and no more " + "than 4 ep's allowed"); + ret = -EINVAL; + goto out; + } + + if (!cb) { + err("Function-layer callback required"); + ret = -EINVAL; + goto out; + } + + if (dev_desc->bMaxPacketSize0 != USBDEV_EP0_MAX_PACKET_SIZE) { + warn("EP0 Max Packet size must be %d", + USBDEV_EP0_MAX_PACKET_SIZE); + dev_desc->bMaxPacketSize0 = USBDEV_EP0_MAX_PACKET_SIZE; + } + + memset(&usbdev, 0, sizeof(struct usb_dev)); + + usbdev.state = DEFAULT; + usbdev.dev_desc = dev_desc; + usbdev.if_desc = if_desc; + usbdev.conf_desc = config_desc; + for (i=0; i<6; i++) + usbdev.str_desc[i] = str_desc[i]; + usbdev.func_cb = cb; + usbdev.cb_data = cb_data; + + /* Initialize default control endpoint */ + ep0 = &usbdev.ep[0]; + ep0->active = 1; + ep0->type = CONTROL_EP; + ep0->max_pkt_size = USBDEV_EP0_MAX_PACKET_SIZE; + spin_lock_init(&ep0->lock); + ep0->desc = NULL; // ep0 has no descriptor + ep0->address = 0; + ep0->direction = 0; + ep0->reg = &ep_reg[0]; + + /* Initialize the other requested endpoints */ + for (i = 0; i < if_desc->bNumEndpoints; i++) { + struct usb_endpoint_descriptor* epd = &ep_desc[i]; + endpoint_t *ep; + + if ((epd->bEndpointAddress & 0x80) == USB_DIR_IN) { + ep = &usbdev.ep[2]; + ep->address = 2; + if (ep->active) { + ep = &usbdev.ep[3]; + ep->address = 3; + if (ep->active) { + err("too many IN ep's requested"); + ret = -ENODEV; + goto out; + } + } + } else { + ep = &usbdev.ep[4]; + ep->address = 4; + if (ep->active) { + ep = &usbdev.ep[5]; + ep->address = 5; + if (ep->active) { + err("too many OUT ep's requested"); + ret = -ENODEV; + goto out; + } + } + } + + ep->active = 1; + epd->bEndpointAddress &= ~0x0f; + epd->bEndpointAddress |= (u8)ep->address; + ep->direction = epd->bEndpointAddress & 0x80; + ep->type = epd->bmAttributes & 0x03; + ep->max_pkt_size = le16_to_cpu(epd->wMaxPacketSize); + spin_lock_init(&ep->lock); + ep->desc = epd; + ep->reg = &ep_reg[ep->address]; + } + + /* + * initialize the full config descriptor + */ + usbdev.full_conf_desc = fcd = kmalloc(le16_to_cpu(config_desc->wTotalLength), + ALLOC_FLAGS); + if (!fcd) { + err("failed to alloc full config descriptor"); + ret = -ENOMEM; + goto out; + } + + memcpy(fcd, config_desc, USB_DT_CONFIG_SIZE); + fcd += USB_DT_CONFIG_SIZE; + memcpy(fcd, if_desc, USB_DT_INTERFACE_SIZE); + fcd += USB_DT_INTERFACE_SIZE; + for (i = 0; i < if_desc->bNumEndpoints; i++) { + memcpy(fcd, &ep_desc[i], USB_DT_ENDPOINT_SIZE); + fcd += USB_DT_ENDPOINT_SIZE; + } + + /* Now we're ready to enable the controller */ + au_writel(0x0002, USBD_ENABLE); + udelay(100); + au_writel(0x0003, USBD_ENABLE); + udelay(100); + + /* build and send config table based on ep descriptors */ + for (i = 0; i < 6; i++) { + endpoint_t *ep; + if (i == 1) + continue; // skip dummy ep + ep = &usbdev.ep[i]; + if (ep->active) { + au_writel((ep->address << 4) | 0x04, USBD_CONFIG); + au_writel(((ep->max_pkt_size & 0x380) >> 7) | + (ep->direction >> 4) | (ep->type << 4), + USBD_CONFIG); + au_writel((ep->max_pkt_size & 0x7f) << 1, USBD_CONFIG); + au_writel(0x00, USBD_CONFIG); + au_writel(ep->address, USBD_CONFIG); + } else { + u8 dir = (i==2 || i==3) ? DIR_IN : DIR_OUT; + au_writel((i << 4) | 0x04, USBD_CONFIG); + au_writel(((16 & 0x380) >> 7) | dir | + (BULK_EP << 4), USBD_CONFIG); + au_writel((16 & 0x7f) << 1, USBD_CONFIG); + au_writel(0x00, USBD_CONFIG); + au_writel(i, USBD_CONFIG); + } + } + + /* + * Enable Receive FIFO Complete interrupts only. Transmit + * complete is being handled by the DMA done interrupts. + */ + au_writel(0x31, USBD_INTEN); + + /* + * Controller is now enabled, request DMA and IRQ + * resources. + */ + + /* request the USB device transfer complete interrupt */ + if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, SA_INTERRUPT, + "USBdev req", &usbdev)) { + err("Can't get device request intr"); + ret = -ENXIO; + goto out; + } + /* request the USB device suspend interrupt */ + if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, SA_INTERRUPT, + "USBdev sus", &usbdev)) { + err("Can't get device suspend intr"); + ret = -ENXIO; + goto out; + } + + /* Request EP0 DMA and IRQ */ + if ((ep0->indma = request_au1000_dma(ep_dma_id[0].id, + ep_dma_id[0].str, + dma_done_ep0_intr, + SA_INTERRUPT, + &usbdev)) < 0) { + err("Can't get %s DMA", ep_dma_id[0].str); + ret = -ENXIO; + goto out; + } + if ((ep0->outdma = request_au1000_dma(ep_dma_id[1].id, + ep_dma_id[1].str, + NULL, 0, NULL)) < 0) { + err("Can't get %s DMA", ep_dma_id[1].str); + ret = -ENXIO; + goto out; + } + + // Flush the ep0 buffers and FIFOs + endpoint_flush(ep0); + // start packet reception on ep0 + kickstart_receive_packet(ep0); + + /* Request DMA and IRQ for the other endpoints */ + for (i = 2; i < 6; i++) { + endpoint_t *ep = &usbdev.ep[i]; + if (!ep->active) + continue; + + // Flush the endpoint buffers and FIFOs + endpoint_flush(ep); + + if (ep->direction == USB_DIR_IN) { + ep->indma = + request_au1000_dma(ep_dma_id[ep->address].id, + ep_dma_id[ep->address].str, + dma_done_ep_intr, + SA_INTERRUPT, + &usbdev); + if (ep->indma < 0) { + err("Can't get %s DMA", + ep_dma_id[ep->address].str); + ret = -ENXIO; + goto out; + } + } else { + ep->outdma = + request_au1000_dma(ep_dma_id[ep->address].id, + ep_dma_id[ep->address].str, + NULL, 0, NULL); + if (ep->outdma < 0) { + err("Can't get %s DMA", + ep_dma_id[ep->address].str); + ret = -ENXIO; + goto out; + } + + // start packet reception on OUT endpoint + kickstart_receive_packet(ep); + } + } + + out: + if (ret) + usbdev_exit(); + return ret; +} + +EXPORT_SYMBOL(usbdev_init); +EXPORT_SYMBOL(usbdev_exit); +EXPORT_SYMBOL(usbdev_alloc_packet); +EXPORT_SYMBOL(usbdev_receive_packet); +EXPORT_SYMBOL(usbdev_send_packet); +EXPORT_SYMBOL(usbdev_get_byte_count); diff --git a/arch/mips/au1000/csb250/Makefile b/arch/mips/au1000/csb250/Makefile new file mode 100644 index 00000000000..c0c4dcdccae --- /dev/null +++ b/arch/mips/au1000/csb250/Makefile @@ -0,0 +1,8 @@ +# +# Copyright 2002 Cogent Computer Systems +# dan@embeddededge.com +# +# Makefile for the Cogent CSB250 Au1500 board. Copied from Pb1500. +# + +obj-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/csb250/board_setup.c b/arch/mips/au1000/csb250/board_setup.c new file mode 100644 index 00000000000..90426eaffb2 --- /dev/null +++ b/arch/mips/au1000/csb250/board_setup.c @@ -0,0 +1,239 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Cogent CSB250 board setup. + * + * Copyright 2002 Cogent Computer Systems, Inc. + * dan@embeddededge.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/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> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/keyboard.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/pgtable.h> +#include <asm/au1000.h> +#include <asm/csb250.h> + +extern int (*board_pci_idsel)(unsigned int devsel, int assert); +int csb250_pci_idsel(unsigned int devsel, int assert); + +void __init board_setup(void) +{ + u32 pin_func, pin_val; + u32 sys_freqctrl, sys_clksrc; + + + // set AUX clock to 12MHz * 8 = 96 MHz + au_writel(8, SYS_AUXPLL); + au_writel(0, SYS_PINSTATERD); + udelay(100); + +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + + /* GPIO201 is input for PCMCIA card detect */ + /* GPIO203 is input for PCMCIA interrupt request */ + au_writel(au_readl(GPIO2_DIR) & (u32)(~((1<<1)|(1<<3))), GPIO2_DIR); + + /* zero and disable FREQ2 */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD clocks */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + au_writel(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* + * Route 48MHz FREQ2 into USB Host and/or Device + */ +#ifdef CONFIG_USB_OHCI + sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); +#endif +#ifdef CONFIG_AU1X00_USB_DEVICE + sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); +#endif + au_writel(sys_clksrc, SYS_CLKSRC); + + + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); +#ifndef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB host + pin_func |= 0x8000; +#endif + au_writel(pin_func, SYS_PINFUNC); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + + /* Configure GPIO2....it's used by PCI among other things. + */ + + /* Make everything but GP200 (PCI RST) an input until we get + * the pins set correctly. + */ + au_writel(0x00000001, GPIO2_DIR); + + /* Set the pins used for output. + * A zero bit will leave PCI reset, LEDs off, power up USB, + * IDSEL disabled. + */ + pin_val = ((3 << 30) | (7 << 19) | (1 << 17) | (1 << 16)); + au_writel(pin_val, GPIO2_OUTPUT); + + /* Set the output direction. + */ + pin_val = ((3 << 14) | (7 << 3) | (1 << 1) | (1 << 0)); + au_writel(pin_val, GPIO2_DIR); + +#ifdef CONFIG_PCI + /* Use FREQ1 for the PCI output clock. We use the + * CPU clock of 384 MHz divided by 12 to get 32 MHz PCI. + * If Michael changes the CPU speed, we need to adjust + * that here as well :-). + */ + + /* zero and disable FREQ1 + */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0x000ffc00; + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable PCI clock + */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x000f8000; + au_writel(sys_clksrc, SYS_CLKSRC); + + /* Get current values (which really should match above). + */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0x000ffc00; + + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x000f8000; + + /* FREQ1 = cpu/12 = 32 MHz + */ + sys_freqctrl |= ((5<<12) | (1<<11) | (0<<10)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* Just connect the clock without further dividing. + */ + sys_clksrc |= ((3<<17) | (0<<16) | (0<<15)); + au_writel(sys_clksrc, SYS_CLKSRC); + + udelay(1); + + /* Now that clocks should be running, take PCI out of reset. + */ + pin_val = au_readl(GPIO2_OUTPUT); + pin_val |= ((1 << 16) | 1); + au_writel(pin_val, GPIO2_OUTPUT); + + // Setup PCI bus controller + au_writel(0, Au1500_PCI_CMEM); + au_writel(0x00003fff, Au1500_CFG_BASE); + + /* We run big endian without any of the software byte swapping, + * so configure the PCI bridge to help us out. + */ + au_writel(0xf | (2<<6) | (1<<5) | (1<<4), Au1500_PCI_CFG); + + au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV); + au_writel(0, Au1500_PCI_MWBASE_REV_CCL); + au_writel(0x02a00356, Au1500_PCI_STATCMD); + au_writel(0x00003c04, Au1500_PCI_HDRTYPE); + au_writel(0x00000008, Au1500_PCI_MBAR); + au_sync(); + + board_pci_idsel = csb250_pci_idsel; +#endif + + /* Enable sys bus clock divider when IDLE state or no bus activity. */ + au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); + +#ifdef CONFIG_RTC + // Enable the RTC if not already enabled + if (!(au_readl(0xac000028) & 0x20)) { + printk("enabling clock ...\n"); + au_writel((au_readl(0xac000028) | 0x20), 0xac000028); + } + // Put the clock in BCD mode + if (readl(0xac00002C) & 0x4) { /* reg B */ + au_writel(au_readl(0xac00002c) & ~0x4, 0xac00002c); + au_sync(); + } +#endif +} + +/* The IDSEL is selected in the GPIO2 register. We will make device + * 12 appear in slot 0 and device 13 appear in slot 1. + */ +int +csb250_pci_idsel(unsigned int devsel, int assert) +{ + int retval; + unsigned int gpio2_pins; + + retval = 1; + + /* First, disable both selects, then assert the one requested. + */ + au_writel(0xc000c000, GPIO2_OUTPUT); + au_sync(); + + if (assert) { + if (devsel == 12) + gpio2_pins = 0x40000000; + else if (devsel == 13) + gpio2_pins = 0x80000000; + else { + gpio2_pins = 0xc000c000; + retval = 0; + } + au_writel(gpio2_pins, GPIO2_OUTPUT); + } + au_sync(); + + return retval; +} diff --git a/arch/mips/au1000/csb250/init.c b/arch/mips/au1000/csb250/init.c new file mode 100644 index 00000000000..4320057fc43 --- /dev/null +++ b/arch/mips/au1000/csb250/init.c @@ -0,0 +1,95 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Cogent CSB250 board setup + * + * Copyright 2002 Cogent Computer Systems, Inc. + * dan@embeddededge.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> +#include <linux/sched.h> + +int prom_argc; +char **prom_argv, **prom_envp; +extern void __init prom_init_cmdline(void); +extern char *prom_getenv(char *envname); + +/* When we get initrd working someday......... +*/ +int my_initrd_start, my_initrd_size; + +/* Start arguments and environment. +*/ +static char *csb_env[2]; +static char *csb_arg[4]; +static char *arg1 = "console=ttyS3,38400"; +static char *arg2 = "root=/dev/nfs rw ip=any"; +static char *env1 = "ethaddr=00:30:23:50:00:00"; + +const char *get_system_type(void) +{ + return "Cogent CSB250"; +} + +int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + unsigned char *memsize_str; + unsigned long memsize; + + /* We use a0 and a1 to pass initrd start and size. + */ + if (((uint) argc > 0) && ((uint)argv > 0)) { + my_initrd_start = (uint)argc; + my_initrd_size = (uint)argv; + } + + /* First argv is ignored. + */ + prom_argc = 3; + prom_argv = csb_arg; + prom_envp = csb_env; + csb_arg[1] = arg1; + csb_arg[2] = arg2; + csb_env[0] = env1; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_CSB250; + + prom_init_cmdline(); + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + memsize = 0x02000000; + } else { + memsize = simple_strtol(memsize_str, NULL, 0); + } + add_memory_region(0, memsize, BOOT_MEM_RAM); + return 0; +} diff --git a/arch/mips/au1000/csb250/irqmap.c b/arch/mips/au1000/csb250/irqmap.c new file mode 100644 index 00000000000..5cb1166be35 --- /dev/null +++ b/arch/mips/au1000/csb250/irqmap.c @@ -0,0 +1,60 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + + { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0}, + { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_202, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_203, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_207, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/db1x00/Makefile b/arch/mips/au1000/db1x00/Makefile new file mode 100644 index 00000000000..4c7d763f211 --- /dev/null +++ b/arch/mips/au1000/db1x00/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor Db1x00 board. + +lib-y := init.o board_setup.o irqmap.o +obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c new file mode 100644 index 00000000000..ac05ba0ff63 --- /dev/null +++ b/arch/mips/au1000/db1x00/board_setup.c @@ -0,0 +1,127 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Alchemy Db1x00 board setup. + * + * Copyright 2000 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/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> + +#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-db1x00/db1x00.h> + +/* not correct for db1550 */ +static BCSR * const bcsr = (BCSR *)0xAE000000; + +void board_reset (void) +{ + /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ + au_writel(0x00000000, 0xAE00001C); +} + +void __init board_setup(void) +{ + u32 pin_func; + + pin_func = 0; + /* not valid for 1550 */ +#ifdef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB device + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); + au_writel(pin_func, SYS_PINFUNC); +#endif + +#if defined(CONFIG_IRDA) && (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100)) + /* set IRFIRSEL instead of GPIO15 */ + pin_func = au_readl(SYS_PINFUNC) | (u32)((1<<8)); + au_writel(pin_func, SYS_PINFUNC); + /* power off until the driver is in use */ + bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK; + bcsr->resets |= BCSR_RESETS_IRDA_MODE_OFF; + au_sync(); +#endif + au_writel(0, 0xAE000010); /* turn off pcmcia power */ + +#ifdef CONFIG_MIPS_MIRAGE + /* enable GPIO[31:0] inputs */ + au_writel(0, SYS_PININPUTEN); + + /* GPIO[20] is output, tristate the other input primary GPIO's */ + au_writel((u32)(~(1<<20)), SYS_TRIOUTCLR); + + /* set GPIO[210:208] instead of SSI_0 */ + pin_func = au_readl(SYS_PINFUNC) | (u32)(1); + + /* set GPIO[215:211] for LED's */ + pin_func |= (u32)((5<<2)); + + /* set GPIO[214:213] for more LED's */ + pin_func |= (u32)((5<<12)); + + /* set GPIO[207:200] instead of PCMCIA/LCD */ + pin_func |= (u32)((3<<17)); + au_writel(pin_func, SYS_PINFUNC); + + /* Enable speaker amplifier. This should + * be part of the audio driver. + */ + au_writel(au_readl(GPIO2_DIR) | 0x200, GPIO2_DIR); + au_writel(0x02000200, GPIO2_OUTPUT); +#endif + + au_sync(); + +#ifdef CONFIG_MIPS_DB1000 + printk("AMD Alchemy Au1000/Db1000 Board\n"); +#endif +#ifdef CONFIG_MIPS_DB1500 + printk("AMD Alchemy Au1500/Db1500 Board\n"); +#endif +#ifdef CONFIG_MIPS_DB1100 + printk("AMD Alchemy Au1100/Db1100 Board\n"); +#endif +#ifdef CONFIG_MIPS_BOSPORUS + printk("AMD Alchemy Bosporus Board\n"); +#endif +#ifdef CONFIG_MIPS_MIRAGE + printk("AMD Alchemy Mirage Board\n"); +#endif +#ifdef CONFIG_MIPS_DB1550 + printk("AMD Alchemy Au1550/Db1550 Board\n"); +#endif +} diff --git a/arch/mips/au1000/db1x00/init.c b/arch/mips/au1000/db1x00/init.c new file mode 100644 index 00000000000..51eee94a5e8 --- /dev/null +++ b/arch/mips/au1000/db1x00/init.c @@ -0,0 +1,74 @@ +/* + * BRIEF MODULE DESCRIPTION + * PB1000 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/config.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) +{ +#ifdef CONFIG_MIPS_BOSPORUS + return "Alchemy Bosporus Gateway Reference"; +#else + return "Alchemy Db1x00"; +#endif +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_DB1000; /* set the platform # */ + + 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); +} diff --git a/arch/mips/au1000/db1x00/irqmap.c b/arch/mips/au1000/db1x00/irqmap.c new file mode 100644 index 00000000000..8f6ef0dbe1f --- /dev/null +++ b/arch/mips/au1000/db1x00/irqmap.c @@ -0,0 +1,72 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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 <linux/bitops.h> + +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/mach-au1x00/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + +#ifndef CONFIG_MIPS_MIRAGE +#ifdef CONFIG_MIPS_DB1550 + { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 0 IRQ# */ + { AU1000_GPIO_5, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 1 IRQ# */ +#else + { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 0 Fully_Interted# */ + { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 0 STSCHG# */ + { AU1000_GPIO_2, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 0 IRQ# */ + + { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 1 Fully_Interted# */ + { AU1000_GPIO_4, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 1 STSCHG# */ + { AU1000_GPIO_5, INTC_INT_LOW_LEVEL, 0 }, /* PCMCIA Card 1 IRQ# */ +#endif +#else + { AU1000_GPIO_7, INTC_INT_RISE_EDGE, 0 }, /* touchscreen pen down */ +#endif + +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/db1x00/mirage_ts.c b/arch/mips/au1000/db1x00/mirage_ts.c new file mode 100644 index 00000000000..ade35e43200 --- /dev/null +++ b/arch/mips/au1000/db1x00/mirage_ts.c @@ -0,0 +1,261 @@ +/* + * linux/arch/mips/au1000/db1x00/mirage_ts.c + * + * BRIEF MODULE DESCRIPTION + * Glue between Mirage board-specific touchscreen pieces + * and generic Wolfson Codec touchscreen support. + * + * Based on pb1100_ts.c used in Hydrogen II. + * + * Copyright (c) 2003 Embedded Edge, LLC + * dan@embeddededge.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/config.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/proc_fs.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/wait.h> + +#include <asm/segment.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/delay.h> +#include <asm/au1000.h> + +/* + * Imported interface to Wolfson Codec driver. + */ +extern void *wm97xx_ts_get_handle(int which); +extern int wm97xx_ts_ready(void* ts_handle); +extern void wm97xx_ts_set_cal(void* ts_handle, int xscale, int xtrans, int yscale, int ytrans); +extern u16 wm97xx_ts_get_ac97(void* ts_handle, u8 reg); +extern void wm97xx_ts_set_ac97(void* ts_handle, u8 reg, u16 val); +extern int wm97xx_ts_read_data(void* ts_handle, long* x, long* y, long* pressure); +extern void wm97xx_ts_send_data(void* ts_handle, long x, long y, long z); + +int wm97xx_comodule_present = 1; + + +#define TS_NAME "mirage_ts" + +#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg) +#define DPRINTK(format, arg...) printk("%s: " format "\n", __FUNCTION__ , ## arg) + + +#define PEN_DOWN_IRQ AU1000_GPIO_7 + +static struct task_struct *ts_task = 0; +static DECLARE_COMPLETION(ts_complete); +static DECLARE_WAIT_QUEUE_HEAD(pendown_wait); + +#ifdef CONFIG_WM97XX_FIVEWIRETS +static int release_pressure = 1; +#else +static int release_pressure = 50; +#endif + +typedef struct { + long x; + long y; +} DOWN_EVENT; + +#define SAMPLE_RATE 50 /* samples per second */ +#define PEN_DEBOUNCE 5 /* samples for settling - fn of SAMPLE_RATE */ +#define PEN_UP_TIMEOUT 10 /* in seconds */ +#define PEN_UP_SETTLE 5 /* samples per second */ + +static struct { + int xscale; + int xtrans; + int yscale; + int ytrans; +} mirage_ts_cal = +{ +#if 0 + xscale: 84, + xtrans: -157, + yscale: 66, + ytrans: -150, +#else + xscale: 84, + xtrans: -150, + yscale: 66, + ytrans: -146, +#endif +}; + + +static void pendown_irq(int irqnr, void *devid, struct pt_regs *regs) +{ +//DPRINTK("got one 0x%x", au_readl(SYS_PINSTATERD)); + wake_up(&pendown_wait); +} + +static int ts_thread(void *id) +{ + static int pen_was_down = 0; + static DOWN_EVENT pen_xy; + long x, y, z; + void *ts; /* handle */ + struct task_struct *tsk = current; + int timeout = HZ / SAMPLE_RATE; + + ts_task = tsk; + + daemonize(); + tsk->tty = NULL; + tsk->policy = SCHED_FIFO; + tsk->rt_priority = 1; + strcpy(tsk->comm, "touchscreen"); + + /* only want to receive SIGKILL */ + spin_lock_irq(&tsk->sigmask_lock); + siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); + recalc_sigpending(tsk); + spin_unlock_irq(&tsk->sigmask_lock); + + /* get handle for codec */ + ts = wm97xx_ts_get_handle(0); + + /* proceed only after everybody is ready */ + wait_event_timeout(pendown_wait, wm97xx_ts_ready(ts), HZ/4); + + /* board-specific calibration */ + wm97xx_ts_set_cal(ts, + mirage_ts_cal.xscale, + mirage_ts_cal.xtrans, + mirage_ts_cal.yscale, + mirage_ts_cal.ytrans); + + /* route Wolfson pendown interrupts to our GPIO */ + au_sync(); + wm97xx_ts_set_ac97(ts, 0x4c, wm97xx_ts_get_ac97(ts, 0x4c) & ~0x0008); + au_sync(); + wm97xx_ts_set_ac97(ts, 0x56, wm97xx_ts_get_ac97(ts, 0x56) & ~0x0008); + au_sync(); + wm97xx_ts_set_ac97(ts, 0x52, wm97xx_ts_get_ac97(ts, 0x52) | 0x2008); + au_sync(); + + for (;;) { + interruptible_sleep_on_timeout(&pendown_wait, timeout); + disable_irq(PEN_DOWN_IRQ); + if (signal_pending(tsk)) { + break; + } + + /* read codec */ + if (!wm97xx_ts_read_data(ts, &x, &y, &z)) + z = 0; /* treat no-data and pen-up the same */ + + if (signal_pending(tsk)) { + break; + } + + if (z >= release_pressure) { + y = ~y; /* top to bottom */ + if (pen_was_down > 1 /*&& pen_was_down < PEN_DEBOUNCE*/) {//THXXX + /* bounce ? */ + x = pen_xy.x; + y = pen_xy.y; + --pen_was_down; + } else if (pen_was_down <= 1) { + pen_xy.x = x; + pen_xy.y = y; + if (pen_was_down) + wm97xx_ts_send_data(ts, x, y, z); + pen_was_down = PEN_DEBOUNCE; + } + //wm97xx_ts_send_data(ts, x, y, z); + timeout = HZ / SAMPLE_RATE; + } else { + if (pen_was_down) { + if (--pen_was_down) + z = release_pressure; + else //THXXX + wm97xx_ts_send_data(ts, pen_xy.x, pen_xy.y, z); + } + /* The pendown signal takes some time to settle after + * reading the pen pressure so wait a little + * before enabling the pen. + */ + if (! pen_was_down) { +// interruptible_sleep_on_timeout(&pendown_wait, HZ / PEN_UP_SETTLE); + timeout = HZ * PEN_UP_TIMEOUT; + } + } + enable_irq(PEN_DOWN_IRQ); + } + enable_irq(PEN_DOWN_IRQ); + ts_task = NULL; + complete(&ts_complete); + return 0; +} + +static int __init ts_mirage_init(void) +{ + int ret; + + /* pen down signal is connected to GPIO 7 */ + + ret = request_irq(PEN_DOWN_IRQ, pendown_irq, 0, "ts-pendown", NULL); + if (ret) { + err("unable to get pendown irq%d: [%d]", PEN_DOWN_IRQ, ret); + return ret; + } + + lock_kernel(); + ret = kernel_thread(ts_thread, NULL, CLONE_FS | CLONE_FILES); + if (ret < 0) { + unlock_kernel(); + return ret; + } + unlock_kernel(); + + info("Mirage touchscreen IRQ initialized."); + + return 0; +} + +static void __exit ts_mirage_exit(void) +{ + if (ts_task) { + send_sig(SIGKILL, ts_task, 1); + wait_for_completion(&ts_complete); + } + + free_irq(PEN_DOWN_IRQ, NULL); +} + +module_init(ts_mirage_init); +module_exit(ts_mirage_exit); + diff --git a/arch/mips/au1000/hydrogen3/Makefile b/arch/mips/au1000/hydrogen3/Makefile new file mode 100644 index 00000000000..974f79256bb --- /dev/null +++ b/arch/mips/au1000/hydrogen3/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor PB1000 board. +# + +obj-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/hydrogen3/board_setup.c b/arch/mips/au1000/hydrogen3/board_setup.c new file mode 100644 index 00000000000..2efae106464 --- /dev/null +++ b/arch/mips/au1000/hydrogen3/board_setup.c @@ -0,0 +1,70 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Alchemy Db1x00 board setup. + * + * Copyright 2000 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/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> + +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/keyboard.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/pgtable.h> +#include <asm/au1000.h> + +void board_reset (void) +{ +} + +void __init board_setup(void) +{ + u32 pin_func; + +#ifdef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB device + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); + au_writel(pin_func, SYS_PINFUNC); +#endif + +#if defined(CONFIG_IRDA) && (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100)) + /* set IRFIRSEL instead of GPIO15 */ + pin_func = au_readl(SYS_PINFUNC) | (u32)((1<<8)); + au_writel(pin_func, SYS_PINFUNC); + au_sync(); +#endif + + printk("AMD Alchemy Hydrogen3 Board\n"); +} diff --git a/arch/mips/au1000/hydrogen3/init.c b/arch/mips/au1000/hydrogen3/init.c new file mode 100644 index 00000000000..eee4adf9871 --- /dev/null +++ b/arch/mips/au1000/hydrogen3/init.c @@ -0,0 +1,77 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PB1000 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/config.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/sched.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) +{ +#ifdef CONFIG_MIPS_BOSPORUS + return "Alchemy Bosporus Gateway Reference"; +#else + return "Alchemy Db1x00"; +#endif +} + +int __init prom_init(int argc, char **argv, char **envp, int *prom_vec) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_DB1000; /* set the platform # */ + 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); + return 0; +} diff --git a/arch/mips/au1000/hydrogen3/irqmap.c b/arch/mips/au1000/hydrogen3/irqmap.c new file mode 100644 index 00000000000..6eacaa0daa4 --- /dev/null +++ b/arch/mips/au1000/hydrogen3/irqmap.c @@ -0,0 +1,56 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + + /* { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 }, */ + { AU1000_GPIO_21, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/mtx-1/Makefile b/arch/mips/au1000/mtx-1/Makefile new file mode 100644 index 00000000000..764bf9f7e28 --- /dev/null +++ b/arch/mips/au1000/mtx-1/Makefile @@ -0,0 +1,10 @@ +# +# Copyright 2003 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# Bruno Randolf <bruno.randolf@4g-systems.biz> +# +# Makefile for 4G Systems MTX-1 board. +# + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c new file mode 100644 index 00000000000..638de7bb43f --- /dev/null +++ b/arch/mips/au1000/mtx-1/board_setup.c @@ -0,0 +1,89 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * 4G Systems MTX-1 board setup. + * + * Copyright 2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * Bruno Randolf <bruno.randolf@4g-systems.biz> + * + * 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/delay.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/mach-au1x00/au1000.h> + +void board_reset (void) +{ + /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ + au_writel(0x00000000, 0xAE00001C); +} + +void __init board_setup(void) +{ +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) +#ifdef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB device + au_writel(au_readl(SYS_PINFUNC) & (u32)(~0x8000), SYS_PINFUNC); +#endif + // enable USB power switch + au_writel( au_readl(GPIO2_DIR) | 0x10, GPIO2_DIR ); + au_writel( 0x100000, GPIO2_OUTPUT ); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + +#ifdef CONFIG_PCI +#if defined(__MIPSEB__) + au_writel(0xf | (2<<6) | (1<<4), Au1500_PCI_CFG); +#else + au_writel(0xf, Au1500_PCI_CFG); +#endif +#endif + + // initialize sys_pinfunc: + // disable second ethernet port (SYS_PF_NI2) + // set U3/GPIO23 to GPIO23 (SYS_PF_U3) + au_writel( SYS_PF_NI2 | SYS_PF_U3, SYS_PINFUNC ); + + // initialize GPIO + au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR ); + au_writel( 0x00000001, SYS_OUTPUTCLR ); // set M66EN (PCI 66MHz) to OFF + au_writel( 0x00000008, SYS_OUTPUTSET ); // set PCI CLKRUN# to OFF + au_writel( 0x00000020, SYS_OUTPUTCLR ); // set eth PHY TX_ER to OFF + + // enable LED and set it to green + au_writel( au_readl(GPIO2_DIR) | 0x1800, GPIO2_DIR ); + au_writel( 0x18000800, GPIO2_OUTPUT ); + + printk("4G Systems MTX-1 Board\n"); +} diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c new file mode 100644 index 00000000000..02e7dbcff72 --- /dev/null +++ b/arch/mips/au1000/mtx-1/init.c @@ -0,0 +1,71 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * 4G Systems MTX-1 board setup + * + * Copyright 2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * Bruno Randolf <bruno.randolf@4g-systems.biz> + * + * 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/string.h> +#include <linux/kernel.h> +#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> + +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 "MTX-1"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_MTX1; /* set the platform # */ + + 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); +} diff --git a/arch/mips/au1000/mtx-1/irqmap.c b/arch/mips/au1000/mtx-1/irqmap.c new file mode 100644 index 00000000000..ddcb9d089dc --- /dev/null +++ b/arch/mips/au1000/mtx-1/irqmap.c @@ -0,0 +1,58 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/mach-au1x00/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0}, + { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_202, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_203, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/pb1000/Makefile b/arch/mips/au1000/pb1000/Makefile new file mode 100644 index 00000000000..daa1a507e72 --- /dev/null +++ b/arch/mips/au1000/pb1000/Makefile @@ -0,0 +1,8 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor PB1000 board. + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c new file mode 100644 index 00000000000..2fa211b6932 --- /dev/null +++ b/arch/mips/au1000/pb1000/board_setup.c @@ -0,0 +1,182 @@ +/* + * Copyright 2000 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/config.h> +#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/irq.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/pgtable.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-pb1x00/pb1000.h> + +void board_reset (void) +{ +} + +void __init board_setup(void) +{ + u32 pin_func, static_cfg0; + u32 sys_freqctrl, sys_clksrc; + u32 prid = read_c0_prid(); + + // set AUX clock to 12MHz * 8 = 96 MHz + au_writel(8, SYS_AUXPLL); + au_writel(0, SYS_PINSTATERD); + udelay(100); + +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + /* zero and disable FREQ2 */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD clocks */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + au_writel(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + + switch (prid & 0x000000FF) + { + case 0x00: /* DA */ + case 0x01: /* HA */ + case 0x02: /* HB */ + /* CPU core freq to 48MHz to slow it way down... */ + au_writel(4, SYS_CPUPLL); + + /* + * Setup 48MHz FREQ2 from CPUPLL for USB Host + */ + /* FRDIV2=3 -> div by 8 of 384MHz -> 48MHz */ + sys_freqctrl |= ((3<<22) | (1<<21) | (0<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* CPU core freq to 384MHz */ + au_writel(0x20, SYS_CPUPLL); + + printk("Au1000: 48MHz OHCI workaround enabled\n"); + break; + + default: /* HC and newer */ + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + break; + } + + /* + * Route 48MHz FREQ2 into USB Host and/or Device + */ +#ifdef CONFIG_USB_OHCI + sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); +#endif +#ifdef CONFIG_AU1X00_USB_DEVICE + sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); +#endif + au_writel(sys_clksrc, SYS_CLKSRC); + + // configure pins GPIO[14:9] as GPIO + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080); + +#ifndef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB host + pin_func |= 0x8000; +#endif + au_writel(pin_func, SYS_PINFUNC); + au_writel(0x2800, SYS_TRIOUTCLR); + au_writel(0x0030, SYS_OUTPUTCLR); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + + // make gpio 15 an input (for interrupt line) + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x100); + // we don't need I2S, so make it available for GPIO[31:29] + pin_func |= (1<<5); + au_writel(pin_func, SYS_PINFUNC); + + au_writel(0x8000, SYS_TRIOUTCLR); + + static_cfg0 = au_readl(MEM_STCFG0) & (u32)(~0xc00); + au_writel(static_cfg0, MEM_STCFG0); + + // configure RCE2* for LCD + au_writel(0x00000004, MEM_STCFG2); + + // MEM_STTIME2 + au_writel(0x09000000, MEM_STTIME2); + + // Set 32-bit base address decoding for RCE2* + au_writel(0x10003ff0, MEM_STADDR2); + + // PCI CPLD setup + // expand CE0 to cover PCI + au_writel(0x11803e40, MEM_STADDR1); + + // burst visibility on + au_writel(au_readl(MEM_STCFG0) | 0x1000, MEM_STCFG0); + + au_writel(0x83, MEM_STCFG1); // ewait enabled, flash timing + au_writel(0x33030a10, MEM_STTIME1); // slower timing for FPGA + + /* setup the static bus controller */ + au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ + au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + +#ifdef CONFIG_PCI + au_writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0 + au_writel(0, SDRAM_MBAR); // set mbar to 0 + au_writel(0x2, SDRAM_CMD); // enable memory accesses + au_sync_delay(1); +#endif + + /* Enable Au1000 BCLK switching - note: sed1356 must not use + * its BCLK (Au1000 LCLK) for any timings */ + switch (prid & 0x000000FF) + { + case 0x00: /* DA */ + case 0x01: /* HA */ + case 0x02: /* HB */ + break; + default: /* HC and newer */ + /* Enable sys bus clock divider when IDLE state or no bus + activity. */ + au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); + break; + } +} diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c new file mode 100644 index 00000000000..34713c5df0d --- /dev/null +++ b/arch/mips/au1000/pb1000/init.c @@ -0,0 +1,69 @@ +/* + * BRIEF MODULE DESCRIPTION + * PB1000 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 Pb1000"; +} + +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_PB1000; + + 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); + return 0; +} diff --git a/arch/mips/au1000/pb1000/irqmap.c b/arch/mips/au1000/pb1000/irqmap.c new file mode 100644 index 00000000000..a3c460e3c23 --- /dev/null +++ b/arch/mips/au1000/pb1000/irqmap.c @@ -0,0 +1,54 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/mach-au1x00/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1000_GPIO_15, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/pb1100/Makefile b/arch/mips/au1000/pb1100/Makefile new file mode 100644 index 00000000000..996236df637 --- /dev/null +++ b/arch/mips/au1000/pb1100/Makefile @@ -0,0 +1,8 @@ +# +# Copyright 2000,2001 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor Pb1100 board. + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c new file mode 100644 index 00000000000..13c2f6ca7e3 --- /dev/null +++ b/arch/mips/au1000/pb1100/board_setup.c @@ -0,0 +1,116 @@ +/* + * Copyright 2002 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/config.h> +#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/irq.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/pgtable.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-pb1x00/pb1100.h> + +void board_reset (void) +{ + /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ + au_writel(0x00000000, 0xAE00001C); +} + +void __init board_setup(void) +{ + u32 pin_func; + u32 sys_freqctrl, sys_clksrc; + + // set AUX clock to 12MHz * 8 = 96 MHz + au_writel(8, SYS_AUXPLL); + au_writel(0, SYS_PININPUTEN); + udelay(100); + +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + // configure pins GPIO[14:9] as GPIO + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80); + + /* zero and disable FREQ2 */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD/IrDA clock */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x0000001F; + au_writel(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x0000001F; + + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* + * Route 48MHz FREQ2 into USBH/USBD/IrDA + */ + sys_clksrc |= ((4<<2) | (0<<1) | 0 ); + au_writel(sys_clksrc, SYS_CLKSRC); + + /* setup the static bus controller */ + au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ + au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + + // get USB Functionality pin state (device vs host drive pins) + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); +#ifndef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB host + pin_func |= 0x8000; +#endif + au_writel(pin_func, SYS_PINFUNC); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + + /* Enable sys bus clock divider when IDLE state or no bus activity. */ + au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); + + // Enable the RTC if not already enabled + if (!(readb(0xac000028) & 0x20)) { + writeb(readb(0xac000028) | 0x20, 0xac000028); + au_sync(); + } + // Put the clock in BCD mode + if (readb(0xac00002C) & 0x4) { /* reg B */ + writeb(readb(0xac00002c) & ~0x4, 0xac00002c); + au_sync(); + } +} diff --git a/arch/mips/au1000/pb1100/init.c b/arch/mips/au1000/pb1100/init.c new file mode 100644 index 00000000000..1fae39a608c --- /dev/null +++ b/arch/mips/au1000/pb1100/init.c @@ -0,0 +1,70 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Pb1100 board setup + * + * Copyright 2002 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 Pb1100"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (int *) fw_arg3; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_PB1100; + + 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); +} diff --git a/arch/mips/au1000/pb1100/irqmap.c b/arch/mips/au1000/pb1100/irqmap.c new file mode 100644 index 00000000000..43be7158b9a --- /dev/null +++ b/arch/mips/au1000/pb1100/irqmap.c @@ -0,0 +1,57 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/mach-au1x00/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1000_GPIO_9, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card Fully_Interted# + { AU1000_GPIO_10, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card STSCHG# + { AU1000_GPIO_11, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card IRQ# + { AU1000_GPIO_13, INTC_INT_LOW_LEVEL, 0 }, // DC_IRQ# +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/pb1500/Makefile b/arch/mips/au1000/pb1500/Makefile new file mode 100644 index 00000000000..97a730813cd --- /dev/null +++ b/arch/mips/au1000/pb1500/Makefile @@ -0,0 +1,8 @@ +# +# Copyright 2000,2001 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor Pb1500 board. + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c new file mode 100644 index 00000000000..30bb87282b1 --- /dev/null +++ b/arch/mips/au1000/pb1500/board_setup.c @@ -0,0 +1,138 @@ +/* + * Copyright 2000 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/config.h> +#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/irq.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/pgtable.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-pb1x00/pb1500.h> + +void board_reset (void) +{ + /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ + au_writel(0x00000000, 0xAE00001C); +} + +void __init board_setup(void) +{ + u32 pin_func; + u32 sys_freqctrl, sys_clksrc; + + sys_clksrc = sys_freqctrl = pin_func = 0; + // set AUX clock to 12MHz * 8 = 96 MHz + au_writel(8, SYS_AUXPLL); + au_writel(0, SYS_PINSTATERD); + udelay(100); + +#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + + /* GPIO201 is input for PCMCIA card detect */ + /* GPIO203 is input for PCMCIA interrupt request */ + au_writel(au_readl(GPIO2_DIR) & (u32)(~((1<<1)|(1<<3))), GPIO2_DIR); + + /* zero and disable FREQ2 */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* zero and disable USBH/USBD clocks */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + au_writel(sys_clksrc, SYS_CLKSRC); + + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x00007FE0; + + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); + + /* + * Route 48MHz FREQ2 into USB Host and/or Device + */ +#ifdef CONFIG_USB_OHCI + sys_clksrc |= ((4<<12) | (0<<11) | (0<<10)); +#endif +#ifdef CONFIG_AU1X00_USB_DEVICE + sys_clksrc |= ((4<<7) | (0<<6) | (0<<5)); +#endif + au_writel(sys_clksrc, SYS_CLKSRC); + + + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); +#ifndef CONFIG_AU1X00_USB_DEVICE + // 2nd USB port is USB host + pin_func |= 0x8000; +#endif + au_writel(pin_func, SYS_PINFUNC); +#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) + + + +#ifdef CONFIG_PCI + // Setup PCI bus controller + au_writel(0, Au1500_PCI_CMEM); + au_writel(0x00003fff, Au1500_CFG_BASE); +#if defined(__MIPSEB__) + au_writel(0xf | (2<<6) | (1<<4), Au1500_PCI_CFG); +#else + au_writel(0xf, Au1500_PCI_CFG); +#endif + au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV); + au_writel(0, Au1500_PCI_MWBASE_REV_CCL); + au_writel(0x02a00356, Au1500_PCI_STATCMD); + au_writel(0x00003c04, Au1500_PCI_HDRTYPE); + au_writel(0x00000008, Au1500_PCI_MBAR); + au_sync(); +#endif + + /* Enable sys bus clock divider when IDLE state or no bus activity. */ + au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); + + /* Enable the RTC if not already enabled */ + if (!(au_readl(0xac000028) & 0x20)) { + printk("enabling clock ...\n"); + au_writel((au_readl(0xac000028) | 0x20), 0xac000028); + } + /* Put the clock in BCD mode */ + if (readl(0xac00002C) & 0x4) { /* reg B */ + au_writel(au_readl(0xac00002c) & ~0x4, 0xac00002c); + au_sync(); + } +} diff --git a/arch/mips/au1000/pb1500/init.c b/arch/mips/au1000/pb1500/init.c new file mode 100644 index 00000000000..733d2e469db --- /dev/null +++ b/arch/mips/au1000/pb1500/init.c @@ -0,0 +1,69 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PB1500 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 Pb1500"; +} + +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_PB1500; + + 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); +} diff --git a/arch/mips/au1000/pb1500/irqmap.c b/arch/mips/au1000/pb1500/irqmap.c new file mode 100644 index 00000000000..476e2500168 --- /dev/null +++ b/arch/mips/au1000/pb1500/irqmap.c @@ -0,0 +1,58 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/mach-au1x00/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0}, + { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_202, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_203, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/pb1550/Makefile b/arch/mips/au1000/pb1550/Makefile new file mode 100644 index 00000000000..aa35bc6cb8c --- /dev/null +++ b/arch/mips/au1000/pb1550/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2000 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for the Alchemy Semiconductor PB1000 board. +# + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/pb1550/board_setup.c b/arch/mips/au1000/pb1550/board_setup.c new file mode 100644 index 00000000000..05fd27dc24e --- /dev/null +++ b/arch/mips/au1000/pb1550/board_setup.c @@ -0,0 +1,69 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Alchemy Pb1550 board setup. + * + * Copyright 2000 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/sched.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/console.h> +#include <linux/mc146818rtc.h> +#include <linux/delay.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/mach-au1x00/au1000.h> +#include <asm/mach-pb1x00/pb1550.h> + +void board_reset (void) +{ + /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ + au_writew(au_readw(0xAF00001C) & ~(1<<15), 0xAF00001C); +} + +void __init board_setup(void) +{ + u32 pin_func; + + /* 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(); + + printk("AMD Alchemy Pb1550 Board\n"); +} diff --git a/arch/mips/au1000/pb1550/init.c b/arch/mips/au1000/pb1550/init.c new file mode 100644 index 00000000000..41daa3371be --- /dev/null +++ b/arch/mips/au1000/pb1550/init.c @@ -0,0 +1,69 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PB1550 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 Pb1550"; +} + +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_PB1550; + + 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); +} diff --git a/arch/mips/au1000/pb1550/irqmap.c b/arch/mips/au1000/pb1550/irqmap.c new file mode 100644 index 00000000000..889d4949ee7 --- /dev/null +++ b/arch/mips/au1000/pb1550/irqmap.c @@ -0,0 +1,55 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/mach-au1x00/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/au1000/xxs1500/Makefile b/arch/mips/au1000/xxs1500/Makefile new file mode 100644 index 00000000000..44d7f7056ae --- /dev/null +++ b/arch/mips/au1000/xxs1500/Makefile @@ -0,0 +1,9 @@ +# +# Copyright 2003 MontaVista Software Inc. +# Author: MontaVista Software, Inc. +# ppopov@mvista.com or source@mvista.com +# +# Makefile for MyCable XXS1500 board. +# + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/xxs1500/board_setup.c b/arch/mips/au1000/xxs1500/board_setup.c new file mode 100644 index 00000000000..9dadc82536f --- /dev/null +++ b/arch/mips/au1000/xxs1500/board_setup.c @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2003 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/config.h> +#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/irq.h> +#include <asm/keyboard.h> +#include <asm/mipsregs.h> +#include <asm/reboot.h> +#include <asm/pgtable.h> +#include <asm/au1000.h> + +void board_reset (void) +{ + /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ + au_writel(0x00000000, 0xAE00001C); +} + +void __init board_setup(void) +{ + u32 pin_func; + + // set multiple use pins (UART3/GPIO) to UART (it's used as UART too) + pin_func = au_readl(SYS_PINFUNC) & (u32)(~SYS_PF_UR3); + pin_func |= SYS_PF_UR3; + au_writel(pin_func, SYS_PINFUNC); + + // enable UART + au_writel(0x01, UART3_ADDR+UART_MOD_CNTRL); // clock enable (CE) + mdelay(10); + au_writel(0x03, UART3_ADDR+UART_MOD_CNTRL); // CE and "enable" + mdelay(10); + + // enable DTR = USB power up + au_writel(0x01, UART3_ADDR+UART_MCR); //? UART_MCR_DTR is 0x01??? + +#ifdef CONFIG_PCMCIA_XXS1500 + /* setup pcmcia signals */ + au_writel(0, SYS_PININPUTEN); + + /* gpio 0, 1, and 4 are inputs */ + au_writel(1 | (1<<1) | (1<<4), SYS_TRIOUTCLR); + + /* enable GPIO2 if not already enabled */ + au_writel(1, GPIO2_ENABLE); + /* gpio2 208/9/10/11 are inputs */ + au_writel((1<<8) | (1<<9) | (1<<10) | (1<<11), GPIO2_DIR); + + /* turn off power */ + au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30), GPIO2_OUTPUT); +#endif + + +#ifdef CONFIG_PCI +#if defined(__MIPSEB__) + au_writel(0xf | (2<<6) | (1<<4), Au1500_PCI_CFG); +#else + au_writel(0xf, Au1500_PCI_CFG); +#endif +#endif +} diff --git a/arch/mips/au1000/xxs1500/init.c b/arch/mips/au1000/xxs1500/init.c new file mode 100644 index 00000000000..03f755291b5 --- /dev/null +++ b/arch/mips/au1000/xxs1500/init.c @@ -0,0 +1,68 @@ +/* + * BRIEF MODULE DESCRIPTION + * XXS1500 board setup + * + * Copyright 2003 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 "XXS1500"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_XXS1500; /* set the platform # */ + + 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); +} diff --git a/arch/mips/au1000/xxs1500/irqmap.c b/arch/mips/au1000/xxs1500/irqmap.c new file mode 100644 index 00000000000..954800a0ab5 --- /dev/null +++ b/arch/mips/au1000/xxs1500/irqmap.c @@ -0,0 +1,66 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * Copyright 2003 Embedded Edge, LLC + * dan@embeddededge.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/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/au1000.h> + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0}, + { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_202, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_203, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 }, + { AU1500_GPIO_207, INTC_INT_LOW_LEVEL, 0 }, + + { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_GPIO_2, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 }, + { AU1000_GPIO_4, INTC_INT_LOW_LEVEL, 0 }, /* CF interrupt */ + { AU1000_GPIO_5, INTC_INT_LOW_LEVEL, 0 }, +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile new file mode 100644 index 00000000000..efbeac32681 --- /dev/null +++ b/arch/mips/boot/Makefile @@ -0,0 +1,49 @@ +# +# 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, 1998, 2001, 2002 by Ralf Baechle +# Copyright (C) 2004 Maciej W. Rozycki +# + +# +# Some DECstations need all possible sections of an ECOFF executable +# +ifdef CONFIG_MACH_DECSTATION + E2EFLAGS = -a +else + E2EFLAGS = +endif + +# +# Drop some uninteresting sections in the kernel. +# This is only relevant for ELF kernels but doesn't hurt a.out +# +drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options +strip-flags = $(addprefix --remove-section=,$(drop-sections)) + +VMLINUX = vmlinux + +all: vmlinux.ecoff vmlinux.srec addinitrd + +vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX) + $(obj)/elf2ecoff $(VMLINUX) vmlinux.ecoff $(E2EFLAGS) + +$(obj)/elf2ecoff: $(obj)/elf2ecoff.c + $(HOSTCC) -o $@ $^ + +vmlinux.srec: $(VMLINUX) + $(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $(obj)/vmlinux.srec + +$(obj)/addinitrd: $(obj)/addinitrd.c + $(HOSTCC) -o $@ $^ + +archhelp: + @echo '* vmlinux.ecoff - ECOFF boot image' + @echo '* vmlinux.srec - SREC boot image' + +clean-files += addinitrd \ + elf2ecoff \ + vmlinux.ecoff \ + vmlinux.srec diff --git a/arch/mips/boot/addinitrd.c b/arch/mips/boot/addinitrd.c new file mode 100644 index 00000000000..8b303330477 --- /dev/null +++ b/arch/mips/boot/addinitrd.c @@ -0,0 +1,131 @@ +/* + * addinitrd - program to add a initrd image to an ecoff kernel + * + * (C) 1999 Thomas Bogendoerfer + * minor modifications, cleanup: Guido Guenther <agx@sigxcpu.org> + * further cleanup: Maciej W. Rozycki + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <netinet/in.h> + +#include "ecoff.h" + +#define MIPS_PAGE_SIZE 4096 +#define MIPS_PAGE_MASK (MIPS_PAGE_SIZE-1) + +#define swab16(x) \ + ((unsigned short)( \ + (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \ + (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) )) + +#define swab32(x) \ + ((unsigned int)( \ + (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ + (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ + (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ + (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) )) + +#define SWAB(a) (swab ? swab32(a) : (a)) + +void die (char *s) +{ + perror (s); + exit (1); +} + +int main (int argc, char *argv[]) +{ + int fd_vmlinux,fd_initrd,fd_outfile; + FILHDR efile; + AOUTHDR eaout; + SCNHDR esecs[3]; + struct stat st; + char buf[1024]; + unsigned long loadaddr; + unsigned long initrd_header[2]; + int i,cnt; + int swab = 0; + + if (argc != 4) { + printf ("Usage: %s <vmlinux> <initrd> <outfile>\n",argv[0]); + exit (1); + } + + if ((fd_vmlinux = open (argv[1],O_RDONLY)) < 0) + die ("open vmlinux"); + if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile) + die ("read file header"); + if (read (fd_vmlinux, &eaout, sizeof eaout) != sizeof eaout) + die ("read aout header"); + if (read (fd_vmlinux, esecs, sizeof esecs) != sizeof esecs) + die ("read section headers"); + /* + * check whether the file is good for us + */ + /* TBD */ + + /* + * check, if we have to swab words + */ + if (ntohs(0xaa55) == 0xaa55) { + if (efile.f_magic == swab16(MIPSELMAGIC)) + swab = 1; + } else { + if (efile.f_magic == swab16(MIPSEBMAGIC)) + swab = 1; + } + + /* make sure we have an empty data segment for the initrd */ + if (eaout.dsize || esecs[1].s_size) { + fprintf (stderr, "Data segment not empty. Giving up!\n"); + exit (1); + } + if ((fd_initrd = open (argv[2], O_RDONLY)) < 0) + die ("open initrd"); + if (fstat (fd_initrd, &st) < 0) + die ("fstat initrd"); + loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size) + + MIPS_PAGE_SIZE-1) & ~MIPS_PAGE_MASK) - 8; + if (loadaddr < (SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size))) + loadaddr += MIPS_PAGE_SIZE; + initrd_header[0] = SWAB(0x494E5244); + initrd_header[1] = SWAB(st.st_size); + eaout.dsize = esecs[1].s_size = initrd_header[1] = SWAB(st.st_size+8); + eaout.data_start = esecs[1].s_vaddr = esecs[1].s_paddr = SWAB(loadaddr); + + if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC,0666)) < 0) + die ("open outfile"); + if (write (fd_outfile, &efile, sizeof efile) != sizeof efile) + die ("write file header"); + if (write (fd_outfile, &eaout, sizeof eaout) != sizeof eaout) + die ("write aout header"); + if (write (fd_outfile, esecs, sizeof esecs) != sizeof esecs) + die ("write section headers"); + /* skip padding */ + if(lseek(fd_vmlinux, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1) + die ("lseek vmlinux"); + if(lseek(fd_outfile, SWAB(esecs[0].s_scnptr), SEEK_SET) == (off_t)-1) + die ("lseek outfile"); + /* copy text segment */ + cnt = SWAB(eaout.tsize); + while (cnt) { + if ((i = read (fd_vmlinux, buf, sizeof buf)) <= 0) + die ("read vmlinux"); + if (write (fd_outfile, buf, i) != i) + die ("write vmlinux"); + cnt -= i; + } + if (write (fd_outfile, initrd_header, sizeof initrd_header) != sizeof initrd_header) + die ("write initrd header"); + while ((i = read (fd_initrd, buf, sizeof buf)) > 0) + if (write (fd_outfile, buf, i) != i) + die ("write initrd"); + close (fd_vmlinux); + close (fd_initrd); + return 0; +} diff --git a/arch/mips/boot/ecoff.h b/arch/mips/boot/ecoff.h new file mode 100644 index 00000000000..8c3eed2877f --- /dev/null +++ b/arch/mips/boot/ecoff.h @@ -0,0 +1,62 @@ +/* + * Some ECOFF definitions. + */ +typedef struct filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + long f_symptr; /* file pointer to symbolic header */ + long f_nsyms; /* sizeof(symbolic hdr) */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +} FILHDR; +#define FILHSZ sizeof(FILHDR) + +#define OMAGIC 0407 +#define MIPSEBMAGIC 0x160 +#define MIPSELMAGIC 0x162 + +typedef struct scnhdr { + char s_name[8]; /* section name */ + long s_paddr; /* physical address, aliased s_nlib */ + long s_vaddr; /* virtual address */ + long s_size; /* section size */ + long s_scnptr; /* file ptr to raw data for section */ + long s_relptr; /* file ptr to relocation */ + long s_lnnoptr; /* file ptr to gp histogram */ + unsigned short s_nreloc; /* number of relocation entries */ + unsigned short s_nlnno; /* number of gp histogram entries */ + long s_flags; /* flags */ +} SCNHDR; +#define SCNHSZ sizeof(SCNHDR) +#define SCNROUND ((long)16) + +typedef struct aouthdr { + short magic; /* see above */ + short vstamp; /* version stamp */ + long tsize; /* text size in bytes, padded to DW bdry*/ + long dsize; /* initialized data " " */ + long bsize; /* uninitialized data " " */ + long entry; /* entry pt. */ + long text_start; /* base of text used for this file */ + long data_start; /* base of data used for this file */ + long bss_start; /* base of bss used for this file */ + long gprmask; /* general purpose register mask */ + long cprmask[4]; /* co-processor register masks */ + long gp_value; /* the gp value used for this object */ +} AOUTHDR; +#define AOUTHSZ sizeof(AOUTHDR) + +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define SMAGIC 0411 +#define LIBMAGIC 0443 + +#define N_TXTOFF(f, a) \ + ((a).magic == ZMAGIC || (a).magic == LIBMAGIC ? 0 : \ + ((a).vstamp < 23 ? \ + ((FILHSZ + AOUTHSZ + (f).f_nscns * SCNHSZ + 7) & 0xfffffff8) : \ + ((FILHSZ + AOUTHSZ + (f).f_nscns * SCNHSZ + SCNROUND-1) & ~(SCNROUND-1)) ) ) +#define N_DATOFF(f, a) \ + N_TXTOFF(f, a) + (a).tsize; diff --git a/arch/mips/boot/elf2ecoff.c b/arch/mips/boot/elf2ecoff.c new file mode 100644 index 00000000000..c3543d9eb26 --- /dev/null +++ b/arch/mips/boot/elf2ecoff.c @@ -0,0 +1,616 @@ +/* + * Copyright (c) 1995 + * Ted Lemon (hereinafter referred to as the author) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + */ + +/* elf2ecoff.c + + This program converts an elf executable to an ECOFF executable. + No symbol table is retained. This is useful primarily in building + net-bootable kernels for machines (e.g., DECstation and Alpha) which + only support the ECOFF object file format. */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <elf.h> +#include <limits.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include "ecoff.h" + +/* + * Some extra ELF definitions + */ +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ + +/* -------------------------------------------------------------------- */ + +struct sect { + unsigned long vaddr; + unsigned long len; +}; + +int *symTypeTable; +int must_convert_endian = 0; +int format_bigendian = 0; + +static void copy(int out, int in, off_t offset, off_t size) +{ + char ibuf[4096]; + int remaining, cur, count; + + /* Go to the start of the ELF symbol table... */ + if (lseek(in, offset, SEEK_SET) < 0) { + perror("copy: lseek"); + exit(1); + } + + remaining = size; + while (remaining) { + cur = remaining; + if (cur > sizeof ibuf) + cur = sizeof ibuf; + remaining -= cur; + if ((count = read(in, ibuf, cur)) != cur) { + fprintf(stderr, "copy: read: %s\n", + count ? strerror(errno) : + "premature end of file"); + exit(1); + } + if ((count = write(out, ibuf, cur)) != cur) { + perror("copy: write"); + exit(1); + } + } +} + +/* + * Combine two segments, which must be contiguous. If pad is true, it's + * okay for there to be padding between. + */ +static void combine(struct sect *base, struct sect *new, int pad) +{ + if (!base->len) + *base = *new; + else if (new->len) { + if (base->vaddr + base->len != new->vaddr) { + if (pad) + base->len = new->vaddr - base->vaddr; + else { + fprintf(stderr, + "Non-contiguous data can't be converted.\n"); + exit(1); + } + } + base->len += new->len; + } +} + +static int phcmp(const void *v1, const void *v2) +{ + const Elf32_Phdr *h1 = v1; + const Elf32_Phdr *h2 = v2; + + if (h1->p_vaddr > h2->p_vaddr) + return 1; + else if (h1->p_vaddr < h2->p_vaddr) + return -1; + else + return 0; +} + +static char *saveRead(int file, off_t offset, off_t len, char *name) +{ + char *tmp; + int count; + off_t off; + if ((off = lseek(file, offset, SEEK_SET)) < 0) { + fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno)); + exit(1); + } + if (!(tmp = (char *) malloc(len))) { + fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name, + len); + exit(1); + } + count = read(file, tmp, len); + if (count != len) { + fprintf(stderr, "%s: read: %s.\n", + name, + count ? strerror(errno) : "End of file reached"); + exit(1); + } + return tmp; +} + +#define swab16(x) \ + ((unsigned short)( \ + (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \ + (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) )) + +#define swab32(x) \ + ((unsigned int)( \ + (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ + (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ + (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ + (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) )) + +static void convert_elf_hdr(Elf32_Ehdr * e) +{ + e->e_type = swab16(e->e_type); + e->e_machine = swab16(e->e_machine); + e->e_version = swab32(e->e_version); + e->e_entry = swab32(e->e_entry); + e->e_phoff = swab32(e->e_phoff); + e->e_shoff = swab32(e->e_shoff); + e->e_flags = swab32(e->e_flags); + e->e_ehsize = swab16(e->e_ehsize); + e->e_phentsize = swab16(e->e_phentsize); + e->e_phnum = swab16(e->e_phnum); + e->e_shentsize = swab16(e->e_shentsize); + e->e_shnum = swab16(e->e_shnum); + e->e_shstrndx = swab16(e->e_shstrndx); +} + +static void convert_elf_phdrs(Elf32_Phdr * p, int num) +{ + int i; + + for (i = 0; i < num; i++, p++) { + p->p_type = swab32(p->p_type); + p->p_offset = swab32(p->p_offset); + p->p_vaddr = swab32(p->p_vaddr); + p->p_paddr = swab32(p->p_paddr); + p->p_filesz = swab32(p->p_filesz); + p->p_memsz = swab32(p->p_memsz); + p->p_flags = swab32(p->p_flags); + p->p_align = swab32(p->p_align); + } + +} + +static void convert_elf_shdrs(Elf32_Shdr * s, int num) +{ + int i; + + for (i = 0; i < num; i++, s++) { + s->sh_name = swab32(s->sh_name); + s->sh_type = swab32(s->sh_type); + s->sh_flags = swab32(s->sh_flags); + s->sh_addr = swab32(s->sh_addr); + s->sh_offset = swab32(s->sh_offset); + s->sh_size = swab32(s->sh_size); + s->sh_link = swab32(s->sh_link); + s->sh_info = swab32(s->sh_info); + s->sh_addralign = swab32(s->sh_addralign); + s->sh_entsize = swab32(s->sh_entsize); + } +} + +static void convert_ecoff_filehdr(struct filehdr *f) +{ + f->f_magic = swab16(f->f_magic); + f->f_nscns = swab16(f->f_nscns); + f->f_timdat = swab32(f->f_timdat); + f->f_symptr = swab32(f->f_symptr); + f->f_nsyms = swab32(f->f_nsyms); + f->f_opthdr = swab16(f->f_opthdr); + f->f_flags = swab16(f->f_flags); +} + +static void convert_ecoff_aouthdr(struct aouthdr *a) +{ + a->magic = swab16(a->magic); + a->vstamp = swab16(a->vstamp); + a->tsize = swab32(a->tsize); + a->dsize = swab32(a->dsize); + a->bsize = swab32(a->bsize); + a->entry = swab32(a->entry); + a->text_start = swab32(a->text_start); + a->data_start = swab32(a->data_start); + a->bss_start = swab32(a->bss_start); + a->gprmask = swab32(a->gprmask); + a->cprmask[0] = swab32(a->cprmask[0]); + a->cprmask[1] = swab32(a->cprmask[1]); + a->cprmask[2] = swab32(a->cprmask[2]); + a->cprmask[3] = swab32(a->cprmask[3]); + a->gp_value = swab32(a->gp_value); +} + +static void convert_ecoff_esecs(struct scnhdr *s, int num) +{ + int i; + + for (i = 0; i < num; i++, s++) { + s->s_paddr = swab32(s->s_paddr); + s->s_vaddr = swab32(s->s_vaddr); + s->s_size = swab32(s->s_size); + s->s_scnptr = swab32(s->s_scnptr); + s->s_relptr = swab32(s->s_relptr); + s->s_lnnoptr = swab32(s->s_lnnoptr); + s->s_nreloc = swab16(s->s_nreloc); + s->s_nlnno = swab16(s->s_nlnno); + s->s_flags = swab32(s->s_flags); + } +} + +int main(int argc, char *argv[]) +{ + Elf32_Ehdr ex; + Elf32_Phdr *ph; + Elf32_Shdr *sh; + char *shstrtab; + int i, pad; + struct sect text, data, bss; + struct filehdr efh; + struct aouthdr eah; + struct scnhdr esecs[6]; + int infile, outfile; + unsigned long cur_vma = ULONG_MAX; + int addflag = 0; + int nosecs; + + text.len = data.len = bss.len = 0; + text.vaddr = data.vaddr = bss.vaddr = 0; + + /* Check args... */ + if (argc < 3 || argc > 4) { + usage: + fprintf(stderr, + "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n"); + exit(1); + } + if (argc == 4) { + if (strcmp(argv[3], "-a")) + goto usage; + addflag = 1; + } + + /* Try the input file... */ + if ((infile = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, "Can't open %s for read: %s\n", + argv[1], strerror(errno)); + exit(1); + } + + /* Read the header, which is at the beginning of the file... */ + i = read(infile, &ex, sizeof ex); + if (i != sizeof ex) { + fprintf(stderr, "ex: %s: %s.\n", + argv[1], + i ? strerror(errno) : "End of file reached"); + exit(1); + } + + if (ex.e_ident[EI_DATA] == ELFDATA2MSB) + format_bigendian = 1; + + if (ntohs(0xaa55) == 0xaa55) { + if (!format_bigendian) + must_convert_endian = 1; + } else { + if (format_bigendian) + must_convert_endian = 1; + } + if (must_convert_endian) + convert_elf_hdr(&ex); + + /* Read the program headers... */ + ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff, + ex.e_phnum * sizeof(Elf32_Phdr), + "ph"); + if (must_convert_endian) + convert_elf_phdrs(ph, ex.e_phnum); + /* Read the section headers... */ + sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff, + ex.e_shnum * sizeof(Elf32_Shdr), + "sh"); + if (must_convert_endian) + convert_elf_shdrs(sh, ex.e_shnum); + /* Read in the section string table. */ + shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset, + sh[ex.e_shstrndx].sh_size, "shstrtab"); + + /* Figure out if we can cram the program header into an ECOFF + header... Basically, we can't handle anything but loadable + segments, but we can ignore some kinds of segments. We can't + handle holes in the address space. Segments may be out of order, + so we sort them first. */ + + qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp); + + for (i = 0; i < ex.e_phnum; i++) { + /* Section types we can ignore... */ + if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE || + ph[i].p_type == PT_PHDR + || ph[i].p_type == PT_MIPS_REGINFO) + continue; + /* Section types we can't handle... */ + else if (ph[i].p_type != PT_LOAD) { + fprintf(stderr, + "Program header %d type %d can't be converted.\n", + ex.e_phnum, ph[i].p_type); + exit(1); + } + /* Writable (data) segment? */ + if (ph[i].p_flags & PF_W) { + struct sect ndata, nbss; + + ndata.vaddr = ph[i].p_vaddr; + ndata.len = ph[i].p_filesz; + nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; + nbss.len = ph[i].p_memsz - ph[i].p_filesz; + + combine(&data, &ndata, 0); + combine(&bss, &nbss, 1); + } else { + struct sect ntxt; + + ntxt.vaddr = ph[i].p_vaddr; + ntxt.len = ph[i].p_filesz; + + combine(&text, &ntxt, 0); + } + /* Remember the lowest segment start address. */ + if (ph[i].p_vaddr < cur_vma) + cur_vma = ph[i].p_vaddr; + } + + /* Sections must be in order to be converted... */ + if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || + text.vaddr + text.len > data.vaddr + || data.vaddr + data.len > bss.vaddr) { + fprintf(stderr, + "Sections ordering prevents a.out conversion.\n"); + exit(1); + } + + /* If there's a data section but no text section, then the loader + combined everything into one section. That needs to be the + text section, so just make the data section zero length following + text. */ + if (data.len && !text.len) { + text = data; + data.vaddr = text.vaddr + text.len; + data.len = 0; + } + + /* If there is a gap between text and data, we'll fill it when we copy + the data, so update the length of the text segment as represented in + a.out to reflect that, since a.out doesn't allow gaps in the program + address space. */ + if (text.vaddr + text.len < data.vaddr) + text.len = data.vaddr - text.vaddr; + + /* We now have enough information to cons up an a.out header... */ + eah.magic = OMAGIC; + eah.vstamp = 200; + eah.tsize = text.len; + eah.dsize = data.len; + eah.bsize = bss.len; + eah.entry = ex.e_entry; + eah.text_start = text.vaddr; + eah.data_start = data.vaddr; + eah.bss_start = bss.vaddr; + eah.gprmask = 0xf3fffffe; + memset(&eah.cprmask, '\0', sizeof eah.cprmask); + eah.gp_value = 0; /* unused. */ + + if (format_bigendian) + efh.f_magic = MIPSEBMAGIC; + else + efh.f_magic = MIPSELMAGIC; + if (addflag) + nosecs = 6; + else + nosecs = 3; + efh.f_nscns = nosecs; + efh.f_timdat = 0; /* bogus */ + efh.f_symptr = 0; + efh.f_nsyms = 0; + efh.f_opthdr = sizeof eah; + efh.f_flags = 0x100f; /* Stripped, not sharable. */ + + memset(esecs, 0, sizeof esecs); + strcpy(esecs[0].s_name, ".text"); + strcpy(esecs[1].s_name, ".data"); + strcpy(esecs[2].s_name, ".bss"); + if (addflag) { + strcpy(esecs[3].s_name, ".rdata"); + strcpy(esecs[4].s_name, ".sdata"); + strcpy(esecs[5].s_name, ".sbss"); + } + esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start; + esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start; + esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start; + if (addflag) { + esecs[3].s_paddr = esecs[3].s_vaddr = 0; + esecs[4].s_paddr = esecs[4].s_vaddr = 0; + esecs[5].s_paddr = esecs[5].s_vaddr = 0; + } + esecs[0].s_size = eah.tsize; + esecs[1].s_size = eah.dsize; + esecs[2].s_size = eah.bsize; + if (addflag) { + esecs[3].s_size = 0; + esecs[4].s_size = 0; + esecs[5].s_size = 0; + } + esecs[0].s_scnptr = N_TXTOFF(efh, eah); + esecs[1].s_scnptr = N_DATOFF(efh, eah); +#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10 +#define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1)) + esecs[2].s_scnptr = esecs[1].s_scnptr + + ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah)); + if (addflag) { + esecs[3].s_scnptr = 0; + esecs[4].s_scnptr = 0; + esecs[5].s_scnptr = 0; + } + esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0; + esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0; + esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0; + esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0; + if (addflag) { + esecs[3].s_relptr = esecs[4].s_relptr + = esecs[5].s_relptr = 0; + esecs[3].s_lnnoptr = esecs[4].s_lnnoptr + = esecs[5].s_lnnoptr = 0; + esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc = + 0; + esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0; + } + esecs[0].s_flags = 0x20; + esecs[1].s_flags = 0x40; + esecs[2].s_flags = 0x82; + if (addflag) { + esecs[3].s_flags = 0x100; + esecs[4].s_flags = 0x200; + esecs[5].s_flags = 0x400; + } + + /* Make the output file... */ + if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) { + fprintf(stderr, "Unable to create %s: %s\n", argv[2], + strerror(errno)); + exit(1); + } + + if (must_convert_endian) + convert_ecoff_filehdr(&efh); + /* Write the headers... */ + i = write(outfile, &efh, sizeof efh); + if (i != sizeof efh) { + perror("efh: write"); + exit(1); + + for (i = 0; i < nosecs; i++) { + printf + ("Section %d: %s phys %lx size %lx file offset %lx\n", + i, esecs[i].s_name, esecs[i].s_paddr, + esecs[i].s_size, esecs[i].s_scnptr); + } + } + fprintf(stderr, "wrote %d byte file header.\n", i); + + if (must_convert_endian) + convert_ecoff_aouthdr(&eah); + i = write(outfile, &eah, sizeof eah); + if (i != sizeof eah) { + perror("eah: write"); + exit(1); + } + fprintf(stderr, "wrote %d byte a.out header.\n", i); + + if (must_convert_endian) + convert_ecoff_esecs(&esecs[0], nosecs); + i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr)); + if (i != nosecs * sizeof(struct scnhdr)) { + perror("esecs: write"); + exit(1); + } + fprintf(stderr, "wrote %d bytes of section headers.\n", i); + + pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15; + if (pad) { + pad = 16 - pad; + i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad); + if (i < 0) { + perror("ipad: write"); + exit(1); + } + fprintf(stderr, "wrote %d byte pad.\n", i); + } + + /* + * Copy the loadable sections. Zero-fill any gaps less than 64k; + * complain about any zero-filling, and die if we're asked to zero-fill + * more than 64k. + */ + for (i = 0; i < ex.e_phnum; i++) { + /* Unprocessable sections were handled above, so just verify that + the section can be loaded before copying. */ + if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) { + if (cur_vma != ph[i].p_vaddr) { + unsigned long gap = + ph[i].p_vaddr - cur_vma; + char obuf[1024]; + if (gap > 65536) { + fprintf(stderr, + "Intersegment gap (%ld bytes) too large.\n", + gap); + exit(1); + } + fprintf(stderr, + "Warning: %ld byte intersegment gap.\n", + gap); + memset(obuf, 0, sizeof obuf); + while (gap) { + int count = + write(outfile, obuf, + (gap > + sizeof obuf ? sizeof + obuf : gap)); + if (count < 0) { + fprintf(stderr, + "Error writing gap: %s\n", + strerror(errno)); + exit(1); + } + gap -= count; + } + } + fprintf(stderr, "writing %d bytes...\n", + ph[i].p_filesz); + copy(outfile, infile, ph[i].p_offset, + ph[i].p_filesz); + cur_vma = ph[i].p_vaddr + ph[i].p_filesz; + } + } + + /* + * Write a page of padding for boot PROMS that read entire pages. + * Without this, they may attempt to read past the end of the + * data section, incur an error, and refuse to boot. + */ + { + char obuf[4096]; + memset(obuf, 0, sizeof obuf); + if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) { + fprintf(stderr, "Error writing PROM padding: %s\n", + strerror(errno)); + exit(1); + } + } + + /* Looks like we won... */ + exit(0); +} diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile new file mode 100644 index 00000000000..a5e6554b232 --- /dev/null +++ b/arch/mips/cobalt/Makefile @@ -0,0 +1,7 @@ +# +# 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 + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/cobalt/int-handler.S b/arch/mips/cobalt/int-handler.S new file mode 100644 index 00000000000..1a21dec1b3c --- /dev/null +++ b/arch/mips/cobalt/int-handler.S @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle + * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) + */ +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/cobalt/cobalt.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .text + .align 5 + NESTED(cobalt_handle_int, PT_SIZE, sp) + SAVE_ALL + CLI + + la ra, ret_from_irq + move a1, sp + j cobalt_irq + + END(cobalt_handle_int) diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c new file mode 100644 index 00000000000..6d2a8158139 --- /dev/null +++ b/arch/mips/cobalt/irq.c @@ -0,0 +1,102 @@ +/* + * IRQ vector handles + * + * 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, 2003 by Ralf Baechle + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/i8259.h> +#include <asm/irq_cpu.h> +#include <asm/gt64120.h> +#include <asm/ptrace.h> + +#include <asm/cobalt/cobalt.h> + +extern void cobalt_handle_int(void); + +/* + * We have two types of interrupts that we handle, ones that come in through + * 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 + * 18 - Galileo chip (timer) IE_IRQ0 + * 19 - Tulip 0 + NCR SCSI IE_IRQ1 + * 20 - Tulip 1 IE_IRQ2 + * 21 - 16550 UART IE_IRQ3 + * 22 - VIA southbridge PIC IE_IRQ4 + * 23 - unused IE_IRQ5 + * + * The VIA chip is a master/slave 8259 setup and has the following interrupts: + * + * 8 - RTC + * 9 - PCI + * 14 - IDE0 + * 15 - IDE1 + */ + +asmlinkage void cobalt_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; + } + + if (pending & CAUSEF_IP6) { /* int 22 */ + int irq = i8259_irq(); + + if (irq >= 0) + do_IRQ(irq, regs); + return; + } + + if (pending & CAUSEF_IP3) { /* int 19 */ + do_IRQ(COBALT_ETH0_IRQ, regs); + return; + } + + if (pending & CAUSEF_IP4) { /* int 20 */ + do_IRQ(COBALT_ETH1_IRQ, regs); + return; + } + + if (pending & CAUSEF_IP5) { /* int 21 */ + do_IRQ(COBALT_SERIAL_IRQ, regs); + return; + } + + if (pending & CAUSEF_IP7) { /* int 23 */ + do_IRQ(COBALT_QUBE_SLOT_IRQ, regs); + return; + } +} + +void __init arch_init_irq(void) +{ + set_except_vector(0, cobalt_handle_int); + + init_i8259_irqs(); /* 0 ... 15 */ + mips_cpu_irq_init(16); /* 16 ... 23 */ + + /* + * Mask all cpu interrupts + * (except IE4, we already masked those at VIA level) + */ + change_c0_status(ST0_IM, IE_IRQ4); +} diff --git a/arch/mips/cobalt/promcon.c b/arch/mips/cobalt/promcon.c new file mode 100644 index 00000000000..f03df761e9f --- /dev/null +++ b/arch/mips/cobalt/promcon.c @@ -0,0 +1,87 @@ +/* + * 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); diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c new file mode 100644 index 00000000000..084c8e59f42 --- /dev/null +++ b/arch/mips/cobalt/reset.c @@ -0,0 +1,68 @@ +/* + * Cobalt Reset operations + * + * 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/sched.h> +#include <linux/mm.h> +#include <asm/cacheflush.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/reboot.h> +#include <asm/system.h> +#include <asm/mipsregs.h> + +void cobalt_machine_restart(char *command) +{ + *(volatile char *)0xbc000000 = 0x0f; + + /* + * Ouch, we're still alive ... This time we take the silver bullet ... + * ... and find that we leave the hardware in a state in which the + * kernel in the flush locks up somewhen during of after the PCI + * detection stuff. + */ + set_c0_status(ST0_BEV | ST0_ERL); + change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + flush_cache_all(); + write_c0_wired(0); + __asm__ __volatile__( + "jr\t%0" + : + : "r" (0xbfc00000)); +} + +extern int led_state; +#define kLED 0xBC000000 +#define LEDSet(x) (*(volatile unsigned char *) kLED) = (( unsigned char)x) + +void cobalt_machine_halt(void) +{ + int mark; + + /* Blink our cute? little LED (number 3)... */ + while (1) { + led_state = led_state | ( 1 << 3 ); + LEDSet(led_state); + mark = jiffies; + while (jiffies<(mark+HZ)); + led_state = led_state & ~( 1 << 3 ); + LEDSet(led_state); + mark = jiffies; + while (jiffies<(mark+HZ)); + } +} + +/* + * This triggers the luser mode device driver for the power switch ;-) + */ +void cobalt_machine_power_off(void) +{ + printk("You can switch the machine off now.\n"); + cobalt_machine_halt(); +} diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c new file mode 100644 index 00000000000..6b4737e425e --- /dev/null +++ b/arch/mips/cobalt/setup.c @@ -0,0 +1,150 @@ +/* + * Setup pointers to hardware dependent routines. + * + * 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) 1996, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) + * + */ +#include <linux/config.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/bootinfo.h> +#include <asm/time.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/processor.h> +#include <asm/reboot.h> +#include <asm/gt64120.h> + +#include <asm/cobalt/cobalt.h> + +extern void cobalt_machine_restart(char *command); +extern void cobalt_machine_halt(void); +extern void cobalt_machine_power_off(void); + +int cobalt_board_id; + +static char my_cmdline[CL_SIZE] = { + "console=ttyS0,115200 " +#ifdef CONFIG_IP_PNP + "ip=on " +#endif +#ifdef CONFIG_ROOT_NFS + "root=/dev/nfs " +#else + "root=/dev/hda1 " +#endif + }; + +const char *get_system_type(void) +{ + return "MIPS Cobalt"; +} + +static void __init cobalt_timer_setup(struct irqaction *irq) +{ + /* Load timer value for 150 Hz */ + GALILEO_OUTL(500000, GT_TC0_OFS); + + /* Register our timer interrupt */ + setup_irq(COBALT_TIMER_IRQ, irq); + + /* Enable timer ints */ + GALILEO_OUTL((GALILEO_ENTC0 | GALILEO_SELTC0), GT_TC_CONTROL_OFS); + /* Unmask timer int */ + GALILEO_OUTL(0x100, GT_INTRMASK_OFS); +} + +extern struct pci_ops gt64111_pci_ops; + +static struct resource cobalt_mem_resource = { + "GT64111 PCI MEM", GT64111_IO_BASE, 0xffffffffUL, IORESOURCE_MEM +}; + +static struct resource cobalt_io_resource = { + "GT64111 IO MEM", 0x00001000UL, 0x0fffffffUL, IORESOURCE_IO +}; + +static struct resource cobalt_io_resources[] = { + { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, + { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, + { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, +}; + +#define COBALT_IO_RESOURCES (sizeof(cobalt_io_resources)/sizeof(struct resource)) + +static struct pci_controller cobalt_pci_controller = { + .pci_ops = >64111_pci_ops, + .mem_resource = &cobalt_mem_resource, + .mem_offset = 0, + .io_resource = &cobalt_io_resource, + .io_offset = 0x00001000UL - GT64111_IO_BASE +}; + +static void __init cobalt_setup(void) +{ + unsigned int devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0); + int i; + + _machine_restart = cobalt_machine_restart; + _machine_halt = cobalt_machine_halt; + _machine_power_off = cobalt_machine_power_off; + + board_timer_setup = cobalt_timer_setup; + + set_io_port_base(KSEG1ADDR(GT64111_IO_BASE)); + + /* + * This is a prom style console. We just poke at the + * UART to make it talk. + * Only use this console if you really screw up and can't + * get to the stage of setting up a real serial console. + */ + /*ns16550_setup_console();*/ + + /* request I/O space for devices used on all i[345]86 PCs */ + for (i = 0; i < COBALT_IO_RESOURCES; i++) + request_resource(&ioport_resource, cobalt_io_resources + i); + + /* Read the cobalt id register out of the PCI config space */ + PCI_CFG_SET(devfn, (VIA_COBALT_BRD_ID_REG & ~0x3)); + cobalt_board_id = GALILEO_INL(GT_PCI0_CFGDATA_OFS); + cobalt_board_id >>= ((VIA_COBALT_BRD_ID_REG & 3) * 8); + cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(cobalt_board_id); + +#ifdef CONFIG_PCI + register_pci_controller(&cobalt_pci_controller); +#endif +} + +early_initcall(cobalt_setup); + +/* + * Prom init. We read our one and only communication with the firmware. + * Grab the amount of installed memory + */ + +void __init prom_init(void) +{ + int argc = fw_arg0; + + strcpy(arcs_cmdline, my_cmdline); + + mips_machgroup = MACH_GROUP_COBALT; + + add_memory_region(0x0, argc & 0x7fffffff, BOOT_MEM_RAM); +} + +unsigned long __init prom_free_prom_memory(void) +{ + /* Nothing to do! */ + return 0; +} diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig new file mode 100644 index 00000000000..caad7ca27ab --- /dev/null +++ b/arch/mips/configs/atlas_defconfig @@ -0,0 +1,1104 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11-rc2 +# Wed Jan 26 02:49:00 2005 +# +CONFIG_MIPS=y +# CONFIG_MIPS64 is not set +# CONFIG_64BIT is not set +CONFIG_MIPS32=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y + +# +# Machine selection +# +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ITE8172 is not set +CONFIG_MIPS_ATLAS=y +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SOC_AU1X00 is not set +# CONFIG_SIBYTE_SB1xxx_SOC is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_MIPS_BONITO64=y +CONFIG_MIPS_MSC=y +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_MIPS_BOARDS_GEN=y +CONFIG_MIPS_GT64120=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_BOOT_ELF32=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS64 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_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_64BIT_PHYS_ADDR is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +CONFIG_CPU_HAS_SYNC=y +# CONFIG_PREEMPT is not set + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_UMEM=m +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_LBD is not set +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_ATA_OVER_ETH=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=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=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_TUNNEL=m +CONFIG_IP_TCPDIAG=m +CONFIG_IP_TCPDIAG_IPV6=y + +# +# IP: Virtual Server Configuration +# +CONFIG_IP_VS=m +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IPV6=m +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_TUNNEL=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_CT_ACCT=y +CONFIG_IP_NF_CONNTRACK_MARK=y +CONFIG_IP_NF_CT_PROTO_SCTP=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_REALM=m +CONFIG_IP_NF_MATCH_SCTP=m +CONFIG_IP_NF_MATCH_COMMENT=m +CONFIG_IP_NF_MATCH_CONNMARK=m +CONFIG_IP_NF_MATCH_HASHLIMIT=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_CONNMARK=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_PHYSDEV=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +CONFIG_IP6_NF_RAW=m + +# +# Bridge: Netfilter Configuration +# +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_XFRM=y +CONFIG_XFRM_USER=m + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=y +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_NET_DIVERT=y +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CLK_JIFFIES=y +# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set +# CONFIG_NET_SCH_CLK_CPU is not set +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +CONFIG_NET_CLS_IND=y +# CONFIG_CLS_U32_MARK is not set +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +CONFIG_LAN_SAA9730=y + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=m +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_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=y + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +CONFIG_MOUSE_SERIAL=m +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=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_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 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR 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_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_MINIX_FS=m +CONFIG_ROMFS_FS=m +CONFIG_QUOTA=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=m +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +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_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +CONFIG_DEVPTS_FS_SECURITY=y +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_IS |