Sat Aug 27 13:42:46 2011 UTC ()
Add loongson support to evbmips, based on the OpenBSD loongson port
and the existing evbmips/gdium support.
This has been tested on a lemote fuloong device (boots multiuser),
should also support other lemote devices (maybe with minor adjustments,
or adding missing drivers). There is some gdium support here too, but it
may not be yet complete (someone with a gdium would need to have a look,
hi macallan@ :)
loongson kernels are 64bits only: the loongson2f has ressources located
above the 2Gb physical address, and it's much easier to access it
using XKPHYS than trying to make it fit in the limited 32bit kernel
virtual space.


(bouyer)
diff -r0 -r1.1 src/sys/arch/evbmips/conf/LOONGSON
diff -r0 -r1.1 src/sys/arch/evbmips/conf/files.loongson
diff -r0 -r1.1 src/sys/arch/evbmips/conf/std.loongson
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/autoconf.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/autoconf.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/bonito_mainbus.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/gdium_machdep.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/generic2e_machdep.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/isa_machdep.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson2_machdep.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson_bus_defs.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson_bus_io.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson_bus_mem.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson_intr.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson_intr.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/loongson_isa.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/machdep.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/mainbus.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/yeeloong_machdep.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/gcscpcib_pci.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/glx.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/glxreg.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/glxvar.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/kb3310.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/kb3310var.h
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/pcib.c
diff -r0 -r1.1 src/sys/arch/evbmips/loongson/dev/pcibvar.h

File Added: src/sys/arch/evbmips/conf/LOONGSON
# $NetBSD: LOONGSON,v 1.1 2011/08/27 13:42:44 bouyer Exp $
#
# LOONGSON machine description file
# 
# This machine description file is used to generate the default NetBSD
# kernel.  The generic kernel does not include all options, subsystems
# and device drivers, but should be useful for most applications.
#
# The machine description file can be customised for your specific
# machine to reduce the kernel size and improve its performance.
#
# For further information on compiling NetBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

include		"arch/evbmips/conf/std.loongson"

options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary

#ident 		"GDIUM-$Revision: 1.1 $"

maxusers	16

# Standard system options
options 	DDB			# in-kernel debugger
#options 	DDB_ONPANIC=0		# don't enter debugger on panic
options 	DDB_HISTORY_SIZE=512	# enable history editing in DDB
#options 	KGDB			# remote debugger
options 	DIAGNOSTIC		# extra kernel debugging checks
#options 	DEBUG			# extra kernel debugging support
#options 	PMAP_FAULTINFO
#options 	LOCKDEBUG
makeoptions	DEBUG="-g"
options 	KTRACE			# system call tracing support
options 	MSGBUFSIZE=8192		# dmesg buffer size

## UVM options.
#options 	UVM_PAGE_TRKOWN
#options 	UVMHIST
#options 	UVMHIST_PRINT	# Loud!

#options 	SCSIVERBOSE		# human readable SCSI error messages
#options 	PCMCIAVERBOSE		# verbose PCMCIA configuration messages
#options 	PCMCIADEBUG
#options 	PCMCIACISDEBUG

#options 	RTC_OFFSET=0	# hardware clock is this many mins. west of GMT
#options 	RTC_OFFSET=-540		# JST-9
#options 	RTC_OFFSET=480		# PST8
					# In NO RTC_OFFSET , inherit RTC_OFFSET
					# from Windows CE.
options 	NTP			# network time protocol

#options 	WINCE_DEFAULT_SETTING	# Debugging use

#options 	SYSCALL_DEBUG		# for debug
#options 	HPCMIPS_L1CACHE_DISABLE	# disable L1 cache for debug
options 	USERCONF		# userconf(4) support
#options	PIPE_SOCKETPAIR		# smaller, but slower pipe(2)
options 	SYSCTL_INCLUDE_DESCR	# Include sysctl descriptions in kernel

# Filesystem options
file-system 	FFS		# fast filesystem with user and group quotas
file-system 	MFS		# memory-based filesystem
file-system 	NFS		# Sun NFS-compatible filesystem (client)
file-system	EXT2FS		# second extended file system (linux)
#file-system	LFS		# Log-based filesystem (still experimental)
file-system 	CD9660		# ISO 9660 + Rock Ridge file system
file-system 	MSDOSFS		# MS-DOS file system
#file-system 	FDESC		# /dev/fd
file-system 	KERNFS		# /kern (kernel informational filesystem)
#file-system 	NULLFS		# loopback file system
#file-system 	OVERLAY		# overlay file system
file-system 	PROCFS		# /proc
#file-system 	UMAPFS		# NULLFS + uid and gid remapping
file-system 	UNION
file-system	PTYFS		# /dev/pts/N support
#file-system	TMPFS		# Efficient memory file-system
#file-system	UDF		# experimental - OSTA UDF CD/DVD file-system

options 	NFSSERVER	# Sun NFS-compatible filesystem (server)
options 	WAPBL		# File system journaling support - Experimental
#options	UFS_DIRHASH	# UFS Large Directory Hashing - Experimental
#options 	QUOTA		# legacy UFS quotas
#options 	QUOTA2		# new, in-filesystem UFS quotas
#options 	FFS_NO_SNAPSHOT	# No FFS snapshot support

# Networking options
#options 	GATEWAY		# IP packet forwarding
options 	INET		# IP + ICMP + TCP + UDP
options 	INET6		# IPV6
#options 	IPSEC		# IP security
#options 	IPSEC_ESP	# IP security (encryption part; define w/ IPSEC)
#options 	IPSEC_NAT_T	# IPsec NAT traversal (NAT-T)
#options 	IPSEC_DEBUG	# debug for IP security
#options 	MROUTING	# Multicast routing support
#options 	PIM		# Protocol Independent Multicast
#options 	ISO		# OSI networking
#options 	TPIP		# TPIP
#options 	EON		# OSI tunneling over IP
options 	PFIL_HOOKS	# pfil(9) packet filter hooks
options 	IPFILTER_LOG	# ipmon(8) log support
options 	IPFILTER_LOOKUP	# ippool(8) support
options 	IPFILTER_COMPAT # Compat for IP-Filter
#options 	IPFILTER_DEFAULT_BLOCK	# block all packets by default

#options 	ALTQ		# Manipulate network interfaces' output queues
#options 	ALTQ_BLUE	# Stochastic Fair Blue
#options 	ALTQ_CBQ	# Class-Based Queueing
#options 	ALTQ_CDNR	# Diffserv Traffic Conditioner
#options 	ALTQ_FIFOQ	# First-In First-Out Queue
#options 	ALTQ_FLOWVALVE	# RED/flow-valve (red-penalty-box)
#options 	ALTQ_HFSC	# Hierarchical Fair Service Curve
#options 	ALTQ_LOCALQ	# Local queueing discipline
#options 	ALTQ_PRIQ	# Priority Queueing
#options 	ALTQ_RED	# Random Early Detection
#options 	ALTQ_RIO	# RED with IN/OUT
#options 	ALTQ_WFQ	# Weighted Fair Queueing

# NetBSD backwards compatibility
options 	COMPAT_43
options 	COMPAT_16
options 	COMPAT_20
options 	COMPAT_30	# NetBSD 3.0 compatibility.
options 	COMPAT_40	# NetBSD 4.0 compatibility.
options 	COMPAT_50	# NetBSD 5.0 compatibility.
options		COMPAT_BSDPTY	# /dev/[pt]ty?? ptys.


#options 	NFS_BOOT_DHCP
options 	NFS_BOOT_BOOTP
#options 	NFS_BOOT_BOOTPARAM

# compile options
#makeoptions	DEFGP="-G 10"

config		netbsd		root on ? type ?

# WS console uses SUN or VT100 terminal emulation
options 	WSEMUL_VT100
#options 	WSDISPLAY_DEFAULTSCREENS=4
options 	FONT_GALLANT12x22
# compatibility to other console drivers
options 	WSDISPLAY_COMPAT_RAWKBD		# can get raw scancodes
#
# Hpckbd will set key board layout appropriately. You can use option
# 'PCKBD_LAYOUT' to overrite the default layout.
#
#options 	PCKBD_LAYOUT="(KB_US | KB_SWAPCTRLCAPS | KB_MACHDEP)"

mainbus0	at root
cpu0		at mainbus0
bonito0		at mainbus0
pci0		at bonito0
sisfb0		at pci0 dev ? function ?
#X#voyagerfb0	at pci0 dev ? function ?
#genfb0		at pci0 dev ? function ?
wsdisplay*	at wsemuldisplaydev?
ehci*		at pci0 dev ? function ?
#options 	EHCI_DEBUG
ohci*		at pci0 dev ? function ?
#options 	OHCI_DEBUG, USB_DEBUG, UHUB_DEBUG

gcscpcib* at pci? dev ? function ?	# AMD CS5535/CS5536 PCI-ISA w/
gpio*   at gcscpcib?			# timecounter, watchdog and GPIO
isa0	at gcscpcib?

pcib*	at pci?
isa0	at pcib?

mcclock*	at isa? port 0x70		# mc146818-compatible
com0		at isa? port 0x2f8 irq 3	# Fuloong 2F only
com1		at isa? port 0x3f8 irq 4	# Fuloong 2F only (IR port)

pciide* 	at pci? dev ? function ? flags 0x0000	# GENERIC pciide driver
viaide* 	at pci? dev ? function ?	# VIA/AMD/Nvidia IDE controllers

# ATA (IDE) bus support
atabus* at ata?
options 	ATADEBUG

# IDE drives
# Flags are used only with controllers that support DMA operations
# and mode settings (e.g. some pciide controllers)
# The lowest order four bits (rightmost digit) of the flags define the PIO
# mode to use, the next set of four bits the DMA mode and the third set the
# UltraDMA mode. For each set of four bits, the 3 lower bits define the mode
# to use, and the last bit must be 1 for this setting to be used.
# For DMA and UDMA, 0xf (1111) means 'disable'.
# 0x0fac means 'use PIO mode 4, DMA mode 2, disable UltraDMA'.
# (0xc=1100, 0xa=1010, 0xf=1111)
# 0x0000 means "use whatever the drive claims to support".
wd*	at atabus? drive ? flags 0x0000

# ATAPI bus support
#atapibus* at atapi?

# ATAPI devices
# flags have the same meaning as for IDE drives.
#cd*	at atapibus? drive ? flags 0x0000	# ATAPI CD-ROM drives
#sd*	at atapibus? drive ? flags 0x0000	# ATAPI disk drives
#st*	at atapibus? drive ? flags 0x0000	# ATAPI tape drives
#uk*	at atapibus? drive ? flags 0x0000	# ATAPI unknown

ral*	at pci? dev ? function ?	# RL2561S 802.11b/g
rtk*	at pci? dev ? function ?	# RTL8139 100/10 Ethernet
re*	at pci? dev ? function ?	# Realtek 8139C+/8169/8169S/8110S
# MII/PHY support
rgephy*	at mii? phy ?			# Realtek 8169S/8110S internal PHYs
rlphy*	at mii? phy ?			# Realtek 8139/8201L PHYs
ukphy*	at mii? phy ?			# generic unknown PHYs

# USB Hubs
usb*	at ehci?
usb*	at ohci?
uhub*	at usb?
uhub*	at uhub? port ?

# USB HID device
uhidev*	at uhub? port ? configuration ? interface ?

# USB Mice
ums*		at uhidev? reportid ?
wsmouse*	at ums? mux 0

# USB Keyboards
ukbd*	at uhidev? reportid ?
wskbd*	at ukbd? console ? mux 1

# USB Generic HID devices
uhid*	at uhidev? reportid ?

# USB serial adapter
uftdi*	at uhub? port ? configuration ?

# USB Printer
ulpt*	at uhub? port ? configuration ? interface ?

# USB Modem
umodem*	at uhub? port ? configuration ?
ucom*	at umodem?

# Option N.V. Wireless WAN modems
uhso*	at uhub? port ? configuration ?

# USB Mass Storage
umass*	at uhub? port ? configuration ? interface ?
scsibus*	at umass? channel ?
sd*		at scsibus? target ? lun ?	# SCSI disk drives
cd*		at scsibus? target ? lun ?	# SCSI CD-ROM drives

# FTDI FT8U100AX serial adapter
uftdi*	at uhub? port ?
ucom*	at uftdi? portno ?

uplcom*	at uhub? port ?		# I/O DATA USB-RSAQ2 serial adapter
ucom*	at uplcom? portno ?

umct*	at uhub? port ?		# MCT USB-RS232 serial adapter
ucom*	at umct? portno ?

# USB Generic driver
ugen*	at uhub? port ?

#
# accept filters
pseudo-device   accf_data		# "dataready" accept filter
pseudo-device   accf_http		# "httpready" accept filter

pseudo-device	loop		1	# network loopback
pseudo-device	ppp			# serial-line IP ports
pseudo-device	pppoe			# PPP over Ethernet (RFC 2516)
pseudo-device	pty			# pseudo-terminals
pseudo-device	bpfilter		# packet filter ports
#pseudo-device	carp			# Common Address Redundancy Protocol
pseudo-device	ipfilter		# IP filter, NAT

pseudo-device	vnd			# virtual disk ick
#options 	VND_COMPRESSION		# compressed vnd(4)
#pseudo-device	ccd		4	# concatenated disks
pseudo-device	fss			# file system snapshot device
#pseudo-device	cgd		4	# cryptographic disks
pseudo-device	rnd			# /dev/random and in-kernel generator
pseudo-device	clockctl		# user control of clock subsystem

pseudo-device	wsmux			# mouse & keyboard multiplexor
#pseudo-device	md			# memory disk device (ramdisk)

#pseudo-device	raid		8	# RAIDframe disk driver
#options 	RAID_AUTOCONFIG		# auto-configuration of RAID components
# Options to enable various other RAIDframe RAID types.
# options	RF_INCLUDE_EVENODD=1
# options	RF_INCLUDE_RAID5_RS=1
# options	RF_INCLUDE_PARITYLOGGING=1
# options	RF_INCLUDE_CHAINDECLUSTER=1
# options	RF_INCLUDE_INTERDECLUSTER=1
# options 	RF_INCLUDE_PARITY_DECLUSTERING=1
# options	RF_INCLUDE_PARITY_DECLUSTERING_DS=1

# for IPv6
pseudo-device	gif			# IPv[46] over IPv[46] tunnel (RFC1933)
#pseudo-device	faith			# IPv[46] tcp relay translation i/f
pseudo-device	stf			# 6to4 IPv6 over IPv4 encapsulation

## IEEE 802.1Q Virtual LAN encapsulation, see vlan(4).
pseudo-device	vlan

## Simple inter-network traffic bridging
pseudo-device	bridge
#options	BRIDGE_IPF		# bridge uses IP/IPv6 pfil hooks too
pseudo-device	agr			# IEEE 802.3ad link aggregation
pseudo-device	ksyms			# /dev/ksyms
#pseudo-device	pf			# PF packet filter
#pseudo-device	pflog			# PF log if

# Veriexec
#
# a pseudo device needed for veriexec
#pseudo-device	veriexec		1
#
# Uncomment the fingerprint methods below that are desired. Note that
# removing fingerprint methods will have almost no impact on the kernel
# code size.
#
#options VERIFIED_EXEC_FP_RMD160
#options VERIFIED_EXEC_FP_SHA256
#options VERIFIED_EXEC_FP_SHA384
#options VERIFIED_EXEC_FP_SHA512
#options VERIFIED_EXEC_FP_SHA1
#options VERIFIED_EXEC_FP_MD5

File Added: src/sys/arch/evbmips/conf/files.loongson
#	$NetBSD: files.loongson,v 1.1 2011/08/27 13:42:44 bouyer Exp $

# Standard stanzas config(8) can't run without
maxpartitions 16
maxusers 8 16 64

file	arch/evbmips/loongson/autoconf.c
file	arch/evbmips/loongson/loongson_bus_io.c
file	arch/evbmips/loongson/loongson_bus_mem.c
file	kern/subr_disk_mbr.c
file	arch/evbmips/loongson/loongson_intr.c
file	arch/evbmips/evbmips/interrupt.c
file	arch/evbmips/loongson/gdium_machdep.c
file	arch/evbmips/loongson/generic2e_machdep.c
file	arch/evbmips/loongson/yeeloong_machdep.c
file	arch/evbmips/loongson/isa_machdep.c		isa
file	arch/evbmips/loongson/loongson2_machdep.c
file	arch/evbmips/loongson/machdep.c

file	arch/mips/mips/bus_dma.c
file	arch/mips/mips/mips3_clock.c
file	arch/mips/mips/mips3_clockintr.c

# Memory Disk
file	dev/md_root.c				memory_disk_hooks

include "dev/ata/files.ata"
include "dev/scsipi/files.scsipi"
include	"dev/i2o/files.i2o"
include	"dev/isa/files.isa"
include	"dev/pci/files.pci"
include	"dev/pci/files.agp"
include	"dev/usb/files.usb"
include "dev/bluetooth/files.bluetooth"

device	mainbus {[addr = -1] }
attach	mainbus at root
file	arch/evbmips/loongson/mainbus.c			mainbus

file   arch/evbmips/loongson/bonito_mainbus.c		bonito_mainbus

device	cpu
attach	cpu at mainbus
file	arch/evbmips/evbmips/cpu.c		cpu

device	clock
attach	clock at mainbus

include "arch/mips/conf/files.bonito"

# AMD Geode CS5536 companion chip
file	arch/evbmips/loongson/dev/glx.c		bonito & pci

# AMD Geode CS5535/CS5536 PCI-ISA bridge
device  gcscpcib: isabus, sysmon_wdog, gpiobus
attach  gcscpcib at pci with gcscpcib_pci
file	arch/evbmips/loongson/dev/gcscpcib_pci.c gcscpcib_pci
file	dev/ic/gcscpcib.c			gcscpcib

# Other PCI-ISA bridges
device	pcib: isabus
attach	pcib at pci
file	arch/evbmips/loongson/dev/pcib.c	pcib | gcscpcib

file	arch/mips/pci/pciide_machdep.c		pciide_common

device	mcclock: mc146818
attach	mcclock at isa with mcclock_isa
file	arch/evbmips/isa/mcclock_isa.c		mcclock_isa

# Lemote Yeeloong KB3310B Embedded Controller
device	ykbec
attach	ykbec at isa
file	arch/evbmips/loongson/dev/kb3310.c		ykbec needs-flag

# Silicon Motion SM502 master device
#device	voyager {}: gpiobus
#attach	voyager at pci
#file	arch/loongson/dev/voyager.c			voyager

# SM502 specific I2C bus bit-banging
#device	gdiumiic: i2cbus, i2c_bitbang
#attach	gdiumiic at gpio
#file	arch/loongson/dev/gdiumiic.c			gdiumiic

# Gdium ST7 controller
#device	stsec
#attach	stsec at i2c
#file	arch/loongson/dev/stsec.c			stsec

# Gdium M41T8x RTC
#device	mfokclock
#attach	mfokclock at i2c
#file	arch/loongson/dev/m41t8xclock.c			mfokclock

# SM502 OHCI
#attach	ohci at voyager with ohci_voyager
#file	arch/loongson/dev/ohci_voyager.c		ohci_voyager

# Silicon Motion SM502/SM712 frame buffer
#device	smfb: wsemuldisplaydev, rasops16
#attach	smfb at pci with smfb_pci
#attach	smfb at voyager with smfb_voyager
#file	arch/loongson/dev/smfb.c			smfb	needs-flag

File Added: src/sys/arch/evbmips/conf/std.loongson
# $NetBSD: std.loongson,v 1.1 2011/08/27 13:42:44 bouyer Exp $

machine evbmips mips
include		"conf/std"	# MI standard options

options 	MIPS3_ENABLE_CLOCK_INTR
options 	ENABLE_MIPS_16KB_PAGE

options 	PMON

# Platform support
options		MIPS3_LOONGSON2
options		MIPS3
options		MIPS3_LOONGSON2F
options 	LOONGSON2		# IDT LOONGSON2

makeoptions	LP64="yes"

options 	EXEC_ELF64
options		EXEC_ELF32	# exec ELF32 binaries
options		EXEC_SCRIPT	# exec #! scripts
options 	COMPAT_NETBSD32

#makeoptions	AFLAGS+="-Wa,-mfix-loongson2f-jump -Wa,-mfix-loongson2f-nop"
#makeoptions	CFLAGS+="-Wa,-mfix-loongson2f-jump -Wa,-mfix-loongson2f-nop"
#makeoptions	CPUFLAGS="-mips3 -mdivide-breaks" # CPU codegen options
makeoptions	CPUFLAGS="-mips3 -mdivide-breaks -Wa,-mfix-loongson2f-btb" # CPU codegen options
makeoptions	DEFTEXTADDR="0x80200000"
makeoptions	BOARDTYPE="loongson"

include "arch/evbmips/conf/files.loongson"

File Added: src/sys/arch/evbmips/loongson/autoconf.c
/*	$NetBSD: autoconf.c,v 1.1 2011/08/27 13:42:44 bouyer Exp $	*/

/*
 * Copyright 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Simon Burge for Wasabi Systems, Inc.
 *
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed for the NetBSD Project by
 *      Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.1 2011/08/27 13:42:44 bouyer Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/cpu.h>

static void	findroot(void);

enum devclass bootdev_class = DV_DULL;
char          bootdev[16];

void
cpu_configure(void)
{

	intr_init();

	/* Kick off autoconfiguration. */
	(void)splhigh();
	if (config_rootfound("mainbus", NULL) == NULL)
		panic("no mainbus found");

	/*
	 * Hardware interrupts will be enabled in
	 * sys/arch/mips/mips/mips3_clockintr.c:mips3_initclocks()
	 * to avoid hardclock(9) by CPU INT5 before softclockintr is
	 * initialized in initclocks().
	 */
}

void
cpu_rootconf(void)
{
	findroot();

	printf("boot device: %s\n",
		booted_device ? booted_device->dv_xname : "<unknown>");

	setroot(booted_device, booted_partition);
}

extern char	bootstring[];
extern int	netboot;

static void
findroot(void)
{
	device_t dv;
	deviter_t di;

	if (booted_device)
		return;

	if ((booted_device == NULL) && netboot == 0) {
		for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL;
		     dv = deviter_next(&di)) {
			if (device_class(dv) == DV_DISK &&
			    device_is_a(dv, "wd"))
				    booted_device = dv;
		}
		deviter_release(&di);
	}

	/*
	 * XXX Match up MBR boot specification with BSD disklabel for root?
	 */
	booted_partition = 0;

	return;
}

void
device_register(struct device *dev, void *aux)
{
	prop_dictionary_t dict;

	if ((booted_device == NULL) && (netboot == 1))
		if (device_class(dev) == DV_IFNET)
			booted_device = dev;
	if (device_is_a(dev, "genfb")) {
		dict = device_properties(dev);
		/*
		 * this is a hack
		 * is_console and address need to be checked against reality
		 */
		prop_dictionary_set_bool(dict, "is_console", 1);
		prop_dictionary_set_uint32(dict, "width", 1024);
		prop_dictionary_set_uint32(dict, "height", 600);
		prop_dictionary_set_uint32(dict, "depth", 16);
		prop_dictionary_set_uint32(dict, "linebytes", 2048);
		prop_dictionary_set_uint32(dict, "address", 0x04000000);
	}
}

File Added: src/sys/arch/evbmips/loongson/autoconf.h
/*	$OpenBSD: autoconf.h,v 1.8 2010/08/31 10:24:46 pirofti Exp $ */

/*
 * Copyright (c) 2001-2003 Opsycon AB  (www.opsycon.se / www.opsycon.com)
 *
 * 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.
 *
 * 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.
 *
 */

/*
 * Definitions used by autoconfiguration.
 */

#ifndef _MACHINE_AUTOCONF_H_
#define _MACHINE_AUTOCONF_H_

#include <sys/bus.h>
#include <sys/kcore.h>
#include <mips/bonito/bonitovar.h>

struct bonito_config;
struct mips_isa_chipset;
struct bonito_irqmap;

/*
 * List of legacy I/O ranges.
 */
struct legacy_io_range {
	bus_addr_t	start;
	bus_size_t	end;	/* inclusive */
};

/*
 * Per platform information.
 */

struct platform {
	const int			 system_type;
	const char			*vendor;
	const char			*product;

	const struct bonito_config	*bonito_config;
	struct mips_isa_chipset		*isa_chipset;
	const struct legacy_io_range	*legacy_io_ranges;
	int				bonito_mips_intr;
	int				isa_mips_intr;
	void				(*isa_intr)(int, vaddr_t, uint32_t);
	int				(*p_pci_intr_map)(int, int, int, pci_intr_handle_t *);
	const struct bonito_irqmap	*irq_map;

	void				(*setup)(void);
	void				(*device_register)(struct device *,
					    void *);

	void				(*powerdown)(void);
	void				(*reset)(void);
	int				(*suspend)(void);
	int				(*resume)(void);
};

#define LOONGSON_CLASS		0x0060	/* Loongson + PMON2000 class */	
#define LOONGSON_2E		0x0060	/* Generic Loongson 2E system */	
#define LOONGSON_YEELOONG	0x0061	/* Lemote Yeeloong */
#define LOONGSON_GDIUM		0x0062	/* EMTEC Gdium Liberty */
#define LOONGSON_FULOONG	0x0063	/* Lemote Fuloong */ 
#define LOONGSON_LYNLOONG	0x0064	/* Lemote Lynloong */ 

extern const struct platform *sys_platform;
extern uint loongson_ver;

struct mainbus_attach_args {
	const char	*maa_name;
};

extern char bootdev[];
extern enum devclass bootdev_class;

void	loongson2e_setup(paddr_t, paddr_t, vaddr_t, vaddr_t, bus_dma_tag_t);
void	loongson2f_setup(paddr_t, paddr_t, vaddr_t, vaddr_t, bus_dma_tag_t);

extern bus_space_tag_t comconsiot;
extern bus_addr_t comconsaddr;
extern int comconsrate;

extern phys_ram_seg_t mem_clusters[];
extern int mem_cluster_cnt;

#endif /* _MACHINE_AUTOCONF_H_ */

File Added: src/sys/arch/evbmips/loongson/bonito_mainbus.c
/*	$NetBSD: bonito_mainbus.c,v 1.1 2011/08/27 13:42:44 bouyer Exp $	*/

