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
# $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
# $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
# $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"
/* $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);
}
}
/* $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_ */
/* $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);
}
/* $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;
}
/* $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);
}
/* $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");
}
/* $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;
}
/* $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_ */
/* $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>
/* $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>
/* $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;
}
/* $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_ */
/* $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
/* $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);
}
/* $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;
}
/* $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;
}
}
/* $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);
}
/* $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;
}
}
/* $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))))
/* $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);
/* $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
/* $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
/* $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);
}
/* $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 *);