/*-
 * Copyright (c) 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bonito_mainbus.c,v 1.1 2011/08/27 13:42:44 bouyer Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/reboot.h>
#include <sys/device.h>

#include <sys/bus.h>

#include <mips/bonito/bonitoreg.h>

#include <evbmips/loongson/autoconf.h>
#include <evbmips/loongson/loongson_bus_defs.h>
#include <dev/pci/pcivar.h>

static int	bonito_mainbus_match(device_t, cfdata_t, void *);
static void	bonito_mainbus_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(bonito_mainbus, 0,
    bonito_mainbus_match, bonito_mainbus_attach, NULL, NULL);

extern struct cfdriver bonito_cd;

int
bonito_mainbus_match(device_t parent, cfdata_t cf, void *aux)
{
	struct mainbus_attach_args * const maa = aux;

	if (strcmp(maa->maa_name, bonito_cd.cd_name) == 0)
		return (1);

	return (0);
}

void
bonito_mainbus_attach(device_t parent, device_t self, void *aux)
{
	struct pcibus_attach_args pba;
	pcireg_t rev;

	self->dv_private = __UNCONST(&sys_platform->bonito_config);

	/*
	 * There is only one PCI controller on a Loongson chip.
	 */

	rev = PCI_REVISION(REGVAL(BONITO_PCICLASS));

	aprint_normal(": BONITO Memory and PCI controller, %s rev. %d.%d\n",
	    BONITO_REV_FPGA(rev) ? "FPGA" : "ASIC",
	    BONITO_REV_MAJOR(rev), BONITO_REV_MINOR(rev));

	pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY;
	pba.pba_bus = 0;
	pba.pba_bridgetag = NULL;

	pba.pba_iot = &bonito_iot;
	pba.pba_memt = &bonito_memt;
	pba.pba_dmat = &bonito_dmat;
	pba.pba_dmat64 = NULL;
	pba.pba_pc = &bonito_pc;

	(void) config_found_ia(self, "pcibus", &pba, pcibusprint);
}

File Added: src/sys/arch/evbmips/loongson/gdium_machdep.c
/*	$OpenBSD: gdium_machdep.c,v 1.6 2010/05/08 21:59:56 miod Exp $	*/

/*
 * Copyright (c) 2010 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Gdium Liberty specific code and configuration data.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/types.h>

#include <evbmips/loongson/autoconf.h>
#include <evbmips/loongson/loongson_intr.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

int	gdium_revision = 0;

void	gdium_attach_hook(device_t, device_t, struct pcibus_attach_args *);
void	gdium_device_register(struct device *, void *);
int	gdium_intr_map(int, int, int, pci_intr_handle_t *);
void	gdium_powerdown(void);
void	gdium_reset(void);

const struct bonito_config gdium_bonito = {
	.bc_adbase = 11,

	.bc_gpioIE = LOONGSON_INTRMASK_GPIO,
	.bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR |
	    LOONGSON_INTRMASK_PCI_PARERR,
	.bc_intSteer = 0,
	.bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR |
	    LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR,

	.bc_attach_hook = gdium_attach_hook,
};


const struct platform gdium_platform = {
	.system_type = LOONGSON_GDIUM,
	.vendor = "EMTEC",
	.product = "Gdium",

	.bonito_config = &gdium_bonito,
	.isa_chipset = NULL,
	.legacy_io_ranges = NULL,
	.bonito_mips_intr = MIPS_INT_MASK_4,
	.isa_mips_intr = 0,
	.isa_intr = NULL,
	.p_pci_intr_map = gdium_intr_map,
	.irq_map = loongson2f_irqmap,

	.setup = NULL,
	.device_register = gdium_device_register,

	.powerdown = gdium_powerdown,
	.reset = gdium_reset
};

void
gdium_attach_hook(device_t parent, device_t self,
    struct pcibus_attach_args *pba)
{
	pci_chipset_tag_t pc = pba->pba_pc;
	pcireg_t id;
	pcitag_t tag;
#ifdef notyet
	int bar;
#endif
#if 0
	pcireg_t reg;
	int dev, func;
#endif

	if (pba->pba_bus != 0)
		return;

#ifdef notyet
	/*
	 * Clear all BAR of the mini PCI slot; PMON did not initialize
	 * it, and we do not want it to conflict with anything.
	 */
	tag = pci_make_tag(pc, 0, 13, 0);
	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 4)
		pci_conf_write(pc, tag, bar, 0);
#else
	/*
	 * Force a non conflicting BAR for the wireless controller,
	 * until proper resource configuration code is added to
	 * bonito (work in progress).
	 */
	tag = pci_make_tag(pc, 0, 13, 0);
	pci_conf_write(pc, tag, PCI_MAPREG_START, 0x06228000);
#endif

	/*
	 * Figure out which motherboard we are running on.
	 * Might not be good enough...
	 */
	tag = pci_make_tag(pc, 0, 17, 0);
	id = pci_conf_read(pc, tag, PCI_ID_REG);
	if (id == PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
		gdium_revision = 1;
	
#if 0
	/*
	 * Tweak the usb controller capabilities.
	 */
	for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
		tag = pci_make_tag(pc, 0, dev, 0);
		id = pci_conf_read(pc, tag, PCI_ID_REG);
		if (id != PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
			continue;
		if (gdium_revision != 0) {
			reg = pci_conf_read(pc, tag, 0xe0);
			/* enable ports 1 and 2 */
			reg |= 0x00000003;
			pci_conf_write(pc, tag, 0xe0, reg);
		} else {
			for (func = 0; func < 2; func++) {
				tag = pci_make_tag(pc, 0, dev, func);
				id = pci_conf_read(pc, tag, PCI_ID_REG);
				if (PCI_VENDOR(id) != PCI_VENDOR_NEC)
					continue;
				if (PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB &&
				    PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB2)
					continue;

				reg = pci_conf_read(pc, tag, 0xe0);
				/* enable ports 1 and 3, disable port 2 */
				reg &= ~0x00000007;
				reg |= 0x00000005;
				pci_conf_write(pc, tag, 0xe0, reg);
				pci_conf_write(pc, tag, 0xe4, 0x00000020);
			}
		}
	}
#endif
}

int
gdium_intr_map(int dev, int fn, int pin, pci_intr_handle_t *ihp)
{
	switch (dev) {
	/* mini-PCI slot */
	case 13:	/* C D A B */
		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA + (pin + 1) % 4);
		return 0;
	/* Frame buffer */
	case 14:
		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA);
		return 0;
	/* USB */
	case 15:
		if (gdium_revision == 0)
			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
			    (pin - 1));
		else
			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIB);
		return 0;
	/* Ethernet */
	case 16:
		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCID);
		return 0;
	/* USB, not present in old motherboard revision */
	case 17:
		if (gdium_revision != 0) {
			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIC);
			return 0;
		} else
			break;
	default:
		break;
	}

	return 1;
}

/*
 * Due to PMON limitations on the Gdium Liberty, we do not get boot device
 * information from PMON.
 *
 * Because of this, we always pretend the G-Key port is the boot device.
 *
 * Note that, unlike on the Lemote machines, other USB devices gets a fixed
 * numbering (USB0 and USB1).
 */

extern struct cfdriver bonito_cd;
extern struct cfdriver pci_cd;
extern struct cfdriver ehci_cd;
extern struct cfdriver usb_cd;
extern struct cfdriver uhub_cd;
extern struct cfdriver umass_cd;
extern struct cfdriver scsibus_cd;
extern struct cfdriver sd_cd;

#include <dev/pci/pcivar.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>

void
gdium_device_register(struct device *dev, void *aux)
{
	static int gkey_chain_pos = 0;
	static struct device *lastparent = NULL;

	if (dev->dv_parent != lastparent && gkey_chain_pos != 0)
		return;

	switch (gkey_chain_pos) {
	case 0:	/* bonito at mainbus */
		if (device_is_a(dev, "bonito"))
			goto advance;
		break;
	case 1:	/* pci at bonito */
		if (device_is_a(dev, "pci"))
			goto advance;
		break;
	case 2:	/* ehci at pci dev 15 */
		if (device_is_a(dev, "ehci")) {
			struct pci_attach_args *paa = aux;
			if (paa->pa_device == 15)
				goto advance;
		}
		break;
	case 3:	/* usb at ehci */
		if (device_is_a(dev, "usb"))
			goto advance;
		break;
	case 4:	/* uhub at usb */
		if (device_is_a(dev, "uhub"))
			goto advance;
		break;
	case 5:	/* umass at uhub port 3 */
		if (device_is_a(dev, "umass")) {
			struct usb_attach_arg *uaa = aux;
			if (uaa->port == 3)
				goto advance;
		}
		break;
	case 6:	/* scsibus at umass */
		if (device_is_a(dev, "scsibus"))
			goto advance;
		break;
	case 7:	/* sd at scsibus */
		if (booted_device == NULL)
			booted_device = dev;
		break;
	}

	return;

advance:
	gkey_chain_pos++;
	lastparent = dev;
}

void
gdium_powerdown()
{
	REGVAL(BONITO_GPIODATA) |= 0x00000002;
	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
}

void
gdium_reset()
{
	REGVAL(BONITO_GPIODATA) &= ~0x00000002;
	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
}

File Added: src/sys/arch/evbmips/loongson/generic2e_machdep.c
/*	$OpenBSD: generic2e_machdep.c,v 1.2 2011/04/15 20:40:06 deraadt Exp $	*/

/*
 * Copyright (c) 2010 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*-
 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

/*
 * Generic Loongson 2E code and configuration data.
 */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: generic2e_machdep.c,v 1.1 2011/08/27 13:42:44 bouyer Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/types.h>


#include <dev/ic/i8259reg.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

#include <evbmips/loongson/autoconf.h>
#include <mips/pmon/pmon.h>
#include <evbmips/loongson/loongson_intr.h>
#include <evbmips/loongson/loongson_isa.h>
#include <evbmips/loongson/loongson_bus_defs.h>

#include "com.h"
#include "isa.h"

#if NCOM > 0
#include <sys/termios.h>
#include <dev/ic/comvar.h>
#endif

void	generic2e_device_register(struct device *, void *);
void	generic2e_reset(void);

void	generic2e_setup(void);

void	generic2e_pci_attach_hook(device_t, device_t,
    struct pcibus_attach_args *);
int	generic2e_intr_map(int, int, int, pci_intr_handle_t *);

void	generic2e_isa_attach_hook(struct device *, struct device *,
	    struct isabus_attach_args *);
void	*generic2e_isa_intr_establish(void *, int, int, int,
	     int (*)(void *), void *);
void	generic2e_isa_intr_disestablish(void *, void *);
const struct evcnt * generic2e_isa_intr_evcnt(void *, int);
const char * generic2e_isa_intr_string(void *, int);

void 	generic2e_isa_intr(int, vaddr_t, uint32_t);

void	via686sb_setup(pci_chipset_tag_t, int);

/* PnP IRQ assignment for VIA686 SuperIO components */
#define	VIA686_IRQ_PCIA		9
#define	VIA686_IRQ_PCIB		10
#define	VIA686_IRQ_PCIC		11
#define	VIA686_IRQ_PCID		13

static int generic2e_via686sb_dev = -1;

const struct bonito_config generic2e_bonito = {
	.bc_adbase = 11,

	.bc_gpioIE = 0xffffffff,
	.bc_intEdge = BONITO_INTRMASK_SYSTEMERR | BONITO_INTRMASK_MASTERERR |
	    BONITO_INTRMASK_RETRYERR | BONITO_INTRMASK_MBOX,
	.bc_intSteer = 0,
	.bc_intPol = 0,

	.bc_attach_hook = generic2e_pci_attach_hook,
};

const struct legacy_io_range generic2e_legacy_ranges[] = {
	/* no isa space access restrictions */
	{ 0,		BONITO_PCIIO_LEGACY },

	{ 0 }
};

struct mips_isa_chipset generic2e_isa_chipset = {
	.ic_v = NULL,

	.ic_attach_hook = generic2e_isa_attach_hook,
	.ic_intr_establish = generic2e_isa_intr_establish,
	.ic_intr_disestablish = generic2e_isa_intr_disestablish,
	.ic_intr_evcnt = generic2e_isa_intr_evcnt,
	.ic_intr_string = generic2e_isa_intr_string,
};

const struct platform generic2e_platform = {
	.system_type = LOONGSON_2E,
	.vendor = "Generic",
	.product = "Loongson2E",

	.bonito_config = &generic2e_bonito,
	.isa_chipset = &generic2e_isa_chipset,
	.legacy_io_ranges = generic2e_legacy_ranges,
	.bonito_mips_intr = MIPS_INT_MASK_0,
	.isa_mips_intr = MIPS_INT_MASK_3,
	.isa_intr = generic2e_isa_intr,
	.p_pci_intr_map = generic2e_intr_map,
	.irq_map = loongson2e_irqmap,

	.setup = generic2e_setup,
	.device_register = generic2e_device_register,

	.powerdown = NULL,
	.reset = generic2e_reset
};

/*
 * PCI model specific routines
 */

void
generic2e_pci_attach_hook(device_t parent, device_t self,
    struct pcibus_attach_args *pba)
{
	pci_chipset_tag_t pc = pba->pba_pc;
	pcireg_t id;
	pcitag_t tag;
	int dev;

	if (pba->pba_bus != 0)
		return;

	/*
	 * Check for a VIA 686 southbridge; if one is found, remember
	 * its location, needed by generic2e_intr_map().
	 */

	for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
		tag = pci_make_tag(pc, 0, dev, 0);
		id = pci_conf_read(pc, tag, PCI_ID_REG);
		if (id == PCI_ID_CODE(PCI_VENDOR_VIATECH,
		    PCI_PRODUCT_VIATECH_VT82C686A_ISA)) {
			generic2e_via686sb_dev = dev;
			break;
		}
	}

	if (generic2e_via686sb_dev != 0)
		via686sb_setup(pc, generic2e_via686sb_dev);
}

int
generic2e_intr_map(int dev, int fn, int pin, pci_intr_handle_t *ihp)
{
	if (dev == generic2e_via686sb_dev) {
		switch (fn) {
		case 1:	/* PCIIDE */
			/* will use compat interrupt */
			break;
		case 2:	/* USB */
			*ihp = BONITO_ISA_IRQ(VIA686_IRQ_PCIB);
			return 0;
		case 3:	/* USB */
			*ihp = BONITO_ISA_IRQ(VIA686_IRQ_PCIC);
			return 0;
		case 4:	/* power management, SMBus */
			break;
		case 5:	/* Audio */
			*ihp = BONITO_ISA_IRQ(VIA686_IRQ_PCIA);
			return 0;
		case 6:	/* Modem */
			break;
		default:
			break;
		}
	} else {
		*ihp = BONITO_DIRECT_IRQ(BONITO_INTR_GPIN +
		    pin - PCI_INTERRUPT_PIN_A);
		return 0;
	}

	return 1;
}

/*
 * ISA model specific routines
 */

void
generic2e_isa_attach_hook(struct device *parent, struct device *self,
    struct isabus_attach_args *iba)
{
	loongson_set_isa_imr(loongson_isaimr);
}

void *
generic2e_isa_intr_establish(void *v, int irq, int type, int level,
    int (*handler)(void *), void *arg)
{
	void *ih;
	uint imr;

	ih = evbmips_intr_establish(BONITO_ISA_IRQ(irq), handler, arg);
	if (ih == NULL)
		return NULL;
	/* enable interrupt */
	imr = loongson_isaimr;
	imr |= (1 << irq);
	loongson_set_isa_imr(imr); 
	return ih;
}

void
generic2e_isa_intr_disestablish(void *v, void *ih)
{
	evbmips_intr_disestablish(ih);
}

const struct evcnt *
generic2e_isa_intr_evcnt(void *v, int irq)
{

        if (irq == 0 || irq >= BONITO_NISA || irq == 2)
		panic("generic2e_isa_intr_evcnt: bogus isa irq 0x%x", irq);

	return (&bonito_intrhead[BONITO_ISA_IRQ(irq)].intr_count);
}

const char *
generic2e_isa_intr_string(void *v, int irq)
{
	if (irq == 0 || irq >= BONITO_NISA || irq == 2)
		panic("generic2e_isa_intr_string: bogus isa irq 0x%x", irq);

	return loongson_intr_string(&generic2e_bonito, irq);
}

void
generic2e_isa_intr(int ipl, vaddr_t pc, uint32_t ipending)
{
#if NISA > 0
	struct evbmips_intrhand *ih;
	uint64_t isr, mask = 0;
	int rc, irq, ret;
	uint8_t ocw1, ocw2;

	for (;;) {
		REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) = 
		    OCW3_SELECT | OCW3_POLL;
		ocw1 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3);
		if ((ocw1 & OCW3_POLL_PENDING) == 0)
			break;

		irq = OCW3_POLL_IRQ(ocw1);

		if (irq == 2) /* cascade */ {
			REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) = 
			    OCW3_SELECT | OCW3_POLL;
			ocw2 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3);
			if (ocw2 & OCW3_POLL_PENDING)
				irq = OCW3_POLL_IRQ(ocw2);
			else
				irq = 2;
		} else
			ocw2 = 0;

		/*
		 * Mask the interrupt before servicing it.
		 */
		isr = 1UL << irq;
		loongson_set_isa_imr(loongson_isaimr & ~isr);

		mask |= isr;

		rc = 0;
		LIST_FOREACH(ih,
		    &bonito_intrhead[BONITO_ISA_IRQ(irq)].intrhand_head,
		    ih_q) {
			ret = (*ih->ih_func)(ih->ih_arg);
			if (ret) {
				rc = 1;
				bonito_intrhead[BONITO_ISA_IRQ(irq)].intr_count.ev_count++;
			}

			if (ret == 1)
				break;
		}

		/* Send a specific EOI to the 8259. */
		loongson_isa_specific_eoi(irq);

		if (rc == 0) {
			printf("spurious isa interrupt %d\n", irq);
		}
	}

	/*
	 * Reenable interrupts which have been serviced.
	 */
	if (mask != 0)
		loongson_set_isa_imr(loongson_isaimr | mask);

#endif
}

/*
 * Other model specific routines
 */

void
generic2e_reset()
{
	REGVAL(BONITO_BONGENCFG) &= ~BONITO_BONGENCFG_CPUSELFRESET;
	REGVAL(BONITO_BONGENCFG) |= BONITO_BONGENCFG_CPUSELFRESET;
	delay(1000000);
}

void
generic2e_setup(void)
{
#if NCOM > 0
	const char *envvar;
	int serial;

	envvar = pmon_getenv("nokbd");
	serial = envvar != NULL;
	envvar = pmon_getenv("novga");
	serial = serial && envvar != NULL;

	if (serial) {
                comconsiot = &bonito_iot;
                comconsaddr = 0x3f8;
                comconsrate = 115200; /* default PMON console speed */
	}
#endif
}

void
generic2e_device_register(struct device *dev, void *aux)
{
	const char *name = device_xname(dev);

	if (dev->dv_class != bootdev_class)
		return;	

	/* 
	 * The device numbering must match. There's no way
	 * pmon tells us more info. Depending on the usb slot
	 * and hubs used you may be lucky. Also, assume umass/sd for usb
	 * attached devices.
	 */
	switch (bootdev_class) {
	case DV_DISK:
		if (device_is_a(dev, "wd") && strcmp(name, bootdev) == 0) {
			if (booted_device == NULL)
				booted_device = dev;
		} else {
			/* XXX this really only works safely for usb0... */
		    	if ((device_is_a(dev, "sd") ||
			    device_is_a(dev, "cd")) &&
			    strncmp(bootdev, "usb", 3) == 0 &&
			    strcmp(name + 2, bootdev + 3) == 0) {
				if (booted_device == NULL)
					booted_device = dev;
			}
		}
		break;
	case DV_IFNET:
		/*
		 * This relies on the onboard Ethernet interface being
		 * attached before any other (usb) interface.
		 */
		if (booted_device == NULL)
			booted_device = dev;
		break;
	default:
		break;
	}
}

/*
 * Initialize a VIA686 south bridge.
 *
 * PMON apparently does not perform enough initialization; one may argue this
 * could be done with a specific pcib(4) driver, but then no other system
 * will hopefully need this, so keep it local to the 2E setup code.
 */

#define	VIA686_ISA_ROM_CONTROL		0x40
#define	VIA686_ROM_WRITE_ENABLE			0x00000001
#define	VIA686_NO_ROM_WAIT_STATE		0x00000002
#define	VIA686_EXTEND_ALE			0x00000004
#define	VIA686_IO_RECOVERY_TIME			0x00000008
#define	VIA686_CHIPSET_EXTRA_WAIT_STATES	0x00000010
#define	VIA686_ISA_EXTRA_WAIT_STATES		0x00000020
#define	VIA686_ISA_EXTENDED_BUS_READY		0x00000040
#define	VIA686_ISA_EXTRA_COMMAND_DELAY		0x00000080
#define	VIA686_ISA_REFRESH			0x00000100
#define	VIA686_DOUBLE_DMA_CLOCK			0x00000800
#define	VIA686_PORT_92_FAST_RESET		0x00002000
#define	VIA686_IO_MEDIUM_RECOVERY_TIME		0x00004000
#define	VIA686_KBC_DMA_MISC12		0x44
#define	VIA686_ISA_MASTER_TO_LINE_BUFFER	0x00008000
#define	VIA686_POSTED_MEMORY_WRITE_ENABLE	0x00010000
#define	VIA686_PCI_BURST_INTERRUPTABLE		0x00020000
#define	VIA686_FLUSH_LINE_BUFFER_ON_INTR	0x00200000
#define	VIA686_GATE_INTR			0x00400000
#define	VIA686_PCI_MASTER_WRITE_WAIT_STATE	0x00800000
#define	VIA686_PCI_RESET			0x01000000
#define	VIA686_PCI_READ_DELAY_TRANSACTION_TMO	0x02000000
#define	VIA686_PCI_WRITE_DELAY_TRANSACTION_TMO	0x04000000
#define	VIA686_ICR_SHADOW_ENABLE		0x10000000
#define	VIA686_EISA_PORT_4D0_4D1_ENABLE		0x20000000
#define	VIA686_PCI_DELAY_TRANSACTION_ENABLE	0x40000000
#define	VIA686_CPU_RESET_SOURCE_INIT		0x80000000
#define	VIA686_MISC3_IDE_INTR		0x48
#define	VIA686_IDE_PRIMARY_CHAN_MASK		0x00030000
#define	VIA686_IDE_PRIMARY_CHAN_SHIFT			16
#define	VIA686_IDE_SECONDARY_CHAN_MASK		0x000c0000
#define	VIA686_IDE_SECONDARY_CHAN_SHIFT			18
#define	VIA686_IDE_IRQ14	00
#define	VIA686_IDE_IRQ15	01
#define	VIA686_IDE_IRQ10	02
#define	VIA686_IDE_IRQ11	03
#define	VIA686_IDE_PGNT				0x00800000
#define	VIA686_PNP_DMA_IRQ		0x50
#define	VIA686_DMA_FDC_MASK			0x00000003
#define	VIA686_DMA_FDC_SHIFT				0
#define	VIA686_DMA_LPT_MASK			0x0000000c
#define	VIA686_DMA_LPT_SHIFT				2
#define	VIA686_IRQ_FDC_MASK			0x00000f00
#define	VIA686_IRQ_FDC_SHIFT				8
#define	VIA686_IRQ_LPT_MASK			0x0000f000
#define	VIA686_IRQ_LPT_SHIFT				12
#define	VIA686_IRQ_COM0_MASK			0x000f0000
#define	VIA686_IRQ_COM0_SHIFT				16
#define	VIA686_IRQ_COM1_MASK			0x00f00000
#define	VIA686_IRQ_COM1_SHIFT				20
#define	VIA686_PCI_LEVEL_PNP_IRQ2	0x54
#define	VIA686_PCI_IRQD_EDGE			0x00000001
#define	VIA686_PCI_IRQC_EDGE			0x00000002
#define	VIA686_PCI_IRQB_EDGE			0x00000004
#define	VIA686_PCI_IRQA_EDGE			0x00000008
#define	VIA686_IRQ_PCIA_MASK			0x0000f000
#define	VIA686_IRQ_PCIA_SHIFT				12
#define	VIA686_IRQ_PCIB_MASK			0x000f0000
#define	VIA686_IRQ_PCIB_SHIFT				16
#define	VIA686_IRQ_PCIC_MASK			0x00f00000
#define	VIA686_IRQ_PCIC_SHIFT				20
#define	VIA686_IRQ_PCID_MASK			0xf0000000
#define	VIA686_IRQ_PCID_SHIFT				28

void
via686sb_setup(pci_chipset_tag_t pc, int dev)
{
	pcitag_t tag;
	pcireg_t reg;
	uint elcr;

	tag = pci_make_tag(pc, 0, dev, 0);

	/*
	 * Generic ISA bus initialization.
	 */

	reg = pci_conf_read(pc, tag, VIA686_ISA_ROM_CONTROL);
	reg |= VIA686_IO_RECOVERY_TIME | VIA686_ISA_REFRESH;
	pci_conf_write(pc, tag, VIA686_ISA_ROM_CONTROL, reg);

	reg = pci_conf_read(pc, tag, VIA686_KBC_DMA_MISC12);
	reg |= VIA686_CPU_RESET_SOURCE_INIT |
	    VIA686_PCI_DELAY_TRANSACTION_ENABLE |
	    VIA686_EISA_PORT_4D0_4D1_ENABLE |
	    VIA686_PCI_WRITE_DELAY_TRANSACTION_TMO |
	    VIA686_PCI_READ_DELAY_TRANSACTION_TMO |
	    VIA686_PCI_MASTER_WRITE_WAIT_STATE | VIA686_GATE_INTR |
	    VIA686_FLUSH_LINE_BUFFER_ON_INTR;
	reg &= ~VIA686_ISA_MASTER_TO_LINE_BUFFER;
	pci_conf_write(pc, tag, VIA686_KBC_DMA_MISC12, reg);

	/*
	 * SuperIO devices interrupt and DMA setup.
	 */

	reg = pci_conf_read(pc, tag, VIA686_MISC3_IDE_INTR);
	reg &= ~(VIA686_IDE_PRIMARY_CHAN_MASK | VIA686_IDE_SECONDARY_CHAN_MASK);
	reg |= (VIA686_IDE_IRQ14 << VIA686_IDE_PRIMARY_CHAN_SHIFT);
	reg |= (VIA686_IDE_IRQ15 << VIA686_IDE_SECONDARY_CHAN_SHIFT);
	reg |= VIA686_IDE_PGNT;
	pci_conf_write(pc, tag, VIA686_MISC3_IDE_INTR, reg);

	reg = pci_conf_read(pc, tag, VIA686_PNP_DMA_IRQ);
	reg &= ~(VIA686_DMA_FDC_MASK | VIA686_DMA_LPT_MASK);
	reg |= (2 << VIA686_DMA_FDC_SHIFT) | (3 << VIA686_DMA_LPT_SHIFT);
	reg &= ~(VIA686_IRQ_FDC_MASK | VIA686_IRQ_LPT_MASK);
	reg |= (6 << VIA686_IRQ_FDC_SHIFT) | (7 << VIA686_IRQ_LPT_SHIFT);
	reg &= ~(VIA686_IRQ_COM0_MASK | VIA686_IRQ_COM1_MASK);
	reg |= (4 << VIA686_IRQ_COM0_SHIFT) | (3 << VIA686_IRQ_COM1_SHIFT);

	reg = pci_conf_read(pc, tag, VIA686_PCI_LEVEL_PNP_IRQ2);
	reg &= ~(VIA686_PCI_IRQA_EDGE | VIA686_PCI_IRQB_EDGE |
	    VIA686_PCI_IRQB_EDGE | VIA686_PCI_IRQD_EDGE);
	reg &= ~(VIA686_IRQ_PCIA_MASK | VIA686_IRQ_PCIB_MASK |
	    VIA686_IRQ_PCIC_MASK | VIA686_IRQ_PCID_MASK);
	reg |= (VIA686_IRQ_PCIA << VIA686_IRQ_PCIA_SHIFT) |
	    (VIA686_IRQ_PCIB << VIA686_IRQ_PCIB_SHIFT) |
	    (VIA686_IRQ_PCIC << VIA686_IRQ_PCIC_SHIFT) |
	    (VIA686_IRQ_PCID << VIA686_IRQ_PCID_SHIFT);

	/*
	 * Interrupt controller setup.
	 */

	/* reset; program device, four bytes */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW1) =
	    ICW1_SELECT | ICW1_IC4;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW2) = ICW2_VECTOR(0);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW3) = ICW3_CASCADE(2);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW4) = ICW4_8086;
	/* leave interrupts masked */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1) = 0xff;
	/* special mask mode (if available) */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) =
	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM;
	/* read IRR by default. */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) = OCW3_SELECT | OCW3_RR;

	/* reset; program device, four bytes */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW1) =
	    ICW1_SELECT | ICW1_IC4;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW2) = ICW2_VECTOR(8);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW3) = ICW3_SIC(2);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW4) = ICW4_8086;
	/* leave interrupts masked */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1) = 0xff;
	/* special mask mode (if available) */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) =
	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM;
	/* read IRR by default. */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) = OCW3_SELECT | OCW3_RR;

	/* setup ELCR: PCI interrupts are level-triggered. */
	elcr = (1 << VIA686_IRQ_PCIA) | (1 << VIA686_IRQ_PCIB) |
	    (1 << VIA686_IRQ_PCIC) | (1 << VIA686_IRQ_PCID);
	REGVAL8(BONITO_PCIIO_BASE + 0x4d0) = (elcr >> 0) & 0xff;
	REGVAL8(BONITO_PCIIO_BASE + 0x4d1) = (elcr >> 8) & 0xff;

	__asm__ __volatile__ ("sync" ::: "memory");

	/*
	 * Update interrupt information for secondary functions.
	 * Although this information is not used by pci_intr_establish()
	 * because of generic2e_intr_map() behaviour, it seems to be
	 * required to complete proper interrupt routing.
	 */

	tag = pci_make_tag(pc, 0, dev, 2);
	reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
	reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
	reg |= VIA686_IRQ_PCIB << PCI_INTERRUPT_LINE_SHIFT;
	pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);

	tag = pci_make_tag(pc, 0, dev, 3);
	reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
	reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
	reg |= VIA686_IRQ_PCIC << PCI_INTERRUPT_LINE_SHIFT;
	pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);

	tag = pci_make_tag(pc, 0, dev, 5);
	reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
	reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
	reg |= VIA686_IRQ_PCIA << PCI_INTERRUPT_LINE_SHIFT;
	pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
}

File Added: src/sys/arch/evbmips/loongson/isa_machdep.c
/*	$OpenBSD: isa_machdep.c,v 1.1 2010/05/08 21:59:56 miod Exp $	*/

/*
 * Copyright (c) 2009, 2010 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Legacy device support.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <evbmips/loongson/autoconf.h>
#include <machine/intr.h>

#include <dev/ic/i8259reg.h>

#include <dev/pci/pcivar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

#include <evbmips/loongson/loongson_isa.h>

uint	loongson_isaimr;

void
loongson_set_isa_imr(uint newimr)
{
	uint imr1, imr2;

	imr1 = 0xff & ~newimr;
	imr1 &= ~(1 << 2);	/* enable cascade */
	imr2 = 0xff & ~(newimr >> 8);

	/*
	 * For some reason, trying to write the same value to the PIC
	 * registers causes an immediate system freeze (at least on the
	 * 2F and CS5536 based Lemote Yeeloong), so we only do this if
	 * the value changes.
	 * Note that interrupts have been disabled by the caller.
	 */
	//if ((newimr ^ loongson_isaimr) & 0xff00)
		REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1) = imr2;
	//if ((newimr ^ loongson_isaimr) & 0x00ff)
		REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1) = imr1;
	__asm__ __volatile__ ("sync" ::: "memory");
	loongson_isaimr = newimr;
}

void
loongson_isa_specific_eoi(int bit)
{
	KASSERT((bit < 16) && (bit >= 0));
	loongson_isaimr &= ~(1 << bit);
	if (bit & 8) {
		(void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1);
		REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1) =
		    (0xff & ~(loongson_isaimr >> 8));
		__asm__ __volatile__ ("sync" ::: "memory");
		REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW2) =
		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(bit & 7);
		bit = 2;
		__asm__ __volatile__ ("sync" ::: "memory");
	}
	(void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1) =
	    (0xff & ~(loongson_isaimr));
	__asm__ __volatile__ ("sync" ::: "memory");
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW2) =
	    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(bit);
	__asm__ __volatile__ ("sync" ::: "memory");
}

File Added: src/sys/arch/evbmips/loongson/loongson2_machdep.c
/*	$OpenBSD: loongson2_machdep.c,v 1.11 2011/03/31 20:37:44 miod Exp $	*/

/*
 * Copyright (c) 2009, 2010 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/kcore.h>

#include <uvm/uvm_extern.h>

#include <evbmips/loongson/autoconf.h>
#include <evbmips/loongson/loongson_intr.h>
#include <machine/kcore.h>
#include <machine/cpu.h>
#include <mips/pmon/pmon.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

boolean_t is_memory_range(paddr_t, psize_t, psize_t);
static void loongson2f_setup_window(uint, uint, uint64_t, uint64_t, uint64_t, uint);

/*
 * Canonical crossbow assignments on Loongson 2F based designs.
 * Might need to move to a per-design header file in the future.
 */

#define	MASTER_CPU		0
#define	MASTER_PCI		1

#define	WINDOW_CPU_LOW		0
#define	WINDOW_CPU_PCILO	1
#define	WINDOW_CPU_PCIHI	2
#define	WINDOW_CPU_DDR		3

#define	WINDOW_PCI_DDR		0

#define	DDR_PHYSICAL_BASE	0x0000000000000000UL	/* memory starts at 0 */
#define	DDR_PHYSICAL_SIZE	0x0000000080000000UL	/* up to 2GB */
#define	DDR_WINDOW_BASE		0x0000000080000000UL	/* mapped at 2GB */

#define	PCI_RESOURCE_BASE	0x0000000000000000UL
#define	PCI_RESOURCE_SIZE	0x0000000080000000UL

#define	PCI_DDR_BASE		0x0000000080000000UL	/* PCI->DDR at 2GB */

/* bonito interrupt mappings */
const struct bonito_irqmap loongson2e_irqmap[BONITO_NDIRECT] = {
	{ "mbox0",	BONITO_INTR_MBOX + 0,	IRQ_F_INT0 },
	{ "mbox1",	BONITO_INTR_MBOX + 1,	IRQ_F_INT0 },
	{ "mbox2",	BONITO_INTR_MBOX + 2,	IRQ_F_INT0 },
	{ "mbox3",	BONITO_INTR_MBOX + 3,	IRQ_F_INT0 },
	{ "dmardy",	BONITO_INTR_MBOX + 4,	IRQ_F_INT0 },
	{ "dmaempty",	BONITO_INTR_MBOX + 5,	IRQ_F_INT0 },
	{ "copyrdy",	BONITO_INTR_MBOX + 6,	IRQ_F_INT0 },
	{ "copyempty",	BONITO_INTR_MBOX + 7,	IRQ_F_INT0 },
	{ "coperr",	BONITO_INTR_MBOX + 8,	IRQ_F_INT1 },
	{ "pciirq",	BONITO_INTR_MBOX + 9,	IRQ_F_INT0 },
	{ "mastererr",	BONITO_INTR_MBOX + 10,	IRQ_F_INT1 },
	{ "systemerr",	BONITO_INTR_MBOX + 11,	IRQ_F_INT1 },
	{ "dramerr",	BONITO_INTR_MBOX + 12,	IRQ_F_INT1 },
	{ "retryerr",	BONITO_INTR_MBOX + 13,	IRQ_F_INT1 },
	{ NULL,		BONITO_INTR_MBOX + 14,	0 },
	{ NULL,		BONITO_INTR_MBOX + 15,	0 },
	{ "gpio0",	BONITO_INTR_GPIO + 0,	IRQ_F_INT0 },
	{ "gpio1",	BONITO_INTR_GPIO + 1,	IRQ_F_INT0 },
	{ "gpio2",	BONITO_INTR_GPIO + 2,	IRQ_F_INT0 },
	{ "gpio3",	BONITO_INTR_GPIO + 3,	IRQ_F_INT0 },
	{ "gpio4",	BONITO_INTR_GPIO + 4,	IRQ_F_INT0 },
	{ "gpio5",	BONITO_INTR_GPIO + 5,	IRQ_F_INT0 },
	{ "gpio6",	BONITO_INTR_GPIO + 6,	IRQ_F_INT0 },
	{ "gpio7",	BONITO_INTR_GPIO + 7,	IRQ_F_INT0 },
	{ "gpio8",	BONITO_INTR_GPIO + 8,	IRQ_F_INT0 },
	{ "gpin0",	BONITO_INTR_GPIN + 0,	IRQ_F_INT0 },
	{ "gpin1",	BONITO_INTR_GPIN + 1,	IRQ_F_INT0 },
	{ "gpin2",	BONITO_INTR_GPIN + 2,	IRQ_F_INT0 },
	{ "gpin3",	BONITO_INTR_GPIN + 3,	IRQ_F_INT0 },
	{ "gpin4",	BONITO_INTR_GPIN + 4,	IRQ_F_INT0 },
	{ "gpin5",	BONITO_INTR_GPIN + 5,	IRQ_F_INT0 },
	{ NULL,		BONITO_INTR_GPIN + 6,	0 },
};

const struct bonito_irqmap loongson2f_irqmap[BONITO_NDIRECT] = {
	{ "gpio0",	LOONGSON_INTR_GPIO0,	IRQ_F_INT0 },
	{ "gpio1",	LOONGSON_INTR_GPIO1,	IRQ_F_INT0 },
	{ "gpio2",	LOONGSON_INTR_GPIO2,	IRQ_F_INT0 },
	{ "gpio3",	LOONGSON_INTR_GPIO3,	IRQ_F_INT0 },

	{ "pci inta",	LOONGSON_INTR_PCIA,	IRQ_F_INT0 },
	{ "pci intb",	LOONGSON_INTR_PCIB,	IRQ_F_INT0 },
	{ "pci intc",	LOONGSON_INTR_PCIC,	IRQ_F_INT0 },
	{ "pci intd",	LOONGSON_INTR_PCID,	IRQ_F_INT0 },

	{ "pci perr",	LOONGSON_INTR_PCI_PARERR, IRQ_F_EDGE|IRQ_F_INT1 },
	{ "pci serr",	LOONGSON_INTR_PCI_SYSERR, IRQ_F_EDGE|IRQ_F_INT1 },

	{ "denali",	LOONGSON_INTR_DRAM_PARERR, IRQ_F_INT1 },

	{ "mips int0",	LOONGSON_INTR_INT0,	IRQ_F_INT0 },
	{ "mips int1",	LOONGSON_INTR_INT1,	IRQ_F_INT1 },
	{ "mips int2",	LOONGSON_INTR_INT2,	IRQ_F_INT2 },
	{ "mips int3",	LOONGSON_INTR_INT3,	IRQ_F_INT3 },
};

/*
 * Setup memory mappings for Loongson 2E processors.
 */

void
loongson2e_setup(paddr_t memlo, paddr_t memhi,
    vaddr_t vkernstart, vaddr_t vkernend, bus_dma_tag_t t)
{
	if (memhi > ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)) {
		pmon_printf("WARNING! %d MB of memory will not be used",
		    memhi - ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20));
		memhi = (DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20;
	}

	physmem = btoc(memlo + memhi);

	/* do NOT stomp on exception area */
	/* mips_page_physload() will skip the kernel */
	mem_clusters[0].start = DDR_PHYSICAL_BASE;
	mem_clusters[0].size = memlo;
	mem_cluster_cnt = 1;

	if (memhi != 0) {
		mem_clusters[1].start = BONITO_PCIHI_BASE;
		mem_clusters[1].size = memhi;
		mem_cluster_cnt = 2;
	}

	t->_wbase = PCI_DDR_BASE;
	t->_bounce_alloc_lo = DDR_PHYSICAL_BASE;
	t->_bounce_alloc_hi = DDR_PHYSICAL_BASE + DDR_PHYSICAL_SIZE;
}

/*
 * Setup memory mappings for Loongson 2F processors.
 */

void
loongson2f_setup(paddr_t memlo, paddr_t memhi,
    vaddr_t vkernstart, vaddr_t vkernend, bus_dma_tag_t t)
{
	/*
	 * Because we'll only set up a 2GB window for the PCI bus to
	 * access local memory, we'll limit ourselves to 2GB of usable
	 * memory as well.
	 *
	 * Note that this is a bad justification for this; it should be
	 * possible to setup a 1GB PCI space / 3GB memory access window,
	 * and use bounce buffers if physmem > 3GB; but at the moment
	 * there is no need to solve this problem until Loongson 2F-based
	 * hardware with more than 2GB of memory is commonly encountered.
	 *
	 * Also note that, despite the crossbar window registers being
	 * 64-bit wide, the upper 32-bit always read back as zeroes, so
	 * it is dubious whether it is possible to use more than a 4GB
	 * address space... and thus more than 2GB of physical memory.
	 */

	physmem = btoc(memlo + memhi);
	if (physmem > btoc(DDR_PHYSICAL_SIZE)) {
		pmon_printf("WARNING! %d MB of memory will not be used",
		    (physmem >> 20) - (DDR_PHYSICAL_SIZE >> 20));
		memhi = DDR_PHYSICAL_SIZE - btoc(256 << 20);
	}

	physmem = btoc(memlo + memhi);

	/*
	 * PMON configures the system with only the low 256MB of memory
	 * accessible.
	 *
	 * We need to reprogram the address windows in order to be able to
	 * access the whole memory, both by the local processor and by the
	 * PCI bus.
	 *
	 * To make our life easier, we'll setup the memory as a contiguous
	 * range starting at 2GB, and take into account the fact that the
	 * first 256MB are also aliased at address zero (which is where the
	 * kernel is loaded, really).
	 */

	if (memhi != 0 ) {
		/* do NOT stomp on exception area */
		/* also make sure to skip the kernel */
		const paddr_t kernend = MIPS_KSEG0_TO_PHYS(round_page(vkernend));
		mem_clusters[0].start = DDR_WINDOW_BASE + kernend;
		mem_clusters[0].size = (memlo + memhi - kernend);
		t->_wbase = PCI_DDR_BASE;
		t->_bounce_alloc_lo = DDR_WINDOW_BASE;
		t->_bounce_alloc_hi = DDR_WINDOW_BASE + DDR_PHYSICAL_SIZE;
		mem_cluster_cnt = 1;
	} else {
		/* do NOT stomp on exception area */
		/* mips_page_physload() will skip the kernel */
		mem_clusters[0].start = DDR_PHYSICAL_BASE + PAGE_SIZE;
		mem_clusters[0].size = (memlo + memhi - PAGE_SIZE - PAGE_SIZE);
		t->_wbase = PCI_DDR_BASE;
		t->_bounce_alloc_lo = DDR_PHYSICAL_BASE;
		t->_bounce_alloc_hi = DDR_PHYSICAL_BASE + DDR_PHYSICAL_SIZE;
		mem_cluster_cnt = 1;
	}

	/*
	 * Allow access to memory beyond 256MB, by programming the
	 * Loongson 2F address window registers.
	 * This also makes sure PCI->DDR accesses can use a contiguous
	 * area regardless of the actual memory size.
	 */

	/*
	 * Master #0 (cpu) window #0 allows access to the low 256MB
	 * of memory at address zero onwards.
	 * This window is inherited from PMON; we set it up just in case.
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_LOW, DDR_PHYSICAL_BASE,
	    ~(0x0fffffffUL), DDR_PHYSICAL_BASE, MASTER_CPU);

	/*
	 * Master #0 (cpu) window #1 allows access to the ``low'' PCI
	 * space (from 0x10000000 to 0x1fffffff).
	 * This window is inherited from PMON; we set it up just in case.
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCILO, BONITO_PCILO_BASE,
	    ~(0x0fffffffUL), BONITO_PCILO_BASE, MASTER_PCI);

	/*
	 * Master #1 (PCI) window #0 allows access to the memory space
	 * by PCI devices at addresses 0x80000000 onwards.
	 * This window is inherited from PMON, but its mask might be too
	 * restrictive (256MB) so we make sure it matches our needs.
	 */
	loongson2f_setup_window(MASTER_PCI, WINDOW_PCI_DDR, PCI_DDR_BASE,
	    ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);

	/*
	 * Master #0 (CPU) window #2 allows access to a subset of the ``high''
	 * PCI space (from 0x40000000 to 0x7fffffff only).
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCIHI, LS2F_PCIHI_BASE,
	    ~((uint64_t)LS2F_PCIHI_SIZE - 1), LS2F_PCIHI_BASE, MASTER_PCI);

	/*
	 * Master #0 (CPU) window #3 allows access to the whole memory space
	 * at addresses 0x80000000 onwards.
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_DDR, DDR_WINDOW_BASE,
	    ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);

}

/*
 * Setup a window in the Loongson2F crossbar.
 */

static void
loongson2f_setup_window(uint master, uint window, uint64_t base, uint64_t mask,
    uint64_t mmap, uint slave)
{
	volatile uint64_t *awrreg;

	awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
	    LOONGSON_AWR_BASE(master, window));
	*awrreg = base;
	(void)*awrreg;

	awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
	    LOONGSON_AWR_SIZE(master, window));
	*awrreg = mask;
	(void)*awrreg;

	awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
	    LOONGSON_AWR_MMAP(master, window));
	*awrreg = mmap | slave;
	(void)*awrreg;
}

/*
 * Return whether a given physical address points to managed memory.
 * (used by /dev/mem)
 */

boolean_t
is_memory_range(paddr_t pa, psize_t len, psize_t limit)
{
	uint64_t fp, lp;
	int i;

	fp = atop(pa);
	lp = atop(round_page(pa + len));

	if (limit != 0 && lp > atop(limit))
		return FALSE;

	/*
	 * Allow access to the low 256MB aliased region on 2F systems,
	 * if we are accessing memory at 2GB onwards.
	 */
	if (pa < 0x10000000 && loongson_ver >= 0x2f) {
		fp += btoc(mem_clusters[0].start);
		lp += btoc(mem_clusters[0].start);
	}

	for (i = 0; i < VM_PHYSSEG_MAX; i++)
		if (fp >= btoc(mem_clusters[i].start) &&
		    lp <= btoc(mem_clusters[i].start + mem_clusters[i].size))
			return TRUE;

	return FALSE;
}

File Added: src/sys/arch/evbmips/loongson/loongson_bus_defs.h
/* $NetBSD: loongson_bus_defs.h,v 1.1 2011/08/27 13:42:45 bouyer Exp $ */

#ifndef _LOONGSON_BUS_H_
#define	_LOONGSON_BUS_H_

#include <machine/bus_defs.h>

extern struct extent *loongson_io_ex;
extern struct extent *loongson_mem_ex;
extern int	ex_mallocsafe;
extern struct mips_bus_space bonito_iot;
extern struct mips_bus_space bonito_memt;
extern struct mips_bus_dma_tag bonito_dmat;
extern struct mips_pci_chipset bonito_pc;

void    bonito_bus_io_init(bus_space_tag_t, void *);
void    bonito_bus_mem_init(bus_space_tag_t, void *);

#endif /* _LOONGSON_BUS_H_ */

File Added: src/sys/arch/evbmips/loongson/loongson_bus_io.c
/*	$NetBSD: loongson_bus_io.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $	*/

/*-
 * Copyright (c) 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

/*
 * Platform-specific PCI bus I/O support for loongson-based systems
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: loongson_bus_io.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/locore.h>

#include <mips/bonito/bonitoreg.h>

#include <sys/bus.h>

#include <evbmips/loongson/loongson_bus_defs.h>

#define	CHIP			bonito
#define CHIP_IO			/* defined */

#define	CHIP_EX_MALLOC_SAFE(v)	(ex_mallocsafe)
#define	CHIP_EXTENT(v)		(loongson_io_ex)

/* IO region 1 */
#define	CHIP_W1_BUS_START(v)	0x00000000UL
#define	CHIP_W1_BUS_END(v)	0x000fffffUL
#define	CHIP_W1_SYS_START(v)	((u_long)BONITO_PCIIO_BASE)
#define	CHIP_W1_SYS_END(v)	((u_long)BONITO_PCIIO_BASE + 0x000fffffUL)

#include <mips/mips/bus_space_alignstride_chipdep.c>

File Added: src/sys/arch/evbmips/loongson/loongson_bus_mem.c
/*	$NetBSD: loongson_bus_mem.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $	*/

/*-
 * Copyright (c) 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

/*
 * Platform-specific PCI bus memory support for the Gdium Liberty 1000.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: loongson_bus_mem.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/locore.h>

#include <mips/bonito/bonitoreg.h>

#include <sys/bus.h>

#include <evbmips/loongson/loongson_bus_defs.h>

#define	CHIP			bonito
#define	CHIP_MEM		/* defined */

#define	CHIP_EX_MALLOC_SAFE(v)	(ex_mallocsafe)
#define	CHIP_MEM_EXTENT(v)	(loongson_mem_ex)

/*
 * There are actually 3 PCILO memory windows, but PMON configures them
 * so that they map PCI memory space contiguously.
 */

/* MEM region 1 */
#define	CHIP_W1_BUS_START(v)	0x00000000UL
#define	CHIP_W1_BUS_END(v)	0x0bffffffUL
#define	CHIP_W1_SYS_START(v)	((u_long)BONITO_PCILO_BASE)
#define	CHIP_W1_SYS_END(v)	((u_long)BONITO_PCILO_BASE + 0x0bffffffUL)

#ifdef _LP64 /* XXX per-cpu type ! */
/* MEM region 2 */
#define	CHIP_W2_BUS_START(v)	0x20000000UL
#define	CHIP_W2_BUS_END(v)	0x7fffffffUL
#if 1
#define	CHIP_W2_SYS_START(v)	((u_long)BONITO_PCIHI_BASE)
#define	CHIP_W2_SYS_END(v)	((u_long)BONITO_PCIHI_BASE + 0xe0000000UL)
#else
#define	CHIP_W2_SYS_START(v)	((u_long)0)
#define	CHIP_W2_SYS_END(v)	((u_long)BONITO_PCIHI_BASE + 0xe0000000UL)
#endif
#endif

#include <mips/mips/bus_space_alignstride_chipdep.c>

File Added: src/sys/arch/evbmips/loongson/loongson_intr.c
/*      $NetBSD: loongson_intr.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $      */

/*-
 * Copyright (c) 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: loongson_intr.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");

#define __INTR_PRIVATE

#include <sys/param.h>
#include <sys/device.h>
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/bus.h>
#include <sys/malloc.h>

#include <mips/mips3_clock.h>
#include <machine/locore.h>

#include <evbmips/loongson/autoconf.h>
#include <evbmips/loongson/loongson_intr.h>

#include <mips/locore.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

#include <dev/pci/pciidereg.h>
#include <dev/isa/isavar.h>

#include "isa.h"

#ifdef INTR_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif

struct bonito_intrhead bonito_intrhead[BONITO_NINTS];

/*
 * This is a mask of bits to clear in the SR when we go to a
 * given hardware interrupt priority level.
 */
static const struct ipl_sr_map loongson_ipl_sr_map = {
    .sr_bits = {
	[IPL_NONE] =		0,
	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1,
	[IPL_VM] =
	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
	    MIPS_INT_MASK_0 |
	    MIPS_INT_MASK_1 |
	    MIPS_INT_MASK_2 |
	    MIPS_INT_MASK_3 |
	    MIPS_INT_MASK_4,
	[IPL_SCHED] =
	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
	    MIPS_INT_MASK_0 |
	    MIPS_INT_MASK_1 |
	    MIPS_INT_MASK_2 |
	    MIPS_INT_MASK_3 |
	    MIPS_INT_MASK_4 |
	    MIPS_INT_MASK_5,
	[IPL_DDB] =		MIPS_INT_MASK,
	[IPL_HIGH] =            MIPS_INT_MASK,
    },
};


void
evbmips_intr_init(void)
{
	const struct bonito_config * const bc = sys_platform->bonito_config;
	const struct bonito_irqmap *irqmap;
	int i;

	ipl_sr_map = loongson_ipl_sr_map;

	for (i = 0; i < BONITO_NDIRECT; i++) {
		irqmap = &sys_platform->irq_map[i];
		if (irqmap->name == NULL)
			continue;
		DPRINTF(("attach %d %s\n", i, irqmap->name));
		evcnt_attach_dynamic(&bonito_intrhead[i].intr_count,
		    EVCNT_TYPE_INTR, NULL, "bonito", irqmap->name);
		LIST_INIT(&bonito_intrhead[i].intrhand_head);
	}

	REGVAL(BONITO_GPIOIE) = bc->bc_gpioIE;
	REGVAL(BONITO_INTEDGE) = bc->bc_intEdge;
	/* REGVAL(BONITO_INTSTEER) = bc->bc_intSteer; XXX */
	REGVAL(BONITO_INTPOL) = bc->bc_intPol;
	REGVAL(BONITO_INTENCLR) = 0xffffffff;
	(void)REGVAL(BONITO_INTENCLR);

	if (sys_platform->isa_chipset != NULL) {
		int irq;
		static char irqstr[8];
		for (irq = 0; irq < BONITO_NISA; irq++) {
			i = BONITO_ISA_IRQ(irq);
			sprintf(irqstr, "irq %d", irq);
			DPRINTF(("attach %d %d %s\n", i, irq, irqstr));
			evcnt_attach_dynamic(&bonito_intrhead[i].intr_count,
			    EVCNT_TYPE_INTR, NULL, "isa", irqstr);
			LIST_INIT(&bonito_intrhead[i].intrhand_head);
		}
	}
}

void
evbmips_iointr(int ppl, vaddr_t pc, uint32_t ipending)
{
	struct evbmips_intrhand *ih;
	int irq;
	uint32_t isr0, isr, imr;

	/*
	 * Read the interrupt pending registers, mask them with the
	 * ones we have enabled, and service them in order of decreasing
	 * priority.
	 */
	isr0 = REGVAL(BONITO_INTISR);
	imr = REGVAL(BONITO_INTEN);

	if (ipending & sys_platform->bonito_mips_intr) {
		isr = isr0 & imr & LOONGSON_INTRMASK_LVL4;

		REGVAL(BONITO_INTENCLR) = isr;
		(void)REGVAL(BONITO_INTENCLR);

		for (irq = 0; irq < BONITO_NINTS; irq++) {
			if ((isr & (1 << irq)) == 0)
				continue;
			bonito_intrhead[irq].intr_count.ev_count++;
			LIST_FOREACH (ih,
			    &bonito_intrhead[irq].intrhand_head, ih_q) {
				(*ih->ih_func)(ih->ih_arg);
			}
		}
		REGVAL(BONITO_INTENSET) = isr;
		(void)REGVAL(BONITO_INTENSET);
	}
	if (isr0 & LOONGSON_INTRMASK_INT0)
		sys_platform->isa_intr(ppl, pc, ipending);
}

void *
loongson_pciide_compat_intr_establish(void *v, struct device *dev,
    const struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
{
	pci_chipset_tag_t pc = pa->pa_pc; 
	void *cookie;
	int bus, irq;

	pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);

	/*
	 * If this isn't PCI bus #0, all bets are off.
	 */
	if (bus != 0)
		return (NULL);

	irq = PCIIDE_COMPAT_IRQ(chan);
#if NISA > 0
	if (sys_platform->isa_chipset != NULL)
		cookie = isa_intr_establish(sys_platform->isa_chipset, irq,
		    IST_EDGE, IPL_BIO, func, arg);
	else
#endif
		cookie = NULL;
	if (cookie == NULL)
		return (NULL);
	printf("%s: %s channel interrupting at %s\n", dev->dv_xname,
	    PCIIDE_CHANNEL_NAME(chan),
	    isa_intr_string(sys_platform->isa_chipset, irq));
	return (cookie);
}

int
loongson_pci_intr_map(const struct pci_attach_args *pa,
    pci_intr_handle_t *ihp)
{
	pcitag_t bustag = pa->pa_intrtag;
	int buspin = pa->pa_intrpin;
	pci_chipset_tag_t pc = pa->pa_pc;
	int device, function;

	if (buspin == 0) {
		/* No IRQ used. */
		return (1);
	}

	if (buspin > 4) {
		printf("loongson_pci_intr_map: bad interrupt pin %d\n",
		    buspin);
		return (1);
	}

	pci_decompose_tag(pc, bustag, NULL, &device, &function);
	return (sys_platform->p_pci_intr_map(device, function, buspin, ihp));
}

const char *
loongson_pci_intr_string(void *v, pci_intr_handle_t ih)
{
	
	const struct bonito_config *bc = v;
	return loongson_intr_string(bc, ih);
}

const struct evcnt *
loongson_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
{

	return &bonito_intrhead[ih].intr_count;
}

void *
loongson_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
    int (*func)(void *), void *arg)
{
	if (BONITO_IRQ_IS_ISA(ih)) {
		if (sys_platform->isa_chipset == NULL)
			panic("ISA interrupt on non-ISA platform");
		return sys_platform->isa_chipset->ic_intr_establish(v,
		    BONITO_IRQ_TO_ISA(ih), IST_EDGE, level, func, arg);
	}
	return evbmips_intr_establish(ih, func, arg);
}

void
loongson_pci_intr_disestablish(void *v, void *cookie)
{
	struct evbmips_intrhand *ih = cookie;
	if (BONITO_IRQ_IS_ISA(ih->ih_irq)) {
		if (sys_platform->isa_chipset == NULL)
			panic("ISA interrupt on non-ISA platform");
		sys_platform->isa_chipset->ic_intr_disestablish(v, ih);
		return;
	}
	return (evbmips_intr_disestablish(cookie));
}

void
loongson_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
    int *iline)
{

	/*
	 * We actually don't need to do anything; everything is handled
	 * in pci_intr_map().
	 */
	*iline = 0;
}


void *
evbmips_intr_establish(int irq, int (*func)(void *), void *arg)
{
	struct evbmips_intrhand *ih;
	int s;

	KASSERT(irq < BONITO_NINTS);
	DPRINTF(("loongson_intr_establish %d %p", irq, func));

	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT|M_ZERO);
	if (ih == NULL)
		return NULL;

	ih->ih_func = func;
	ih->ih_arg = arg;
	ih->ih_irq = irq;
	DPRINTF((" ih %p", ih));

	/* link it into tables */
	s = splhigh();
	LIST_INSERT_HEAD(&bonito_intrhead[irq].intrhand_head, ih, ih_q);
	/* and enable it */
	DPRINTF((" inten 0x%x", REGVAL(BONITO_INTEN)));
	if (bonito_intrhead[irq].refcnt++ == 0 && !BONITO_IRQ_IS_ISA(irq))
		REGVAL(BONITO_INTENSET) = (1 << ih->ih_irq);
	DPRINTF((" now 0x%x\n", REGVAL(BONITO_INTEN)));
	splx(s);

	return (ih);
}

void
evbmips_intr_disestablish(void *cookie)
{
	struct evbmips_intrhand *ih = cookie;
	int s;

	s = splhigh();
	LIST_REMOVE(ih, ih_q);
	bonito_intrhead[ih->ih_irq].refcnt--;
	if (bonito_intrhead[ih->ih_irq].refcnt == 0 &&
	    !BONITO_IRQ_IS_ISA(ih->ih_irq))
		REGVAL(BONITO_INTENCLR) = (1 << ih->ih_irq);
	splx(s);
	free(ih, M_DEVBUF);
}

const char *
loongson_intr_string(const struct bonito_config *bc, int irq)
{
	static char irqstr[12]; /* 8 + 2 + NULL + sanity */
	if (BONITO_IRQ_IS_ISA(irq)) {
		sprintf(irqstr, "isa irq %d", BONITO_IRQ_TO_ISA(irq));
		return irqstr;
	}
	return sys_platform->irq_map[irq].name;
}

File Added: src/sys/arch/evbmips/loongson/loongson_intr.h
/*	$NetBSD: loongson_intr.h,v 1.1 2011/08/27 13:42:45 bouyer Exp $	*/

/*-
 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

#ifndef _LOONGSON_INTR_H_
#define	_LOONGSON_INTR_H_

#include <machine/intr.h>
#include <mips/bonito/bonitoreg.h>
#include <sys/evcnt.h>

LIST_HEAD(bonito_intrhand_head, evbmips_intrhand);

struct bonito_intrhead {
	struct evcnt intr_count;
	struct bonito_intrhand_head intrhand_head;
	int refcnt;
};
extern struct bonito_intrhead bonito_intrhead[BONITO_NINTS];

/* interrupt mappings */
struct bonito_irqmap {
	const char *name;
	uint8_t irqidx;
	uint8_t flags;
};

#define IRQ_F_INVERT	0x80	/* invert polarity */
#define IRQ_F_EDGE	0x40	/* edge trigger */
#define IRQ_F_INT0	0x00	/* INT0 */
#define IRQ_F_INT1	0x01	/* INT1 */
#define IRQ_F_INT2	0x02	/* INT2 */
#define IRQ_F_INT3	0x03	/* INT3 */
#define IRQ_F_INTMASK	0x07	/* INT mask */

extern const struct bonito_irqmap loongson2e_irqmap[BONITO_NDIRECT];
extern const struct bonito_irqmap loongson2f_irqmap[BONITO_NDIRECT];

int	loongson_pci_intr_map(const struct pci_attach_args *,
	    pci_intr_handle_t *);
const char *loongson_pci_intr_string(void *, pci_intr_handle_t);
const struct evcnt *loongson_pci_intr_evcnt(void *, pci_intr_handle_t);
void *	loongson_pci_intr_establish(void *, pci_intr_handle_t, int,
	    int (*)(void *), void *);
void	loongson_pci_intr_disestablish(void *, void *);
void	loongson_pci_conf_interrupt(void *, int, int, int, int, int *);
void *	loongson_pciide_compat_intr_establish(void *,
	    device_t, const struct pci_attach_args *, int,
	    int (*)(void *), void *);

const char *loongson_intr_string(const struct bonito_config *, int);
#endif /* ! _LOONGSON_INTR_H_ */

File Added: src/sys/arch/evbmips/loongson/loongson_isa.h
/*	$OpenBSD: isa_machdep.h,v 1.2 2010/05/08 21:59:56 miod Exp $	*/

/*
 * Copyright (c) 2007 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice, this permission notice, and the disclaimer below
 * appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef	_LOONGSON_ISA_H_
#define	_LOONGSON_ISA_H_

void	loongson_isa_specific_eoi(int);
void	loongson_set_isa_imr(uint);

extern uint loongson_isaimr;

#endif

File Added: src/sys/arch/evbmips/loongson/machdep.c
/*	$NetBSD: machdep.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $	*/

/*
 * Copyright 2001, 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc.
 *
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed for the NetBSD Project by
 *      Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department, The Mach Operating System project at
 * Carnegie-Mellon University and Ralph Campbell.
 *
 * 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. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
 *
 *	@(#)machdep.c   8.3 (Berkeley) 1/12/94
 *	from: Utah Hdr: machdep.c 1.63 91/04/24
 */

/*
 * Copyright (c) 2009, 2010 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");

#include "opt_ddb.h"
#include "opt_execfmt.h"
#include "opt_modular.h"

#define _MIPS_BUS_DMA_PRIVATE

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/mount.h>
#include <sys/kcore.h>
#include <sys/boot_flag.h>
#include <sys/termios.h>
#include <sys/ksyms.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <dev/cons.h>

#include "ksyms.h"

#if NKSYMS || defined(DDB) || defined(MODULAR)
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
#include <sys/exec_elf.h>
#endif

#include <evbmips/loongson/autoconf.h>
#include <evbmips/loongson/loongson_intr.h>
#include <evbmips/loongson/loongson_bus_defs.h>
#include <machine/cpu.h>
#include <machine/psl.h>

#include <mips/locore.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>
#include <mips/pmon/pmon.h>
#include <dev/pci/sisfb.h>

#include "com.h"
#if NCOM > 0
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#ifdef LOW_DEBUG
#define DPRINTF(x) printf x
#define DPPRINTF(x) pmon_printf x
#else
#define DPRINTF(x)
#define DPPRINTF(x)
#endif

bus_space_tag_t comconsiot;
bus_addr_t comconsaddr;
int comconsrate = 0;
#endif /* NCOM > 0 */

#include "sisfb.h"


int ex_mallocsafe = 0;
struct extent *loongson_io_ex = NULL;
struct extent *loongson_mem_ex = NULL;
struct mips_bus_space bonito_iot;
struct mips_bus_space bonito_memt;
struct mips_bus_dma_tag bonito_dmat;
struct mips_pci_chipset bonito_pc;

uint loongson_ver;

const struct platform *sys_platform;
struct bonito_flavour {
	const char *prefix;
	const struct platform *platform;
};

extern const struct platform fuloong_platform;
extern const struct platform gdium_platform;
extern const struct platform generic2e_platform;
extern const struct platform lynloong_platform;
extern const struct platform yeeloong_platform;

const struct bonito_flavour bonito_flavours[] = {
	/* Lemote Fuloong 2F mini-PC */
	{ "LM6002",	&fuloong_platform }, /* dual Ethernet, no prefix */
	{ "LM6003",	&fuloong_platform },
	{ "LM6004",	&fuloong_platform },
	/* EMTEC Gdium Liberty 1000 */
	{ "Gdium",	&gdium_platform },
	/* Lemote Yeeloong 8.9" netbook */
	{ "LM8089",	&yeeloong_platform },
	/* supposedly Lemote Yeeloong 10.1" netbook, but those found so far
	   report themselves as LM8089 */
	{ "LM8101",	&yeeloong_platform },
	/* Lemote Lynloong all-in-one computer */
	{ "LM9001",	&lynloong_platform },
	{ NULL }
};

/* For sysctl_hw. */
extern char cpu_model[];

/* Maps for VM objects. */
struct vm_map *phys_map = NULL;

int	netboot;		/* Are we netbooting? */

phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
int mem_cluster_cnt;

void	mach_init(int, int32_t, int32_t, int32_t, char *);

static int  pmoncngetc(dev_t);
static void pmoncnputc(dev_t, int);

struct consdev pmoncons = {
        NULL,		/* probe */
	NULL, 		/* init */
	pmoncngetc, 	/* getc */
	pmoncnputc,	/* putc */
	nullcnpollc,	/* poolc */
	NULL,		/* BELL */
	makedev(0, 0),
	CN_DEAD
};

/*
 * Do all the stuff that locore normally does before calling main().
 */
void
mach_init(int32_t argc, int32_t argva, int32_t enva, int32_t callvec,
    char *boot_esym)
{
	void *kernend;
#ifdef NOTYET
	int howto;
#endif
	const char *env;
	int i;
	psize_t memlo, memhi;
	const struct bonito_flavour *f;
	char *ssym = NULL, *esym = NULL;
	pcireg_t reg;
	pcitag_t pcitag;

	extern char edata[], end[];

	/*
	 * Clear the BSS segment.
	 */
	memset(edata, 0, (char *)end - edata);

	pmon_init(argc, argva, enva, callvec);
	DPPRINTF(("pmon hello\n"));

	cn_tab = &pmoncons;

	DPRINTF(("hello 0x%x %d 0x%x 0x%x %p stack %p\n", pmon_callvec, argc, argva, enva, boot_esym, &i));

	/*
	 * Reserve space for the symbol table, if it exists.
	 */

#if NKSYMS || defined(DDB) || defined(MODULAR)
	/* Attempt to locate ELF header and symbol table after kernel. */
	if (end[0] == ELFMAG0 && end[1] == ELFMAG1 &&
	    end[2] == ELFMAG2 && end[3] == ELFMAG3) {
		/* ELF header exists directly after kernel. */
		ssym = end;
		esym = boot_esym;
		kernend = (void *)mips_round_page(esym);
	} else {
		ssym = (char *)(vaddr_t)*(int32_t *)end;
		if (((long)ssym - (long)end) >= 0 &&
		    ((long)ssym - (long)end) <= 0x1000 &&
		    ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 &&
		    ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3) {
			/* Pointers exist directly after kernel. */
			esym = (char *)(vaddr_t)*((int32_t *)end + 1);
			kernend = (void *)mips_round_page(esym);
		} else {
			/* Pointers aren't setup either... */
			ssym = NULL;
			esym = NULL;
			kernend = (void *)mips_round_page(end);
		}
	}
	DPRINTF(("ssym %p esym %p\n", ssym, esym));
#endif

	/*
	 * Set up the exception vectors and CPU-specific function
	 * vectors early on.  We need the wbflush() vector set up
	 * before comcnattach() is called (or at least before the
	 * first printf() after that is called).
	 * Also clears the I+D caches.
	 */
	DPRINTF(("mips_vector_init "));
	mips_vector_init(NULL, false);

	DPRINTF(("uvm_setpagesize\n"));
	/* set the VM page size */
	uvm_setpagesize();
#if NKSYMS || defined(DDB) || defined(MODULAR)
	//ksyms_addsyms_elf((vaddr_t)esym - (vaddr_t)ssym, ssym, esym);
#endif

	/*
	 * Try and figure out what kind of hardware we are.
	 */

	env = pmon_getenv("systype");
	if (env == NULL) {
		printf("Unable to figure out system type!\n");
		goto unsupported;
	}
	if (strcmp(env, "Bonito") != 0) {
		printf("This kernel doesn't support system type \"%s\".\n",
		    env);
		goto unsupported;
	}

	/*
	 * While the kernel supports other processor types than Loongson,
	 * we are not expecting a Bonito-based system with a different
	 * processor.  Just to be on the safe side, refuse to run on
	 * non Loongson2 processors for now.
	 */

	switch ((mips_options.mips_cpu_id >> 8) & 0xff) {
	case MIPS_LOONGSON2:
		switch (mips_options.mips_cpu_id & 0xff) {
		case 0x00:
			loongson_ver = 0x2c;
			break;
		case 0x02:
			loongson_ver = 0x2e;
			break;
		case 0x03:
			loongson_ver = 0x2f;
			break;
		case 0x05:
			loongson_ver = 0x3a;
			break;
		}
		if (loongson_ver == 0x2e || loongson_ver == 0x2f)
			break;
		/* FALLTHROUGH */
	default:
		printf("This kernel doesn't support processor type 0x%x"
		    ", version %d.%d.\n",
		    (mips_options.mips_cpu_id >> 8) & 0xff,
		    (mips_options.mips_cpu_id >> 4) & 0x0f,
		    mips_options.mips_cpu_id & 0x0f);
		goto unsupported;
	}

	/*
	 * Try to figure out what particular machine we run on, depending
	 * on the PMON version information.
	 */

	env = pmon_getenv("Version");
	if (env == NULL) {
		/*
		 * If this is a 2E system, use the generic code and hope
		 * for the best.
		 */
		if (loongson_ver == 0x2e) {
			sys_platform = &generic2e_platform;
		} else {
			printf("Unable to figure out model!\n");
			goto unsupported;
		}
	} else {
		for (f = bonito_flavours; f->prefix != NULL; f++)
			if (strncmp(env, f->prefix, strlen(f->prefix)) ==
			    0) {
				sys_platform = f->platform;
				break;
			}

		if (sys_platform == NULL) {
			/*
			 * Early Lemote designs shipped without a model prefix.
			 * Hopefully these well be close enough to the first
			 * generation Fuloong 2F design (LM6002); let's warn
			 * the user and try this if version is 1.2.something
			 * (1.3 onwards are expected to have a model prefix,
			 *  and there are currently no reports of 1.1 and
			 *  below being 2F systems).
			 *
			 * Note that this could be handled by adding a
			 * "1.2." machine type entry to the flavours table,
			 * but I prefer have it stand out.
			 * LM6002 users are encouraged to add the system
			 * model prefix to the `Version' variable.
			 */
			if (strncmp(env, "1.2.", 4) == 0) {
				printf("No model prefix in version"
				    " string \"%s\".\n"
				    "Attempting to match as Lemote Fuloong\n",
				    env);
				sys_platform = &fuloong_platform;
			}
		}

		if (sys_platform == NULL) {
			printf("This kernel doesn't support model \"%s\"."
			    "\n", env);
			goto unsupported;
		}
	}

	sprintf(cpu_model, "%s %s", sys_platform->vendor, 
	    sys_platform->product);
	DPRINTF(("Found %s, setting up.\n", cpu_model));

	/*
	 * Figure out memory information.
	 * PMON reports it in two chunks, the memory under the 256MB
	 * CKSEG limit, and memory above that limit.  We need to do the
	 * math ourselves.
	 */

	env = pmon_getenv("memsize");
	if (env == NULL) {
		printf("Could not get memory information"
		    " from the firmware\n");
		goto unsupported;
	}
	memlo = strtoul(env, NULL, 10);	/* size in MB */
	DPRINTF(("memlo %" PRIdPSIZE, memlo));
	if (memlo < 0 || memlo > 256) {
		printf("Incorrect low memory size `%s'\n", env);
		goto unsupported;
	}

	/* 3A PMON only reports up to 240MB as low memory */
	if (memlo >= 240) {
		env = pmon_getenv("highmemsize");
		if (env == NULL)
			memhi = 0;
		else
			memhi = strtoul(env, NULL, 10);	/* size in MB */
		if (memhi < 0 || memhi > (64 * 1024) - 256) {
			printf("Incorrect high memory size `%s'\n",
			    env);
			/* better expose the problem than limit to 256MB */
			goto unsupported;
		}
	} else
		memhi = 0;

	DPRINTF(("memhi %" PRIdPSIZE "\n", memhi));
	memlo = memlo * 1024 * 1024;
	memhi = memhi * 1024 * 1024;

	switch (loongson_ver) {
	case 0x2e:
		loongson2e_setup(memlo, memhi,
		    MIPS_KSEG0_START, (vaddr_t)kernend, &bonito_dmat);
		break;
	default:
	case 0x2f:
	case 0x3a:
		loongson2f_setup(memlo, memhi,
		    MIPS_KSEG0_START, (vaddr_t)kernend, &bonito_dmat);
		break;
	}

	DPRINTF(("bonito_pci_init "));
	bonito_pci_init(&bonito_pc, sys_platform->bonito_config);
	bonito_pc.pc_intr_v = __UNCONST(sys_platform->bonito_config);
	bonito_pc.pc_intr_map = loongson_pci_intr_map;
	bonito_pc.pc_intr_string = loongson_pci_intr_string;
	bonito_pc.pc_intr_evcnt = loongson_pci_intr_evcnt;
	bonito_pc.pc_intr_establish = loongson_pci_intr_establish;
	bonito_pc.pc_intr_disestablish = loongson_pci_intr_disestablish;
	bonito_pc.pc_conf_interrupt = loongson_pci_conf_interrupt;
	bonito_pc.pc_pciide_compat_intr_establish =
	    loongson_pciide_compat_intr_establish;
	DPRINTF(("bonito_bus_io_init "));
	bonito_bus_io_init(&bonito_iot, NULL);
	DPRINTF(("bonito_bus_mem_init\n"));
	bonito_bus_mem_init(&bonito_memt, NULL);

	bonito_dmat._cookie = __UNCONST(sys_platform);
	bonito_dmat._dmamap_ops = mips_bus_dmamap_ops;
	bonito_dmat._dmamem_ops = mips_bus_dmamem_ops;
	bonito_dmat._dmatag_ops = mips_bus_dmatag_ops;

	DPRINTF(("sys_platform->setup %p\n", sys_platform->setup));
	if (sys_platform->setup != NULL)
		(*(sys_platform->setup))();

#if NCOM > 0
	DPRINTF(("comconsrate %d\n", comconsrate));
	if (comconsrate > 0) {
		if (comcnattach(comconsiot, comconsaddr, comconsrate,
		    COM_FREQ, COM_TYPE_NORMAL,
		    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8) != 0)
			panic("unable to initialize serial console");
	}
#endif /* NCOM > 0 */

	for (i = 0; i < 32 - 0x11; i++) {
		pcitag = pci_make_tag(&bonito_pc, 0, i, 0);
		reg = pci_conf_read(&bonito_pc, pcitag, PCI_CLASS_REG);
		DPRINTF(("dev %d class 0x%x", i, reg));
		reg = pci_conf_read(&bonito_pc, pcitag, PCI_ID_REG);
		DPRINTF((" id 0x%x; ", reg));
#if NSISFB > 0
		if (cn_tab == &pmoncons)
			sisfb_cnattach(&bonito_memt, &bonito_iot, &bonito_pc, 
			    pcitag, reg);
#endif
	}
	DPRINTF(("\n"));

	/*
	 * Get the timer from PMON.
	 */
	DPRINTF(("search cpuclock "));
	env = pmon_getenv("cpuclock");
	DPRINTF(("got %s ", env));
	if (env != NULL) {
		curcpu()->ci_cpu_freq =
		    strtoul(env, NULL, 10);
	}
	
	DPRINTF(("cpuclock %ld\n", curcpu()->ci_cpu_freq));

	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
		curcpu()->ci_cpu_freq /= 2;


	/* Compute the number of ticks for hz. */
	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;

	/* Compute the delay divisor. */
	curcpu()->ci_divisor_delay =
	    ((curcpu()->ci_cpu_freq + 500000) / 1000000);

	/*
	 * Get correct cpu frequency if the CPU runs at twice the
	 * external/cp0-count frequency.
	 */
	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT)
		curcpu()->ci_cpu_freq *= 2;

#ifdef DEBUG
	printf("Timer calibration: %lu cycles/sec\n",
	    curcpu()->ci_cpu_freq);
#endif

#if NCOM > 0 && 0
	/*
	 * Delay to allow firmware putchars to complete.
	 * FIFO depth * character time.
	 * character time = (1000000 / (defaultrate / 10))
	 */
	delay(160000000 / comcnrate);
	if (comcnattach(&gc->gc_iot, MALTA_UART0ADR, comcnrate,
	    COM_FREQ, COM_TYPE_NORMAL,
	    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8) != 0)
		panic("malta: unable to initialize serial console");
#endif /* NCOM > 0 */

	/*
	 * XXX: check argv[0] - do something if "gdb"???
	 */

	/*
	 * Look at arguments passed to us and compute boothowto.
	 */
	boothowto = RB_AUTOBOOT;
#ifdef NOTYET
	for (i = 1; i < argc; i++) {
		for (cp = argv[i]; *cp; cp++) {
			/* Ignore superfluous '-', if there is one */
			if (*cp == '-')
				continue;

			howto = 0;
			BOOT_FLAG(*cp, howto);
			if (! howto)
				printf("bootflag '%c' not recognised\n", *cp);
			else
				boothowto |= howto;
		}
	}
#endif

	/*
	 * Load the rest of the available pages into the VM system.
	 */
	mips_page_physload(MIPS_KSEG0_START, (vaddr_t)kernend,
	    mem_clusters, mem_cluster_cnt, NULL, 0);

	/*
	 * Initialize error message buffer (at end of core).
	 */
	DPRINTF(("mips_init_msgbuf\n"));
	mips_init_msgbuf();

	DPRINTF(("pmap_bootstrap\n"));
	pmap_bootstrap();

	/*
	 * Allocate uarea page for lwp0 and set it.
	 */
	DPRINTF(("curlwp %p ", curlwp));
	DPRINTF(("curlwp stack %p\n", curlwp->l_addr));
	mips_init_lwp0_uarea();

	DPRINTF(("curlwp %p ", curlwp));
	DPRINTF(("curlwp stack %p\n", curlwp->l_addr));

	/*
	 * Initialize debuggers, and break into them, if appropriate.
	 */
#if defined(DDB)
	if (boothowto & RB_KDB)
		Debugger();
#endif
	DPRINTF(("return\n"));
	return;
unsupported:
	panic("unsupported hardware\n");
}

void
consinit(void)
{

	/*
	 * Everything related to console initialization is done
	 * in mach_init().
	 */
}

/*
 * Allocate memory for variable-sized tables,
 */
void
cpu_startup(void)
{
	/*
	 *  Do the common startup items.
	 */
	cpu_startup_common();

	/*
	 * Virtual memory is bootstrapped -- notify the bus spaces
	 * that memory allocation is now safe.
	 */
	ex_mallocsafe = 1;

}

int	waittime = -1;

void
cpu_reboot(int howto, char *bootstr)
{

	/* Take a snapshot before clobbering any registers. */
	savectx(curpcb);

	if (cold) {
		howto |= RB_HALT;
		goto haltsys;
	}

	/* If "always halt" was specified as a boot flag, obey. */
	if (boothowto & RB_HALT)
		howto |= RB_HALT;

	boothowto = howto;
	if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) {
		waittime = 0;
		vfs_shutdown();

		/*
		 * If we've been adjusting the clock, the todr
		 * will be out of synch; adjust it now.
		 */
		resettodr();
	}

	splhigh();

	if (howto & RB_DUMP)
		dumpsys();

haltsys:
	doshutdownhooks();

	pmf_system_shutdown(boothowto);

	if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
		if (sys_platform->powerdown != NULL)
			sys_platform->powerdown();
	}

	if (howto & RB_HALT) {
		printf("\n");
		printf("The operating system has halted.\n");
		printf("Please press any key to reboot.\n\n");
		cnpollc(1);	/* For proper keyboard command handling */
		cngetc();
		cnpollc(0);
	}

	printf("%s\n\n", ((howto & RB_HALT) != 0) ? "halted." : "rebooting...");

	if (sys_platform->reset != NULL)
		sys_platform->reset();

	__asm__ __volatile__ (
		"\t.long 0x3c02bfc0\n"
		"\t.long 0x00400008\n"
	    ::: "v0");
}

/*
 * Early console through pmon routines.
 */

int
pmoncngetc(dev_t dev)
{
	/*
	 * PMON does not give us a getc routine.  So try to get a whole line
	 * and return it char by char, trying not to lose the \n.  Kind
	 * of ugly but should work.
	 *
	 * Note that one could theoretically use pmon_read(STDIN, &c, 1)
	 * but the value of STDIN within PMON is not a constant and there
	 * does not seem to be a way of letting us know which value to use.
	 */
	static char buf[1 + PMON_MAXLN];
	static char *bufpos = buf;
	int c;

	if (*bufpos == '\0') {
		bufpos = buf;
		if (pmon_gets(buf) == NULL) {
			/* either an empty line or EOF. assume the former */
			return (int)'\n';
		} else {
			/* put back the \n sign */
			buf[strlen(buf)] = '\n';
		}
	}

	c = (int)*bufpos++;
	if (bufpos - buf > PMON_MAXLN) {
		bufpos = buf;
		*bufpos = '\0';
	}

	return c;
}

void
pmoncnputc(dev_t dev, int c)
{
	if (c == '\n')
		pmon_printf("\n");
	else
		pmon_printf("%c", c);
}

File Added: src/sys/arch/evbmips/loongson/mainbus.c
/*	$NetBSD: mainbus.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $	*/

/*
 * Copyright 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Simon Burge for Wasabi Systems, Inc.
 *
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed for the NetBSD Project by
 *      Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");

#include "opt_pci.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#if defined(PCI_NETBSD_CONFIGURE)
#include <sys/extent.h>
#include <sys/malloc.h>
#endif

#include <dev/pci/pcivar.h>
#if defined(PCI_NETBSD_CONFIGURE)
#include <dev/pci/pciconf.h>
#endif

#include <mips/cache.h>
#include <mips/cpuregs.h>

#include <mips/bonito/bonitoreg.h>

#include <evbmips/loongson/autoconf.h>

#include "locators.h"
#include "pci.h"

static int	mainbus_match(device_t, cfdata_t, void *);
static void	mainbus_attach(device_t, device_t, void *);
static int	mainbus_print(void *, const char *);

CFATTACH_DECL_NEW(mainbus, 0,
    mainbus_match, mainbus_attach, NULL, NULL);

/* There can be only one. */
static bool mainbus_found;

const char * const mainbusdevs[] = {
	"cpu",
	"bonito",
#if 0
	"i2c",
	"gpio",
#endif
};

static int
mainbus_match(device_t parent, cfdata_t match, void *aux)
{
	if (mainbus_found)
		return (0);

	return (1);
}

static void
mainbus_attach(device_t parent, device_t self, void *aux)
{
	size_t i;

	mainbus_found = true;
	aprint_normal("\n");

#if defined(PCI_NETBSD_CONFIGURE)
	{
		struct extent *ioext, *memext;

		ioext = extent_create("pciio",  0x00001000, 0x00003fff,
		    M_DEVBUF, NULL, 0, EX_NOWAIT);
		memext = extent_create("pcimem", 0, BONITO_PCILO_SIZE,
		    M_DEVBUF, NULL, 0, EX_NOWAIT);

		pci_configure_bus(&gdium_configuration.gc_pc, ioext, memext,
		    NULL, 0, mips_dcache_align);
		extent_destroy(ioext);
		extent_destroy(memext);
	}
#endif /* PCI_NETBSD_CONFIGURE */

	for (i = 0; i < __arraycount(mainbusdevs); i++) {
		struct mainbus_attach_args maa;
		maa.maa_name = mainbusdevs[i];
		(void) config_found(self, &maa, mainbus_print);
	}
}

static int
mainbus_print(void *aux, const char *pnp)
{
	struct mainbus_attach_args *maa = aux;

	if (pnp)
		aprint_normal("%s at %s", maa->maa_name, pnp);

	return UNCONF;
}

File Added: src/sys/arch/evbmips/loongson/yeeloong_machdep.c
/*	$OpenBSD: yeeloong_machdep.c,v 1.16 2011/04/15 20:40:06 deraadt Exp $	*/

/*
 * Copyright (c) 2009, 2010 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Lemote {Fu,Lyn,Yee}loong specific code and configuration data.
 * (this file really ought to be named lemote_machdep.c by now)
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/types.h>

#include <evbmips/loongson/autoconf.h>
#include <mips/pmon/pmon.h>
#include <evbmips/loongson/loongson_intr.h>
#include <evbmips/loongson/loongson_bus_defs.h>
#include <evbmips/loongson/loongson_isa.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8259reg.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

#include <evbmips/loongson/dev/kb3310var.h>
#include <evbmips/loongson/dev/glxreg.h>
#include <evbmips/loongson/dev/glxvar.h>

#include "com.h"
#include "isa.h"
#include "ykbec.h"

#if NCOM > 0
#include <sys/termios.h>
#include <dev/ic/comvar.h>
#endif

#ifdef LOW_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif

void	 lemote_device_register(struct device *, void *);
void	 lemote_reset(void);

void	 fuloong_powerdown(void);
void	 fuloong_setup(void);

void	 yeeloong_powerdown(void);

void	 lemote_pci_attach_hook(device_t, device_t,
	    struct pcibus_attach_args *);
int	 lemote_intr_map(int, int, int, pci_intr_handle_t *);

void	 lemote_isa_attach_hook(struct device *, struct device *,
	    struct isabus_attach_args *);
void	*lemote_isa_intr_establish(void *, int, int, int,
	    int (*)(void *), void *);
void	 lemote_isa_intr_disestablish(void *, void *);
const struct evcnt * lemote_isa_intr_evcnt(void *, int);
const char * lemote_isa_intr_string(void *, int);

uint	 lemote_get_isa_imr(void);
uint	 lemote_get_isa_isr(void);
void	 lemote_isa_intr(int, vaddr_t, uint32_t);

const struct bonito_config lemote_bonito = {
	.bc_adbase = 11,

	.bc_gpioIE = LOONGSON_INTRMASK_GPIO,
	.bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR |
	    LOONGSON_INTRMASK_PCI_PARERR,
	.bc_intSteer = 0,
	.bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR |
	    LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR |
	    LOONGSON_INTRMASK_INT0 | LOONGSON_INTRMASK_INT1,

	.bc_attach_hook = lemote_pci_attach_hook,
};

const struct legacy_io_range fuloong_legacy_ranges[] = {
	/* isa */
	{ IO_DMAPG + 4,	IO_DMAPG + 4 },
	/* mcclock */
	{ IO_RTC,	IO_RTC + 1 },
	/* pciide */
	{ 0x170,	0x170 + 7 },
	{ 0x1f0,	0x1f0 + 7 },
	{ 0x376,	0x376 },
	{ 0x3f6,	0x3f6 },
	/* com */
	{ IO_COM1,	IO_COM1 + 8 },		/* IR port */
	{ IO_COM2,	IO_COM2 + 8 },		/* serial port */

	{ 0 }
};

const struct legacy_io_range lynloong_legacy_ranges[] = {
	/* isa */
	{ IO_DMAPG + 4,	IO_DMAPG + 4 },
	/* mcclock */
	{ IO_RTC,	IO_RTC + 1 },
	/* pciide */
	{ 0x170,	0x170 + 7 },
	{ 0x1f0,	0x1f0 + 7 },
	{ 0x376,	0x376 },
	{ 0x3f6,	0x3f6 },
#if 0	/* no external connector */
	/* com */
	{ IO_COM2,	IO_COM2 + 8 },
#endif

	{ 0 }
};

const struct legacy_io_range yeeloong_legacy_ranges[] = {
	/* isa */
	{ IO_DMAPG + 4,	IO_DMAPG + 4 },
	/* pckbc */
	{ IO_KBD,	IO_KBD },
	{ IO_KBD + 4,	IO_KBD + 4 },
	/* mcclock */
	{ IO_RTC,	IO_RTC + 1 },
	/* pciide */
	{ 0x170,	0x170 + 7 },
	{ 0x1f0,	0x1f0 + 7 },
	{ 0x376,	0x376 },
	{ 0x3f6,	0x3f6 },
	/* kb3110b embedded controller */
	{ 0x381,	0x383 },

	{ 0 }
};

struct mips_isa_chipset lemote_isa_chipset = {
	.ic_v = NULL,

	.ic_attach_hook = lemote_isa_attach_hook,
	.ic_intr_establish = lemote_isa_intr_establish,
	.ic_intr_disestablish = lemote_isa_intr_disestablish,
	.ic_intr_evcnt = lemote_isa_intr_evcnt,
	.ic_intr_string = lemote_isa_intr_string,
};

const struct platform fuloong_platform = {
	.system_type = LOONGSON_FULOONG,
	.vendor = "Lemote",
	.product = "Fuloong",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = fuloong_legacy_ranges,
	.bonito_mips_intr = MIPS_INT_MASK_4,
	.isa_mips_intr = MIPS_INT_MASK_0,
	.isa_intr = lemote_isa_intr,
	.p_pci_intr_map = lemote_intr_map,
	.irq_map =loongson2f_irqmap,

	.setup = fuloong_setup,
	.device_register = lemote_device_register,

	.powerdown = fuloong_powerdown,
	.reset = lemote_reset
};

const struct platform lynloong_platform = {
	.system_type = LOONGSON_LYNLOONG,
	.vendor = "Lemote",
	.product = "Lynloong",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = lynloong_legacy_ranges,
	.bonito_mips_intr = MIPS_INT_MASK_4,
	.isa_mips_intr = MIPS_INT_MASK_0,
	.isa_intr = lemote_isa_intr,
	.p_pci_intr_map = lemote_intr_map,
	.irq_map =loongson2f_irqmap,

	.setup = fuloong_setup,
	.device_register = lemote_device_register,

	.powerdown = fuloong_powerdown,
	.reset = lemote_reset
};

const struct platform yeeloong_platform = {
	.system_type = LOONGSON_YEELOONG,
	.vendor = "Lemote",
	.product = "Yeeloong",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = yeeloong_legacy_ranges,
	.bonito_mips_intr = MIPS_INT_MASK_4,
	.isa_mips_intr = MIPS_INT_MASK_0,
	.isa_intr = lemote_isa_intr,
	.p_pci_intr_map = lemote_intr_map,
	.irq_map =loongson2f_irqmap,

	.setup = NULL,
	.device_register = lemote_device_register,

	.powerdown = yeeloong_powerdown,
	.reset = lemote_reset,
#if NYKBEC > 0
	.suspend = ykbec_suspend,
	.resume = ykbec_resume
#endif
};

static int stray_intr[BONITO_NISA];

/*
 * PCI model specific routines
 */

void
lemote_pci_attach_hook(device_t parent, device_t self,
    struct pcibus_attach_args *pba)
{
	pci_chipset_tag_t pc = pba->pba_pc;
	pcireg_t id;
	pcitag_t tag;
	int dev, i;

	if (pba->pba_bus != 0)
		return;

	/*
	 * Check for an AMD CS5536 chip; if one is found, register
	 * the proper PCI configuration space hooks.
	 */

	for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
		tag = pci_make_tag(pc, 0, dev, 0);
		id = pci_conf_read(pc, tag, PCI_ID_REG);
		DPRINTF(("lemote_pci_attach_hook id 0x%x\n", id));
		if (id == PCI_ID_CODE(PCI_VENDOR_AMD,
		    PCI_PRODUCT_AMD_CS5536_PCISB)) {
			glx_init(pc, tag, dev);
			break;
		}
	}
	wrmsr(GCSC_PIC_SHDW, 0);
	DPRINTF(("PMON setup picregs:"));
	for (i = 0; i < 12; i++) {
		if (i == 6)
			DPRINTF((" | "));
		DPRINTF((" 0x%x", (uint32_t)(rdmsr(GCSC_PIC_SHDW) & 0xff)));
	}
	DPRINTF(("\n"));
	DPRINTF(("intsel 0x%x 0x%x\n", REGVAL8(BONITO_PCIIO_BASE + 0x4d0),
	    REGVAL8(BONITO_PCIIO_BASE + 0x4d1)));
	/* setup legacy interrupt controller */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1) = 0xff;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW1) =
	    ICW1_SELECT | ICW1_IC4;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW2) = ICW2_VECTOR(0);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW3) = ICW3_CASCADE(2);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_ICW4) = ICW4_8086;
	delay(100);
	/* mask all interrupts */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW1) = 0xff;

	/* read ISR by default. */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3) =
	    OCW3_SELECT | OCW3_RR;
	(void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + PIC_OCW3);

	/* reset; program device, four bytes */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1) = 0xff;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW1) =
	    ICW1_SELECT | ICW1_IC4;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW2) = ICW2_VECTOR(8);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW3) = ICW3_SIC(2);
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_ICW4) = ICW4_8086;
	delay(100);
	/* leave interrupts masked */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW1) = 0xff;
	/* read ISR by default. */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3) =
	    OCW3_SELECT | OCW3_RR;
	(void)REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + PIC_OCW3);
}

int
lemote_intr_map(int dev, int fn, int pin, pci_intr_handle_t *ihp)
{
	switch (dev) {
	/* onboard devices, only pin A is wired */
	case 6:
	case 7:
	case 8:
	case 9:
		if (pin == PCI_INTERRUPT_PIN_A) {
			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
			    (dev - 6));
			return 0;
		}
		break;
	/* PCI slot */
	case 10:
		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
		    (pin - PCI_INTERRUPT_PIN_A));
		return 0;
	/* Geode chip */
	case 14:
		switch (fn) {
		case 1:	/* Flash */
			*ihp = BONITO_ISA_IRQ(6);
			return 0;
		case 3:	/* AC97 */
			*ihp = BONITO_ISA_IRQ(9);
			return 0;
		case 4:	/* OHCI */
		case 5:	/* EHCI */
			*ihp = BONITO_ISA_IRQ(11);
			return 0;
		}
		break;
	default:
		break;
	}

	return 1;
}

/*
 * ISA model specific routines
 */

void
lemote_isa_attach_hook(struct device *parent, struct device *self,
    struct isabus_attach_args *iba)
{
	loongson_set_isa_imr(loongson_isaimr);
}

void *
lemote_isa_intr_establish(void *v, int irq, int type, int level,
    int (*handler)(void *), void *arg)
{
	void *ih;
	uint imr;

	ih =  evbmips_intr_establish(BONITO_ISA_IRQ(irq), handler, arg);
	if (ih == NULL)
		return NULL;
	/* enable interrupt */
	imr = lemote_get_isa_imr();
	imr |= (1 << irq);
	DPRINTF(("lemote_isa_intr_establish: enable irq %d 0x%x\n",
	    irq, imr));
	loongson_set_isa_imr(imr);
	return ih;
}

void
lemote_isa_intr_disestablish(void *v, void *ih)
{
	evbmips_intr_disestablish(ih);
}

const struct evcnt *
lemote_isa_intr_evcnt(void *v, int irq)
{

        if (irq == 0 || irq >= BONITO_NISA || irq == 2)
		panic("lemote_isa_intr_evcnt: bogus isa irq 0x%x", irq);

	return (&bonito_intrhead[BONITO_ISA_IRQ(irq)].intr_count);
}

const char *
lemote_isa_intr_string(void *v, int irq)
{
	if (irq == 0 || irq >= BONITO_NISA || irq == 2)
		panic("lemote_isa_intr_string: bogus isa irq 0x%x", irq);

	return loongson_intr_string(&lemote_bonito, BONITO_ISA_IRQ(irq));
}

/*
 * Legacy (ISA) interrupt handling
 */

/*
 * Process legacy interrupts.
 *
 * XXX On 2F, ISA interrupts only occur on LOONGSON_INTR_INT0, but since
 * XXX the other LOONGSON_INTR_INT# are unmaskable, bad things will happen
 * XXX if they ever are triggered...
 */
void
lemote_isa_intr(int ipl, vaddr_t pc, uint32_t ipending)
{
#if NISA > 0
	uint32_t isr, imr, mask;
	int bit;
	struct evbmips_intrhand *ih;
	int rc;
	//int i;

	imr = lemote_get_isa_imr();
	isr = lemote_get_isa_isr() & imr;

	/*
	 * Now process allowed interrupts.
	 */
	if (isr != 0) {
		int bitno, ret;

		/* Service higher level interrupts first */
		bit = BONITO_NISA - 1;
		for (bitno = bit, mask = 1UL << bitno;
		    mask != 0;
		    bitno--, mask >>= 1) {
			if ((isr & mask) == 0)
				continue;
			loongson_isa_specific_eoi(bitno);
			rc = 0;
			LIST_FOREACH(ih,
			    &bonito_intrhead[BONITO_ISA_IRQ(bitno)].intrhand_head,
			    ih_q) {
				ret = (*ih->ih_func)(ih->ih_arg);
				if (ret) {
					rc = 1;
					bonito_intrhead[BONITO_ISA_IRQ(bitno)].intr_count.ev_count++;
				}
			}
			if (rc == 0) {
				if (stray_intr[bitno]++ & 0x10000) {
					printf("spurious isa interrupt %d\n",
					    bitno);
					stray_intr[bitno] = 0;
				}
			}

			if ((isr ^= mask) == 0)
				break;
		}

		/*
		 * Reenable interrupts which have been serviced.
		 */
		loongson_set_isa_imr(imr);
	}

#endif
	return;
}

uint
lemote_get_isa_imr()
{
	uint imr1, imr2;

	imr1 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1);
	imr1 &= ~(1 << 2);	/* hide cascade */
	imr2 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1);

	return (imr2 << 8) | imr1;
}

uint
lemote_get_isa_isr()
{
	uint isr1, isr2 = 0;

	isr1 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU1);
	isr1 &= ~(1<<2);
	isr2 = REGVAL8(BONITO_PCIIO_BASE + IO_ICU2);

	return (isr1 | (isr2 << 8));
}

/*
 * Other model specific routines
 */

void
fuloong_powerdown()
{
	vaddr_t gpiobase;

	gpiobase = BONITO_PCIIO_BASE + (rdmsr(GCSC_DIVIL_LBAR_GPIO) & 0xff00);
	/* enable GPIO 13 */
	REGVAL(gpiobase + GCSC_GPIOL_OUT_EN) = GCSC_GPIO_ATOMIC_VALUE(13, 1);
	/* set GPIO13 value to zero */
	REGVAL(gpiobase + GCSC_GPIOL_OUT_VAL) = GCSC_GPIO_ATOMIC_VALUE(13, 0);
}

void
yeeloong_powerdown()
{
	REGVAL(BONITO_GPIODATA) &= ~0x00000001;
	REGVAL(BONITO_GPIOIE) &= ~0x00000001;
}

void
lemote_reset()
{
	wrmsr(GCSC_GLCP_SYS_RST, rdmsr(GCSC_GLCP_SYS_RST) | 1);
}

void
fuloong_setup(void)
{
#if NCOM > 0
	const char *envvar;
	int serial;

	envvar = pmon_getenv("nokbd");
	serial = envvar != NULL;
	envvar = pmon_getenv("novga");
	serial = serial && envvar != NULL;

	//serial = 1; /* XXXXXX */
	if (serial) {
                comconsiot = &bonito_iot;
                comconsaddr = 0x2f8;
                comconsrate = 115200; /* default PMON console speed */
	}
#endif
}

void
lemote_device_register(struct device *dev, void *aux)
{
	const char *name = device_xname(dev);

	if (dev->dv_class != bootdev_class)
		return;	

	/* 
	 * The device numbering must match. There's no way
	 * pmon tells us more info. Depending on the usb slot
	 * and hubs used you may be lucky. Also, assume umass/sd for usb
	 * attached devices.
	 */
	switch (bootdev_class) {
	case DV_DISK:
		if (device_is_a(dev, "wd") && strcmp(name, bootdev) == 0) {
			if (booted_device == NULL)
				booted_device = dev;
		} else {
			/* XXX this really only works safely for usb0... */
		    	if ((device_is_a(dev, "sd") ||
			    device_is_a(dev, "cd") == 0) &&
			    strncmp(bootdev, "usb", 3) == 0 &&
			    strcmp(name + 2, bootdev + 3) == 0) {
				if (booted_device == NULL)
					booted_device = dev;
			}
		}
		break;
	case DV_IFNET:
		/*
		 * This relies on the onboard Ethernet interface being
		 * attached before any other (usb) interface.
		 */
		if (booted_device == NULL)
			booted_device = dev;
		break;
	default:
		break;
	}
}

File Added: src/sys/arch/evbmips/loongson/dev/gcscpcib_pci.c
/* $NetBSD: gcscpcib_pci.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $ */
/* $OpenBSD: gcscpcib.c,v 1.6 2007/11/17 17:02:47 mbalmer Exp $	*/

/*
 * Copyright (c) 2008 Yojiro UO <yuo@nui.org>
 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
 * Copyright (c) 2007 Michael Shalayeff
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * AMD CS5535/CS5536 series LPC bridge also containing timer, watchdog and GPIO.
 * machine-dependent attachement.
 */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gcscpcib_pci.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");


#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/timetc.h>
#include <sys/wdog.h>

#include <sys/bus.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/gpio/gpiovar.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/ic/gcscpcibreg.h>
#include <dev/ic/gcscpcibvar.h>

#include <evbmips/loongson/dev/glxvar.h>
#include <evbmips/loongson/dev/pcibvar.h>

struct gcscpcib_pci_softc {
        /* we call pcibattach() which assumes softc starts like this: */
	struct pcib_softc       sc_pcib;
	/* MI gcscpcib datas */
	struct gcscpcib_softc	sc_gcscpcib;
};

static int      gcscpcib_pci_match(device_t, cfdata_t, void *);
static void     gcscpcib_pci_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(gcscpcib_pci, sizeof(struct gcscpcib_pci_softc),
        gcscpcib_pci_match, gcscpcib_pci_attach, NULL, NULL);


static int
gcscpcib_pci_match(device_t parent, cfdata_t match, void *aux)
{ 
	struct pci_attach_args *pa = aux;

	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_BRIDGE ||
	    PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_BRIDGE_ISA)
		return 0;

	switch (PCI_PRODUCT(pa->pa_id)) {
	case PCI_PRODUCT_NS_CS5535_ISA:
	case PCI_PRODUCT_AMD_CS5536_PCIB:
		return 2;	/* supersede pcib(4) */
	}

	return 0;
}

static void
gcscpcib_pci_attach(device_t parent, device_t self, void *aux)
{
	struct gcscpcib_pci_softc *sc = device_private(self);
	struct pci_attach_args *pa = (struct pci_attach_args *)aux;

	sc->sc_pcib.sc_pc = pa->pa_pc;
	sc->sc_pcib.sc_tag = pa->pa_tag;
	/* Attach the PCI-ISA bridge at first */
	pcibattach(parent, self, aux);
	/* then attach gcscpcib itself */
	gcscpcib_attach(self, &sc->sc_gcscpcib, pa->pa_iot);
}

uint64_t
gcsc_rdmsr(uint msr)
{
	return rdmsr(msr);
}

void
gcsc_wrmsr(uint msr, uint64_t v)
{
	wrmsr(msr, v);
}

File Added: src/sys/arch/evbmips/loongson/dev/glx.c
/*	$OpenBSD: glx.c,v 1.6 2010/10/14 21:23:04 pirofti Exp $	*/

/*
 * Copyright (c) 2009 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * AMD CS5536 PCI Mess
 * XXX too many hardcoded numbers... need to expand glxreg.h
 */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: glx.c,v 1.1 2011/08/27 13:42:45 bouyer Exp $");


#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <evbmips/loongson/autoconf.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/pci/pciidereg.h>
#include <dev/usb/usb.h>
#include <dev/usb/ohcireg.h>
#include <dev/usb/ehcireg.h>

#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>

#include <evbmips/loongson/dev/glxreg.h>
#include <evbmips/loongson/dev/glxvar.h>

#ifdef GLX_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif

/*
 * Since the purpose of this code is to present a different view of the
 * PCI configuration space, it can not attach as a real device.
 * (well it could, and then we'd have to attach a fake pci to it,
 * and fake the configuration space accesses anyways - is it worth doing?)
 *
 * We just keep the `would-be softc' structure as global variables.
 */

static pci_chipset_tag_t	glxbase_pc;
static pcitag_t			glxbase_tag;
static int			glxbase_dev;

/* MSR access through PCI configuration space */
#define	PCI_MSR_CTRL		0x00f0
#define	PCI_MSR_ADDR		0x00f4
#define	PCI_MSR_LO32		0x00f8
#define	PCI_MSR_HI32		0x00fc

/* access to the MSR through the PCI mailbox needs the same transformation
 * as done by hardware when a MSR request reaches the CS5536.
 */
#define GLX_MSR_ADDR_TARGET	0x00003fff
#define GLX_MSR_ADDR_RF		0xffffc000
#define GLX_MSR_ADDR_RF_SHIFT	9

static uint glx_msra2mbxa(uint);
static uint
glx_msra2mbxa(uint msr)
{
	uint rf = (msr & GLX_MSR_ADDR_RF);
	return ((rf << GLX_MSR_ADDR_RF_SHIFT) | (msr & GLX_MSR_ADDR_TARGET));
}

pcireg_t glx_pci_read_hook(void *, pcitag_t, int);
void	glx_pci_write_hook(void *, pcitag_t, int, pcireg_t);

pcireg_t glx_get_status(void);
pcireg_t glx_fn0_read(int);
void	glx_fn0_write(int, pcireg_t);
pcireg_t glx_fn2_read(int);
void	glx_fn2_write(int, pcireg_t);
pcireg_t glx_fn3_read(int);
void	glx_fn3_write(int, pcireg_t);
pcireg_t glx_fn4_read(int);
void	glx_fn4_write(int, pcireg_t);
pcireg_t glx_fn5_read(int);
void	glx_fn5_write(int, pcireg_t);
pcireg_t glx_fn6_read(int);
void	glx_fn6_write(int, pcireg_t);
pcireg_t glx_fn7_read(int);
void	glx_fn7_write(int, pcireg_t);

pcireg_t (*gen_pci_conf_read)(void *, pcitag_t, int);
void (*gen_pci_conf_write)(void *, pcitag_t, int, pcireg_t);

void
glx_init(pci_chipset_tag_t pc, pcitag_t tag, int dev)
{
	uint64_t msr;

	glxbase_pc = pc;
	glxbase_dev = dev;
	glxbase_tag = tag;

	/*
	 * Register PCI configuration hooks to make the various
	 * embedded devices visible as PCI subfunctions.
	 */

	gen_pci_conf_read = pc->pc_conf_read;
	pc->pc_conf_read = glx_pci_read_hook;
	gen_pci_conf_write = pc->pc_conf_write;
	pc->pc_conf_write = glx_pci_write_hook;

	/*
	 * Perform some Geode intialization.
	 */

	msr = rdmsr(GCSC_DIVIL_BALL_OPTS);	/* 0x71 */
	wrmsr(GCSC_DIVIL_BALL_OPTS, msr | 0x01);

	/*
	 * Route usb and audio
	 */

	msr = 0;
	msr |= 11 << 8;
	msr |= 9 << 16;
	wrmsr(GCSC_PIC_YSEL_LOW, msr);

	/*
	 * serial interrupts
	 */
	msr = 0;
	msr |= 4 << 24;
	msr |= 3 << 28;
	wrmsr(GCSC_PIC_YSEL_HIGH, msr);

	/*
	 * and IDE
	 */
	msr = 0;
	msr |= 1 << 14;
	wrmsr(GCSC_PIC_IRQM_PRIM, msr);

	/* no interrupts from theses */
	wrmsr(GCSC_PIC_ZSEL_LOW, 0);
	wrmsr(GCSC_PIC_ZSEL_HIGH, 0);
	wrmsr(GCSC_PIC_IRQM_LPC, 0);

	DPRINTF(("IO space 0x%" PRIx64 "\n", rdmsr(0x80000014)));
}

uint64_t
rdmsr(uint msr)
{
	uint64_t lo, hi;
	int s;

#ifdef DIAGNOSTIC
	if (glxbase_tag == 0)
		panic("rdmsr invoked before glx initialization");
#endif

	s = splhigh();
	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_ADDR,
	    glx_msra2mbxa(msr));
	lo = (uint32_t)pci_conf_read(glxbase_pc, glxbase_tag, PCI_MSR_LO32);
	hi = (uint32_t)pci_conf_read(glxbase_pc, glxbase_tag, PCI_MSR_HI32);
	splx(s);
	return (hi << 32) | lo;
}

void
wrmsr(uint msr, uint64_t value)
{
	int s;

#ifdef DIAGNOSTIC
	if (glxbase_tag == 0)
		panic("wrmsr invoked before glx initialization");
#endif

	s = splhigh();
	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_ADDR,
	    glx_msra2mbxa(msr));
	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_LO32, (uint32_t)value);
	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_HI32, value >> 32);
	splx(s);
}

pcireg_t
glx_pci_read_hook(void *v, pcitag_t tag, int offset)
{
	int bus, dev, fn;
	pcireg_t data;

	/*
	 * Do not get in the way of MSR programming
	 */
	if (tag == glxbase_tag && offset >= PCI_MSR_CTRL)
		return gen_pci_conf_read(v, tag, offset);

	pci_decompose_tag(glxbase_pc, tag, &bus, &dev, &fn);
	if (bus != 0 || dev != glxbase_dev)
		return gen_pci_conf_read(v, tag, offset);

	data = 0;

	switch (fn) {
	case 0:	/* PCI-ISA bridge */
		data = glx_fn0_read(offset);
		break;
	case 1:	/* Flash memory */
		break;
	case 2:	/* IDE controller */
		data = glx_fn2_read(offset);
		break;
	case 3:	/* AC97 codec */
		data = glx_fn3_read(offset);
		break;
	case 4:	/* OHCI controller */
		data = glx_fn4_read(offset);
		break;
	case 5:	/* EHCI controller */
		data = glx_fn5_read(offset);
		break;
	case 6:	/* UDC */
		break;
	case 7:	/* OTG */
		break;
	}

	return data;
}

void
glx_pci_write_hook(void *v, pcitag_t tag,
    int offset, pcireg_t data)
{
	int bus, dev, fn;

	/*
	 * Do not get in the way of MSR programming
	 */
	if (tag == glxbase_tag && offset >= PCI_MSR_CTRL) {
		gen_pci_conf_write(v, tag, offset, data);
		return;
	}
		

	pci_decompose_tag(glxbase_pc, tag, &bus, &dev, &fn);
	if (bus != 0 || dev != glxbase_dev) {
		gen_pci_conf_write(v, tag, offset, data);
		return;
	}

	switch (fn) {
	case 0:	/* PCI-ISA bridge */
		glx_fn0_write(offset, data);
		break;
	case 1:	/* Flash memory */
		break;
	case 2:	/* IDE controller */
		glx_fn2_write(offset, data);
		break;
	case 3:	/* AC97 codec */
		glx_fn3_write(offset, data);
		break;
	case 4:	/* OHCI controller */
		glx_fn4_write(offset, data);
		break;
	case 5:	/* EHCI controller */
		glx_fn5_write(offset, data);
		break;
	case 6:	/* USB UDC */
		break;
	case 7:	/* USB OTG */
		break;
	}
}

pcireg_t
glx_get_status()
{
	uint64_t msr;
	pcireg_t data;

	data = 0;
	msr = rdmsr(GCSC_GLPCI_GLD_MSR_ERROR);
	if (msr & (1UL << 5))
		data |= PCI_COMMAND_PARITY_ENABLE;
	data |= PCI_STATUS_66MHZ_SUPPORT |
	    PCI_STATUS_BACKTOBACK_SUPPORT | PCI_STATUS_DEVSEL_MEDIUM;
	if (msr & (1UL << 21))
		data |= PCI_STATUS_PARITY_DETECT;
	if (msr & (1UL << 20))
		data |= PCI_STATUS_TARGET_TARGET_ABORT;
	if (msr & (1UL << 17))
		data |= PCI_STATUS_MASTER_TARGET_ABORT;
	if (msr & (1UL << 16))
		data |= PCI_STATUS_MASTER_ABORT;

	return data;
}

/*
 * Function 0: PCI-ISA bridge
 */

static const pcireg_t pcib_bar_sizes[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4] = {
	0x008,
	0x100,
	0x040,
	0x020,
	0x080,
	0x020
};

static pcireg_t pcib_bar_values[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4];

static const uint64_t pcib_bar_msr[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4] = {
	GCSC_DIVIL_LBAR_SMB,
	GCSC_DIVIL_LBAR_GPIO,
	GCSC_DIVIL_LBAR_MFGPT,
	GCSC_DIVIL_LBAR_IRQ,
	GCSC_DIVIL_LBAR_PMS,
	GCSC_DIVIL_LBAR_ACPI
};

pcireg_t
glx_fn0_read(int reg)
{
	uint64_t msr;
	pcireg_t data;
	int index;

	switch (reg) {
	case PCI_ID_REG:
	case PCI_SUBSYS_ID_REG:
		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCIB);
		break;
	case PCI_COMMAND_STATUS_REG:
		data = glx_get_status();
		data |= PCI_COMMAND_MASTER_ENABLE;
		msr = rdmsr(GCSC_DIVIL_LBAR_SMB);
		if (msr & (1ULL << 32))
			data |= PCI_COMMAND_IO_ENABLE;
		break;
	case PCI_CLASS_REG:
		msr = rdmsr(GCSC_GLCP_CHIP_REV_ID);
		data = (PCI_CLASS_BRIDGE << PCI_CLASS_SHIFT) |
		    (PCI_SUBCLASS_BRIDGE_ISA << PCI_SUBCLASS_SHIFT) |
		    (msr & PCI_REVISION_MASK);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		data = (0x80 << PCI_HDRTYPE_SHIFT) |
		    (((msr & 0xff00000000UL) >> 32) << PCI_LATTIMER_SHIFT) |
		    (0x08 << PCI_CACHELINE_SHIFT);
		break;
	case PCI_MAPREG_START + 0x00:
	case PCI_MAPREG_START + 0x04:
	case PCI_MAPREG_START + 0x08:
	case PCI_MAPREG_START + 0x0c:
	case PCI_MAPREG_START + 0x10:
	case PCI_MAPREG_START + 0x14:
	case PCI_MAPREG_START + 0x18:
		index = (reg - PCI_MAPREG_START) / 4;
		if (pcib_bar_msr[index] == 0)
			data = 0;
		else {
			data = pcib_bar_values[index];
			if (data == 0xffffffff)
				data = PCI_MAPREG_IO_ADDR_MASK;
			else
				data = (pcireg_t)rdmsr(pcib_bar_msr[index]);
			data &= ~(pcib_bar_sizes[index] - 1);
			if (data != 0)
				data |= PCI_MAPREG_TYPE_IO;
		}
		break;
	case PCI_INTERRUPT_REG:
		data = (0x40 << PCI_MAX_LAT_SHIFT) |
		    (PCI_INTERRUPT_PIN_NONE << PCI_INTERRUPT_PIN_SHIFT);
		break;
	default:
		data = 0;
		break;
	}

	return data;
}

void
glx_fn0_write(int reg, pcireg_t data)
{
	uint64_t msr;
	int index;

	switch (reg) {
	case PCI_COMMAND_STATUS_REG:
		for (index = 0; index < __arraycount(pcib_bar_msr); index++) {
			if (pcib_bar_msr[index] == 0)
				continue;
			msr = rdmsr(pcib_bar_msr[index]);
			if (data & PCI_COMMAND_IO_ENABLE)
				msr |= 1ULL << 32;
			else
				msr &= ~(1ULL << 32);
			wrmsr(pcib_bar_msr[index], msr);
		}

		msr = rdmsr(GCSC_GLPCI_GLD_MSR_ERROR);
		if (data & PCI_COMMAND_PARITY_ENABLE)
			msr |= 1ULL << 5;
		else
			msr &= ~(1ULL << 5);
		wrmsr(GCSC_GLPCI_GLD_MSR_ERROR, msr);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		msr &= 0xff00000000ULL;
		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
		break;
	case PCI_MAPREG_START + 0x00:
	case PCI_MAPREG_START + 0x04:
	case PCI_MAPREG_START + 0x08:
	case PCI_MAPREG_START + 0x0c:
	case PCI_MAPREG_START + 0x10:
	case PCI_MAPREG_START + 0x14:
	case PCI_MAPREG_START + 0x18:
		index = (reg - PCI_MAPREG_START) / 4;
		if (data == 0xffffffff) {
			pcib_bar_values[index] = data;
		} else if (pcib_bar_msr[index] != 0) {
			if ((data & PCI_MAPREG_TYPE_MASK) ==
			    PCI_MAPREG_TYPE_IO) {
				data &= PCI_MAPREG_IO_ADDR_MASK;
				data &= ~(pcib_bar_sizes[index] - 1);
				wrmsr(pcib_bar_msr[index],
				    (0x0000f000ULL << 32) | (1ULL << 32) | data);
			} else {
				wrmsr(pcib_bar_msr[index], 0ULL);
			}
			pcib_bar_values[index] = 0;
		}
		break;
	}
}

/*
 * Function 2: IDE Controller
 */

static pcireg_t pciide_bar_size = 0x10;
static pcireg_t pciide_bar_value;

pcireg_t
glx_fn2_read(int reg)
{
	uint64_t msr;
	pcireg_t data;

	switch (reg) {
	case PCI_ID_REG:
	case PCI_SUBSYS_ID_REG:
		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_IDE);
		break;
	case PCI_COMMAND_STATUS_REG:
		data = glx_get_status();
		data |= PCI_COMMAND_IO_ENABLE;
		msr = rdmsr(GCSC_GLIU_PAE);
		if ((msr & (0x3 << 4)) == 0x03)
			data |= PCI_COMMAND_MASTER_ENABLE;
		break;
	case PCI_CLASS_REG:
		msr = rdmsr(GCSC_IDE_GLD_MSR_CAP);
		data = (PCI_CLASS_MASS_STORAGE << PCI_CLASS_SHIFT) |
		    (PCI_SUBCLASS_MASS_STORAGE_IDE << PCI_SUBCLASS_SHIFT) |
		    (PCIIDE_INTERFACE_BUS_MASTER_DMA << PCI_INTERFACE_SHIFT) |
		    (msr & PCI_REVISION_MASK);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		data = (0x00 << PCI_HDRTYPE_SHIFT) |
		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
		    (0x08 << PCI_CACHELINE_SHIFT);
		break;
	case PCI_MAPREG_START + 0x10:
		data = pciide_bar_value;
		if (data == 0xffffffff)
			data = PCI_MAPREG_IO_ADDR_MASK & ~(pciide_bar_size - 1);
		else {
			msr = rdmsr(GCSC_IDE_IO_BAR);
			data = msr & 0xfffffff0;
		}
		if (data != 0)
			data |= PCI_MAPREG_TYPE_IO;
		break;
	case PCI_INTERRUPT_REG:
		/* compat mode */
		data = (0x40 << PCI_MAX_LAT_SHIFT) |
		    (PCI_INTERRUPT_PIN_NONE << PCI_INTERRUPT_PIN_SHIFT);
		break;
	/*
	 * The following registers are used by pciide(4)
	 */
	case PCIIDE_CHANSTATUS_EN:
		data = rdmsr(GCSC_IDE_CFG);
		break;
	case /* AMD756_DATATIM XXX */ 0x48:
		data = rdmsr(GCSC_IDE_DTC);
		break;
	case /* AMD756_UDMA XXX*/ 0x50:
		data = rdmsr(GCSC_IDE_ETC);
		break;
	default:
		DPRINTF(("unimplemented pciide reg 0x%x\n", reg));
		data = 0;
		break;
	}

	return data;
}

void
glx_fn2_write(int reg, pcireg_t data)
{
	uint64_t msr;

	switch (reg) {
	case PCI_COMMAND_STATUS_REG:
		msr = rdmsr(GCSC_GLIU_PAE);
		if (data & PCI_COMMAND_MASTER_ENABLE)
			msr |= 0x03 << 4;
		else
			msr &= ~(0x03 << 4);
		wrmsr(GCSC_GLIU_PAE, msr);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		msr &= 0xff00000000ULL;
		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
		break;
	case PCI_MAPREG_START + 0x10:
		if (data == 0xffffffff) {
			pciide_bar_value = data;
		} else {
			if ((data & PCI_MAPREG_TYPE_MASK) ==
			    PCI_MAPREG_TYPE_IO) {
				data &= PCI_MAPREG_IO_ADDR_MASK;
				msr = (uint32_t)data & 0xfffffff0;
				wrmsr(GCSC_IDE_IO_BAR, msr);
			} else {
				wrmsr(GCSC_IDE_IO_BAR, 0);
			}
			pciide_bar_value = 0;
		}
		break;
	/*
	 * The following registers are used by pciide(4)
	 */
	case PCIIDE_CHANSTATUS_EN:
		wrmsr(GCSC_IDE_CFG, (uint32_t)data);
		break;
	case /* AMD756_DATATIM XXX */ 0x48:
		wrmsr(GCSC_IDE_DTC, (uint32_t)data);
		break;
	case /* AMD756_UDMA XXX*/ 0x50:
		wrmsr(GCSC_IDE_ETC, (uint32_t)data);
		break;
	default:
		DPRINTF(("unimplemented pciide reg 0x%x\n", reg));
	}
}

/*
 * Function 3: AC97 Codec
 */

static pcireg_t ac97_bar_size = 0x80;
static pcireg_t ac97_bar_value;

pcireg_t
glx_fn3_read(int reg)
{
	uint64_t msr;
	pcireg_t data;

	switch (reg) {
	case PCI_ID_REG:
	case PCI_SUBSYS_ID_REG:
		data = PCI_ID_CODE(PCI_VENDOR_AMD,
		    PCI_PRODUCT_AMD_CS5536_AUDIO);
		break;
	case PCI_COMMAND_STATUS_REG:
		data = glx_get_status();
		data |= PCI_COMMAND_IO_ENABLE;
		msr = rdmsr(GCSC_GLIU_PAE);
		if ((msr & (0x3 << 8)) == 0x03)
			data |= PCI_COMMAND_MASTER_ENABLE;
		break;
	case PCI_CLASS_REG:
		msr = rdmsr(GCSC_ACC_GLD_MSR_CAP);
		data = (PCI_CLASS_MULTIMEDIA << PCI_CLASS_SHIFT) |
		    (PCI_SUBCLASS_MULTIMEDIA_AUDIO << PCI_SUBCLASS_SHIFT) |
		    (msr & PCI_REVISION_MASK);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		data = (0x00 << PCI_HDRTYPE_SHIFT) |
		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
		    (0x08 << PCI_CACHELINE_SHIFT);
		break;
	case PCI_MAPREG_START:
		data = ac97_bar_value;
		if (data == 0xffffffff)
			data = PCI_MAPREG_IO_ADDR_MASK & ~(ac97_bar_size - 1);
		else {
			msr = rdmsr(GCSC_GLIU_IOD_BM1);
			data = (msr >> 20) & 0x000fffff;
			data &= (msr & 0x000fffff);
		}
		if (data != 0)
			data |= PCI_MAPREG_TYPE_IO;
		break;
	case PCI_INTERRUPT_REG:
		data = (0x40 << PCI_MAX_LAT_SHIFT) |
		    (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT);
		break;
	default:
		data = 0;
		break;
	}

	return data;
}

void
glx_fn3_write(int reg, pcireg_t data)
{
	uint64_t msr;

	switch (reg) {
	case PCI_COMMAND_STATUS_REG:
		msr = rdmsr(GCSC_GLIU_PAE);
		if (data & PCI_COMMAND_MASTER_ENABLE)
			msr |= 0x03 << 8;
		else
			msr &= ~(0x03 << 8);
		wrmsr(GCSC_GLIU_PAE, msr);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		msr &= 0xff00000000ULL;
		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
		break;
	case PCI_MAPREG_START:
		if (data == 0xffffffff) {
			ac97_bar_value = data;
		} else {
			if ((data & PCI_MAPREG_TYPE_MASK) ==
			    PCI_MAPREG_TYPE_IO) {
				data &= PCI_MAPREG_IO_ADDR_MASK;
				msr = rdmsr(GCSC_GLIU_IOD_BM1);
				msr &= 0x0fffff0000000000ULL;
				msr |= 5ULL << 61;	/* AC97 */
				msr |= ((uint64_t)data & 0xfffff) << 20;
				msr |= 0x000fffff & ~(ac97_bar_size - 1);
				wrmsr(GCSC_GLIU_IOD_BM1, msr);
			} else {
				wrmsr(GCSC_GLIU_IOD_BM1, 0);
			}
			ac97_bar_value = 0;
		}
		break;
	}
}

/*
 * Function 4: OHCI Controller
 */

static pcireg_t ohci_bar_size = 0x1000;
static pcireg_t ohci_bar_value;

pcireg_t
glx_fn4_read(int reg)
{
	uint64_t msr;
	pcireg_t data;

	switch (reg) {
	case PCI_ID_REG:
	case PCI_SUBSYS_ID_REG:
		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_OHCI);
		break;
	case PCI_COMMAND_STATUS_REG:
		data = glx_get_status();
		msr = rdmsr(GCSC_USB_MSR_OHCB);
		if (msr & (1ULL << 34))
			data |= PCI_COMMAND_MASTER_ENABLE;
		if (msr & (1ULL << 33))
			data |= PCI_COMMAND_MEM_ENABLE;
		break;
	case PCI_CLASS_REG:
		msr = rdmsr(GCSC_USB_GLD_MSR_CAP);
		data = (PCI_CLASS_SERIALBUS << PCI_CLASS_SHIFT) |
		    (PCI_SUBCLASS_SERIALBUS_USB << PCI_SUBCLASS_SHIFT) |
		    (PCI_INTERFACE_OHCI << PCI_INTERFACE_SHIFT) |
		    (msr & PCI_REVISION_MASK);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		data = (0x00 << PCI_HDRTYPE_SHIFT) |
		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
		    (0x08 << PCI_CACHELINE_SHIFT);
		break;
	case PCI_MAPREG_START + 0x00:
		data = ohci_bar_value;
		if (data == 0xffffffff)
			data = PCI_MAPREG_MEM_ADDR_MASK & ~(ohci_bar_size - 1);
		else {
			msr = rdmsr(GCSC_USB_MSR_OHCB);
			data = msr & 0xffffff00;
		}
		if (data != 0)
			data |= PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
		break;
	case PCI_CAPLISTPTR_REG:
		data = 0x40;
		break;
	case PCI_INTERRUPT_REG:
		data = (0x40 << PCI_MAX_LAT_SHIFT) |
		    (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT);
		break;
	case 0x40:	/* USB capability pointer */
		data = 0;
		break;
	default:
		data = 0;
		break;
	}

	return data;
}

void
glx_fn4_write(int reg, pcireg_t data)
{
	uint64_t msr;

	switch (reg) {
	case PCI_COMMAND_STATUS_REG:
		msr = rdmsr(GCSC_USB_MSR_OHCB);
		if (data & PCI_COMMAND_MASTER_ENABLE)
			msr |= 1ULL << 34;
		else
			msr &= ~(1ULL << 34);
		if (data & PCI_COMMAND_MEM_ENABLE)
			msr |= 1ULL << 33;
		else
			msr &= ~(1ULL << 33);
		wrmsr(GCSC_USB_MSR_OHCB, msr);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		msr &= 0xff00000000ULL;
		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
		break;
	case PCI_MAPREG_START + 0x00:
		if (data == 0xffffffff) {
			ohci_bar_value = data;
		} else {
			if ((data & PCI_MAPREG_TYPE_MASK) ==
			    PCI_MAPREG_TYPE_MEM) {
				data &= PCI_MAPREG_MEM_ADDR_MASK;
				msr = rdmsr(GCSC_GLIU_P2D_BM3);
				msr &= 0x0fffff0000000000ULL;
				msr |= 2ULL << 61;	/* USB */
				msr |= (((uint64_t)data) >> 12) << 20;
				msr |= 0x000fffff;
				wrmsr(GCSC_GLIU_P2D_BM3, msr);

				msr = rdmsr(GCSC_USB_MSR_OHCB);
				msr &= ~0xffffff00ULL;
				msr |= data;
			} else {
				msr = rdmsr(GCSC_USB_MSR_OHCB);
				msr &= ~0xffffff00ULL;
			}
			wrmsr(GCSC_USB_MSR_OHCB, msr);
			ohci_bar_value = 0;
		}
		break;
	default:
		break;
	}
}

/*
 * Function 5: EHCI Controller
 */

static pcireg_t ehci_bar_size = 0x1000;
static pcireg_t ehci_bar_value;

pcireg_t
glx_fn5_read(int reg)
{
	uint64_t msr;
	pcireg_t data;

	switch (reg) {
	case PCI_ID_REG:
	case PCI_SUBSYS_ID_REG:
		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_EHCI);
		break;
	case PCI_COMMAND_STATUS_REG:
		data = glx_get_status();
		msr = rdmsr(GCSC_USB_MSR_EHCB);
		if (msr & (1ULL << 34))
			data |= PCI_COMMAND_MASTER_ENABLE;
		if (msr & (1ULL << 33))
			data |= PCI_COMMAND_MEM_ENABLE;
		break;
	case PCI_CLASS_REG:
		msr = rdmsr(GCSC_USB_GLD_MSR_CAP);
		data = (PCI_CLASS_SERIALBUS << PCI_CLASS_SHIFT) |
		    (PCI_SUBCLASS_SERIALBUS_USB << PCI_SUBCLASS_SHIFT) |
		    (PCI_INTERFACE_EHCI << PCI_INTERFACE_SHIFT) |
		    (msr & PCI_REVISION_MASK);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		data = (0x00 << PCI_HDRTYPE_SHIFT) |
		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
		    (0x08 << PCI_CACHELINE_SHIFT);
		break;
	case PCI_MAPREG_START + 0x00:
		data = ehci_bar_value;
		if (data == 0xffffffff)
			data = PCI_MAPREG_MEM_ADDR_MASK & ~(ehci_bar_size - 1);
		else {
			msr = rdmsr(GCSC_USB_MSR_EHCB);
			data = msr & 0xffffff00;
		}
		if (data != 0)
			data |= PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
		break;
	case PCI_CAPLISTPTR_REG:
		data = 0x40;
		break;
	case PCI_INTERRUPT_REG:
		data = (0x40 << PCI_MAX_LAT_SHIFT) |
		    (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT);
		break;
	case 0x40:	/* USB capability pointer */
		data = 0;
		break;
	case PCI_USBREV:
		msr = rdmsr(GCSC_USB_MSR_EHCB);
		data = PCI_USBREV_2_0;
		data |= ((msr >> 40) & 0x3f) << 8;	/* PCI_EHCI_FLADJ */
		break;
	default:
		data = 0;
		break;
	}

	return data;
}

void
glx_fn5_write(int reg, pcireg_t data)
{
	uint64_t msr;

	switch (reg) {
	case PCI_COMMAND_STATUS_REG:
		msr = rdmsr(GCSC_USB_MSR_EHCB);
		if (data & PCI_COMMAND_MASTER_ENABLE)
			msr |= 1ULL << 34;
		else
			msr &= ~(1ULL << 34);
		if (data & PCI_COMMAND_MEM_ENABLE)
			msr |= 1ULL << 33;
		else
			msr &= ~(1ULL << 33);
		wrmsr(GCSC_USB_MSR_EHCB, msr);
		break;
	case PCI_BHLC_REG:
		msr = rdmsr(GCSC_GLPCI_CTRL);
		msr &= 0xff00000000ULL;
		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
		break;
	case PCI_MAPREG_START + 0x00:
		if (data == 0xffffffff) {
			ehci_bar_value = data;
		} else {
			if ((data & PCI_MAPREG_TYPE_MASK) ==
			    PCI_MAPREG_TYPE_MEM) {
				data &= PCI_MAPREG_MEM_ADDR_MASK;
				msr = rdmsr(GCSC_GLIU_P2D_BM4);
				msr &= 0x0fffff0000000000ULL;
				msr |= 2ULL << 61;	/* USB */
				msr |= (((uint64_t)data) >> 12) << 20;
				msr |= 0x000fffff;
				wrmsr(GCSC_GLIU_P2D_BM4, msr);

				msr = rdmsr(GCSC_USB_MSR_EHCB);
				msr &= ~0xffffff00ULL;
				msr |= data;
			} else {
				msr = rdmsr(GCSC_USB_MSR_EHCB);
				msr &= ~0xffffff00ULL;
			}
			wrmsr(GCSC_USB_MSR_EHCB, msr);
			ehci_bar_value = 0;
		}
		break;
	default:
		break;
	}
}

File Added: src/sys/arch/evbmips/loongson/dev/glxreg.h
/*	$OpenBSD: glxreg.h,v 1.1 2010/10/14 21:23:05 pirofti Exp $	*/

/*
 * Copyright (c) 2009 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * AMD 5536 Geode companion chip MSR registers
 */

/*
 * Base addresses of the MSR groups.
 */

#define	GCSC_SB_MSR_BASE		0x51000000
#define	GCSC_GLIU_MSR_BASE		0x51010000
#define	GCSC_USB_MSR_BASE		0x51200000
#define	GCSC_IDE_MSR_BASE		0x51300000
#define	GCSC_DIVIL_MSR_BASE		0x51400000
#define	GCSC_ACC_MSR_BASE		0x51500000
#define	GCSC_GLCP_MSR_BASE		0x51700000

/*
 * GeodeLink Interface Unit (GLIU)
 */

#define	GCSC_GLIU_GLD_MSR_CAP		(GCSC_GLIU_MSR_BASE + 0x00)
#define	GCSC_GLIU_GLD_MSR_CONFIG	(GCSC_GLIU_MSR_BASE + 0x01)
#define	GCSC_GLIU_GLD_MSR_SMI		(GCSC_GLIU_MSR_BASE + 0x02)
#define	GCSC_GLIU_GLD_MSR_ERROR		(GCSC_GLIU_MSR_BASE + 0x03)
#define	GCSC_GLIU_GLD_MSR_PM		(GCSC_GLIU_MSR_BASE + 0x04)
#define	GCSC_GLIU_GLD_MSR_DIAG		(GCSC_GLIU_MSR_BASE + 0x05)

#define	GCSC_GLIU_P2D_BM0		(GCSC_GLIU_MSR_BASE + 0x20)
#define	GCSC_GLIU_P2D_BM1		(GCSC_GLIU_MSR_BASE + 0x21)
#define	GCSC_GLIU_P2D_BM2		(GCSC_GLIU_MSR_BASE + 0x22)
#define	GCSC_GLIU_P2D_BMK0		(GCSC_GLIU_MSR_BASE + 0x23)
#define	GCSC_GLIU_P2D_BMK1		(GCSC_GLIU_MSR_BASE + 0x24)
#define	GCSC_GLIU_P2D_BM3		(GCSC_GLIU_MSR_BASE + 0x25)
#define	GCSC_GLIU_P2D_BM4		(GCSC_GLIU_MSR_BASE + 0x26)

#define	GCSC_GLIU_COH			(GCSC_GLIU_MSR_BASE + 0x80)
#define	GCSC_GLIU_PAE			(GCSC_GLIU_MSR_BASE + 0x81)
#define	GCSC_GLIU_ARB			(GCSC_GLIU_MSR_BASE + 0x82)
#define	GCSC_GLIU_ASMI			(GCSC_GLIU_MSR_BASE + 0x83)
#define	GCSC_GLIU_AERR			(GCSC_GLIU_MSR_BASE + 0x84)
#define	GCSC_GLIU_DEBUG			(GCSC_GLIU_MSR_BASE + 0x85)
#define	GCSC_GLIU_PHY_CAP		(GCSC_GLIU_MSR_BASE + 0x86)
#define	GCSC_GLIU_NOUT_RESP		(GCSC_GLIU_MSR_BASE + 0x87)
#define	GCSC_GLIU_NOUT_WDATA		(GCSC_GLIU_MSR_BASE + 0x88)
#define	GCSC_GLIU_WHOAMI		(GCSC_GLIU_MSR_BASE + 0x8b)
#define	GCSC_GLIU_SLV_DIS		(GCSC_GLIU_MSR_BASE + 0x8c)
#define	GCSC_GLIU_STATISTIC_CNT0	(GCSC_GLIU_MSR_BASE + 0xa0)
#define	GCSC_GLIU_STATISTIC_MASK0	(GCSC_GLIU_MSR_BASE + 0xa1)
#define	GCSC_GLIU_STATISTIC_ACTION0	(GCSC_GLIU_MSR_BASE + 0xa2)
#define	GCSC_GLIU_STATISTIC_CNT1	(GCSC_GLIU_MSR_BASE + 0xa4)
#define	GCSC_GLIU_STATISTIC_MASK1	(GCSC_GLIU_MSR_BASE + 0xa5)
#define	GCSC_GLIU_STATISTIC_ACTION1	(GCSC_GLIU_MSR_BASE + 0xa6)
#define	GCSC_GLIU_STATISTIC_CNT2	(GCSC_GLIU_MSR_BASE + 0xa8)
#define	GCSC_GLIU_STATISTIC_MASK2	(GCSC_GLIU_MSR_BASE + 0xa9)
#define	GCSC_GLIU_STATISTIC_ACTION2	(GCSC_GLIU_MSR_BASE + 0xaa)
#define	GCSC_GLIU_RQ_COMP_VAL		(GCSC_GLIU_MSR_BASE + 0xc0)
#define	GCSC_GLIU_RQ_COMP_MASK		(GCSC_GLIU_MSR_BASE + 0xc1)
#define	GCSC_GLIU_DA_COMP_VAL_LO	(GCSC_GLIU_MSR_BASE + 0xd0)
#define	GCSC_GLIU_DA_COMP_VAL_HI	(GCSC_GLIU_MSR_BASE + 0xd1)
#define	GCSC_GLIU_DA_COMP_MASK_LO	(GCSC_GLIU_MSR_BASE + 0xd2)
#define	GCSC_GLIU_DA_COMP_MASK_HI	(GCSC_GLIU_MSR_BASE + 0xd3)

#define	GCSC_GLIU_IOD_BM0		(GCSC_GLIU_MSR_BASE + 0xe0)
#define	GCSC_GLIU_IOD_BM1		(GCSC_GLIU_MSR_BASE + 0xe1)
#define	GCSC_GLIU_IOD_BM2		(GCSC_GLIU_MSR_BASE + 0xe2)
#define	GCSC_GLIU_IOD_BM3		(GCSC_GLIU_MSR_BASE + 0xe3)
#define	GCSC_GLIU_IOD_BM4		(GCSC_GLIU_MSR_BASE + 0xe4)
#define	GCSC_GLIU_IOD_BM5		(GCSC_GLIU_MSR_BASE + 0xe5)
#define	GCSC_GLIU_IOD_BM6		(GCSC_GLIU_MSR_BASE + 0xe6)
#define	GCSC_GLIU_IOD_BM7		(GCSC_GLIU_MSR_BASE + 0xe7)
#define	GCSC_GLIU_IOD_BM8		(GCSC_GLIU_MSR_BASE + 0xe8)
#define	GCSC_GLIU_IOD_BM9		(GCSC_GLIU_MSR_BASE + 0xe9)
#define	GCSC_GLIU_IOD_SC0		(GCSC_GLIU_MSR_BASE + 0xea)
#define	GCSC_GLIU_IOD_SC1		(GCSC_GLIU_MSR_BASE + 0xeb)
#define	GCSC_GLIU_IOD_SC2		(GCSC_GLIU_MSR_BASE + 0xec)
#define	GCSC_GLIU_IOD_SC3		(GCSC_GLIU_MSR_BASE + 0xed)
#define	GCSC_GLIU_IOD_SC4		(GCSC_GLIU_MSR_BASE + 0xee)
#define	GCSC_GLIU_IOD_SC5		(GCSC_GLIU_MSR_BASE + 0xef)
#define	GCSC_GLIU_IOD_SC6		(GCSC_GLIU_MSR_BASE + 0xf0)
#define	GCSC_GLIU_IOD_SC7		(GCSC_GLIU_MSR_BASE + 0xf1)

/*
 * GeodeLink PCI South Bridge (SB)
 */

#define	GCSC_GLPCI_GLD_MSR_CAP		(GCSC_SB_MSR_BASE + 0x00)
#define	GCSC_GLPCI_GLD_MSR_CONFIG	(GCSC_SB_MSR_BASE + 0x01)
#define	GCSC_GLPCI_GLD_MSR_SMI		(GCSC_SB_MSR_BASE + 0x02)
#define	GCSC_GLPCI_GLD_MSR_ERROR	(GCSC_SB_MSR_BASE + 0x03)
#define	GCSC_GLPCI_GLD_MSR_PM		(GCSC_SB_MSR_BASE + 0x04)
#define	GCSC_GLPCI_GLD_MSR_DIAG		(GCSC_SB_MSR_BASE + 0x05)

#define	GCSC_GLPCI_CTRL			(GCSC_SB_MSR_BASE + 0x10)
#define	GCSC_GLPCI_R0			(GCSC_SB_MSR_BASE + 0x20)
#define	GCSC_GLPCI_R1			(GCSC_SB_MSR_BASE + 0x21)
#define	GCSC_GLPCI_R2			(GCSC_SB_MSR_BASE + 0x22)
#define	GCSC_GLPCI_R3			(GCSC_SB_MSR_BASE + 0x23)
#define	GCSC_GLPCI_R4			(GCSC_SB_MSR_BASE + 0x24)
#define	GCSC_GLPCI_R5			(GCSC_SB_MSR_BASE + 0x25)
#define	GCSC_GLPCI_R6			(GCSC_SB_MSR_BASE + 0x26)
#define	GCSC_GLPCI_R7			(GCSC_SB_MSR_BASE + 0x27)
#define	GCSC_GLPCI_R8			(GCSC_SB_MSR_BASE + 0x28)
#define	GCSC_GLPCI_R9			(GCSC_SB_MSR_BASE + 0x29)
#define	GCSC_GLPCI_R10			(GCSC_SB_MSR_BASE + 0x2a)
#define	GCSC_GLPCI_R11			(GCSC_SB_MSR_BASE + 0x2b)
#define	GCSC_GLPCI_R12			(GCSC_SB_MSR_BASE + 0x2c)
#define	GCSC_GLPCI_R13			(GCSC_SB_MSR_BASE + 0x2d)
#define	GCSC_GLPCI_R14			(GCSC_SB_MSR_BASE + 0x2e)
#define	GCSC_GLPCI_R15			(GCSC_SB_MSR_BASE + 0x2f)
#define	GCSC_GLPCI_PCIHEAD_BYTE0_3	(GCSC_SB_MSR_BASE + 0x30)
#define	GCSC_GLPCI_PCIHEAD_BYTE4_7	(GCSC_SB_MSR_BASE + 0x31)
#define	GCSC_GLPCI_PCIHEAD_BYTE8_B	(GCSC_SB_MSR_BASE + 0x32)
#define	GCSC_GLPCI_PCIHEAD_BYTEC_F	(GCSC_SB_MSR_BASE + 0x33)

/*
 * AC97 Audio Codec Controller (ACC)
 */

#define	GCSC_ACC_GLD_MSR_CAP		(GCSC_ACC_MSR_BASE + 0x00)
#define	GCSC_ACC_GLD_MSR_CONFIG		(GCSC_ACC_MSR_BASE + 0x01)
#define	GCSC_ACC_GLD_MSR_SMI		(GCSC_ACC_MSR_BASE + 0x02)
#define	GCSC_ACC_GLD_MSR_ERROR		(GCSC_ACC_MSR_BASE + 0x03)
#define	GCSC_ACC_GLD_MSR_PM		(GCSC_ACC_MSR_BASE + 0x04)
#define	GCSC_ACC_GLD_MSR_DIAG		(GCSC_ACC_MSR_BASE + 0x05)

/*
 * USB Controller Registers (USB)
 */

#define	GCSC_USB_GLD_MSR_CAP		(GCSC_USB_MSR_BASE + 0x00)
#define	GCSC_USB_GLD_MSR_CONFIG		(GCSC_USB_MSR_BASE + 0x01)
#define	GCSC_USB_GLD_MSR_SMI		(GCSC_USB_MSR_BASE + 0x02)
#define	GCSC_USB_GLD_MSR_ERROR		(GCSC_USB_MSR_BASE + 0x03)
#define	GCSC_USB_GLD_MSR_PM		(GCSC_USB_MSR_BASE + 0x04)
#define	GCSC_USB_GLD_MSR_DIAG		(GCSC_USB_MSR_BASE + 0x05)

#define	GCSC_USB_MSR_OHCB		(GCSC_USB_MSR_BASE + 0x08)
#define	GCSC_USB_MSR_EHCB		(GCSC_USB_MSR_BASE + 0x09)
#define	GCSC_USB_MSR_UDCB		(GCSC_USB_MSR_BASE + 0x0a)
#define	GCSC_USB_MSR_UOCB		(GCSC_USB_MSR_BASE + 0x0b)

/*
 * IDE Controller Registers (IDE)
 */

#define	GCSC_IDE_GLD_MSR_CAP		(GCSC_IDE_MSR_BASE + 0x00)
#define	GCSC_IDE_GLD_MSR_CONFIG		(GCSC_IDE_MSR_BASE + 0x01)
#define	GCSC_IDE_GLD_MSR_SMI		(GCSC_IDE_MSR_BASE + 0x02)
#define	GCSC_IDE_GLD_MSR_ERROR		(GCSC_IDE_MSR_BASE + 0x03)
#define	GCSC_IDE_GLD_MSR_PM		(GCSC_IDE_MSR_BASE + 0x04)
#define	GCSC_IDE_GLD_MSR_DIAG		(GCSC_IDE_MSR_BASE + 0x05)

#define	GCSC_IDE_IO_BAR			(GCSC_IDE_MSR_BASE + 0x08)
#define	GCSC_IDE_CFG			(GCSC_IDE_MSR_BASE + 0x10)
#define	GCSC_IDE_DTC			(GCSC_IDE_MSR_BASE + 0x12)
#define	GCSC_IDE_CAST			(GCSC_IDE_MSR_BASE + 0x13)
#define	GCSC_IDE_ETC			(GCSC_IDE_MSR_BASE + 0x14)
#define	GCSC_IDE_PM			(GCSC_IDE_MSR_BASE + 0x15)

/*
 * Diverse Integration Logic (DIVIL)
 */

#define	GCSC_DIVIL_GLD_MSR_CAP		(GCSC_DIVIL_MSR_BASE + 0x00)
#define	GCSC_DIVIL_GLD_MSR_CONFIG	(GCSC_DIVIL_MSR_BASE + 0x01)
#define	GCSC_DIVIL_GLD_MSR_SMI		(GCSC_DIVIL_MSR_BASE + 0x02)
#define	GCSC_DIVIL_GLD_MSR_ERROR	(GCSC_DIVIL_MSR_BASE + 0x03)
#define	GCSC_DIVIL_GLD_MSR_PM		(GCSC_DIVIL_MSR_BASE + 0x04)
#define	GCSC_DIVIL_GLD_MSR_DIAG		(GCSC_DIVIL_MSR_BASE + 0x05)

#define	GCSC_DIVIL_LBAR_IRQ		(GCSC_DIVIL_MSR_BASE + 0x08)
#define	GCSC_DIVIL_LBAR_KEL		(GCSC_DIVIL_MSR_BASE + 0x09)
#define	GCSC_DIVIL_LBAR_SMB		(GCSC_DIVIL_MSR_BASE + 0x0b)
#define	GCSC_DIVIL_LBAR_GPIO		(GCSC_DIVIL_MSR_BASE + 0x0c)
#define	GCSC_DIVIL_LBAR_MFGPT		(GCSC_DIVIL_MSR_BASE + 0x0d)
#define	GCSC_DIVIL_LBAR_ACPI		(GCSC_DIVIL_MSR_BASE + 0x0e)
#define	GCSC_DIVIL_LBAR_PMS		(GCSC_DIVIL_MSR_BASE + 0x0f)
#define	GCSC_DIVIL_LBAR_FLSH0		(GCSC_DIVIL_MSR_BASE + 0x10)
#define	GCSC_DIVIL_LBAR_FLSH1		(GCSC_DIVIL_MSR_BASE + 0x11)
#define	GCSC_DIVIL_LBAR_FLSH2		(GCSC_DIVIL_MSR_BASE + 0x12)
#define	GCSC_DIVIL_LBAR_FLSH3		(GCSC_DIVIL_MSR_BASE + 0x13)
#define	GCSC_DIVIL_LEG_IO		(GCSC_DIVIL_MSR_BASE + 0x14)
#define	GCSC_DIVIL_BALL_OPTS		(GCSC_DIVIL_MSR_BASE + 0x15)
#define	GCSC_DIVIL_SOFT_IRQ		(GCSC_DIVIL_MSR_BASE + 0x16)
#define	GCSC_DIVIL_SOFT_RESET		(GCSC_DIVIL_MSR_BASE + 0x17)
#define	GCSC_NORF_CTL			(GCSC_DIVIL_MSR_BASE + 0x18)
#define	GCSC_NORF_T01			(GCSC_DIVIL_MSR_BASE + 0x19)
#define	GCSC_NORF_T23			(GCSC_DIVIL_MSR_BASE + 0x1a)
#define	GCSC_NANDF_DATA			(GCSC_DIVIL_MSR_BASE + 0x1b)
#define	GCSC_NANDF_CTL			(GCSC_DIVIL_MSR_BASE + 0x1c)
#define	GCSC_NANDF_RSVD			(GCSC_DIVIL_MSR_BASE + 0x1d)
#define	GCSC_DIVIL_AC_DMA		(GCSC_DIVIL_MSR_BASE + 0x1e)
#define	GCSC_KELX_CTL			(GCSC_DIVIL_MSR_BASE + 0x1f)
#define	GCSC_PIC_YSEL_LOW		(GCSC_DIVIL_MSR_BASE + 0x20)
#define	GCSC_PIC_YSEL_HIGH		(GCSC_DIVIL_MSR_BASE + 0x21)
#define	GCSC_PIC_ZSEL_LOW		(GCSC_DIVIL_MSR_BASE + 0x22)
#define	GCSC_PIC_ZSEL_HIGH		(GCSC_DIVIL_MSR_BASE + 0x23)
#define	GCSC_PIC_IRQM_PRIM		(GCSC_DIVIL_MSR_BASE + 0x24)
#define	GCSC_PIC_IRQM_LPC		(GCSC_DIVIL_MSR_BASE + 0x25)
#define	GCSC_PIC_XIRR_STS_LOW		(GCSC_DIVIL_MSR_BASE + 0x26)
#define	GCSC_PIC_XIRR_STS_HIGH		(GCSC_DIVIL_MSR_BASE + 0x27)
#define	GCSC_MFGPT_IRQ			(GCSC_DIVIL_MSR_BASE + 0x28)
#define	GCSC_MFGPT_NR			(GCSC_DIVIL_MSR_BASE + 0x29)
#define	GCSC_MFGPT_RSVD			(GCSC_DIVIL_MSR_BASE + 0x2a)
#define	GCSC_MFGPT_SETUP		(GCSC_DIVIL_MSR_BASE + 0x2b)
#define	GCSC_FLPY_3F2_SHDW		(GCSC_DIVIL_MSR_BASE + 0x30)
#define	GCSC_FLPY_3F7_SHDW		(GCSC_DIVIL_MSR_BASE + 0x31)
#define	GCSC_FLPY_372_SHDW		(GCSC_DIVIL_MSR_BASE + 0x32)
#define	GCSC_FLPY_377_SHDW		(GCSC_DIVIL_MSR_BASE + 0x33)
#define	GCSC_PIC_SHDW			(GCSC_DIVIL_MSR_BASE + 0x34)
#define	GCSC_PIT_SHDW			(GCSC_DIVIL_MSR_BASE + 0x36)
#define	GCSC_PIT_CNTRL			(GCSC_DIVIL_MSR_BASE + 0x37)
#define	GCSC_UART1_MOD			(GCSC_DIVIL_MSR_BASE + 0x38)
#define	GCSC_UART1_DONG			(GCSC_DIVIL_MSR_BASE + 0x39)
#define	GCSC_UART1_CONF			(GCSC_DIVIL_MSR_BASE + 0x3a)
#define	GCSC_UART1_RSVD_MSR		(GCSC_DIVIL_MSR_BASE + 0x3b)
#define	GCSC_UART2_MOD			(GCSC_DIVIL_MSR_BASE + 0x3c)
#define	GCSC_UART2_DONG			(GCSC_DIVIL_MSR_BASE + 0x3d)
#define	GCSC_UART2_CONF			(GCSC_DIVIL_MSR_BASE + 0x3e)
#define	GCSC_UART2_RSVD_MSR		(GCSC_DIVIL_MSR_BASE + 0x3f)
#define	GCSC_DMA_MAP			(GCSC_DIVIL_MSR_BASE + 0x40)
#define	GCSC_DMA_SHDW_CH0		(GCSC_DIVIL_MSR_BASE + 0x41)
#define	GCSC_DMA_SHDW_CH1		(GCSC_DIVIL_MSR_BASE + 0x42)
#define	GCSC_DMA_SHDW_CH2		(GCSC_DIVIL_MSR_BASE + 0x43)
#define	GCSC_DMA_SHDW_CH3		(GCSC_DIVIL_MSR_BASE + 0x44)
#define	GCSC_DMA_SHDW_CH4		(GCSC_DIVIL_MSR_BASE + 0x45)
#define	GCSC_DMA_SHDW_CH5		(GCSC_DIVIL_MSR_BASE + 0x46)
#define	GCSC_DMA_SHDW_CH6		(GCSC_DIVIL_MSR_BASE + 0x47)
#define	GCSC_DMA_SHDW_CH7		(GCSC_DIVIL_MSR_BASE + 0x48)
#define	GCSC_DMA_MSK_SHDW		(GCSC_DIVIL_MSR_BASE + 0x49)
#define	GCSC_LPC_EADDR			(GCSC_DIVIL_MSR_BASE + 0x4c)
#define	GCSC_LPC_ESTAT			(GCSC_DIVIL_MSR_BASE + 0x4d)
#define	GCSC_LPC_SIRQ			(GCSC_DIVIL_MSR_BASE + 0x4e)
#define	GCSC_LPC_RSVD			(GCSC_DIVIL_MSR_BASE + 0x4f)
#define	GCSC_PMC_LTMR			(GCSC_DIVIL_MSR_BASE + 0x50)
#define	GCSC_PMC_RSVD			(GCSC_DIVIL_MSR_BASE + 0x51)
#define	GCSC_RTC_RAM_LOCK		(GCSC_DIVIL_MSR_BASE + 0x54)
#define	GCSC_RTC_DOMA_OFFSET		(GCSC_DIVIL_MSR_BASE + 0x55)
#define	GCSC_RTC_MONA_OFFSET		(GCSC_DIVIL_MSR_BASE + 0x56)
#define	GCSC_RTC_CEN_OFFSET		(GCSC_DIVIL_MSR_BASE + 0x57)

/*
 * GeodeLink Control Processor (GLCP)
 */

#define	GCSC_GLCP_GLD_MSR_CAP		(GCSC_GLCP_MSR_BASE + 0x00)
#define	GCSC_GLCP_GLD_MSR_CONFIG	(GCSC_GLCP_MSR_BASE + 0x01)
#define	GCSC_GLCP_GLD_MSR_SMI		(GCSC_GLCP_MSR_BASE + 0x02)
#define	GCSC_GLCP_GLD_MSR_ERROR		(GCSC_GLCP_MSR_BASE + 0x03)
#define	GCSC_GLCP_GLD_MSR_PM		(GCSC_GLCP_MSR_BASE + 0x04)
#define	GCSC_GLCP_GLD_MSR_DIAG		(GCSC_GLCP_MSR_BASE + 0x05)

#define	GCSC_GLCP_CLK_DIS_DELAY		(GCSC_GLCP_MSR_BASE + 0x08)
#define	GCSC_GLCP_PMCLKDISABLE		(GCSC_GLCP_MSR_BASE + 0x09)
#define	GCSC_GLCP_GLB_PM		(GCSC_GLCP_MSR_BASE + 0x0b)
#define	GCSC_GLCP_DBGOUT		(GCSC_GLCP_MSR_BASE + 0x0c)
#define	GCSC_GLCP_DOWSER		(GCSC_GLCP_MSR_BASE + 0x0e)
#define	GCSC_GLCP_CLKOFF		(GCSC_GLCP_MSR_BASE + 0x10)
#define	GCSC_GLCP_CLKACTIVE		(GCSC_GLCP_MSR_BASE + 0x11)
#define	GCSC_GLCP_CLKDISABLE		(GCSC_GLCP_MSR_BASE + 0x12)
#define	GCSC_GLCP_CLK4ACK		(GCSC_GLCP_MSR_BASE + 0x13)
#define	GCSC_GLCP_SYS_RST		(GCSC_GLCP_MSR_BASE + 0x14)
#define	GCSC_GLCP_DBGCLKCTRL		(GCSC_GLCP_MSR_BASE + 0x16)
#define	GCSC_GLCP_CHIP_REV_ID		(GCSC_GLCP_MSR_BASE + 0x17)

/*
 * GPIO registers
 */

#define	GCSC_GPIOL_OUT_VAL		0x0000
#define	GCSC_GPIOL_OUT_EN		0x0004
#define	GCSC_GPIOL_OUT_OD_EN		0x0008
#define	GCSC_GPIOL_OUT_INVRT_EN		0x000c
#define	GCSC_GPIOL_OUT_AUX1_SEL		0x0010
#define	GCSC_GPIOL_OUT_AUX2_SEL		0x0014
#define	GCSC_GPIOL_PU_EN		0x0018
#define	GCSC_GPIOL_PD_EN		0x001c
#define	GCSC_GPIOL_IN_EN		0x0020
#define	GCSC_GPIOL_IN_INV_EN		0x0024
#define	GCSC_GPIOL_IN_FLTR_EN		0x0028
#define	GCSC_GPIOL_IN_EVNTCNT_EN	0x002c
#define	GCSC_GPIOL_READ_BACK		0x0030
#define	GCSC_GPIOL_IN_AUX1_SEL		0x0034
#define	GCSC_GPIOL_EVNT_EN		0x0038
#define	GCSC_GPIOL_LOCK_EN		0x003c
#define	GCSC_GPIOL_POSEDGE_EN		0x0040
#define	GCSC_GPIOL_NEGEDGE_EN		0x0044
#define	GCSC_GPIOL_POSEDGE_STS		0x0048
#define	GCSC_GPIOL_NEGEDGE_STS		0x004c
#define	GCSC_GPIO_FLTR0_AMNT		0x0050
#define	GCSC_GPIO_FLTR0_CNT		0x0052
#define	GCSC_GPIO_EVNTCNT0		0x0054
#define	GCSC_GPIO_EVNTCNT0_COMP		0x0056
#define	GCSC_GPIO_FLTR1_AMNT		0x0058
#define	GCSC_GPIO_FLTR1_CNT		0x005a
#define	GCSC_GPIO_EVNTCNT1		0x005c
#define	GCSC_GPIO_EVNTCNT1_COMP		0x005e
#define	GCSC_GPIO_FLTR2_AMNT		0x0060
#define	GCSC_GPIO_FLTR2_CNT		0x0062
#define	GCSC_GPIO_EVNTCNT2		0x0064
#define	GCSC_GPIO_EVNTCNT2_COMP		0x0066
#define	GCSC_GPIO_FLTR3_AMNT		0x0068
#define	GCSC_GPIO_FLTR3_CNT		0x006a
#define	GCSC_GPIO_EVNTCNT3		0x006c
#define	GCSC_GPIO_EVNTCNT3_COMP		0x006e
#define	GCSC_GPIO_FLTR4_AMNT		0x0070
#define	GCSC_GPIO_FLTR4_CNT		0x0072
#define	GCSC_GPIO_EVNTCNT4		0x0074
#define	GCSC_GCSC_GPIO_EVNTCNT4_COMP	0x0076
#define	GCSC_GPIO_FLTR5_AMNT		0x0078
#define	GCSC_GPIO_FLTR5_CNT		0x007a
#define	GCSC_GPIO_EVNTCNT5		0x007c
#define	GCSC_GPIO_EVNTCNT5_COMP		0x007e
#define	GCSC_GPIOH_OUT_VAL		0x0080
#define	GCSC_GPIOH_OUT_EN		0x0084
#define	GCSC_GPIOH_OUT_OD_EN		0x0088
#define	GCSC_GPIOH_OUT_INVRT_EN		0x008c
#define	GCSC_GPIOH_OUT_AUX1_SEL		0x0090
#define	GCSC_GPIOH_OUT_AUX2_SEL		0x0094
#define	GCSC_GPIOH_PU_EN		0x0098
#define	GCSC_GPIOH_PD_EN		0x009c
#define	GCSC_GPIOH_IN_EN		0x00a0
#define	GCSC_GPIOH_IN_INV_EN		0x00a4
#define	GCSC_GPIOH_IN_FLTR_EN		0x00a8
#define	GCSC_GPIOH_IN_EVNTCNT_E		0x00ac
#define	GCSC_GPIOH_READ_BACK		0x00b0
#define	GCSC_GPIOH_IN_AUX1_SEL		0x00b4
#define	GCSC_GPIOH_EVNT_EN		0x00b8
#define	GCSC_GPIOH_LOCK_EN		0x00bc
#define	GCSC_GPIOH_POSEDGE_EN		0x00c0
#define	GCSC_GPIOH_NEGEDGE_EN		0x00c4
#define	GCSC_GPIOH_POSEDGE_STS		0x00c8
#define	GCSC_GPIOH_NEGEDGE_STS		0x00cc
#define	GCSC_GPIO_FLTR6_AMNT		0x00d0
#define	GCSC_GPIO_FLTR6_CNT		0x00d2
#define	GCSC_GPIO_EVNTCNT6		0x00d4
#define	GCSC_GPIO_EVNTCNT6_COMP		0x00d6
#define	GCSC_GPIO_FLTR7_AMNT		0x00d8
#define	GCSC_GPIO_FLTR7_CNT		0x00da
#define	GCSC_GPIO_EVNTCNT7		0x00dc
#define	GCSC_GPIO_EVNTCNT7_COMP		0x00de
#define	GCSC_GPIO_MAP_X			0x00e0
#define	GCSC_GPIO_MAP_Y			0x00e4
#define	GCSC_GPIO_MAP_Z			0x00e8
#define	GCSC_GPIO_MAP_W			0x00ec
#define	GCSC_GPIO_FE0_SEL		0x00f0
#define	GCSC_GPIO_FE1_SEL		0x00f1
#define	GCSC_GPIO_FE2_SEL		0x00f2
#define	GCSC_GPIO_FE3_SEL		0x00f3
#define	GCSC_GPIO_FE4_SEL		0x00f4
#define	GCSC_GPIO_FE5_SEL		0x00f5
#define	GCSC_GPIO_FE6_SEL		0x00f6
#define	GCSC_GPIO_FE7_SEL		0x00f7
#define	GCSC_GPIOL_EVNTCNT_DEC		0x00f8
#define	GCSC_GPIOH_EVNTCNT_DEC		0x00fc

#define	GCSC_GPIO_ATOMIC_VALUE(pin,feature) \
	((feature) ? \
	    ((0 << (16 + (pin))) | (1 << (pin))) : \
	    ((1 << (16 + (pin))) | (0 << (pin))))

File Added: src/sys/arch/evbmips/loongson/dev/glxvar.h
/*	$OpenBSD: glxvar.h,v 1.1 2010/10/14 21:23:05 pirofti Exp $	*/

/*
 * Copyright (c) 2009 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

void		glx_init(pci_chipset_tag_t, pcitag_t, int);

uint64_t	rdmsr(uint);
void		wrmsr(uint, uint64_t);

File Added: src/sys/arch/evbmips/loongson/dev/kb3310.c
/*	$OpenBSD: kb3310.c,v 1.16 2010/10/14 21:23:04 pirofti Exp $	*/
/*
 * Copyright (c) 2010 Otto Moerbeek <otto@drijf.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>
#include <sys/timeout.h>

#include <mips64/archtype.h>
#include <machine/apmvar.h>
#include <evbmips/loongson/autoconf.h>
#include <machine/bus.h>
#include <dev/isa/isavar.h>

#include <dev/pci/glxreg.h>

#include <loongson/dev/bonitoreg.h>
#include <loongson/dev/kb3310var.h>

#include "apm.h"
#include "pckbd.h"
#include "hidkbd.h"

#if NPCKBD > 0 || NHIDKBD > 0
#include <dev/ic/pckbcvar.h>
#include <dev/pckbc/pckbdvar.h>
#include <dev/usb/hidkbdvar.h>
#endif

struct cfdriver ykbec_cd = {
	NULL, "ykbec", DV_DULL,
};

#ifdef KB3310_DEBUG
#define DPRINTF(x)	printf x
#else
#define DPRINTF(x)
#endif

#define IO_YKBEC		0x381
#define IO_YKBECSIZE		0x3

static const struct {
	const char *desc;	
	int type;
} ykbec_table[] = {
#define YKBEC_FAN	0
	{ NULL,				SENSOR_FANRPM },
#define YKBEC_ITEMP	1
	{ "Internal temperature",	SENSOR_TEMP },
#define YKBEC_FCAP	2
	{ "Battery full charge capacity", SENSOR_AMPHOUR },
#define YKBEC_BCURRENT	3
	{ "Battery current", 		SENSOR_AMPS },
#define YKBEC_BVOLT	4
	{ "Battery voltage",		SENSOR_VOLTS_DC },
#define YKBEC_BTEMP	5
	{ "Battery temperature",	SENSOR_TEMP },
#define YKBEC_CAP	6
	{ "Battery capacity", 		SENSOR_PERCENT },
#define YKBEC_CHARGING	7
	{ "Battery charging",		SENSOR_INDICATOR },
#define YKBEC_AC	8
	{ "AC-Power",			SENSOR_INDICATOR }
#define YKBEC_NSENSORS	9
};

struct ykbec_softc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	struct ksensor		sc_sensor[YKBEC_NSENSORS];
	struct ksensordev	sc_sensordev;
#if NPCKBD > 0 || NHIDKBD > 0
	struct timeout		sc_bell_tmo;
#endif
};

static struct ykbec_softc *ykbec_sc;
static int ykbec_chip_config;

extern void loongson_set_isa_imr(uint);

int	ykbec_match(struct device *, void *, void *);
void	ykbec_attach(struct device *, struct device *, void *);

const struct cfattach ykbec_ca = {
	sizeof(struct ykbec_softc), ykbec_match, ykbec_attach
};

int	ykbec_apminfo(struct apm_power_info *);
void	ykbec_bell(void *, u_int, u_int, u_int, int);
void	ykbec_bell_stop(void *);
void	ykbec_print_bat_info(struct ykbec_softc *);
u_int	ykbec_read(struct ykbec_softc *, u_int);
u_int	ykbec_read16(struct ykbec_softc *, u_int);
void	ykbec_refresh(void *arg);
void	ykbec_write(struct ykbec_softc *, u_int, u_int);

#if NAPM > 0
struct apm_power_info ykbec_apmdata;
const char *ykbec_batstate[] = {
	"high",
	"low",
	"critical",
	"charging",
	"unknown"
};
#define BATTERY_STRING(x) ((x) < nitems(ykbec_batstate) ? \
	ykbec_batstate[x] : ykbec_batstate[4])
#endif

int
ykbec_match(struct device *parent, void *match, void *aux)
{
	struct isa_attach_args *ia = aux;
	bus_space_handle_t ioh;

	if (sys_platform->system_type != LOONGSON_YEELOONG)
		return (0);

	if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_YKBEC) ||
	    /* (ia->ia_iosize != 0 && ia->ia_iosize != IO_YKBECSIZE) || XXX isa.c */
	    ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 ||
	    ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK)
		return (0);

	if (bus_space_map(ia->ia_iot, IO_YKBEC, IO_YKBECSIZE, 0, &ioh))
		return (0);

	bus_space_unmap(ia->ia_iot, ioh, IO_YKBECSIZE);

	ia->ia_iobase = IO_YKBEC;
	ia->ia_iosize = IO_YKBECSIZE;

	return (1);
}

void
ykbec_attach(struct device *parent, struct device *self, void *aux)
{
	struct isa_attach_args *ia = aux;
	struct ykbec_softc *sc = (struct ykbec_softc *)self;
	int i;

	sc->sc_iot = ia->ia_iot;
	if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0,
	    &sc->sc_ioh)) {
		aprint_error(": couldn't map I/O space");
		return;
	}

	/* Initialize sensor data. */
	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
	    sizeof(sc->sc_sensordev.xname));
	if (sensor_task_register(sc, ykbec_refresh, 5) == NULL) {
		aprint_error(", unable to register update task\n");
		return;
	}

#ifdef DEBUG
	ykbec_print_bat_info(sc);
#endif
	aprint_normal("\n");

	for (i = 0; i < YKBEC_NSENSORS; i++) {
		sc->sc_sensor[i].type = ykbec_table[i].type; 
		if (ykbec_table[i].desc) 
			strlcpy(sc->sc_sensor[i].desc, ykbec_table[i].desc,
			    sizeof(sc->sc_sensor[i].desc));
		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
	}

	sensordev_install(&sc->sc_sensordev);

#if NAPM > 0
	/* make sure we have the apm state initialized before apm attaches */
	ykbec_refresh(sc);
	apm_setinfohook(ykbec_apminfo);
#endif
#if NPCKBD > 0 || NHIDKBD > 0
	timeout_set(&sc->sc_bell_tmo, ykbec_bell_stop, sc);
#if NPCKBD > 0
	pckbd_hookup_bell(ykbec_bell, sc);
#endif
#if NHIDKBD > 0
	hidkbd_hookup_bell(ykbec_bell, sc);
#endif
#endif
	ykbec_sc = sc;
}

void
ykbec_write(struct ykbec_softc *mcsc, u_int reg, u_int datum)
{
	struct ykbec_softc *sc = (struct ykbec_softc *)mcsc;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff);
	bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff);
	bus_space_write_1(iot, ioh, 2, datum);
}

u_int
ykbec_read(struct ykbec_softc *mcsc, u_int reg)
{
	struct ykbec_softc *sc = (struct ykbec_softc *)mcsc;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff);
	bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff);
	return bus_space_read_1(iot, ioh, 2);
}

u_int
ykbec_read16(struct ykbec_softc *mcsc, u_int reg)
{
	u_int val;

	val = ykbec_read(mcsc, reg);
	return (val << 8) | ykbec_read(mcsc, reg + 1);
}

#define KB3310_FAN_SPEED_DIVIDER	480000

#define ECTEMP_CURRENT_REG		0xf458
#define REG_FAN_SPEED_HIGH		0xfe22
#define REG_FAN_SPEED_LOW		0xfe23

#define REG_DESIGN_CAP_HIGH		0xf77d
#define REG_DESIGN_CAP_LOW		0xf77e
#define REG_FULLCHG_CAP_HIGH		0xf780
#define REG_FULLCHG_CAP_LOW		0xf781

#define REG_DESIGN_VOL_HIGH		0xf782
#define REG_DESIGN_VOL_LOW		0xf783
#define REG_CURRENT_HIGH		0xf784
#define REG_CURRENT_LOW			0xf785
#define REG_VOLTAGE_HIGH		0xf786
#define REG_VOLTAGE_LOW			0xf787
#define REG_TEMPERATURE_HIGH		0xf788
#define REG_TEMPERATURE_LOW		0xf789
#define REG_RELATIVE_CAT_HIGH		0xf492
#define REG_RELATIVE_CAT_LOW		0xf493
#define REG_BAT_VENDOR			0xf4c4
#define REG_BAT_CELL_COUNT		0xf4c6

#define REG_BAT_CHARGE			0xf4a2
#define BAT_CHARGE_AC			0x00
#define BAT_CHARGE_DISCHARGE		0x01
#define BAT_CHARGE_CHARGE		0x02

#define REG_POWER_FLAG			0xf440
#define POWER_FLAG_ADAPTER_IN		(1<<0)
#define POWER_FLAG_POWER_ON		(1<<1)
#define POWER_FLAG_ENTER_SUS		(1<<2)

#define REG_BAT_STATUS			0xf4b0
#define BAT_STATUS_BAT_EXISTS		(1<<0)
#define BAT_STATUS_BAT_FULL		(1<<1)
#define BAT_STATUS_BAT_DESTROY		(1<<2)
#define BAT_STATUS_BAT_LOW		(1<<5)

#define REG_CHARGE_STATUS		0xf4b1
#define CHARGE_STATUS_PRECHARGE		(1<<1)
#define CHARGE_STATUS_OVERHEAT		(1<<2)

#define REG_BAT_STATE			0xf482
#define BAT_STATE_DISCHARGING		(1<<0)
#define BAT_STATE_CHARGING		(1<<1)

#define	REG_BEEP_CONTROL		0xf4d0
#define	BEEP_ENABLE			(1<<0)

#define REG_PMUCFG			0xff0c
#define PMUCFG_STOP_MODE		(1<<7)
#define PMUCFG_IDLE_MODE		(1<<6)
#define PMUCFG_LPC_WAKEUP		(1<<5)
#define PMUCFG_RESET_8051		(1<<4)
#define PMUCFG_SCI_WAKEUP		(1<<3)
#define PMUCFG_WDT_WAKEUP		(1<<2)
#define PMUCFG_GPWU_WAKEUP		(1<<1)
#define PMUCFG_IRQ_IDLE			(1<<0)

#define REG_USB0			0xf461
#define REG_USB1			0xf462
#define REG_USB2			0xf463
#define USB_FLAG_ON			1
#define USB_FLAG_OFF			0

#define REG_FAN_CONTROL			0xf4d2
#define	REG_FAN_ON			1
#define REG_FAN_OFF			0

#define YKBEC_SCI_IRQ			0xa

#ifdef DEBUG
void
ykbec_print_bat_info(struct ykbec_softc *sc)
{
	uint bat_status, count, dvolt, dcap;

	printf(": battery ");
	bat_status = ykbec_read(sc, REG_BAT_STATUS);
	if (!ISSET(bat_status, BAT_STATUS_BAT_EXISTS)) {
		printf("absent");
		return;
	}
		
	count = ykbec_read(sc, REG_BAT_CELL_COUNT);
	dvolt = ykbec_read16(sc, REG_DESIGN_VOL_HIGH);
	dcap = ykbec_read16(sc, REG_DESIGN_CAP_HIGH);
	printf("%d cells, design capacity %dmV %dmAh", count, dvolt, dcap);
}
#endif

void
ykbec_refresh(void *arg)
{
	struct ykbec_softc *sc = (struct ykbec_softc *)arg;
	u_int val, bat_charge, bat_status, charge_status, bat_state, power_flag;
	u_int cap_pct, fullcap;
	int current;
#if NAPM > 0
	struct apm_power_info old;
#endif

	val = ykbec_read16(sc, REG_FAN_SPEED_HIGH) & 0xfffff;
	if (val != 0) {
		val = KB3310_FAN_SPEED_DIVIDER / val;
		sc->sc_sensor[YKBEC_FAN].value = val;
		CLR(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID);
	} else
		SET(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID);

	val = ykbec_read(sc, ECTEMP_CURRENT_REG);
	sc->sc_sensor[YKBEC_ITEMP].value = val * 1000000 + 273150000;

	fullcap = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH);
	sc->sc_sensor[YKBEC_FCAP].value = fullcap * 1000;

	current = ykbec_read16(sc, REG_CURRENT_HIGH);
	/* sign extend short -> int, int -> int64 will be done next statement */
	current |= -(current & 0x8000);
	sc->sc_sensor[YKBEC_BCURRENT].value = -1000 * current;

	sc->sc_sensor[YKBEC_BVOLT].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) *
	    1000;

	val = ykbec_read16(sc, REG_TEMPERATURE_HIGH);
	sc->sc_sensor[YKBEC_BTEMP].value = val * 1000000 + 273150000;

	cap_pct = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH);
	sc->sc_sensor[YKBEC_CAP].value = cap_pct * 1000;

	bat_charge = ykbec_read(sc, REG_BAT_CHARGE);
	bat_status = ykbec_read(sc, REG_BAT_STATUS);
	charge_status = ykbec_read(sc, REG_CHARGE_STATUS);
	bat_state = ykbec_read(sc, REG_BAT_STATE);
	power_flag = ykbec_read(sc, REG_POWER_FLAG);

	sc->sc_sensor[YKBEC_CHARGING].value = !!ISSET(bat_state,
	    BAT_STATE_CHARGING);
	sc->sc_sensor[YKBEC_AC].value = !!ISSET(power_flag,
	    POWER_FLAG_ADAPTER_IN);

	sc->sc_sensor[YKBEC_CAP].status = ISSET(bat_status, BAT_STATUS_BAT_LOW) ?
		SENSOR_S_CRIT : SENSOR_S_OK;

#if NAPM > 0
	bcopy(&ykbec_apmdata, &old, sizeof(old));
	ykbec_apmdata.battery_life = cap_pct;
	ykbec_apmdata.ac_state = ISSET(power_flag, POWER_FLAG_ADAPTER_IN) ?
	    APM_AC_ON : APM_AC_OFF;
	if (!ISSET(bat_status, BAT_STATUS_BAT_EXISTS)) {
		ykbec_apmdata.battery_state = APM_BATTERY_ABSENT;
		ykbec_apmdata.minutes_left = 0;
		ykbec_apmdata.battery_life = 0;
	} else {
		if (ISSET(bat_state, BAT_STATE_CHARGING))
			ykbec_apmdata.battery_state = APM_BATT_CHARGING;
		else if (ISSET(bat_status, BAT_STATUS_BAT_LOW))
			ykbec_apmdata.battery_state = APM_BATT_CRITICAL;
		/* XXX arbitrary */
		else if (cap_pct > 60)
			ykbec_apmdata.battery_state = APM_BATT_HIGH;
		else
			ykbec_apmdata.battery_state = APM_BATT_LOW;

		/* if charging, current is positive */
		if (ISSET(bat_state, BAT_STATE_CHARGING))
			current = 0;
		else
			current = -current;
		/* XXX Yeeloong draw is about 1A */
		if (current <= 0)
			current = 1000;
		/* XXX at 5?%, the Yeeloong shuts down */
		if (cap_pct <= 5)
			cap_pct = 0;
		else
			cap_pct -= 5;
		fullcap = cap_pct * 60 * fullcap / 100;
		ykbec_apmdata.minutes_left = fullcap / current;

	}
	if (old.ac_state != ykbec_apmdata.ac_state) 
		apm_record_event(APM_POWER_CHANGE, "AC power",
			ykbec_apmdata.ac_state ? "restored" : "lost");
	if (old.battery_state != ykbec_apmdata.battery_state) 
		apm_record_event(APM_POWER_CHANGE, "battery",
		    BATTERY_STRING(ykbec_apmdata.battery_state));
#endif
}


#if NAPM > 0
int
ykbec_apminfo(struct apm_power_info *info)
{
	 bcopy(&ykbec_apmdata, info, sizeof(struct apm_power_info));
	 return 0;
}

int
ykbec_suspend()
{
	struct ykbec_softc *sc = ykbec_sc;
	int ctrl;

	/*
	 * Set up wakeup sources: currently only the internal keyboard.
	 */
	loongson_set_isa_imr(1 << 1);

	/* USB */
	DPRINTF(("USB\n"));
	ykbec_write(sc, REG_USB0, USB_FLAG_OFF); 
	ykbec_write(sc, REG_USB1, USB_FLAG_OFF); 
	ykbec_write(sc, REG_USB2, USB_FLAG_OFF); 

	/* EC */
	DPRINTF(("REG_PMUCFG\n"));
	ctrl = PMUCFG_SCI_WAKEUP | PMUCFG_WDT_WAKEUP | PMUCFG_GPWU_WAKEUP |
	    PMUCFG_LPC_WAKEUP | PMUCFG_STOP_MODE | PMUCFG_RESET_8051;
	ykbec_write(sc, REG_PMUCFG, ctrl);

	/* FAN */
	DPRINTF(("FAN\n"));
	ykbec_write(sc, REG_FAN_CONTROL, REG_FAN_OFF);

	/* CPU */
	DPRINTF(("CPU\n"));
	ykbec_chip_config = REGVAL(LOONGSON_CHIP_CONFIG0);
	enableintr();
	REGVAL(LOONGSON_CHIP_CONFIG0) = ykbec_chip_config & ~0x7;
	(void)REGVAL(LOONGSON_CHIP_CONFIG0);

	/*
	 * When a resume interrupt fires, we will enter the interrupt
	 * dispatcher, which will do nothing because we are at splhigh,
	 * and execution flow will return here and continue.
	 */
	(void)disableintr();

	return 0;
}

int
ykbec_resume()
{
	struct ykbec_softc *sc = ykbec_sc;

	/* CPU */
	DPRINTF(("CPU\n"));
	REGVAL(LOONGSON_CHIP_CONFIG0) = ykbec_chip_config;
	(void)REGVAL(LOONGSON_CHIP_CONFIG0);

	/* FAN */
	DPRINTF(("FAN\n"));
	ykbec_write(sc, REG_FAN_CONTROL, REG_FAN_ON);

	/* USB */
	DPRINTF(("USB\n"));
	ykbec_write(sc, REG_USB0, USB_FLAG_ON); 
	ykbec_write(sc, REG_USB1, USB_FLAG_ON); 
	ykbec_write(sc, REG_USB2, USB_FLAG_ON); 

	ykbec_refresh(sc);

	return 0;
}
#endif

#if NPCKBD > 0 || NHIDKBD > 0
void
ykbec_bell(void *arg, u_int pitch, u_int period, u_int volume, int poll)
{
	struct ykbec_softc *sc = (struct ykbec_softc *)arg;
	int bctrl;
	int s;

	s = spltty();
	bctrl = ykbec_read(sc, REG_BEEP_CONTROL);
	if (volume == 0 || timeout_pending(&sc->sc_bell_tmo)) {
		timeout_del(&sc->sc_bell_tmo);
		/* inline ykbec_bell_stop(arg); */
		ykbec_write(sc, REG_BEEP_CONTROL, bctrl & ~BEEP_ENABLE);
	}

	if (volume != 0) {
		ykbec_write(sc, REG_BEEP_CONTROL, bctrl | BEEP_ENABLE);
		if (poll) {
			delay(period * 1000);
			ykbec_write(sc, REG_BEEP_CONTROL, bctrl & ~BEEP_ENABLE);
		} else {
			timeout_add_msec(&sc->sc_bell_tmo, period);
		}
	}
	splx(s);
}

void
ykbec_bell_stop(void *arg)
{
	struct ykbec_softc *sc = (struct ykbec_softc *)arg;
	int s;

	s = spltty();
	ykbec_write(sc, REG_BEEP_CONTROL,
	    ykbec_read(sc, REG_BEEP_CONTROL) & ~BEEP_ENABLE);
	splx(s);
}
#endif

File Added: src/sys/arch/evbmips/loongson/dev/kb3310var.h
/*	$OpenBSD: kb3310var.h,v 1.1 2010/08/31 10:24:46 pirofti Exp $	*/
/*
 * Copyright (c) 2009 Paul Irofti <pirofti@openbsd.org>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _LOONGSON_DEV_YKBECVAR_H_
#define _LOONGSON_DEV_YKBECVAR_H_

int ykbec_suspend(void);
int ykbec_resume(void);

#endif

File Added: src/sys/arch/evbmips/loongson/dev/pcib.c
/*	$NetBSD: pcib.c,v 1.1 2011/08/27 13:42:46 bouyer Exp $	*/

/*-
 * Copyright (c) 1996, 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.1 2011/08/27 13:42:46 bouyer Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>


#include <evbmips/loongson/autoconf.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/isa/isavar.h>

#include <evbmips/loongson/loongson_bus_defs.h>
#include <evbmips/loongson/dev/pcibvar.h>

#include "isa.h"

int	pcibmatch(device_t, cfdata_t, void *);
void	pcib_callback(device_t);

CFATTACH_DECL3_NEW(pcib, sizeof(struct pcib_softc),
    pcibmatch, pcibattach, pcibdetach, NULL, pcibrescan, pcibchilddet,
	DVF_DETACH_SHUTDOWN);


int
pcibmatch(device_t parent, cfdata_t match, void *aux)
{
	struct pci_attach_args *pa = aux;

	switch (PCI_VENDOR(pa->pa_id)) {
	case PCI_VENDOR_INTEL:
		switch (PCI_PRODUCT(pa->pa_id)) {
		case PCI_PRODUCT_INTEL_SIO:
		case PCI_PRODUCT_INTEL_82371MX:
		case PCI_PRODUCT_INTEL_82371AB_ISA:
		case PCI_PRODUCT_INTEL_82440MX_ISA:
			/* The above bridges mis-identify themselves */
			return (1);
		}
		break;
	case PCI_VENDOR_SIS:
		switch (PCI_PRODUCT(pa->pa_id)) {
		case PCI_PRODUCT_SIS_85C503:
			/* mis-identifies itself as a miscellaneous prehistoric */
			return (1);
		}
		break;
	case PCI_VENDOR_VIATECH:
		switch (PCI_PRODUCT(pa->pa_id)) {
		case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
			/* mis-identifies itself as a ISA bridge */
			return (0);
		}
		break;
	}

	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
		return (1);

	return (0);
}

void
pcibattach(device_t parent, device_t self, void *aux)
{
	struct pcib_softc *sc = device_private(self);
	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
	char devinfo[256];

	aprint_naive("\n");

	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
	    PCI_REVISION(pa->pa_class));

	/*
	 * Wait until all PCI devices are attached before attaching isa;
	 * otherwise this might mess the interrupt setup on some systems.
	 */
	sc->sc_pc = pa->pa_pc;
	sc->sc_tag = pa->pa_tag;

	if (!pmf_device_register(self, NULL, NULL))
		aprint_error_dev(self, "couldn't establish power handler\n");
	config_defer(self, pcib_callback);
}

int
pcibdetach(device_t self, int flags)
{
	int rc;

	if ((rc = config_detach_children(self, flags)) != 0)
		return rc;
	pmf_device_deregister(self);
	return 0;
}

void
pcibchilddet(device_t self, device_t child)
{
	struct pcib_softc *sc = device_private(self);

	if (sc->sc_isabus == child)
		sc->sc_isabus = NULL;
}

int
pcibrescan(device_t self, const char *ifattr, const int *loc)
{
	struct pcib_softc *sc = device_private(self);
	struct isabus_attach_args iba;

	if (ifattr_match(ifattr, "isabus") && sc->sc_isabus == NULL) {
		/*
		 * Attach the ISA bus behind this bridge.
		 */
		memset(&iba, 0, sizeof(iba));
		iba.iba_iot = &bonito_iot;
		iba.iba_memt = &bonito_memt;
#if NISA > 0
		iba.iba_dmat = &bonito_dmat;
#endif
		iba.iba_ic = sys_platform->isa_chipset;

		if (iba.iba_ic != NULL) 
			sc->sc_isabus =
			    config_found_ia(self, "isabus", &iba, isabusprint);
	}
	return 0;
}


void
pcib_callback(device_t self)
{
	pcibrescan(self, "isabus", NULL);
}

File Added: src/sys/arch/evbmips/loongson/dev/pcibvar.h
/*	$NetBSD: pcibvar.h,v 1.1 2011/08/27 13:42:46 bouyer Exp $	*/

/*-
 * Copyright (c) 1996, 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``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 FOUNDATION OR CONTRIBUTORS
 * 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.
 */

struct pcib_softc {
	pci_chipset_tag_t	sc_pc;
	pcitag_t		sc_tag;
	device_t		sc_isabus;
};

void	pcibattach(device_t, device_t, void *);
void	pcibchilddet(device_t, device_t);
int	pcibdetach(device_t, int);
int	pcibrescan(device_t, const char *, const int *);