Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Index: linux-2.6.11/Documentation/fb/geodefb.txt
===================================================================
--- /dev/null
+++ linux-2.6.11/Documentation/fb/geodefb.txt
@@ -0,0 +1,95 @@
+geodefb.txt
+
+This is the documentation for the AMD Geode LX framebuffer driver.
+
+Kernel Build Configuration Parameters
+-------------------------------------
+These kernel build parameters are operated using "make xconfig" or
+"make menuconfig" from the kernel source root directory.
+The parameter path to these parameters is:
+Device Drivers
+ Graphics Support
+ Support for frame buffer devices
+ AMD Geode generic framebuffer support
+ AMD Geode LX framebuffer driver
+ AMD Geode LX console acceleration
+ AMD Geode Framebuffer panel support
+
+Config_Param Value Definition
+============ ===== ==========
+FB_GEODE (y/m/n) Build AMD Geode generic framebuffer support
+FB_GEODE_LX (y/n) Build AMD Geode LX framebuffer driver (selects CIMARRON)
+FB_GEODE_ACCEL (y/n) Build AMD Geode LX console acceleration
+FB_GEODE_PANEL (y/n) Build AMD Geode Framebuffer panel support
+
+
+Kernel Boot Command Line Argument Options
+-----------------------------------------
+If the geodefb driver has been built into the kernel (not as a module), then
+driver setup options are available via the kernel cmdline interface.
+
+kernel boot command line argument options are available using:
+video=geodefb:[, ...]
+option strings are one of three types:
+identifier as in video=geodefb:off
+identifier=value as in video=geodefb:vfreq=85
+noidenfier as in video=geodefb:noflatpanel
+
+video=option Definition
+============ ==========
+off - specify this option to disable the geodefb.
+vfreq= - specifies the default vertical refresh (default 60)
+vmode= - specifies a mode text string. (default = 640x480@60-16)
+no/compression - disables/enables compression display acceleration (default disabled)
+maxmem - Maximum amount of memory to use for the FB (default 12288K)
+no/accel - disables/enables rendering accelerations (default enabled)
+
+if the module was build with CONFIG_FB_GEODE_PANEL applied
+no/flatpanel - disable/enables flatpanel operation (default enabled)
+no/fphwscale - disable/enables flatpanel hardware scaling (default enabled)
+
+
+Module Parameters:
+------------------
+If geodefb was built as a module, then parameters can be applied
+when the modules is installed (via insmod/modprobe or modules.conf).
+When installing the module, new options are specified as follows:
+modprobe geodefb ... or
+insmod /path/geodefb.ko ...
+
+Module parameters:
+parameter Definition
+========= ==========
+vfreq - Set initial video refresh rate in cycles per second
+vmode - Set initial mode to x@refresh-bpp
+compression - Compression support (0=disabled or 1=enabled)
+maxmem - Maximum amount of memory to use for the FB (in Kbytes)
+accel - HW accleration support (0=disabled or 1=enabled)
+
+if the module was build with CONFIG_FB_GEODE_PANEL applied
+flatpanel - Flatpanel support (0=disabled or 1=enabled)
+fphwscale - FP Hardware Scaling (0=disabled or 1=enabled)
+
+
+Video Modes:
+------------
+The permissible mode parameter values are:
+geometry
+ 640x480, 800x600, 1024x768, 1152x864, 1280x1024, 1600x1200, 1920x1600
+refresh
+ 56, 60, 70, 72, 75, 85, 90, 100
+bpp
+ 8, 16, 32
+
+The permissible mode parameter combinations are defined by the cimarron
+driver, and in cimarron by cim_modes.c.
+
+
+Notes:
+-----
+Since building the geodefb normally select the cimarron driver, please
+review the procedures for building cimarron. To have the framebuffer
+driver work properly with X windows, it is normally necessary to create
+device nodes for /dev/cimarron and possibly links for /dev/videox.
+See cimarron module and lxv4l2 module documentation.
+
Index: linux-2.6.11/Documentation/geode.txt
===================================================================
--- /dev/null
+++ linux-2.6.11/Documentation/geode.txt
@@ -0,0 +1,24 @@
+Running Linux on the AMD Geode Architecture
+=======================================
+
+Configuration Options
+
+The following options enable various Geode and CS5535 features:
+
+CONFIG_MGEODE_GX - Enable GX processor support
+CONFIG_MGEODE_LX - Enable LX processor support
+CONFIG_BLK_DEV_CS5535 - Enable IDE support for the CS5535 companion chip
+CONFIG_HW_RANDOM - Includes support for the LX hardware RNG
+CONFIG_FB_GEODE - Enable Geode framebuffer support
+ CONFIG_FB_GEODE_LX - Enable LX framebuffer support
+ CONFIG_FB_GEODE_ACCEL - Use acceleration for console drawing
+ CONFIG_FB_GEODE_PANEL - Support TFT panels
+CONFIG_USB_OHCI_HCD - Enable OHCI USB support for the CS5535 companion chip
+CONFIG_CIMARRON - (Usually selected automatically) - Support the LX graphics
+ abstraction layer.
+
+In addition - the following kernel option should be selected as a module
+if you are using the Geode ALSA driver modules:
+
+CONFIG_SND_AC97_CODEC
+
Index: linux-2.6.11/Documentation/usb/amd5536udc.txt
===================================================================
--- /dev/null
+++ linux-2.6.11/Documentation/usb/amd5536udc.txt
@@ -0,0 +1,184 @@
+-------------------------------------------------------------------------------
+Howto for Linux device driver for the AMD5536 USB Device Controller (UDC)
+for gadget driver stack
+-------------------------------------------------------------------------------
+
+Author: Thomas Dahlmann
+
+INTRODUCTION:
+
+The AMD5536 UDC is part of x86 southbridge AMD5536 and MIPS CPU Au1200.
+It is a DMA capable usb device controller. The usb port is shared
+between host and UDC. The on-chip UOC controller is used to switch the
+usb port between host, UDC and neutral. So amd5536uoc driver is needed
+to get the UDC operating.
+
+-------------------------------------------------------------------------------
+WHAT YOU NEED:
+-------------------------------------------------------------------------------
+
+copy/replace following files to /usr/src/linux/drivers/usb/gadget
+ amd5536udc.c
+ amd5536udc.h
+ amd5536uoc.c
+ amd5536uoc.h
+ ether.c
+ file_storage.c
+ zero.c
+ inode.c
+ gadget_chips.h
+ Makefile
+ Kconfig
+
+-------------------------------------------------------------------------------
+HOW TO INSTALL IT:
+-------------------------------------------------------------------------------
+
+change to directory /usr/src/linux
+
+configure gadget as module:
+ "make menuconfig"
+ under "Code maturity level options" choose "Prompt for development ..."
+ goto "Device Drivers"
+ goto "USB support" -> "USB Gadget support"
+ choose "Support for USB Gadgets" as module
+ under choice "USB Peripheral Controller" choose "AMD5536-UDC"
+ under "USB Gadget Drivers"
+ choose "Gadget Zero" as module or
+ choose "Ethernet Gagdet" as module or
+ choose "File-backed Storage Gadget" as module
+ exit and save config
+
+compile and install modules:
+ "make modules modules_install"
+
+-------------------------------------------------------------------------------
+HOW TO USE IT:
+-------------------------------------------------------------------------------
+
+*** How to load FILE-BACKED STORAGE gadget driver - mass storage ***
+enable USB mass storage support for linux host:
+ change to directory /usr/src/linux
+ "make menuconfig"
+ under "File systems" choose "DOS/FAT/NT filesystems"
+ choose "MSDOS fs support"
+ under "Device Drivers" under "SCSI device support"
+ choose "SCSI device support"
+ choose "SCSI generic support"
+ under "Device Drivers" under "USB support" in section
+ "USB Device Class drivers" choose
+ "USB Mass Storage support"
+ compile new kernel
+create disk file:
+ "dd bs=1M count=128 if=/dev/zero of=/tmp/disk"
+ => creates a 128Mbyte image file /tmp/disk
+load modules:
+ "modprobe amd5536udc"
+ "modprobe g_file_storage file=/tmp/disk"
+ Note: multiple file arguments are possible, each will be a separate
+ drive for the host side, furthermore devices such as /dev/hda
+ (whole disk will be used) or /dev/hda1 (partition) can be used
+ as argument too
+ "modprobe amd5536uoc"
+create a primary FAT16 disk partition via linux host site:
+ "fdisk /dev/sda", make FAT16 prim. partition
+ => "n", "p", "1", "", "", "t", "6", "w",
+ "mkdosfs /dev/sda1"
+ "sync"
+create primary disk partition via Windows XP host site:
+ right click on "My Computer"
+ choose "Manage" => "Disk Management"
+ choose usb disk and follow instructions of partition menu
+mount usb mass storage device on linux host:
+ make directory "/mnt/gadget/"
+ "mount -t msdos /dev/sda1 /mnt/gadget"
+
+*** How to access files of disk image on UDC side ***
+When files were copied from host to UDC mass storage device then files
+are inside the monolitic disk image (see above) on UDC side. This
+disk image can be mounted via the loopback device driver to a
+directory on UDC side to access these files.
+Steps on UDC side:
+ enable kernel support for loopback device
+ change to directory /usr/src/linux
+ "make menuconfig"
+ under "Block devices" choose "Loopback device support"
+ and recompile the kernel
+ determine offset inside disk image:
+ "fdisk -l -u disk_image", output is like:
+>> You must set cylinders.
+>> You can do this from the extra functions menu.
+>>
+>> Disk /tmp/disk128: 5 heads, 52 sectors, 0 cylinders
+>> Units = sectors of 1 * 512 bytes
+>>
+>> Device Boot Start End Blocks Id System
+>> /tmp/disk128p1 52 262079 131014 6 FAT16
+
+ get offset my multiplying start value by sector size:
+ 52 * 512 = 26624
+ mount disk image:
+ "mount -o loop,offset=26624 -t msdos disk_image /mnt"
+
+
+*** How to load ZERO gadget driver - simple BULK loop back ***
+load modules:
+UDC driver:
+ (a) Slave/Fifo mode: "modprobe amd5536udc use_dma=0"
+ (b) DMA Buffer Fill mode: "modprobe amd5536udc use_dma=1"
+ default:
+ (c) DMA PPBNDU mode: "modprobe amd5536udc"
+ (d) DMA PPBDU mode: "modprobe amd5536udc use_dma=1 use_dma_ppb=1 use_dma_ppb_du=1"
+ (e) fullspeed mode: "modprobe amd5536udc use_fullspeed=1", can be combined
+ with all dma modes
+ (f) special higspeed
+ tx buffer size: "modprobe amd5536udc hs_tx_buf="
+ example: "modprobe amd5536udc use_dma=1 hs_tx_buf=128"
+ => buffer size = 512 bytes (=bulk max packet)
+Gadget Zero driver:
+ (a) Bulk loop: "modprobe g_zero"
+ (b) Int loop: "modprobe g_zero use_interrupt_traffic=1"
+ (c) Source/Sink "modprobe g_zero loopdefault=0"
+ OUT data must all be zero's
+ (d) Source/Sink count "modprobe g_zero loopdefault=0 pattern=1"
+ each OUT packet must count modulo63 (0,1,..,62,0,1,..)
+UOC driver: "modprobe amd5536uoc"
+example:
+ "modprobe amd5536udc"
+ "modprobe g_zero"
+ "modprobe amd5536uoc"
+ => loads driver for DMA PPBNDU mode and Bulk loop
+
+
+*** How to use ETHERNET gadget driver (CDC protocol) ***
+ with Linux Host
+UDC side bringup:
+ load gadget modules
+ "modprobe amd5536udc"
+ "modprobe g_ether"
+ "modprobe amd5536uoc"
+ "ifconfig usb0 192.168.0.2"
+Host side bringup:
+ install support for CDC Ethernet:
+ change to directory /usr/src/linux
+ "make menuconfig"
+ under "Device Drivers" under "USB support" under
+ "USB Network adapters" choose
+ "Multi-purpose USB Networking Framework"
+ choose "CDC Ethernet support"
+ compile mew kernel
+ "modprobe CDCEther"
+ "ifconfig eth1 192.168.0.1"
+ note: assuming there is one network card assigned to eth0,
+ otherwise kernel messages of CDC Ethernet module show
+ which interface (ethX) is used
+Use network connection:
+ after bringup of host and UDC side it behaves like a normal
+ ethernet connection between host and UDC
+ test the connection:
+ host side: "ping -I eth1 192.168.0.2"
+ UDC side : "ping -I usb0 192.168.0.1"
+ note: the "-I" option assures that the USB cable is used, the
+ option can be omitted when the routing table is setup to avoid
+ using other network interfaces as eth0
+
Index: linux-2.6.11/Documentation/usb/amd5536uoc.txt
===================================================================
--- /dev/null
+++ linux-2.6.11/Documentation/usb/amd5536uoc.txt
@@ -0,0 +1,89 @@
+--------------------------------------------------------------------------
+Howto for Linux device driver for the AMD5536 USB Options Controller (UOC)
+--------------------------------------------------------------------------
+
+Author: Karsten Boge
+
+(1)Introduction
+===============
+
+The AMD5536 UOC is part of x86 southbridge AMD5536.
+The USB port is shared between the USB Host Controller
+and the USB Device Controller as defined in BIOS setup.
+The on-chip UOC controller is used to switch the
+usb port between host, UDC and neutral.
+The amd5536uoc driver is needed to get the
+USB Device Controller operating.
+
+(2) Patches
+===========
+
+udc.patch:
+ This containes the UDC driver as together
+ with the UOC driver
+
+(3) Driver source code installation
+===================================
+
+- New files for UOC:
+ drivers/usb/gadget/amd5536uoc.h
+ drivers/usb/gadget/amd5536uoc.c
+
+(4) BIOS setup
+==================
+
+ PCI Configuration
+ UDC: Enabled
+ OTG: Enabled
+ Port 4 assignment: Device
+
+(4) Config options
+==================
+
+ Support for USB Gadgets
+ USB Periheral Controller (?choice?)
+ (X) AMD5536UDC
+
+ The role of the UOC port can be defined
+ within the BIOS setup exclusively.
+
+ Selecting the amd5536udc driver results in
+ building the amd5536uoc driver too.
+ If "Support for USB Gadgets" is configured to be statically
+ linked both modules will be linked into the kernel image
+ otherwise an additional module called amd5536uoc will be built
+
+
+(5) Compile and install
+=======================
+
+ If global USB support is configured to be used as
+ kernel module (usbcore.o) (recomended):
+
+ make modules SUBDIRS=drivers/usb/gadget
+ make modules_install
+
+ If it's linked into the kernel image an new kernel
+ image must be compiled and created before.
+
+(6) Usage
+=========
+
+ modprobe amd5536uoc
+
+ This will load the module and other modules which provide
+ interfaces used by the UOC driver (usbcore, amd5536udc).
+
+ The amd5536uoc driver is needed to power up the uoc logic
+ which controls the pullup resistors connected to either
+ the D+ or D- USB pins.
+ The function of this pullup resistors is to signal the host
+ that a device is connected, and at which speed the device
+ operates.
+
+ Make sure the USB port is assigned to device within the
+ BIOS setup otherwise the modules will not be loaded.
+
+
+
+
Index: linux-2.6.11/MAINTAINERS
===================================================================
--- linux-2.6.11.orig/MAINTAINERS
+++ linux-2.6.11/MAINTAINERS
@@ -255,6 +255,13 @@ P: Ivan Kokshaysky
M: ink@jurassic.park.msu.ru
S: Maintained for 2.4; PCI support for 2.6.
+AMD GEODE PROCESSOR/CHIPSET SUPPORT
+P:
+M:
+L: info-linux@geode.amd.com
+W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
+S: Supported
+
APM DRIVER
P: Stephen Rothwell
M: sfr@canb.auug.org.au
Index: linux-2.6.11/Makefile
===================================================================
--- linux-2.6.11.orig/Makefile
+++ linux-2.6.11/Makefile
@@ -1,7 +1,8 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 11
-EXTRAVERSION =
+AMDVERSION = 02.03.0100
+EXTRAVERSION = -geode-$(AMDVERSION)
NAME=Woozy Numbat
# *DOCUMENTATION*
Index: linux-2.6.11/arch/i386/Kconfig
===================================================================
--- linux-2.6.11.orig/arch/i386/Kconfig
+++ linux-2.6.11/arch/i386/Kconfig
@@ -178,6 +178,7 @@ config M386
- "Pentium-4" for the Intel Pentium 4 or P4-based Celeron.
- "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
- "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
+ - "Geode GX/LX" for AMD Geode GX and LX processors
- "Crusoe" for the Transmeta Crusoe series.
- "Efficeon" for the Transmeta Efficeon series.
- "Winchip-C6" for original IDT Winchip.
@@ -275,6 +276,21 @@ config MK8
use of some extended instructions, and passes appropriate optimization
flags to GCC.
+config MGEODE_GX
+ bool "Geode GX"
+ help
+ Select this for AMD Geode GX and LX processors.
+ Enables use of some extended instructions, and
+ passes appropriate optimization flags to GCC.
+
+config MGEODE_LX
+ bool "Geode LX"
+ help
+ Select this for AMD Geode LX processors.
+ Enables use of some extended instructions, allows
+ you to use various on-chip devices, and passes appropriate
+ optimization flags to GCC.
+
config MCRUSOE
bool "Crusoe"
help
@@ -358,9 +374,9 @@ config X86_XADD
config X86_L1_CACHE_SHIFT
int
- default "7" if MPENTIUM4 || X86_GENERIC
+ default "7" if MPENTIUM4 || X86_GENERIC
default "4" if X86_ELAN || M486 || M386
- default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2
+ default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_GX || MGEODE_LX
default "6" if MK7 || MK8 || MPENTIUMM
config RWSEM_GENERIC_SPINLOCK
@@ -424,12 +440,12 @@ config X86_INTEL_USERCOPY
config X86_USE_PPRO_CHECKSUM
bool
- depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON
+ depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_GX || MGEODE_LX
default y
config X86_USE_3DNOW
bool
- depends on MCYRIXIII || MK7
+ depends on MCYRIXIII || MK7 || MGEODE_GX || MGEODE_LX
default y
config X86_OOSTORE
@@ -530,7 +546,7 @@ config PREEMPT_BKL
config X86_UP_APIC
bool "Local APIC support on uniprocessors" if !SMP
- depends on !(X86_VISWS || X86_VOYAGER)
+ depends on !(X86_VISWS || X86_VOYAGER || MGEODE_GX || MGEODE_LX)
---help---
A local APIC (Advanced Programmable Interrupt Controller) is an
integrated interrupt controller in the CPU. If you have a single-CPU
@@ -729,6 +745,7 @@ config HIGHMEM4G
config HIGHMEM64G
bool "64GB"
+ depends on !MGEODE_GX && !MGEODE_LX
help
Select this if you have a 32-bit processor and more than 4
gigabytes of physical RAM.
Index: linux-2.6.11/arch/i386/defconfig
===================================================================
--- linux-2.6.11.orig/arch/i386/defconfig
+++ linux-2.6.11/arch/i386/defconfig
@@ -1,21 +1,25 @@
#
# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-geode-2.00.00-pre1
+# Fri Jun 3 11:45:26 2005
#
CONFIG_X86=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
+CONFIG_LOCALVERSION=""
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
@@ -23,18 +27,22 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_SYSCTL=y
CONFIG_AUDIT=y
CONFIG_AUDITSYSCALL=y
-CONFIG_LOG_BUF_SHIFT=15
+CONFIG_LOG_BUF_SHIFT=14
CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
#
# Loadable module support
@@ -43,6 +51,7 @@ CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
@@ -66,10 +75,12 @@ CONFIG_X86_PC=y
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
-CONFIG_MPENTIUM4=y
+# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MK8 is not set
+# CONFIG_MGEODE_GX is not set
+CONFIG_MGEODE_LX=y
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
@@ -80,27 +91,19 @@ CONFIG_MPENTIUM4=y
# CONFIG_X86_GENERIC is not set
CONFIG_X86_CMPXCHG=y
CONFIG_X86_XADD=y
-CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=5
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
-CONFIG_X86_GOOD_APIC=y
-CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_USE_3DNOW=y
# CONFIG_HPET_TIMER is not set
-# CONFIG_HPET_EMULATE_RTC is not set
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT=y
-CONFIG_X86_LOCAL_APIC=y
-CONFIG_X86_IO_APIC=y
-CONFIG_X86_TSC=y
-CONFIG_X86_MCE=y
-CONFIG_X86_MCE_NONFATAL=y
-CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_X86_MCE is not set
# CONFIG_TOSHIBA is not set
# CONFIG_I8K is not set
# CONFIG_MICROCODE is not set
@@ -115,18 +118,16 @@ CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
# CONFIG_MATH_EMULATION is not set
-CONFIG_MTRR=y
+# CONFIG_MTRR is not set
# CONFIG_EFI is not set
-CONFIG_IRQBALANCE=y
-CONFIG_HAVE_DEC_LOCK=y
# CONFIG_REGPARM is not set
#
# Power management options (ACPI, APM)
#
CONFIG_PM=y
-CONFIG_SOFTWARE_SUSPEND=y
-# CONFIG_PM_DISK is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
@@ -139,11 +140,14 @@ CONFIG_ACPI_SLEEP_PROC_FS=y
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_VIDEO is not set
CONFIG_ACPI_FAN=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_THERMAL=y
# CONFIG_ACPI_ASUS is not set
+# CONFIG_ACPI_IBM is not set
# CONFIG_ACPI_TOSHIBA is not set
+CONFIG_ACPI_BLACKLIST_YEAR=0
# CONFIG_ACPI_DEBUG is not set
CONFIG_ACPI_BUS=y
CONFIG_ACPI_EC=y
@@ -151,6 +155,7 @@ CONFIG_ACPI_POWER=y
CONFIG_ACPI_PCI=y
CONFIG_ACPI_SYSTEM=y
# CONFIG_X86_PM_TIMER is not set
+# CONFIG_ACPI_CONTAINER is not set
#
# APM (Advanced Power Management) BIOS Support
@@ -173,19 +178,21 @@ CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
-# CONFIG_PCI_USE_VECTOR is not set
+# CONFIG_PCIEPORTBUS is not set
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
-CONFIG_ISA=y
-# CONFIG_EISA is not set
+# CONFIG_ISA is not set
# CONFIG_MCA is not set
# CONFIG_SCx200 is not set
#
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
#
-# CONFIG_PCMCIA is not set
-CONFIG_PCMCIA_PROBE=y
#
# PCI Hotplug Support
@@ -196,8 +203,8 @@ CONFIG_PCMCIA_PROBE=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_MISC=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
#
# Device Drivers
@@ -206,7 +213,9 @@ CONFIG_BINFMT_MISC=y
#
# Generic Driver Options
#
-CONFIG_FW_LOADER=m
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
#
# Memory Technology Devices (MTD)
@@ -228,30 +237,36 @@ CONFIG_PARPORT_PC_CML1=y
#
# Plug and Play support
#
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG is not set
-
-#
-# Protocols
-#
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
+# CONFIG_PNP is not set
#
# Block devices
#
CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
CONFIG_LBD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -262,6 +277,7 @@ CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
+# CONFIG_BLK_DEV_IDE_SATA is not set
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
@@ -270,26 +286,22 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_TASKFILE_IO=y
#
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_CMD640=y
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_BLK_DEV_CMD640 is not set
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_GENERIC is not set
# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_RZ1000=y
+# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
@@ -299,6 +311,7 @@ CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5520 is not set
# CONFIG_BLK_DEV_CS5530 is not set
+CONFIG_BLK_DEV_CS5535=y
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
@@ -313,7 +326,6 @@ CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
CONFIG_IDEDMA_AUTO=y
@@ -346,54 +358,35 @@ CONFIG_CHR_DEV_SG=y
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
#
# SCSI low-level drivers
#
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
-CONFIG_SCSI_DPT_I2O=m
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_MEGARAID is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_SVW is not set
-CONFIG_SCSI_ATA_PIIX=y
-# CONFIG_SCSI_SATA_PROMISE is not set
-CONFIG_SCSI_SATA_SX4=m
-# CONFIG_SCSI_SATA_SIL is not set
-CONFIG_SCSI_SATA_SIS=m
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_IPR=m
-# CONFIG_SCSI_IPR_TRACE is not set
-# CONFIG_SCSI_IPR_DUMP is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
@@ -403,22 +396,12 @@ CONFIG_SCSI_QLA2XXX=y
# CONFIG_SCSI_QLA2300 is not set
# CONFIG_SCSI_QLA2322 is not set
# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -431,33 +414,7 @@ CONFIG_SCSI_QLA2XXX=y
#
# IEEE 1394 (FireWire) support
#
-CONFIG_IEEE1394=y
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
-
-#
-# Device Drivers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=y
-
-#
-# Protocol Drivers
-#
-# CONFIG_IEEE1394_VIDEO1394 is not set
-# CONFIG_IEEE1394_SBP2 is not set
-# CONFIG_IEEE1394_ETH1394 is not set
-# CONFIG_IEEE1394_DV1394 is not set
-CONFIG_IEEE1394_RAWIO=y
-# CONFIG_IEEE1394_CMP is not set
+# CONFIG_IEEE1394 is not set
#
# I2O device support
@@ -489,66 +446,11 @@ CONFIG_IP_MULTICAST=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=y
-# CONFIG_IP_NF_FTP is not set
-# CONFIG_IP_NF_IRC is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-CONFIG_IP_NF_QUEUE=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_LIMIT=y
-CONFIG_IP_NF_MATCH_IPRANGE=y
-CONFIG_IP_NF_MATCH_MAC=y
-CONFIG_IP_NF_MATCH_PKTTYPE=y
-CONFIG_IP_NF_MATCH_MARK=y
-CONFIG_IP_NF_MATCH_MULTIPORT=y
-CONFIG_IP_NF_MATCH_TOS=y
-CONFIG_IP_NF_MATCH_RECENT=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_DSCP=y
-CONFIG_IP_NF_MATCH_AH_ESP=y
-CONFIG_IP_NF_MATCH_LENGTH=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_MATCH_TCPMSS=y
-CONFIG_IP_NF_MATCH_HELPER=y
-CONFIG_IP_NF_MATCH_STATE=y
-CONFIG_IP_NF_MATCH_CONNTRACK=y
-CONFIG_IP_NF_MATCH_OWNER=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_NAT=y
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_SAME=y
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_TOS=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_DSCP=y
-CONFIG_IP_NF_TARGET_MARK=y
-CONFIG_IP_NF_TARGET_CLASSIFY=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_IP_NF_TARGET_TCPMSS=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_RAW=m
+# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
@@ -566,13 +468,12 @@ CONFIG_IP_NF_RAW=m
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
@@ -584,11 +485,10 @@ CONFIG_IP_NF_RAW=m
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
+# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
#
# ARCnet devices
@@ -603,27 +503,18 @@ CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
#
# Tulip family network device support
#
# CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
# CONFIG_B44 is not set
# CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
# CONFIG_DGRS is not set
# CONFIG_EEPRO100 is not set
# CONFIG_E100 is not set
@@ -641,7 +532,6 @@ CONFIG_8139TOO_PIO=y
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
-# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
@@ -654,14 +544,14 @@ CONFIG_8139TOO_PIO=y
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_IXGB is not set
-CONFIG_S2IO=m
-# CONFIG_S2IO_NAPI is not set
+# CONFIG_S2IO is not set
#
# Token Ring devices
@@ -724,6 +614,8 @@ CONFIG_SERIO_I8042=y
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PARKBD is not set
# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
#
# Input Device Drivers
@@ -737,9 +629,6 @@ CONFIG_KEYBOARD_ATKBD=y
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
@@ -765,15 +654,14 @@ CONFIG_SERIAL_8250_NR_UARTS=4
#
# Non-8250 serial port support
#
+CONFIG_SERIAL_GEODE_UART2=y
CONFIG_SERIAL_CORE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-CONFIG_PRINTER=y
-# CONFIG_LP_CONSOLE is not set
+# CONFIG_PRINTER is not set
# CONFIG_PPDEV is not set
# CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
#
# IPMI
@@ -796,29 +684,12 @@ CONFIG_PRINTER=y
#
# Ftape, the floppy tape device driver
#
-CONFIG_AGP=y
-# CONFIG_AGP_ALI is not set
-# CONFIG_AGP_ATI is not set
-# CONFIG_AGP_AMD is not set
-# CONFIG_AGP_AMD64 is not set
-CONFIG_AGP_INTEL=y
-CONFIG_AGP_INTEL_MCH=m
-# CONFIG_AGP_NVIDIA is not set
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_SWORKS is not set
-# CONFIG_AGP_VIA is not set
-# CONFIG_AGP_EFFICEON is not set
-CONFIG_DRM=y
-# CONFIG_DRM_TDFX is not set
-# CONFIG_DRM_GAMMA is not set
-# CONFIG_DRM_R128 is not set
-# CONFIG_DRM_RADEON is not set
-# CONFIG_DRM_I810 is not set
-CONFIG_DRM_I830=y
-# CONFIG_DRM_MGA is not set
-# CONFIG_DRM_SIS is not set
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
# CONFIG_HANGCHECK_TIMER is not set
#
@@ -827,6 +698,11 @@ CONFIG_DRM_I830=y
# CONFIG_I2C is not set
#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
# Misc devices
#
# CONFIG_IBM_ASM is not set
@@ -851,7 +727,6 @@ CONFIG_DRM_I830=y
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
-# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
#
@@ -865,7 +740,6 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
-CONFIG_SND_RAWMIDI=y
CONFIG_SND_SEQUENCER=y
# CONFIG_SND_SEQ_DUMMY is not set
CONFIG_SND_OSSEMUL=y
@@ -878,7 +752,6 @@ CONFIG_SND_SEQUENCER_OSS=y
#
# Generic devices
#
-CONFIG_SND_MPU401_UART=y
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_VIRMIDI is not set
# CONFIG_SND_MTPAV is not set
@@ -886,37 +759,12 @@ CONFIG_SND_MPU401_UART=y
# CONFIG_SND_MPU401 is not set
#
-# ISA devices
-#
-# CONFIG_SND_AD1848 is not set
-# CONFIG_SND_CS4231 is not set
-# CONFIG_SND_CS4232 is not set
-# CONFIG_SND_CS4236 is not set
-# CONFIG_SND_ES1688 is not set
-# CONFIG_SND_ES18XX is not set
-# CONFIG_SND_GUSCLASSIC is not set
-# CONFIG_SND_GUSEXTREME is not set
-# CONFIG_SND_GUSMAX is not set
-# CONFIG_SND_INTERWAVE is not set
-# CONFIG_SND_INTERWAVE_STB is not set
-# CONFIG_SND_OPTI92X_AD1848 is not set
-# CONFIG_SND_OPTI92X_CS4231 is not set
-# CONFIG_SND_OPTI93X is not set
-# CONFIG_SND_SB8 is not set
-# CONFIG_SND_SB16 is not set
-# CONFIG_SND_SBAWE is not set
-# CONFIG_SND_WAVEFRONT is not set
-# CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_OPL3SA2 is not set
-# CONFIG_SND_SGALAXY is not set
-# CONFIG_SND_SSCAPE is not set
-
-#
# PCI devices
#
-CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_CODEC=m
# CONFIG_SND_ALI5451 is not set
# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
# CONFIG_SND_AU8810 is not set
# CONFIG_SND_AU8820 is not set
# CONFIG_SND_AU8830 is not set
@@ -925,6 +773,8 @@ CONFIG_SND_AC97_CODEC=y
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
# CONFIG_SND_KORG1212 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -944,16 +794,18 @@ CONFIG_SND_AC97_CODEC=y
# CONFIG_SND_FM801 is not set
# CONFIG_SND_ICE1712 is not set
# CONFIG_SND_ICE1724 is not set
-CONFIG_SND_INTEL8X0=y
+# CONFIG_SND_INTEL8X0 is not set
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_SONICVIBES is not set
# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
#
-# ALSA USB devices
+# USB devices
#
# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
#
# Open Sound System
@@ -972,6 +824,10 @@ CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_BANDWIDTH is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
#
# USB Host Controller Drivers
@@ -981,6 +837,7 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_OHCI_HCD is not set
CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
#
# USB Device Class drivers
@@ -989,9 +846,14 @@ CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_BLUETOOTH_TTY is not set
# CONFIG_USB_MIDI is not set
# CONFIG_USB_ACM is not set
-CONFIG_USB_PRINTER=y
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_RW_DETECT is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
@@ -1002,7 +864,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_JUMPSHOT is not set
#
-# USB Human Interface Devices (HID)
+# USB Input Devices
#
CONFIG_USB_HID=y
CONFIG_USB_HIDINPUT=y
@@ -1013,7 +875,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_KBTAB is not set
# CONFIG_USB_POWERMATE is not set
# CONFIG_USB_MTOUCH is not set
-CONFIG_USB_EGALAX=m
+# CONFIG_USB_EGALAX is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
@@ -1022,7 +884,6 @@ CONFIG_USB_EGALAX=m
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
#
# USB Multimedia devices
@@ -1034,7 +895,7 @@ CONFIG_USB_EGALAX=m
#
#
-# USB Network adaptors
+# USB Network Adapters
#
# CONFIG_USB_CATC is not set
# CONFIG_USB_KAWETH is not set
@@ -1057,22 +918,37 @@ CONFIG_USB_EGALAX=m
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
-CONFIG_USB_CYTHERM=m
-CONFIG_USB_PHIDGETSERVO=m
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_TEST is not set
#
+# USB ATM/DSL drivers
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1086,10 +962,15 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
CONFIG_AUTOFS4_FS=y
@@ -1100,6 +981,7 @@ CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
# CONFIG_ZISOFS is not set
CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
@@ -1107,6 +989,8 @@ CONFIG_UDF_FS=y
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
#
@@ -1118,6 +1002,7 @@ CONFIG_SYSFS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -1153,6 +1038,7 @@ CONFIG_LOCKD=y
CONFIG_EXPORTFS=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
@@ -1193,6 +1079,7 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
@@ -1211,23 +1098,21 @@ CONFIG_NLS_ISO8859_1=y
#
# Profiling support
#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+# CONFIG_PROFILING is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_EARLY_PRINTK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_FRAME_POINTER is not set
+CONFIG_EARLY_PRINTK=y
CONFIG_4KSTACKS=y
-CONFIG_X86_FIND_SMP_CONFIG=y
-CONFIG_X86_MPPARSE=y
#
# Security options
#
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
@@ -1236,13 +1121,17 @@ CONFIG_X86_MPPARSE=y
# CONFIG_CRYPTO is not set
#
+# Hardware crypto devices
+#
+
+#
# Library routines
#
+# CONFIG_CRC_CCITT is not set
CONFIG_CRC32=y
CONFIG_LIBCRC32C=m
-CONFIG_X86_SMP=y
-CONFIG_X86_HT=y
+# CONFIG_CIMARRON is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_X86_BIOS_REBOOT=y
-CONFIG_X86_TRAMPOLINE=y
-CONFIG_X86_STD_RESOURCES=y
CONFIG_PC=y
Index: linux-2.6.11/arch/i386/kernel/apm.c
===================================================================
--- linux-2.6.11.orig/arch/i386/kernel/apm.c
+++ linux-2.6.11/arch/i386/kernel/apm.c
@@ -1061,22 +1061,23 @@ static int apm_engage_power_management(u
static int apm_console_blank(int blank)
{
- int error;
- u_short state;
+ int error, i;
+ u_short state;
+ u_short dev[3] = { 0x100, 0x1FF, 0x101 };
state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
- /* Blank the first display device */
- error = set_power_state(0x100, state);
- if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
- /* try to blank them all instead */
- error = set_power_state(0x1ff, state);
- if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
- /* try to blank device one instead */
- error = set_power_state(0x101, state);
+
+ for (i = 0; i < 3; i++) {
+ error = set_power_state(dev[i], state);
+
+ if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
+ return 1;
+
+ if (error == APM_NOT_ENGAGED)
+ break;
}
- if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
- return 1;
- if (error == APM_NOT_ENGAGED) {
+
+ if (error == APM_NOT_ENGAGED && state != APM_STATE_READY) {
static int tried;
int eng_error;
if (tried++ == 0) {
Index: linux-2.6.11/arch/i386/kernel/cpu/amd.c
===================================================================
--- linux-2.6.11.orig/arch/i386/kernel/cpu/amd.c
+++ linux-2.6.11/arch/i386/kernel/cpu/amd.c
@@ -145,6 +145,13 @@ static void __init init_amd(struct cpuin
set_bit(X86_FEATURE_K6_MTRR, c->x86_capability);
break;
}
+
+ if ( c->x86_model == 10 ) {
+ /* AMD Geode LX is model 10 */
+ /* placeholder for any needed mods */
+ break;
+ }
+
break;
case 6: /* An Athlon/Duron */
Index: linux-2.6.11/arch/i386/kernel/cpu/cyrix.c
===================================================================
--- linux-2.6.11.orig/arch/i386/kernel/cpu/cyrix.c
+++ linux-2.6.11/arch/i386/kernel/cpu/cyrix.c
@@ -346,6 +346,50 @@ static void __init init_cyrix(struct cpu
return;
}
+
+static void __init init_nsc(struct cpuinfo_x86 *c)
+{
+
+
+ /* Handle the National Semiconductor models with non-Cyrix init */
+ if ( (c->x86 == 5) && (c->x86_model >= 4 && c->x86_model <= 5)) {
+ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+ clear_bit(0*32+31, c->x86_capability);
+
+ get_model_name(c);
+
+ switch ( c->x86_model ) {
+ case 4: /* GX1/SCxx00 */
+
+ /* TODO Finish up the GX1/SCxx00 detection */
+ /* GX1 uses bits 16 and 24 differently -
+ you could probably just do
+
+ clear_bit(0*32+16, &c->x86_capability);
+ clear_bit(0*32+24, &c->x86_capability);
+
+ since I don't think the kernel supports
+ FPU-CMOV or Cyrix MMX. Unsure tho.
+
+ Also checking GX1 cache here needs to be done -
+ display_cacheinfo() won't work according to
+ AMD specs.
+ */
+
+ break;
+
+ case 5: /* GX */
+ display_cacheinfo(c);
+ break;
+ }
+ } else {
+ /* invoke the 'base class' */
+ init_cyrix(c);
+ }
+}
+
+
/*
* Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
* by the fact that they preserve the flags across the division of 5/2.
@@ -426,7 +470,7 @@ int __init cyrix_init_cpu(void)
static struct cpu_dev nsc_cpu_dev __initdata = {
.c_vendor = "NSC",
.c_ident = { "Geode by NSC" },
- .c_init = init_cyrix,
+ .c_init = init_nsc,
.c_identify = generic_identify,
};
Index: linux-2.6.11/drivers/char/hw_random.c
===================================================================
--- linux-2.6.11.orig/drivers/char/hw_random.c
+++ linux-2.6.11/drivers/char/hw_random.c
@@ -1,4 +1,10 @@
/*
+ Added support for the AMD Geode LX RNG
+ (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
+
+
+ derived from
+
Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
(c) Copyright 2003 Red Hat Inc
@@ -95,6 +101,13 @@ static unsigned int via_data_present (vo
static u32 via_data_read (void);
#endif
+#ifdef CONFIG_MGEODE_LX
+static int __init geode_init(struct pci_dev *dev);
+static void geode_cleanup(void);
+static unsigned int geode_data_present (void);
+static u32 geode_data_read (void);
+#endif
+
struct rng_operations {
int (*init) (struct pci_dev *dev);
void (*cleanup) (void);
@@ -122,6 +135,9 @@ enum {
rng_hw_intel,
rng_hw_amd,
rng_hw_via,
+#ifdef CONFIG_MGEODE_LX
+ rng_hw_geode,
+#endif
};
static struct rng_operations rng_vendor_ops[] = {
@@ -139,6 +155,11 @@ static struct rng_operations rng_vendor_
/* rng_hw_via */
{ via_init, via_cleanup, via_data_present, via_data_read, 1 },
#endif
+
+#ifdef CONFIG_MGEODE_LX
+ /* rng_hw_geode */
+ { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
+#endif
};
/*
@@ -159,6 +180,10 @@ static struct pci_device_id rng_pci_tbl[
{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+#ifdef CONFIG_MGEODE_LX
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode },
+#endif
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
@@ -460,7 +485,55 @@ static void via_cleanup(void)
}
#endif
+#ifdef CONFIG_MGEODE_LX
+
+/***********************************************************************
+ *
+ * AMD Geode RNG operations
+ *
+ */
+
+static void __iomem *geode_rng_base = 0x0;
+
+#define GEODE_RNG_DATA_REG 0x50
+#define GEODE_RNG_STATUS_REG 0x54
+
+static u32 geode_data_read(void) {
+ u32 val;
+ val = *((u32 *) (geode_rng_base + GEODE_RNG_DATA_REG));
+ return val;
+}
+
+static unsigned int geode_data_present(void) {
+ u32 val;
+
+ val = *((u32 *) (geode_rng_base + GEODE_RNG_STATUS_REG));
+ return val;
+}
+
+static void geode_cleanup(void) {
+ iounmap(geode_rng_base);
+ geode_rng_base = NULL;
+}
+
+static int geode_init(struct pci_dev *dev) {
+ u32 rng_base = pci_resource_start(dev, 0);
+ if (!rng_base) return 1;
+
+ geode_rng_base = ioremap(rng_base, 0x58);
+
+ if (geode_rng_base == NULL) {
+ printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
+ return -EBUSY;
+ }
+
+ printk(KERN_INFO PFX "Geode RNG registers at %p\n", geode_rng_base);
+ return 0;
+}
+
+#endif
+
/***********************************************************************
*
* /dev/hwrandom character device handling (major 10, minor 183)
@@ -577,7 +650,7 @@ static int __init rng_init (void)
DPRINTK ("ENTER\n");
- /* Probe for Intel, AMD RNGs */
+ /* Probe for Intel, AMD, Geode RNGs */
for_each_pci_dev(pdev) {
ent = pci_match_device (rng_pci_tbl, pdev);
if (ent) {
Index: linux-2.6.11/drivers/char/vt_ioctl.c
===================================================================
--- linux-2.6.11.orig/drivers/char/vt_ioctl.c
+++ linux-2.6.11/drivers/char/vt_ioctl.c
@@ -36,6 +36,10 @@
char vt_dont_switch;
extern struct tty_driver *console_driver;
+/* Adding a notifier chain when we go from VT_TEXT to VT_GRAPHICS */
+
+struct notifier_block *console_notifier_list;
+
#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count)
#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
@@ -474,6 +478,7 @@ int vt_ioctl(struct tty_struct *tty, str
* XXX It should at least call into the driver, fbdev's definitely
* need to restore their engine state. --BenH
*/
+
if (!perm)
return -EPERM;
switch (arg) {
@@ -490,8 +495,17 @@ int vt_ioctl(struct tty_struct *tty, str
if (vt_cons[console]->vc_mode == (unsigned char) arg)
return 0;
vt_cons[console]->vc_mode = (unsigned char) arg;
+
if (console != fg_console)
return 0;
+
+ if (arg == KD_TEXT)
+ notifier_call_chain(&console_notifier_list,
+ CONSOLE_EVENT_SWITCH_TEXT, 0);
+ else if (arg == KD_GRAPHICS)
+ notifier_call_chain(&console_notifier_list,
+ CONSOLE_EVENT_SWITCH_GRAPHICS, 0);
+
/*
* explicitly blank/unblank the screen if switching modes
*/
Index: linux-2.6.11/drivers/ide/Kconfig
===================================================================
--- linux-2.6.11.orig/drivers/ide/Kconfig
+++ linux-2.6.11/drivers/ide/Kconfig
@@ -540,6 +540,14 @@ config BLK_DEV_CS5530
It is safe to say Y to this question.
+config BLK_DEV_CS5535
+ tristate "AMD CS5535 chipset support"
+ help
+ Include support for UDMA on the National Semiconductor/AMD 5535
+ chipset. This will automatically be detected and configured if found.
+
+ It is safe to say Y to this question.
+
config BLK_DEV_HPT34X
tristate "HPT34X chipset support"
help
Index: linux-2.6.11/drivers/ide/pci/Makefile
===================================================================
--- linux-2.6.11.orig/drivers/ide/pci/Makefile
+++ linux-2.6.11/drivers/ide/pci/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.
obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
+obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
Index: linux-2.6.11/drivers/ide/pci/amd74xx.c
===================================================================
--- linux-2.6.11.orig/drivers/ide/pci/amd74xx.c
+++ linux-2.6.11/drivers/ide/pci/amd74xx.c
@@ -72,6 +72,7 @@ static struct amd_ide_chip {
{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, /* AMD Hiddensee */
{ 0 }
};
@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets
/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
+ /* 15 */ DECLARE_AMD_DEV("AMD5536"),
};
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_
#endif
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
Index: linux-2.6.11/drivers/ide/pci/cs5535.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/ide/pci/cs5535.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * CS5535 documentation available from AMD.
+ * */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ide-timing.h"
+#include "cs5535.h"
+
+#if defined(DISPLAY_CS5535_TIMINGS) && defined(CONFIG_PROC_FS)
+#include
+#include
+
+static u8 cs5535_proc = 0;
+static struct pci_dev *bmide_dev;
+static u8 w80 = 0;
+
+static int cs5535_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ unsigned long bibma = pci_resource_start(bmide_dev, 4);
+
+ u8 c0 = 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+
+ c0 = inb_p((u16)bibma + 0x02);
+
+ p += sprintf(p, "\n "
+ "AMD/NS 5535 Chipset.\n");
+
+ p += sprintf(p, "--------------- drive0 --------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s\n",(c0&0x20) ? "yes" : "no ",
+ (c0&0x40) ? "yes" : "no ");
+
+ pci_read_config_byte(bmide_dev, CS5535_CABLE_DETECT, &c0);
+
+ p += sprintf(p, "80 Wire Cable: %s %s\n", (c0 & 1) ? "yes" : "no",
+ (c0 & 2) ? "yes" : "no");
+
+ return p-buffer;
+}
+
+#endif /* DISPLAY_CS5535_TIMINGS && CONFIG_PROC_FS */
+
+/* Format I PIO settings. We seperate out cmd and data for safer timings */
+
+static unsigned int cs5535_pio_cmd_timings[5] =
+{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
+static unsigned int cs5535_pio_dta_timings[5] =
+{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
+
+static unsigned int cs5535_mwdma_timings[3] =
+{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
+
+static unsigned int cs5535_udma_timings[5] =
+{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
+
+/* Macros to check if the register is the reset value - reset value is an
+ invalid timing and indicates the register has not been set previously */
+
+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000)==0x00009172 )
+#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
+
+#define DEFAULT_PIO ( (cs5535_pio_cmd_timings[0] << 16) | cs5535_pio_dta_timings[0] )
+
+static u8 cs5535_get_bios_settings(int unit) {
+
+ u32 pio, dma, dummy;
+ int i;
+
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, dma, dummy);
+ rdmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, pio, dummy);
+
+ if (!CS5535_BAD_DMA(dma)) {
+ for(i = 0; i < 5; i++)
+ if (cs5535_udma_timings[i] == (dma & 0x7FFFFFFF))
+ return XFER_UDMA_0 + i;
+
+ for(i = 0; i < 3; i++)
+ if (cs5535_mwdma_timings[i] == (dma & 0x7FFFFFFF))
+ return XFER_MW_DMA_0 + i;
+ }
+
+ for(i = 0; i < 5; i++)
+ if ((pio & 0xFFFF) == cs5535_pio_dta_timings[i])
+ return XFER_PIO_0 + i;
+
+ return 0;
+}
+
+static u8 cs5535_get_pio_mode(int unit) {
+
+ u32 reg, dummy;
+ int i;
+
+ rdmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, dummy);
+
+ for(i = 0; i < 5; i++) {
+ if ((reg & 0xFFFF) == cs5535_pio_dta_timings[i])
+ return i;
+ }
+
+ BUG();
+ return 0;
+}
+
+static void cs5535_set_speed(ide_drive_t *drive, u8 speed) {
+
+ u32 reg, dummy;
+ int unit = drive->select.b.unit;
+
+ if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+ u8 data1 = speed - XFER_PIO_0;
+ u8 data2 = cs5535_get_pio_mode(!unit);
+
+ u8 cmd = (data1 < data2) ? data1 : data2;
+
+ /* Write the other drive timings */
+ reg = (cs5535_pio_cmd_timings[cmd] << 16) | cs5535_pio_dta_timings[data2];
+ wrmsr(!unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
+
+ /* Write our drive timings*/
+ reg = (cs5535_pio_cmd_timings[cmd] << 16) | cs5535_pio_dta_timings[data1];
+ wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
+
+ /* Write the Format 1 bit in the DMA register */
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+ wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg | 0x80000000, 0);
+ }
+ else {
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+
+
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7)
+ reg = (reg & 0x80000000) | cs5535_udma_timings[speed - XFER_UDMA_0];
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ reg = (reg & 0x80000000) | cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
+ else {
+ printk(KERN_INFO "cs5535: Invalid speed 0x%x requested.\n", speed);
+ return;
+ }
+ wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
+ }
+}
+
+static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
+{
+ if (speed != drive->current_speed)
+ ide_config_drive_speed(drive, speed);
+
+ cs5535_set_speed(drive, speed);
+
+ return 0;
+}
+
+/* tuneproc tunes the PIO speed of the device.
+ It is only called during init when autotune = IDE_TUNE_AUTO,
+ so we can avoid doing any default checking.
+*/
+
+static void cs5535_tuneproc (ide_drive_t *drive,u8 pio)
+{
+ u8 speed = 0;
+
+ if (pio == 255)
+ speed = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO);
+ else if (pio < 100)
+ speed = XFER_PIO_0 + min_t(byte, pio, 5);
+ else if (pio < 200)
+ speed = XFER_MW_DMA_0 + min_t(byte, (pio - 100), 2);
+ else
+ speed = XFER_UDMA_0 + min_t(byte, (pio - 200), 7);
+
+ cs5535_set_drive(drive, speed);
+}
+
+static int cs5535_config_dma(ide_drive_t *drive) {
+
+ int unit = drive->select.b.unit;
+ u8 speed = 0;
+ unsigned long map = XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA | (w80) ? XFER_UDMA_66 : 0;
+
+ if (drive->autotune == IDE_TUNE_DEFAULT) {
+ drive->autotune = IDE_TUNE_NOAUTO;
+
+ speed = cs5535_get_bios_settings(unit);
+
+ if (speed != 0) {
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+
+ drive->current_speed = speed;
+ }
+ }
+
+ if (!speed) {
+ speed = ide_find_best_mode(drive, map);
+ cs5535_set_drive(drive, speed);
+ }
+
+ if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ return HWIF(drive)->ide_dma_on(drive);
+
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+static unsigned int __init init_chipset_cs5535 (struct pci_dev *dev, const char *name)
+{
+ u8 bit;
+
+#if defined(DISPLAY_CS5535_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!cs5535_proc)
+ {
+ cs5535_proc = 1;
+ bmide_dev = dev;
+ ide_pci_create_host_proc("cs5535", cs5535_get_info);
+ }
+#endif
+
+ pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
+ w80 = bit & 1; /* Remember if we have a 80 wire cable */
+
+ return 0;
+}
+
+static void __init init_hwif_cs5535 (ide_hwif_t *hwif)
+{
+ unsigned long dummy;
+ u32 timings;
+
+ hwif->autodma = 0;
+ hwif->tuneproc = &cs5535_tuneproc;
+ hwif->speedproc = &cs5535_set_drive;
+ hwif->ide_dma_check = &cs5535_config_dma;
+
+ hwif->atapi_dma = 1;
+
+ /* We always support UDMA 0, 1 and 2 */
+
+ hwif->ultra_mask = 0x07;
+ hwif->mwdma_mask = 0x07;
+
+ /* If a 80 wire adapter is attached, add in 3 and 4 */
+ if (w80) hwif->ultra_mask |= 0x18;
+
+ hwif->udma_four = w80; /* w80 = 1 if a 80 conductor line is attached */
+
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+
+ hwif->drives[0].autotune = IDE_TUNE_DEFAULT;
+ hwif->drives[1].autotune = IDE_TUNE_DEFAULT;
+
+ rdmsr(ATAC_CH0D0_PIO,timings,dummy);
+
+ if (CS5535_BAD_PIO(timings)) {
+ wrmsr(ATAC_CH0D0_PIO, DEFAULT_PIO, 0);
+ hwif->drives[0].autotune = IDE_TUNE_AUTO;
+ }
+
+ rdmsr(ATAC_CH0D1_PIO,timings,dummy);
+
+ if (CS5535_BAD_PIO(timings)) {
+ wrmsr(ATAC_CH0D1_PIO,DEFAULT_PIO,0);
+ hwif->drives[1].autotune = IDE_TUNE_AUTO;
+ }
+
+ if (!noautodma) hwif->autodma = 1;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static int __devinit cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &cs5535_chipsets[id->driver_data]);
+ return 0;
+}
+
+static struct pci_device_id cs5535_pci_tbl[] __devinitdata =
+{
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "CS5535 IDE",
+ .id_table = cs5535_pci_tbl,
+ .probe = cs5535_init_one,
+};
+
+
+static int cs5535_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+static void cs5535_ide_exit(void)
+{
+ ide_pci_unregister_driver(&driver);
+}
+
+module_init(cs5535_ide_init);
+module_exit(cs5535_ide_exit);
+
+MODULE_AUTHOR("AMD");
+MODULE_DESCRIPTION("PCI driver module for AMD CS5535 IDE");
+MODULE_LICENSE("GPL");
+
Index: linux-2.6.11/drivers/ide/pci/cs5535.h
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/ide/pci/cs5535.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * */
+
+#ifndef CS5535_H
+#define CS5535_H
+
+#include
+#include
+#include
+
+#define DISPLAY_CS5535_TIMINGS
+
+#define MSR_ATAC_BASE 0x51300000
+#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0)
+#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01)
+#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02)
+#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03)
+#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04)
+#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05)
+#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08)
+#define ATAC_RESET (MSR_ATAC_BASE+0x10)
+#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20)
+#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21)
+#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22)
+#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23)
+#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24)
+#define ATAC_BM0_CMD_PRIM 0x00
+#define ATAC_BM0_STS_PRIM 0x02
+#define ATAC_BM0_PRD 0x04
+
+#define CS5535_CABLE_DETECT 0x48
+
+static unsigned int init_chipset_cs5535(struct pci_dev *, const char *);
+static void init_hwif_cs5535(ide_hwif_t *);
+
+static ide_pci_device_t cs5535_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "CS5535",
+ .init_chipset = init_chipset_cs5535,
+ .init_iops = NULL,
+ .init_hwif = init_hwif_cs5535,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .enablebits = { {0x00,0x00,0x00} },
+ .bootable = ON_BOARD,
+ .extra = 0,
+ }
+};
+
+#endif /* CS5535_H */
Index: linux-2.6.11/drivers/serial/Kconfig
===================================================================
--- linux-2.6.11.orig/drivers/serial/Kconfig
+++ linux-2.6.11/drivers/serial/Kconfig
@@ -572,6 +572,17 @@ config SERIAL_AU1X00_CONSOLE
If you have an Alchemy AU1X00 processor (MIPS based) and you want
to use a console on a serial port, say Y. Otherwise, say N.
+config SERIAL_GEODE_UART2
+ bool "Enable AMD CS5535 UART2 as a serial port"
+ depends on MGEODE_GX || MGEODE_LX
+ default y
+ select SERIAL_CORE
+ help
+ Select this to allow the user to select the secondary CS5535 UART
+ as a 16550 serial port instead of the default DDC interface. The
+ UART2 can be selected by specifying geodeuart2 on the command
+ line.
+
config SERIAL_CORE
tristate
Index: linux-2.6.11/drivers/serial/Makefile
===================================================================
--- linux-2.6.11.orig/drivers/serial/Makefile
+++ linux-2.6.11/drivers/serial/Makefile
@@ -49,3 +49,4 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_si
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
+obj-$(CONFIG_SERIAL_GEODE_UART2) += cs5535_uart.o
Index: linux-2.6.11/drivers/serial/cs5535_uart.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/serial/cs5535_uart.c
@@ -0,0 +1,67 @@
+/*
+ * CS5535 UART2 driver
+ * Copyright 2004, AMD
+ */
+
+#include
+#include
+#include
+#include
+
+/* The CS5535 companion chip has two UARTs. This code enables the second
+ UART so other devices can use it. We do it here so we can expose the
+ port early enough for serial debugging
+*/
+
+/* Note - this does not check to see if the CS5535 actually exists */
+
+#define LO(b) (((1 << b) << 16) | 0x0000)
+#define HI(b) ((0x0000 << 16) | (1 << b))
+
+static u32 outtab[16] __initdata =
+{
+ 0x00,HI(4), 0x04,HI(4), 0x08,HI(4),
+ 0x0c,LO(4), 0x10,HI(4), 0x14,LO(4),
+ 0x18,LO(4), 0x1C,LO(4)
+};
+
+static u32 intab[16] __initdata = {
+ 0x20,HI(3), 0x24,LO(3), 0x28,LO(3),
+ 0x2C,LO(3), 0x34,HI(3), 0x38,LO(3),
+ 0x40,LO(3), 0x44,LO(3)
+};
+
+static int __init init_cs5535_uart2(char *str)
+{
+ u32 lo = 0, hi = 0;
+ u32 base; u32 i;
+
+ /* Enable UART2 instead of DDC */
+
+ rdmsr(0x51400014, lo, hi);
+ lo &= 0xFF8FFFFF;
+ lo |= 0x00500000; /* 0x2F8 ttyS1 */
+ wrmsr(0x51400014, lo, hi);
+
+ /* Set up the UART registers */
+ wrmsr(0x5140003E, 0x12, 0x00);
+
+ rdmsr(0x5140000C, lo, hi);
+ base = (u32)(lo & 0xFF00);
+
+ /* Enable the GPIO pins (in and out) */
+
+ for(i = 0; i < 16; i += 2) {
+ outl(outtab[i + 1], base + outtab[i]);
+ outl(intab[i + 1], base + intab[i]);
+ }
+
+ /* Enable the IRQ */
+
+ rdmsr(0x51400021,lo,hi);
+ lo &= 0x0FFFFFFF;
+ lo |= 0x30000000; /* IRQ 3 */
+ wrmsr(0x51400021,lo,hi);
+}
+
+__setup("geodeuart2", init_cs5535_uart2);
Index: linux-2.6.11/drivers/usb/gadget/Kconfig
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/Kconfig
+++ linux-2.6.11/drivers/usb/gadget/Kconfig
@@ -86,6 +86,37 @@ config USB_NET2280
depends on USB_GADGET_NET2280
default USB_GADGET
+config USB_GADGET_AMD5536UDC
+ boolean "AMD5536UDC"
+ depends on PCI || SOC_AU1200
+ select USB_GADGET_DUALSPEED
+ help
+ AMD5536 UDC is a PCI based USB peripheral controller which
+ supports both full and high speed USB 2.0 data transfers.
+
+ It has six configurable endpoints, as well as endpoint zero
+ (for control transfers) and several endpoints with dedicated
+ functions.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "amd5536udc" and force all
+ gadget drivers to also be dynamically linked.
+
+ If the AMD5536UDC driver is configured to be statically
+ linked this module will be linked into the kernel image
+ as well otherwise two additional modules called "amd5536udc"
+ and "amd5536uoc" will be built.
+
+ The AMD5536 USB device port can be used as
+ either a host port or a device port depending on
+ the assignment within the BIOS setup.
+ For more information, see Documentation/usb/amd5536uoc.txt
+
+config USB_AMD5536UDC
+ tristate
+ depends on USB_GADGET_AMD5536UDC
+ default USB_GADGET
+
config USB_GADGET_PXA2XX
boolean "PXA 2xx or IXP 4xx"
depends on ARCH_PXA || ARCH_IXP4XX
@@ -399,4 +430,20 @@ config USB_G_SERIAL
endchoice
+#
+# AMD5536 USB UOC options
+#
+
+config USB_GADGET_AMD5536UOC
+ boolean
+ depends on USB_GADGET_AMD5536UDC
+ default USB_GADGET_AMD5536UDC
+
+config USB_AMD5536UOC
+ tristate
+ depends on USB_GADGET_AMD5536UOC
+ default USB_GADGET
+
endmenu
+
+
Index: linux-2.6.11/drivers/usb/gadget/Makefile
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/Makefile
+++ linux-2.6.11/drivers/usb/gadget/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
+obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
@@ -28,3 +29,8 @@ obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+#
+# AMD5536 USB UOC options
+#
+obj-$(CONFIG_USB_AMD5536UOC) += amd5536uoc.o
+
Index: linux-2.6.11/drivers/usb/gadget/amd5536udc.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,4786 @@
+/*
+ * AMD 5536 UDC high/full speed USB device controller.
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*****************************************************************************
+ * Defines
+ *****************************************************************************/
+
+/* debug control */
+#undef UDC_DEBUG
+//DISABLEDamd #define UDC_DEBUG 1
+#undef UDC_VERBOSE
+//DISABLEDamd #define UDC_VERBOSE
+//DISABLEDamd #define UDC_REGISTER_DUMP
+
+/* device driver registration of kernel 2.6.x usage */
+//#define UDC_USE_DRIVER_REGISTER
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING "01.00.0204 - $Revision: #13 $"
+
+/* kernel version of new gadget stack generation (for 2.6.x) */
+#define UDC_NEW_GADGET_KERNEL KERNEL_VERSION(2,5,59)
+
+/*****************************************************************************
+ * Includes
+ *****************************************************************************/
+
+/* system */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#include
+#else
+#include
+#include
+#include
+#endif
+#include
+#include
+#include
+#include
+#include
+
+/* MIPS config */
+#ifdef CONFIG_SOC_AU1200
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#include
+#else
+#include
+#endif
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+#define CONFIG_USB_NON_PCI_OTGDEVICE
+#endif
+#endif
+
+/* gadget stack */
+#include
+#include
+#include
+
+/* udc specific */
+#include "amd5536udc.h"
+
+/* use RDE timer for new kernel only */
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#define UDC_USE_TIMER
+#endif
+/*****************************************************************************
+ * Static Function Declarations
+ *****************************************************************************/
+
+void udc_tasklet_disconnect(unsigned long);
+#ifdef UDC_USE_TIMER
+void udc_timer_function(unsigned long v);
+void udc_pollstall_timer_function(unsigned long v);
+#endif
+static int udc_rxfifo_read_dwords(struct udc* dev, u32* buf, int dwords);
+static void empty_req_queue (struct udc_ep *);
+static int udc_probe (struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_remove (struct pci_dev *pdev);
+static void udc_basic_init (struct udc *dev);
+static void udc_setup_endpoints (struct udc *dev);
+static void udc_soft_reset(struct udc* dev);
+#ifdef UDC_DEBUG
+static void dump_buffer(u8* buf, u32 bytes);
+static int udc_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int udc_open (struct inode *inode, struct file *file);
+static int udc_release (struct inode *inode, struct file *file);
+#endif
+static struct udc_data_dma* udc_get_last_dma_desc(struct udc_request* req);
+static u32 udc_get_ppbdu_rxbytes(struct udc_request* req);
+static int udc_free_dma_chain(struct udc* dev, struct udc_request* req);
+static int udc_create_dma_chain(struct udc_ep* ep, struct udc_request* req, unsigned long buf_len, int gfp_flags);
+static inline int startup_registers(struct udc* dev);
+#ifdef CONFIG_SOC_AU1200
+void au1200_sync(void);
+#endif
+static int udc_remote_wakeup(struct udc* dev);
+#ifdef UDC_USE_DRIVER_REGISTER
+static int udc_suspend(struct udc* dev);
+static int udc_resume(struct udc* dev);
+#endif
+
+/*****************************************************************************
+ * Data
+ *****************************************************************************/
+
+/* description */
+static const char mod_desc [] = UDC_MOD_DESCRIPTION;
+static const char name [] = DRIVER_NAME_FOR_PRINT;
+
+/* structure to hold endpoint function pointers */
+static struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+spinlock_t udc_irq_spinlock;
+/* stall spin lock */
+spinlock_t udc_stall_spinlock;
+
+/* TODO this is used for dma chaining, global gfp not good */
+static int udc_gfp_flags = 0;
+
+/* slave mode: pending bytes in rx fifo after nyet,
+used if EPIN irq came but no req was available */
+static unsigned int udc_rxfifo_pending = 0;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured = 0;
+#ifdef UDC_IPBUG_3958_WORKAROUND_SOFT_RESET_ON_USBRESET
+static int soft_reset_after_usbreset_occured = 0;
+#endif
+
+#ifdef UDC_USE_TIMER
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer = 0;
+int set_rde = -1;
+DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer = 0;
+DECLARE_COMPLETION(on_pollstall_exit);
+#endif
+
+/* tasklet for usb disconnect */
+DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, (unsigned long) &udc);
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+static struct pci_dev pdev_dummy;
+static struct pci_dev* pdev = &pdev_dummy;
+#endif
+
+#ifdef UDC_IPBUG_3958_WORKAROUND
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending = 0;
+#define UDC_QUEUE_CNAK(ep, num) \
+ if (readl(&((ep)->regs->ctl)) & AMD_BIT(UDC_EPCTL_NAK)) { \
+ DBG("NAK could not be cleared for ep%d\n", num); \
+ cnak_pending |= 1 << (num); \
+ (ep)->naking = 1; \
+ } \
+ else \
+ cnak_pending = cnak_pending & (~(1<<(num)));
+#else
+#define UDC_QUEUE_CNAK(ep, num) {}
+#endif
+#ifdef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH
+/* rxfifo cleari/trash buffer */
+static u8 udc_rxfifo_trash[UDC_RXFIFO_SIZE];
+#endif
+
+#ifdef UDC_IPBUG_3943_WORKAROUND
+/* otg registering count */
+static u32 otg_reg_count = 0;
+#endif
+/* gadget registering count */
+static u32 gadget_bind_count = 0;
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+ ep0_string,
+ "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk", "ep6in-bulk", "ep7in-bulk", "ep8in-bulk",
+ "ep9in-bulk", "ep10in-bulk", "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk", "ep15in-bulk", "ep0out",
+ "ep1out-bulk", "ep2out-bulk", "ep3out-bulk", "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk", "ep8out-bulk",
+ "ep9out-bulk", "ep10out-bulk", "ep11out-bulk", "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+#ifdef UDC_DEBUG
+/* driver callback functions */
+static struct file_operations udc_fops = {
+ owner: THIS_MODULE,
+
+ read: NULL,
+ write: NULL,
+ ioctl: udc_ioctl,
+ open: udc_open,
+ release: udc_release,
+};
+#endif
+
+/* PCI device parameters */
+static struct pci_device_id pci_id[] = {{
+ .vendor = UDC_PCI_VENID,
+ .device = UDC_PCI_DEVID,
+ .class = UDC_PCI_CLASS,
+ .class_mask = UDC_PCI_CLASS_MASK,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+},
+{}
+};
+
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+ .name = (char *) name,
+ .id_table = pci_id,
+ .probe = udc_probe,
+ .remove = udc_remove,
+};
+#endif
+
+#ifdef UDC_DEBUG
+/* data for debuging only */
+static unsigned long no_pref_req = 0;
+static unsigned long no_req = 0;
+static u32 same_cfg = 0;
+static u32 num_enums = 0;
+#endif
+
+/****** following flags can be set by module parameters */
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du = 0;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode = 0;
+/* full speed only mode */
+static int use_fullspeed = 0;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+MODULE_PARM (use_dma, "i");
+MODULE_PARM_DESC (use_dma, "true for DMA");
+MODULE_PARM (use_dma_ppb, "i");
+MODULE_PARM_DESC (use_dma_ppb, "true for DMA in packet per buffer mode");
+MODULE_PARM (use_dma_ppb_du, "i");
+MODULE_PARM_DESC (use_dma_ppb_du, "true for DMA in packet per buffer mode with descriptor update");
+MODULE_PARM (use_fullspeed, "i");
+MODULE_PARM_DESC (use_fullspeed, "true for fullspeed only");
+MODULE_PARM (hs_tx_buf, "l");
+MODULE_PARM_DESC (hs_tx_buf, "high speed tx buffer size for data endpoints in dwords");
+
+MODULE_DESCRIPTION (UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR ("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+MODULE_DEVICE_TABLE (pci, pci_id);
+#endif
+
+/*****************************************************************************
+ * Function Definitions
+ *****************************************************************************/
+
+/* AU specific */
+#ifdef CONFIG_SOC_AU1200
+void au1200_sync(void)
+{
+ au1200_sync_delay();
+}
+#endif
+
+#ifdef UDC_DEBUG
+/**
+ * Dumps byte read access
+ *
+ * \param a address pointer
+ * \return read byte
+ */
+static void print_td(struct udc_data_dma *p)
+{
+ INFO("td = %08lx: status=%08lx bufptr=%08lx next=%08lx\n",
+ (unsigned long) p,
+ (unsigned long) p->status,
+ (unsigned long) p->bufptr,
+ (unsigned long) p->next);
+}
+#endif
+
+/* printing registers --------------------------------------------------------*/
+/**
+ * Prints UDC device registers and endpoint irq registers
+ *
+ * \param dev pointer to device struct
+ */
+static void print_regs(struct udc* dev)
+{
+#ifndef UDC_IPBUG_3943_WORKAROUND
+ DBG( "------- Device registers -------\n");
+ DBG( "dev config = %08lx\n", (unsigned long) dev->regs->cfg);
+ DBG( "dev control = %08lx\n", (unsigned long) dev->regs->ctl);
+ DBG( "dev status = %08lx\n", (unsigned long) dev->regs->sts);
+ DBG( "\n");
+ DBG( "dev int's = %08lx\n", (unsigned long) dev->regs->irqsts);
+ DBG( "dev intmask = %08lx\n", (unsigned long) dev->regs->irqmsk);
+ DBG( "\n");
+ DBG( "dev ep int's = %08lx\n", (unsigned long) dev->regs->ep_irqsts);
+ DBG( "dev ep intmask = %08lx\n", (unsigned long) dev->regs->ep_irqmsk);
+ DBG( "\n");
+#endif
+ DBG( "USE DMA = %d\n", use_dma);
+ if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+ DBG( "DMA mode = PPBNDU (packet per buffer WITHOUT desc. update)\n");
+#ifndef UDC_DEBUG
+ INFO( "DMA mode (PPBNDU)\n");
+#endif
+ }
+ else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+ DBG( "DMA mode = PPBDU (packet per buffer WITH desc. update)\n");
+#ifndef UDC_DEBUG
+ INFO( "DMA mode (PPBDU)\n");
+#endif
+ }
+ if (use_dma && use_dma_bufferfill_mode) {
+ DBG( "DMA mode = BF (buffer fill mode)\n");
+#ifndef UDC_DEBUG
+ INFO( "DMA mode (BF)\n");
+#endif
+ }
+#ifndef UDC_DEBUG
+ if (!use_dma) {
+ INFO( "FIFO mode\n");
+ }
+#endif
+#ifdef UDC_USE_TIMER
+ INFO("RDE timer is used\n");
+#endif
+ DBG("-------------------------------------------------------\n");
+}
+
+/**
+ * Prints snapshot of ep registers
+ *
+ * \param dev pointer to device struct
+ */
+#ifdef UDC_DEBUG
+static void print_ep_regs(struct udc* dev, struct udc_ep_regs* ep_regs)
+{
+ INFO( "ep control = %08lx\n", (unsigned long) ep_regs->ctl);
+ INFO( "ep status = %08lx\n", (unsigned long) ep_regs->sts);
+ INFO( "--------------------------------\n");
+}
+
+/* TODO tdahlman: remove */
+/**
+ * Prints misc information, to be removed
+ *
+ * \param dev pointer to device struct
+ */
+static void print_misc(struct udc* dev)
+{
+ print_regs(dev);
+
+ if (use_dma) {
+
+ INFO("no_req=%ld no_pref_req=%ld\n", no_req, no_pref_req);
+ }
+}
+#endif
+
+/* driver functions ----------------------------------------------------------*/
+/**
+ * Called by OS for insmod
+ *
+ * \param inode file node
+ * \param file struct
+ * \return read byte
+ */
+#ifdef UDC_DEBUG
+static int udc_open (struct inode *inode, struct file *file)
+{
+ int retval = 0;
+
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+ /* module use counter increment */
+ MOD_INC_USE_COUNT;
+#endif
+
+ return retval;
+}
+
+/**
+ * Called by OS for rmmod
+ *
+ * \param inode file node
+ * \param file file struct
+ * \return read byte
+ */
+static int udc_release (struct inode *inode, struct file *file)
+{
+ int retval = 0;
+
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+ /* module use counter decrement */
+ MOD_DEC_USE_COUNT;
+#endif
+ return retval;
+}
+
+/**
+ * Called by OS for ioctl() from user space
+ *
+ * \param inode file node
+ * \param file file struct
+ * \param command ioctl command code
+ * \param argument ioctl argument
+ * \return 0 if success
+ */
+static int udc_ioctl (struct inode *inode,
+ struct file *file,
+ unsigned int command,
+ unsigned long argument)
+{
+ struct udc* dev = udc;
+
+ if (!dev)
+ return -EINVAL;
+
+ /* for testing PM */
+ switch (command)
+ {
+ case 1:
+ udc_remote_wakeup(udc);
+ break;
+ case 5:
+ udc_suspend(udc);
+ break;
+ case 6:
+ udc_resume(udc);
+ break;
+ }
+
+ INFO( "ioctl called\n");
+
+ //print_misc(dev);
+ return 0;
+}
+
+/**
+ * Prints a buffers contents
+ * \param buf pointer to buffer
+ * \param bytes number bytes to print
+ */
+static void dump_buffer(u8* buf, u32 bytes)
+{
+ int i;
+
+ printk("\nbuffer %lx = %d bytes:\n", (unsigned long) buf, bytes);
+ for (i = 0; i < bytes; i++) {
+ printk("%02x", *(buf + i));
+ if ((i+1)%16 == 0)
+ printk("\n");
+ }
+ printk("\n");
+}
+#endif
+
+/**
+ * Masks unused interrupts
+ *
+ * \param dev pointer to device struct
+ * \return 0 if success
+ */
+static int udc_mask_unused_interrupts(struct udc* dev)
+{
+ u32 tmp;
+
+ /* mask all dev interrupts */
+ tmp = AMD_BIT(UDC_DEVINT_SVC) |
+ AMD_BIT(UDC_DEVINT_ENUM) |
+ AMD_BIT(UDC_DEVINT_US) |
+ AMD_BIT(UDC_DEVINT_UR) |
+ AMD_BIT(UDC_DEVINT_ES) |
+ AMD_BIT(UDC_DEVINT_SI) |
+ AMD_BIT(UDC_DEVINT_SOF)|
+ AMD_BIT(UDC_DEVINT_SC);
+ writel(tmp, &dev->regs->irqmsk);
+
+ /* mask all ep interrupts */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/**
+ * Enables endpoint 0 interrupts
+ *
+ * \param dev pointer to device struct
+ * \return 0 if success
+ */
+static int udc_enable_ep0_interrupts(struct udc* dev)
+{
+ u32 tmp;
+
+ DBG("udc_enable_ep0_interrupts()\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ /* enable ep0 irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+ & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/**
+ * Enables device interrupts for SET_INTF and SET_CONFIG
+ *
+ * \param dev pointer to device struct
+ * \return 0 if success
+ */
+static int udc_enable_dev_setup_interrupts(struct udc* dev)
+{
+ u32 tmp;
+
+ DBG("enable device interrupts for setup data\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->irqmsk);
+
+ /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+#ifndef UDC_IPBUG_3943_WORKAROUND
+ & AMD_UNMASK_BIT(UDC_DEVINT_US)
+#endif
+#ifndef UDC_IPBUG_3950_WORKAROUND
+ & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+#endif
+ & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+ writel(tmp, &dev->regs->irqmsk);
+
+ return 0;
+}
+
+/**
+ * Calculates fifo start of endpoint based on preceeding endpoints
+ *
+ * \param ep pointer to ep struct
+ * \return 0 if success
+ */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+ struct udc *dev;
+ u32 tmp;
+ int i;
+
+ if (!ep || !(ep->in))
+ return -EINVAL;
+
+ dev = ep->dev;
+ ep->txfifo = dev->txfifo;
+
+ /* traverse ep's */
+ for (i = 0; i < ep->num; i++) {
+ if (dev->ep[i].regs) {
+ /* read fifo size */
+ tmp = readl(&dev->ep[i].regs->bufin_framenum);
+ tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+ ep->txfifo+= tmp;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Enables endpoint, is called by gadget driver
+ *
+ * \param usbep pointer to ep struct
+ * \param desc pointer to endpoint descriptor
+ * \return 0 if success
+ */
+static int
+udc_enable (struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+ struct udc_ep *ep;
+ struct udc *dev;
+ u32 tmp;
+ unsigned long iflags;
+ u8 udc_csr_epix;
+
+ VDBG("udc_enable()\n");
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ if (!usbep
+ || usbep->name == ep0_string
+ || !desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT) {
+ ERR("udc_enable: !usbep=%d !desc=%d ep->desc!=NULL=%d usbep->name==ep0_string=%d desc->bDescriptorType!=USB_DT_ENDPOINT=%d\n",
+ !usbep, !desc, ep->desc != NULL, usbep->name == ep0_string, desc->bDescriptorType != USB_DT_ENDPOINT);
+ return -EINVAL;
+ }
+
+ DBG("udc_enable() ep %d\n", ep->num);
+
+ dev = ep->dev;
+
+ /* exit on suspend */
+ if (dev->sys_suspended)
+ return -ESHUTDOWN;
+
+ if (!dev->driver
+ || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave (&dev->lock, iflags);
+ ep->desc = desc;
+
+ ep->halted = 0;
+
+ /* set traffic type */
+ tmp = readl(&dev->ep[ep->num].regs->ctl);
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+ writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+ /* set max packet size */
+ tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+ ep->ep.maxpacket = desc->wMaxPacketSize;
+ writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+ /* IN ep */
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+ /* set buffer size (tx fifo entries) */
+ tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+ /* double buffering: fifo size = 2 x max packet size */
+ tmp = AMD_ADDBITS(
+ tmp,
+ desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT /
+ UDC_DWORD_BYTES,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+ /* calc. tx fifo base addr */
+ udc_set_txfifo_addr(ep);
+
+ /* flush fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ } /* OUT ep */
+ else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+ /* set max packet size UDC CSR */
+ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_enabled = 1;
+ }
+
+ /***** UDC CSR reg ****************************/
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* max packet */
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ /* ep number */
+ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+ /* ep direction */
+ tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+ /* ep type */
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+ /* ep config */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ /* clear NAK by writing CNAK */
+ /* avoid BNA for DMA, dont clear NAK until DMA desc. written */
+ if (!use_dma) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ tmp = desc->bEndpointAddress;
+ DBG( "%s enabled\n",
+ usbep->name);
+
+ spin_unlock_irqrestore (&dev->lock, iflags);
+ return 0;
+}
+/**
+ * Resets endpoint
+ *
+ * \param regs pointer to device register struct
+ * \param ep pointer to endpoint
+ */
+static void ep_init (struct udc_regs *regs, struct udc_ep *ep)
+{
+ u32 tmp;
+
+ VDBG("ep-%d reset\n", ep->num);
+ ep->desc = 0;
+ ep->ep.ops = &udc_ep_ops;
+ INIT_LIST_HEAD (&ep->queue);
+
+ ep->ep.maxpacket = (u16) ~0;
+ if (!(ep->dev->sys_suspended)) {
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+
+ /* disable interrupt */
+ tmp = readl(®s->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp, ®s->ep_irqmsk);
+
+ if (ep->in) {
+ /* unset P and IN bit of potential former DMA */
+ tmp = readl(&ep->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+
+ tmp = readl(&ep->regs->sts);
+ tmp |= AMD_BIT(UDC_EPSTS_IN);
+ writel(tmp, &ep->regs->sts);
+
+ /* flush the fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ }
+ /* reset desc pointer */
+ writel(0, &ep->regs->desptr);
+ }
+
+
+}
+
+/**
+ * Disables endpoint, is called by gadget driver
+ *
+ * \param usbep pointer to ep struct
+ * \return 0 if success
+ */
+static int udc_disable (struct usb_ep *usbep)
+{
+ struct udc_ep *ep = NULL;
+ unsigned long iflags;
+
+ if (!usbep)
+ return -EINVAL;
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ if (usbep->name == ep0_string
+ || !ep->desc)
+ return -EINVAL;
+
+ DBG("Disable ep-%d\n", ep->num);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ empty_req_queue(ep);
+ ep_init(ep->dev->regs, ep);
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+ return 0;
+}
+
+/**
+ * Allocates request packet, called by gadget driver
+ *
+ * \param _ep pointer to usb ep struct
+ * \param gfp_flags flags for kmalloc
+ * \return allocated request packet, 0 if error
+ */
+static struct usb_request *
+udc_alloc_request (struct usb_ep *usbep, int gfp)
+{
+ struct udc_request *req;
+ struct udc_data_dma *dma_desc;
+ struct udc_ep *ep;
+
+ VDBG("udc_alloc_req()\n");
+ if (!usbep)
+ return 0;
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ /* TODO gfp flags used for dma chaining later - find better way */
+ udc_gfp_flags = gfp;
+
+ VDBG("udc_alloc_req(): ep%d\n", ep->num);
+ req = kmalloc (sizeof (struct udc_request), gfp);
+ if (!req)
+ return 0;
+
+ memset (req, 0, sizeof *req);
+ req->req.dma = DMA_DONT_USE;
+ INIT_LIST_HEAD (&req->queue);
+
+ if (ep->dma) {
+
+#if defined(CONFIG_MIPS)
+ gfp = GFP_ATOMIC | GFP_DMA;
+#endif
+ /* FIXME ep0 in requests are allocated from data pool here */
+ dma_desc = pci_pool_alloc (ep->dev->data_requests, gfp,
+ &req->td_phys);
+ if (!dma_desc) {
+ kfree (req);
+ return 0;
+ }
+
+ VDBG("udc_alloc_req: req = %lx dma_desc = %lx, req->td_phys = %lx\n",
+ (unsigned long) req, (unsigned long) dma_desc, (unsigned long)req->td_phys);
+ /* prevent from using desc. - set HOST BUSY */
+ dma_desc->status = AMD_ADDBITS(dma_desc->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ dma_desc->bufptr = __constant_cpu_to_le32 (DMA_DONT_USE);
+ req->td_data = dma_desc;
+ req->td_data_last = NULL;
+ req->chain_len = 1;
+ }
+
+ return &req->req;
+}
+
+/**
+ * Frees request packet, called by gadget driver
+ *
+ * \param usbep pointer to usb ep struct
+ * \param usbreq pointer to request packet to be freed
+ */
+static void
+udc_free_request (struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+
+ if (!usbep || !usbreq)
+ return;
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ req = container_of (usbreq, struct udc_request, req);
+ VDBG("free_req req=%lx\n", (unsigned long) req);
+ WARN_ON(!list_empty (&req->queue));
+ if (req->td_data) {
+ VDBG("req->td_data=%lx\n", (unsigned long) req->td_data);
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ /* re-link broken chain */
+ if (req->td_data_last) {
+ req->td_data_last->next = req->td_data_last_next;
+ }
+#endif
+ /* free dma chain if created */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+
+ pci_pool_free (ep->dev->data_requests, req->td_data, req->td_phys);
+ }
+ kfree (req);
+}
+
+/* choose dma buffer allocation method */
+#undef USE_KMALLOC
+#if defined(CONFIG_X86)
+#define USE_KMALLOC
+/* FIXME TMP26: cached dma buffers seem no to work for 2.6.x to be
+ * examined */
+#elif defined(CONFIG_MIPS)
+/* MIPS kernel 2.4 */
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#if !defined(CONFIG_NONCOHERENT_IO)
+#define USE_KMALLOC
+#endif /* !defined(CONFIG_NONCOHERENT_IO) */
+#endif /* LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL */
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifdef CONFIG_DMA_COHERENT
+#define USE_KMALLOC
+#endif /* CONFIG_DMA_COHERENT */
+#endif /* LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL */
+#endif
+
+/**
+ * Allocates data buffer for request packet, called by gadget driver
+ *
+ * \param usbep pointer to usb ep struct
+ * \param bytes number bytes to allocate
+ * \param dma pointer to dma struct
+ * \param gfp_flags flags for allocate
+ * \return pointer to allocated buffer, 0 if error
+ */
+static void *
+udc_alloc_buffer (
+ struct usb_ep *usbep,
+ unsigned len,
+ dma_addr_t *dma,
+ int gfp
+)
+{
+ void *ptr;
+ struct udc_ep *ep;
+ VDBG("alloc_buffer(): %s\n", usbep->name);
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ *dma = DMA_DONT_USE;
+
+ if (!usbep)
+ return 0;
+
+ if (ep->dma) {
+#if defined(USE_KMALLOC)
+
+#if defined(CONFIG_MIPS)
+ gfp = GFP_ATOMIC | GFP_DMA;
+#endif
+ ptr = kmalloc(len, gfp);
+
+ if (ptr)
+ *dma = virt_to_phys(ptr);
+
+#elif LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ ptr = dma_alloc_coherent (&ep->dev->pdev->dev, len, dma, gfp);
+#elif defined (CONFIG_MIPS)
+ ptr = pci_alloc_consistent(ep->dev->pdev, len, dma);
+#else
+#error no memory allocator
+#endif
+ } else
+ ptr = kmalloc(len, gfp);
+
+ VDBG("alloc_buffer() ptr = %lx dma=%lx\n", (unsigned long) ptr, (unsigned long) *dma);
+ return ptr;
+}
+
+
+/**
+ * Free data buffer for request packet, called by gadget driver
+ *
+ * \param usbep pointer to usb ep struct
+ * \param buf pointer to buffer to be freed
+ * \param dma pointer to dma struct
+ * \param len number bytes to be freed
+ * \return pointer to allocated buffer, 0 if error
+ */
+static void
+udc_free_buffer (
+ struct usb_ep *usbep,
+ void *buf,
+ dma_addr_t dma,
+ unsigned len
+) {
+ struct udc_ep *ep;
+
+ VDBG ("ep %s - free buffer %lx\n", usbep->name, (unsigned long) buf);
+
+ /* null pointer ? */
+ if (!buf) {
+ return;
+ }
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep)
+ return;
+
+#ifndef USE_KMALLOC
+ if (dma != DMA_DONT_USE) {
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ dma_free_coherent (&ep->dev->pdev->dev, len, buf, dma);
+#else
+ pci_free_consistent(ep->dev->pdev, len, buf, dma);
+#endif
+ } else
+#endif
+ {
+ if (!(ep->dma))
+ kfree (buf);
+ }
+
+}
+
+/**
+ * Write data to TX fifo for IN packets
+ *
+ * \param ep pointer to ep struct
+ * \param req pointer to request packet
+ * \return allocated request packet, 0 if error
+ */
+static void
+udc_txfifo_write (struct udc_ep *ep, struct usb_request *req)
+{
+ u8 *req_buf;
+ u32 *buf;
+ int i,j;
+ unsigned bytes = 0;
+ unsigned remaining = 0;
+
+ VDBG("udc_txfifo_write()\n");
+
+ if (!req || !ep)
+ return;
+
+ req_buf = req->buf + req->actual;
+ prefetch (req_buf);
+ remaining = req->length - req->actual;
+
+ buf = (u32*) req_buf;
+
+ bytes = ep->ep.maxpacket;
+ if (bytes > remaining)
+ bytes = remaining;
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ writel(*(buf + i), ep->txfifo);
+ }
+
+ /* remaining bytes must be written by byte access */
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ writeb((u8) (*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+ ep->txfifo);
+ }
+
+#ifdef UDC_IPBUG_2253_WORKAROUND
+ {
+ u32 tmp;
+
+ /* NAK if small packet until write confirm completed */
+ if (bytes < UDC_SMALL_PACKET) {
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+ wb_flush();
+ }
+
+ /* dummy write confirm */
+ writel(0, &ep->regs->confirm);
+
+ /* stop NAKing after small packet DMA */
+ if (ep->naking) {
+ /* clear NAK by writing CNAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+#else
+ /* dummy write confirm */
+ writel(0, &ep->regs->confirm);
+#endif
+}
+
+/**
+ * Read dwords from RX fifo for OUT transfers
+ *
+ * \param dev pointer to device struct
+ * \param buf pointer to buffer to be filled
+ * \param dwords number of dwords to be read
+ * \return allocated request packet, 0 if error
+ */
+static int udc_rxfifo_read_dwords(struct udc* dev, u32* buf, int dwords)
+{
+ int i;
+
+ VDBG("udc_read_dwords(): %d dwords\n", dwords);
+
+ for (i = 0; i < dwords; i++)
+ {
+ *(buf + i) = readl(dev->rxfifo);
+ }
+ return 0;
+}
+
+/**
+ * Read bytes from RX fifo for OUT transfers
+ *
+ * \param dev pointer to device struct
+ * \param buf pointer to buffer to be filled
+ * \param bytes number of bytes to be read
+ * \return allocated request packet, 0 if error
+ */
+static int udc_rxfifo_read_bytes(struct udc* dev, u8* buf, int bytes)
+{
+ int i,j;
+ u32 tmp;
+
+ VDBG("udc_read_bytes(): %d bytes\n", bytes);
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ *((u32*) (buf + (i<<2))) = readl(dev->rxfifo);
+ }
+
+ /* remaining bytes must be read by byte access */
+ if (bytes % UDC_DWORD_BYTES) {
+ tmp = readl(dev->rxfifo);
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ *(buf + (i<<2) + j) = (u8) (tmp & UDC_BYTE_MASK);
+ tmp = tmp >> UDC_BITS_PER_BYTE;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Read data from RX fifo for OUT transfers
+ *
+ * \param ep pointer to ep struct
+ * \param req pointer to request packet
+ * \return true if request completes for short or max packet, false otherwise
+ */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+ u8 *buf;
+ unsigned buf_space;
+ unsigned bytes = 0;
+ unsigned finished = 0;
+
+ /* received number bytes */
+ bytes = readl(&ep->regs->sts);
+ bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+ buf_space = req->req.length - req->req.actual;
+ buf = req->req.buf + req->req.actual;
+ if (bytes > buf_space) {
+ if ((buf_space % ep->ep.maxpacket) != 0) {
+ ERR( "%s: received %d bytes, rx-buffer space = %d bytes => buffer overrun\n",
+ ep->ep.name, bytes, buf_space);
+ req->req.status = -EOVERFLOW;
+ }
+ bytes = buf_space;
+ }
+ req->req.actual += bytes;
+
+ /* last packet ? */
+ if (((bytes % ep->ep.maxpacket) != 0)
+ || (!bytes)
+ || ((req->req.actual == req->req.length) && !req->req.zero))
+ finished = 1;
+
+ /* read rx fifo bytes */
+ VDBG("ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+ udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+ return finished;
+}
+
+/**
+ * create/re-init a DMA descriptor or a DMA descriptor chain
+ *
+ * \param ep pointer to endpoint struct
+ * \param req pointer to request packet
+ */
+static int prep_dma (struct udc_ep *ep, struct udc_request *req)
+{
+ int retval = 0;
+ u32 tmp;
+ VDBG("prep_dma\n");
+ VDBG("prep_dma ep%d req->td_data=%lx\n",
+ ep->num, (unsigned long) req->td_data);
+
+ /* set buffer pointer */
+ req->td_data->bufptr = req->req.dma;
+
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+ /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+ if (use_dma_ppb && ep->num != UDC_EP0OUT_IX && ep->num != UDC_EP0IN_IX) {
+
+ retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, udc_gfp_flags);
+ if (retval != 0)
+ {
+ if (retval == -ENOMEM)
+ INFO("Out of DMA memory (allocation failed)\n");
+ return retval;
+ }
+ /*TODO better place ? */
+ if (ep->in) {
+ if (req->req.length == ep->ep.maxpacket) {
+ /* write tx bytes */
+ req->td_data->status = AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+
+ }
+ }
+
+ }
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ else { /* EP0 */
+ /* point to itself */
+ req->td_data->next = req->td_phys;
+ }
+#endif
+
+ if (ep->in) {
+ VDBG("IN: use_dma_ppb=%d req->req.length=%d ep->ep.maxpacket=%d ep%d\n",
+ use_dma_ppb, req->req.length, ep->ep.maxpacket, ep->num);
+ /* if bytes < max packet then tx bytes must */
+ /* be written in packet per buffer mode */
+ if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+ || ep->num == UDC_EP0OUT_IX || ep->num == UDC_EP0IN_IX) {
+ /* write tx bytes */
+ req->td_data->status = AMD_ADDBITS(req->td_data->status,
+ req->req.length,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* reset frame num */
+ req->td_data->status = AMD_ADDBITS(req->td_data->status,
+ 0,
+ UDC_DMA_IN_STS_FRAMENUM);
+ }
+ /* set HOST BUSY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ }
+ else {
+ VDBG("OUT set host ready\n");
+ /* set HOST READY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ }
+
+ return retval;
+}
+
+/**
+ * Completes request packet
+ *
+ * \param ep pointer to ep struct
+ * \param req pointer to request packet
+ * \param sts status of request
+ */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+{
+ struct udc *dev;
+ unsigned halted;
+
+ VDBG("complete_req(): ep%d\n", ep->num);
+
+ dev = ep->dev;
+ /* unmap DMA */
+ if (req->dma_mapping) {
+ if (ep->in)
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 0;
+ req->req.dma = DMA_DONT_USE;
+ }
+
+ halted = ep->halted;
+ ep->halted = 1;
+
+ /* set new status if pending */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = sts;
+
+ /* remove from ep queue */
+ list_del_init (&req->queue);
+
+ VDBG( "req %p => complete %d bytes at %s with sts %d\n",
+ &req->req, req->req.length, ep->ep.name, sts);
+ if (spin_is_locked(&dev->lock)) {
+ spin_unlock (&dev->lock);
+ req->req.complete (&ep->ep, &req->req);
+ spin_lock (&dev->lock);
+ }
+ else {
+ req->req.complete (&ep->ep, &req->req);
+ }
+ ep->halted = halted;
+}
+
+/**
+ * frees pci pool descriptors of a DMA chain
+ *
+ * \param dev pointer to device struct
+ * \param req pointer to request packet
+ * \return 0 if success
+ */
+static int udc_free_dma_chain(struct udc* dev, struct udc_request* req)
+{
+
+ int ret_val = 0;
+ struct udc_data_dma *td;
+ struct udc_data_dma *td_last = NULL;
+ unsigned int i;
+
+ DBG("free chain req = %lx\n", (unsigned long) req);
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ /* re-link broken chain */
+ if (req->td_data_last) {
+ req->td_data_last->next = req->td_data_last_next;
+ }
+#endif
+ /* do not free first desc., will be done by free for request */
+ td_last = req->td_data;
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+ td = UNCAC_ADDR(phys_to_virt(td_last->next));
+#else
+ td = phys_to_virt(td_last->next);
+#endif
+
+ for (i = 1; i < req->chain_len; i++) {
+
+ pci_pool_free (dev->data_requests, td,
+ (dma_addr_t) td_last->next);
+ td_last = td;
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+ td = UNCAC_ADDR(phys_to_virt(td_last->next));
+#else
+ td = phys_to_virt(td_last->next);
+#endif
+ }
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ req->td_data_last = NULL;
+#endif
+ return ret_val;
+}
+
+/**
+ * Iterates to the end of a DMA chain and returns last descriptor
+ *
+ * \param req pointer to request packet
+ * \return pointer to last descriptori of chain
+ */
+static struct udc_data_dma* udc_get_last_dma_desc(struct udc_request* req)
+{
+ struct udc_data_dma *td;
+
+ td = req->td_data;
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+ td = UNCAC_ADDR(phys_to_virt(td->next));
+#else
+ td = phys_to_virt(td->next);
+#endif
+ }
+
+ return td;
+
+}
+
+/**
+ * Iterates to the end of a DMA chain and counts bytes received
+ *
+ * \param req pointer to request packet
+ * \return number of received bytes
+ */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request* req)
+{
+ struct udc_data_dma *td;
+ u32 count;
+
+ td = req->td_data;
+ /* received number bytes */
+ count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+ td = UNCAC_ADDR(phys_to_virt(td->next));
+#else
+ td = phys_to_virt(td->next);
+#endif
+ /* received number bytes */
+ if (td) {
+ count += AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+ }
+ }
+
+ return count;
+
+}
+
+/**
+ * Creates or re-inits a DMA chain
+ *
+ * \param ep pointer to endpoint struct
+ * \param req pointer to request packet
+ * \param buf_len number of buffer bytes per descriptor (except last short)
+ */
+static int udc_create_dma_chain(struct udc_ep* ep, struct udc_request* req, unsigned long buf_len, int gfp_flags)
+{
+ unsigned long bytes = req->req.length;
+ unsigned int i;
+ dma_addr_t dma_addr;
+ struct udc_data_dma *td = NULL;
+ struct udc_data_dma *last = NULL;
+ unsigned long txbytes;
+ unsigned create_new_chain = 0;
+ unsigned len;
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ dma_addr_t last_next = DMA_DONT_USE;
+#endif
+
+ VDBG("udc_create_dma_chain: bytes=%ld buf_len=%ld\n", bytes, buf_len);
+ dma_addr = DMA_DONT_USE;
+
+ /* unset L bit in first desc for OUT */
+ if (!ep->in) {
+ req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+ }
+
+ /* alloc only new desc's if not already available */
+ len = req->req.length / ep->ep.maxpacket;
+ if (req->req.length % ep->ep.maxpacket) {
+ len++;
+ }
+
+ if (len > req->chain_len) {
+ /* shorter chain already allocated before */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+ req->chain_len = len;
+ create_new_chain = 1;
+ }
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ /* re-link broken chain */
+ if (req->td_data_last) {
+ req->td_data_last->next = req->td_data_last_next;
+ }
+ /* if only one td then last_next is root td */
+ last_next = req->td_phys;
+#endif
+
+ td = req->td_data;
+ /* gen. required number of descriptors and buffers */
+ for (i = buf_len; i < bytes; i += buf_len)
+ {
+ /* create or determine next desc. */
+ if (create_new_chain) {
+
+#if defined(CONFIG_MIPS)
+ gfp_flags = GFP_ATOMIC | GFP_DMA;
+#endif
+ td = pci_pool_alloc (ep->dev->data_requests, gfp_flags,
+ &dma_addr);
+ if (!td)
+ return -ENOMEM;
+
+ td->status = 0;
+ }
+ else if (i == buf_len)
+ {
+ /* first td */
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+ td = (struct udc_data_dma*) UNCAC_ADDR(phys_to_virt(req->td_data->next));
+#else
+ td = (struct udc_data_dma*) phys_to_virt(req->td_data->next);
+#endif
+ td->status = 0;
+ }
+ else {
+#if defined (CONFIG_MIPS) && !defined(CONFIG_DMA_COHERENT)
+ td = (struct udc_data_dma*) UNCAC_ADDR(phys_to_virt(last->next));
+#else
+ td = (struct udc_data_dma*) phys_to_virt(last->next);
+#endif
+ td->status = 0;
+ }
+
+
+ if (td) {
+ /* assign buffer */
+ td->bufptr = req->req.dma + i;
+ }
+ else {
+ break;
+ }
+
+ /* short packet ? */
+ if ((bytes - i) >= buf_len) {
+ txbytes = buf_len;
+ }
+ else {
+ /* short packet */
+ txbytes = bytes - i;
+ }
+
+ /* link td and assign tx bytes */
+ if (i == buf_len) {
+ if (create_new_chain) {
+ req->td_data->next = dma_addr;
+ }
+ else {
+ //req->td_data->next = virt_to_phys(td);
+ }
+ /* write tx bytes */
+ if (ep->in) {
+ /* first desc */
+ req->td_data->status = AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* second desc */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ last_next = req->td_data->next;
+#endif
+ }
+ else {
+ if (create_new_chain) {
+ last->next = dma_addr;
+ }
+ else {
+ //last->next = virt_to_phys(td);
+ }
+ if (ep->in) {
+ /* write tx bytes */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ last_next = last->next;
+#endif
+ }
+ last = td;
+ }
+ /* set last bit */
+ if (td) {
+ td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* last desc. points to itself */
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ /* remember broken chain next pointer */
+ req->td_data_last_next = td->next;
+ /* point to itself */
+ td->next = last_next;
+#endif
+ req->td_data_last = td;
+ }
+
+ return 0;
+}
+
+/**
+ * Enabling RX DMA
+ *
+ * \param dev pointer to UDC device object
+ */
+static inline void udc_set_rde(struct udc* dev)
+{
+ u32 tmp;
+
+ VDBG("udc_set_rde()\n");
+#ifdef UDC_USE_TIMER
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+#endif
+ /* set RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+}
+
+/**
+ * Queues a request packet, called by gadget driver
+ *
+ * \param usbep pointer to usb ep struct
+ * \param usbreq pointer to request packet to be freed
+ * \param gfp flags for alloc
+ * \return 0 if success
+ */
+static int
+udc_queue (struct usb_ep *usbep, struct usb_request *usbreq, int gfp)
+{
+ int retval = 0;
+ unsigned long iflags;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc *dev;
+ u32 tmp;
+
+ VDBG ("udc_queue()\n");
+
+ /* check the inputs */
+ req = container_of (usbreq, struct udc_request, req);
+ VDBG("!usbep=%d !req=%d !buf=%d !compl=%d !empty_list=%d \n",
+ !usbep, !usbreq, !usbreq->buf, !usbreq->complete,
+ !list_empty(&req->queue));
+
+ if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+ || !list_empty (&req->queue))
+ return -EINVAL;
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+
+ VDBG("udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+ dev = ep->dev;
+
+ /* exit on suspend */
+ if (dev->sys_suspended)
+ return -ESHUTDOWN;
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* map dma (usally done before) */
+ if (ep->dma && usbreq->length != 0 && usbreq->dma == DMA_DONT_USE) {
+ VDBG("DMA map req %lx\n", (unsigned long) req);
+ if (ep->in)
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_TODEVICE);
+ else
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 1;
+ }
+
+ VDBG( "%s queue req %p, len %d req->td_data=%lx buf %p\n",
+ usbep->name, usbreq, usbreq->length, (unsigned long) req->td_data, usbreq->buf);
+
+ spin_lock_irqsave (&dev->lock, iflags);
+ usbreq->actual = 0;
+ usbreq->status = -EINPROGRESS;
+ req->dma_done = 0;
+
+ /* on empty queue just do first transfer */
+ if (list_empty (&ep->queue)) {
+ /* zlp */
+ if (ep->in && usbreq->length == 0) {
+ /* IN zlp's are handled by hardware */
+ complete_req(ep, req, 0);
+ VDBG( "%s: zlp\n", ep->ep.name);
+ /* if set_config or set_intf is waiting for ack by zlp
+ then set CSR_DONE */
+ if (dev->set_cfg_not_acked) {
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+ writel(tmp, &dev->regs->ctl);
+ dev->set_cfg_not_acked = 0;
+ }
+ /* setup command is ACK'ed now by zlp */
+ if (dev->waiting_zlp_ack_ep0in) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+ dev->waiting_zlp_ack_ep0in = 0;
+ }
+ goto finished;
+ }
+ if (ep->dma) {
+ retval = prep_dma(ep, req);
+ if (retval != 0)
+ goto finished;
+ /* write desc pointer to enable DMA */
+ if (ep->in) {
+ /* set HOST READY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+ }
+
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ if (!ep->in) {
+ /* enable DMA */
+ udc_set_rde(dev);
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 1;
+ }
+#ifdef UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE
+ else {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
+#endif
+ }
+
+ } else if (ep->dma) {
+
+ /* TODO use prep_dma also for OUT ep's, this is not possible
+ for PPB modes currently, because of chain creation reasons */
+ if (ep->in) {
+ retval = prep_dma(ep, req);
+ if (retval != 0)
+ goto finished;
+ }
+
+ }
+ VDBG("list_add\n");
+ /* add request to ep queue */
+ if (req) {
+
+ list_add_tail (&req->queue, &ep->queue);
+
+ /* stop OUT naking */
+ if (!ep->in) {
+ if (!use_dma && udc_rxfifo_pending) {
+ DBG("udc_queue(): pending bytes in rxfifo after nyet\n");
+ /* read pending bytes afer nyet: referring to isr */
+ if (udc_rxfifo_read(ep, req)) {
+ /* finish */
+ complete_req(ep, req, 0);
+ }
+ udc_rxfifo_pending = 0;
+
+ }
+ }
+
+ }
+
+finished:
+ spin_unlock_irqrestore (&dev->lock, iflags);
+ return retval;
+}
+
+/**
+ * Empty request queue of an endpoint
+ *
+ * \param ep pointer to ep struct
+ */
+static void empty_req_queue(struct udc_ep *ep)
+{
+ struct udc_request *req;
+
+ ep->halted = 1;
+ while (!list_empty (&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ complete_req(ep, req, -ESHUTDOWN);
+ }
+}
+
+/**
+ * Dequeues a request packet, called by gadget driver
+ *
+ * \param usbep pointer to usb ep struct
+ * \param usbreq pointer to request packet to be freed
+ * \return 0 if success
+ */
+static int udc_dequeue (struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned req_may_used = 0;
+ unsigned halted;
+ unsigned long iflags;
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ if (!usbep
+ || !usbreq
+ || (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)))
+ return -EINVAL;
+
+ req = container_of (usbreq, struct udc_request, req);
+
+ spin_lock_irqsave (&ep->dev->lock, iflags);
+ halted = ep->halted;
+ ep->halted = 1;
+ /* request in processing or next one */
+ if (ep->queue.next == &req->queue) {
+ req_may_used = 1;
+ }
+ complete_req(ep, req, -ECONNRESET);
+ ep->halted = halted;
+
+ spin_unlock_irqrestore (&ep->dev->lock, iflags);
+ if (req_may_used)
+ return -EOPNOTSUPP;
+ else
+ return 0;
+}
+
+/**
+ * Halt or clear halt of endpoint
+ *
+ * \param usbe pointer to ep struct
+ * \param halt 1 - halt, 0 - clear halt
+ * \return 0 if success
+ */
+static int
+udc_set_halt (struct usb_ep *usbep, int halt)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ unsigned long iflags;
+ int retval = 0;
+
+ if (!usbep)
+ return -EINVAL;
+
+ DBG("set_halt %s: halt=%d\n", usbep->name, halt);
+
+ ep = container_of (usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+ if (!ep->dev->driver
+ || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* exit on suspend */
+ if (ep->dev->sys_suspended)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave (&udc_stall_spinlock, iflags);
+ /* halt or clear halt */
+ if (halt) {
+ if (ep->num == 0)
+ ep->dev->stall_ep0in = 1;
+ else {
+ /* FIXME rxfifo empty should be taken into acount */
+ /* set STALL */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 1;
+
+#ifdef UDC_USE_TIMER
+ /* setup poll timer */
+ if (!timer_pending(&udc_pollstall_timer)) {
+ udc_pollstall_timer.expires = jiffies + HZ
+ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ if (!stop_pollstall_timer) {
+ DBG("start polltimer\n");
+ add_timer(&udc_pollstall_timer);
+ }
+ }
+#endif
+ }
+ } else {
+ /* ep is halted by set_halt() before */
+ if (ep->halted) {
+ tmp = readl(&ep->regs->ctl);
+ /* clear stall bit */
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+ spin_unlock_irqrestore (&udc_stall_spinlock, iflags);
+ return retval;
+}
+
+/**
+ * Return fifo fill state (not used, not implemented)
+ *
+ * \param usbep pointer to usb ep struct
+ * \return available bytes in fifo
+ */
+static int
+udc_fifo_status (struct usb_ep *usbep)
+{
+ return 0;
+}
+
+/**
+ * Flush the endpoint fifo (not implemented)
+ *
+ * \param usbep pointer to usb ep struct
+ */
+static void
+udc_fifo_flush (struct usb_ep *usbep)
+{
+ return;
+}
+
+/* gadget interface */
+static struct usb_ep_ops udc_ep_ops = {
+ .enable = udc_enable,
+ .disable = udc_disable,
+
+ .queue = udc_queue,
+ .dequeue = udc_dequeue,
+
+ .alloc_request = udc_alloc_request,
+ .free_request = udc_free_request,
+
+ .alloc_buffer = udc_alloc_buffer,
+ .free_buffer = udc_free_buffer,
+
+ .set_halt = udc_set_halt,
+ .fifo_status = udc_fifo_status,
+ .fifo_flush = udc_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * Get frame count fifo (not implemented)
+ *
+ * \param gadget pointer to gadget struct
+ * \return frame count
+ */
+static int udc_get_frame (struct usb_gadget *gadget)
+{
+ return 0;
+}
+
+/**
+ * Remote wakeup gadget interface
+ *
+ * \param gadget pointer to gadget struct
+ * \return 0 if success
+ */
+static int udc_wakeup (struct usb_gadget *gadget)
+{
+ struct udc *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of (gadget, struct udc, gadget);
+ udc_remote_wakeup(dev);
+
+ return 0;
+}
+
+/**
+ * gadget ioctl, used for OTG support notification
+ *
+ * \param gadget pointer to gadget struct
+ * \param cmd command
+ * \param par parmater
+ * \return 1 if OTG supported, else 0
+ */
+static int udc_gadget_ioctl (struct usb_gadget *gadget, unsigned cmd, unsigned long par)
+{
+ struct udc *dev;
+ int retval = 0;
+ unsigned long iflags;
+ u32 tmp;
+
+ if (!gadget)
+ return -ENODEV;
+ dev = container_of (gadget, struct udc, gadget);
+ spin_lock_irqsave (&dev->lock, iflags);
+ tmp = readl(&dev->regs->cfg);
+
+ if (tmp & AMD_BIT(UDC_DEVCFG_HNPSFEN))
+ retval = 1;
+ else
+ retval = 0;
+ spin_unlock_irqrestore (&dev->lock, iflags);
+ return retval;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+ .wakeup = udc_wakeup,
+ .get_frame = udc_get_frame,
+ .ioctl = udc_gadget_ioctl,
+};
+
+/**
+ * Setups endpoint parameters, adds endpoints to linked list
+ *
+ * \param dev pointer to dev struct
+ */
+static void make_ep_lists(struct udc *dev)
+{
+ /* make gadget ep lists */
+ INIT_LIST_HEAD (&dev->gadget.ep_list);
+ list_add_tail (&dev->ep [UDC_EPIN_STATUS_IX].ep.ep_list, &dev->gadget.ep_list);
+ list_add_tail (&dev->ep [UDC_EPIN_IX].ep.ep_list, &dev->gadget.ep_list);
+ list_add_tail (&dev->ep [UDC_EPOUT_IX].ep.ep_list, &dev->gadget.ep_list);
+
+ /* fifo config */
+ dev->ep [UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ dev->ep [UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ dev->ep [UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+ dev->ep [UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/**
+ * Sets fifo mode, called by gadget driver
+ *
+ * \param gadget pointer to gadget struct
+ * \param md not used
+ * \return 0 if success
+ */
+int amd5536udc_set_fifo_mode (struct usb_gadget *gadget, int md)
+{
+ struct udc *dev;
+ unsigned long iflags;
+
+ if (!gadget)
+ return -ENODEV;
+
+ dev = container_of (gadget, struct udc, gadget);
+
+ spin_lock_irqsave (&dev->lock, iflags);
+ make_ep_lists(dev);
+ spin_unlock_irqrestore (&dev->lock, iflags);
+
+ return 0;
+}
+EXPORT_SYMBOL (amd5536udc_set_fifo_mode);
+
+/**
+ * \brief
+ * init registers at driver load time
+ *
+ * \param dev pointer to device struc
+ * \return 0 if success
+ */
+static int startup_registers(struct udc* dev)
+{
+ u32 tmp;
+
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* put into initial config */
+ udc_basic_init (dev);
+ /* link up all endpoints */
+ udc_setup_endpoints (dev);
+
+ /* program speed */
+ tmp = readl(&dev->regs->cfg);
+ if (use_fullspeed) {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ }
+ else {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+ }
+ writel(tmp, &dev->regs->cfg);
+
+ return 0;
+}
+
+/**
+ * Inits UDC context
+ *
+ * \param dev pointer to device struct
+ */
+static void udc_basic_init (struct udc *dev)
+{
+ u32 tmp;
+
+ DBG("udc_basic_init()\n");
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+#ifdef UDC_USE_TIMER
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop poll stall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+#endif
+ /* disable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+ writel(tmp, &dev->regs->ctl);
+
+ /* enable dynamic CSR programming */
+ tmp = readl(&dev->regs->cfg);
+ tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+ /* set self powered */
+ tmp |= AMD_BIT(UDC_DEVCFG_SP);
+ /* set remote wakeupable */
+ tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+ writel(tmp, &dev->regs->cfg);
+
+ make_ep_lists(dev);
+
+ dev->data_ep_enabled = 0;
+ dev->data_ep_queued = 0;
+}
+
+/**
+ * Sets initial endpoint parameters
+ *
+ * \param dev pointer to device struct
+ */
+static void udc_setup_endpoints(struct udc *dev)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ u32 reg;
+
+ DBG("udc_setup_endpoints()\n");
+
+ /* read enum speed */
+ tmp = readl(&dev->regs->sts);
+ tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+ if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+ dev->gadget.speed = USB_SPEED_HIGH;
+ }
+ else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+ dev->gadget.speed = USB_SPEED_FULL;
+ }
+
+ /* set basic ep parameters */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ ep = &dev->ep[tmp];
+ ep->dev = dev;
+ ep->ep.name = ep_string [tmp];
+ ep->num = tmp;
+ /* txfifo size is calculated at enable time */
+ ep->txfifo = dev->txfifo;
+
+ /* fifo size */
+ if (tmp < UDC_EPIN_NUM) {
+ ep->fifo_depth = UDC_TXFIFO_SIZE;
+ ep->in = 1;
+ }
+ else {
+ ep->fifo_depth = UDC_RXFIFO_SIZE;
+ ep->in = 0;
+
+ }
+ ep->regs = &dev->ep_regs[tmp];
+ /* TODO ep will be reset only if ep was not enabled before to avoid
+ disabling ep interrupts when ENUM interrupt occurs but ep is
+ not enabled by gadget driver
+ => to be improved for general ep_init() */
+ if (!ep->desc) {
+ ep_init (dev->regs, ep);
+ }
+
+ if (use_dma) {
+ /* TODO ep->dma is not really used, just to indicate that */
+ /* DMA is active: remove this */
+ /* dma regs = dev control regs */
+ ep->dma = (u32*) &dev->regs->ctl;
+
+ /* nak OUT endpoints until enable - not for ep0*/
+ if (tmp != UDC_EP0IN_IX
+ && tmp != UDC_EP0OUT_IX
+ && tmp > UDC_EPIN_NUM) {
+ /* set NAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 1;
+
+ }
+ }
+ }
+ /* EP0 max packet */
+ if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev->ep [UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+ dev->ep [UDC_EP0OUT_IX].ep.maxpacket = UDC_FS_EP0OUT_MAX_PKT_SIZE;
+ }
+ else if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev->ep [UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep [UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+ }
+
+ /* with suspend bug workaround, ep0 params for gadget driver
+ are set at gadget driver bind() call */
+ dev->gadget.ep0 = &dev->ep [UDC_EP0IN_IX].ep;
+ dev->ep [UDC_EP0IN_IX].halted = 0;
+ INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+
+ /* init cfg/alt/int */
+ dev->cur_config = 0;
+ dev->cur_intf = 0;
+ dev->cur_alt = 0;
+}
+
+/**
+ * Bringup after Connect event,
+ * initial bringup to be ready for ep0 events
+ *
+ * \param dev pointer to device struct
+ */
+static void usb_connect (struct udc *dev) {
+
+ INFO("USB Connect\n");
+
+ dev->connected = 1;
+
+ /* put into initial config */
+ udc_basic_init (dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+}
+
+/**
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ *
+ * \param dev pointer to device struct
+ */
+static void usb_disconnect (struct udc *dev) {
+
+ INFO("USB Disconnect\n");
+
+ dev->connected = 0;
+
+ /* mask interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ tasklet_schedule(&disconnect_tasklet);
+}
+
+/**
+ * Tasklet for disconnect to be outside of interrupt
+ * context
+ *
+ * \param par pointer to device struct pointer
+ */
+void udc_tasklet_disconnect(unsigned long par)
+{
+ struct udc* dev = (struct udc*) (*((struct udc**) par));
+ u32 tmp;
+
+ DBG("Tasklet disconnect\n");
+
+ /* call gadget to reset configs etc. */
+ if (spin_is_locked(&dev->lock)) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect (&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ else
+ dev->driver->disconnect (&dev->gadget);
+
+ /* empty queues */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue (&dev->ep [tmp]);
+ }
+ /* disable ep0 */
+ ep_init (dev->regs,
+ &dev->ep [UDC_EP0IN_IX]);
+
+
+ if (!soft_reset_occured) {
+ /* init controller by soft reset */
+#ifdef UDC_IPCASE_8000018724_WORKAROUND
+ udc_soft_reset(dev);
+#endif
+ soft_reset_occured++;
+ }
+#ifndef UDC_IPBUG_3950_WORKAROUND
+ /* re-enable dev interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+#endif
+ /* back to full speed ? */
+ if (use_fullspeed) {
+ tmp = readl(&dev->regs->cfg);
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ writel(tmp, &dev->regs->cfg);
+ }
+
+ /* TODO for AU1200: disable UDC memory */
+}
+
+/**
+ * Reset the UDC core
+ *
+ * \param dev pointer to device struct
+ */
+static void udc_soft_reset(struct udc* dev)
+{
+ DBG("Soft reset\n");
+ /* reset possible waiting interrupts, because int.
+ status is lost after soft reset */
+ /* ep int. status reset */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+ /* device int. status reset */
+ writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+ /* FIXME: reset is the only way to restart DMA now,
+ later if the hw bug is fixed, use a softer way */
+ spin_lock_irq(&udc_irq_spinlock);
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ readl(&dev->regs->cfg);
+ spin_unlock_irq(&udc_irq_spinlock);
+
+}
+
+#ifdef UDC_USE_TIMER
+/**
+ * RDE timer callback to set RDE bit
+ *
+ * \param v timer callback argument
+ */
+void udc_timer_function(unsigned long v)
+{
+ u32 tmp;
+ unsigned int i;
+ unsigned int bulk_data_arrived;
+ spin_lock_irq(&udc_irq_spinlock);
+ if (set_rde) {
+ /* open the fifo if fifo was filled on last timer call */
+ if (set_rde > 1) {
+ bulk_data_arrived = 0;
+ /* check wether OUT bulk data is arrived */
+ for (i = UDC_EPIN_NUM + 1; i < UDC_EP_NUM; i++) {
+ tmp = readl(&udc->ep [i].regs->sts);
+ if (AMD_GETBITS(tmp, UDC_EPSTS_OUT)
+ == UDC_EPSTS_OUT_DATA) {
+ //&& AMD_GETBITS(tmp, UDC_EPSTS_RX_PKT_SIZE)){
+ bulk_data_arrived = 1;
+ break;
+ }
+ }
+ /* if OUT bulk data in fifo wait for queueing which
+ sets RDE, if not open fifo for setup packet */
+ if (!bulk_data_arrived) {
+ /* set RDE */
+ tmp = readl(&udc->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &udc->regs->ctl);
+ }
+ else
+ INFO("ep%d - queueing delay longer than %d second(s)\n",
+ i, UDC_RDE_TIMER_SECONDS);
+ set_rde = -1;
+ }
+ else if (readl(&udc->regs->sts) &
+ AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ /* if fifo empty setup polling, do not just
+ open the fifo */
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ else {
+ /* fifo contains data now, setup timer for opening
+ the fifo when timer expires to be able to receive
+ setup packets, when data packets gets queued by
+ gadget layer then timer will forced to expire with
+ set_rde=0 (RDE is set in udc_queue()) */
+ set_rde++;
+ /* debug: lhadmot_timer_start = 221070 */
+ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+
+ }
+ else
+ set_rde = -1; /* RDE was set by udc_queue() */
+ spin_unlock_irq(&udc_irq_spinlock);
+ if (stop_timer)
+ complete(&on_exit);
+
+}
+
+/**
+ * Handle halt state, used in stall poll timer
+ *
+ * \param ep pointer to endpoint struct
+ */
+static inline void udc_handle_halt_state(struct udc_ep* ep)
+{
+ u32 tmp;
+ /* set stall as long not halted */
+ if (ep->halted == 1) {
+ tmp = readl(&ep->regs->ctl);
+ /* STALL cleared ? */
+ if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+ DBG("ep %d: set STALL again\n", ep->num);
+ /* set STALL again */
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ }
+}
+
+/**
+ * Stall timer callback to poll S bit and set it again after
+ * CLEAR_FEATURE
+ *
+ * \param v timer callback argument
+ */
+void udc_pollstall_timer_function(unsigned long v)
+{
+ struct udc_ep *ep;
+ int halted = 0;
+ unsigned long iflags;
+
+ spin_lock_irqsave (&udc_stall_spinlock, iflags);
+ /* TODO only one IN and OUT endpoints are handled */
+ /* IN poll stall */
+ ep = &udc->ep [UDC_EPIN_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+ /* OUT poll stall */
+ ep = &udc->ep [UDC_EPOUT_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+
+ /* setup timer again when still halted */
+ if (!stop_pollstall_timer && halted) {
+ udc_pollstall_timer.expires = jiffies + HZ
+ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ add_timer(&udc_pollstall_timer);
+ }
+ spin_unlock_irqrestore (&udc_stall_spinlock, iflags);
+
+ if (stop_pollstall_timer)
+ complete(&on_pollstall_exit);
+}
+#endif
+
+#if defined(UDC_IPBUG_3950_WORKAROUND) \
+ || defined(UDC_IPCASE_8000018724_WORKAROUND) \
+ && !defined(UDC_HSB1)
+/**
+ * Called by OTG driver to notify us regarding an OTG event
+ *
+ * \param code notify code
+ */
+void otg_notify(unsigned int code) {
+ VDBG("OTG notify code=%d\n", code);
+ switch (code) {
+ case OTG_GADGET_EVT_SVDROP:
+ /* disconnect event */
+ usb_disconnect(udc);
+ break;
+ case OTG_GADGET_EVT_SVALID:
+ /* connect event */
+ usb_connect(udc);
+ break;
+ case OTG_GADGET_REQ_WAKE:
+ /* remote wakeup event */
+ udc_remote_wakeup(udc);
+ break;
+ }
+}
+#endif
+
+/**
+ * Inits endpoint 0 so that SETUP packets are processed
+ *
+ * \param dev pointer to device struct
+ */
+static void activate_control_endpoints (struct udc *dev)
+{
+ u32 tmp;
+
+ DBG("activate_control_endpoints\n");
+
+ /* flush fifo */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* set ep0 directions */
+ dev->ep[UDC_EP0IN_IX].in = 1;
+ dev->ep[UDC_EP0OUT_IX].in = 0;
+
+ /* set buffer size (tx fifo entries) of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE, UDC_EPIN_BUFF_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+ /* set max packet size of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0_OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0 in UDC CSR */
+ tmp = readl(&dev->csr->ne[0]);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, UDC_CSR_NE_MAX_PKT);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[0]);
+
+ if (use_dma) {
+ dev->ep [UDC_EP0OUT_IX].td->status |= AMD_BIT(UDC_DMA_OUT_STS_L);
+ /* write dma desc address */
+ writel(dev->ep [UDC_EP0OUT_IX].td_stp_dma, &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+ writel(dev->ep [UDC_EP0OUT_IX].td_phys, &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+#ifdef UDC_USE_TIMER
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop pollstall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+#endif
+ /* enable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+ | AMD_BIT(UDC_DEVCTL_RDE)
+ | AMD_BIT(UDC_DEVCTL_TDE);
+ if (use_dma_bufferfill_mode) {
+ tmp |= AMD_BIT(UDC_DEVCTL_BF);
+ }
+ else if (use_dma_ppb_du) {
+ tmp |= AMD_BIT(UDC_DEVCTL_DU);
+ }
+ writel(tmp, &dev->regs->ctl);
+ }
+
+ /* clear NAK by writing CNAK for EP0IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* clear NAK by writing CNAK for EP0OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/**
+ * \brief
+ * Make endpoint 0 ready for control traffic
+ *
+ * \param dev pointer to device struc
+ * \return 0 if success
+ */
+static int setup_ep0(struct udc *dev)
+{
+ activate_control_endpoints (dev);
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ return 0;
+}
+
+/**
+ * \brief
+ * Called by gadget driver to register itself
+ *
+ * \param driver pointer to gadget driver struct
+ * \return 0 if success
+ */
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ int retval;
+ u32 tmp;
+
+ if (!driver || !driver->bind
+ || !driver->unbind
+ || !driver->setup
+ || driver->speed != USB_SPEED_HIGH)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ driver->driver.bus = 0;
+#endif
+ dev->driver = driver;
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ dev->gadget.dev.driver = &driver->driver;
+#endif
+
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifndef CONFIG_MIPS
+ /* FIXME TMP26: temporary disabled device file system usage until
+ * working for Au1200 */
+ device_create_file (&dev->pdev->dev, &dev_attr_function);
+ device_create_file (&dev->pdev->dev, &dev_attr_queues);
+#endif
+#endif
+
+#ifdef CONFIG_USB_OTG
+ dev->gadget.is_otg = 1;
+#endif
+ retval = driver->bind (&dev->gadget);
+ /* e.g. ether gadget needs driver_data on both ep0 endpoints */
+ dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+ dev->ep [UDC_EP0IN_IX].ep.driver_data;
+
+ gadget_bind_count++;
+ if (retval) {
+ DBG( "binding to %s returning %d\n",
+ driver->driver.name, retval);
+ dev->driver = 0;
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ dev->gadget.dev.driver = 0;
+#endif
+ return retval;
+ }
+
+ /* if otg driver already registered */
+ /* call otg bind() to mux udc to phy */
+ if (dev->otg_transceiver) {
+ dev->otg_transceiver->set_peripheral(
+ dev->otg_transceiver, &dev->gadget);
+ /* clear SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+ }
+#ifndef UDC_IPBUG_3950_WORKAROUND
+ usb_connect(dev);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+/**
+ * Called by OTG driver to register itself
+ *
+ *
+ * \param get_transceiver function pointer to get OTG info
+ * \return 0 if success
+ */
+int usb_gadget_register_otg (struct otg_transceiver * (*get_transceiver)(void))
+{
+ struct udc *dev = udc;
+ int retval;
+ u32 tmp;
+
+ if (!get_transceiver)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->otg_transceiver)
+ return -EBUSY;
+
+ dev->otg_transceiver = get_transceiver ();
+
+#if !defined(UDC_HSB1)
+ if (!dev->otg_transceiver->otg_priv)
+ return -EINVAL;
+ dev->otg_driver = (struct usb_otg_gadget_extension *)
+ dev->otg_transceiver->otg_priv;
+#endif
+
+#ifdef UDC_IPBUG_3943_WORKAROUND
+ /* init registers here first with suspend bug */
+ if (!otg_reg_count) {
+ startup_registers(dev);
+ otg_reg_count++;
+ }
+#endif
+
+#ifdef UDC_IPBUG_3950_WORKAROUND
+ /* set notify function */
+ dev->otg_driver->notify = otg_notify;
+#endif
+ /* if gadget driver already registered */
+ /* call gadget bind() to switch to mux udc to phy */
+ /* TODO use SD bit to disconnect/connect later, in */
+ /* AMD5536 RevA0 this does not work ! */
+ if (dev->driver) {
+
+ /* otg driver bind() */
+ retval = dev->otg_transceiver->set_peripheral(
+ dev->otg_transceiver, &dev->gadget);
+ if (retval) {
+ DBG( "error bind to uoc driver\n");
+#if !defined(UDC_HSB1)
+ dev->otg_driver = NULL;
+#endif
+ dev->otg_transceiver = NULL;
+ return retval;
+ }
+ /* get ready for ep0 traffic */
+ setup_ep0(dev);
+
+ /* clear SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+ }
+
+ INFO( "registered uoc driver\n");
+
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_otg);
+
+/**
+ * Called by OTG driver to unregister itself
+ *
+ *
+ * \return 0 if success
+ */
+int usb_gadget_unregister_otg (void)
+{
+ struct udc *dev = udc;
+ unsigned long flags;
+ u32 tmp;
+
+ if (!dev)
+ return -ENODEV;
+
+ spin_lock_irqsave (&dev->lock, flags);
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ dev->otg_supported = 0;
+ if (dev->otg_transceiver) {
+ dev->otg_transceiver->set_peripheral(dev->otg_transceiver, NULL);
+ dev->otg_transceiver = NULL;
+ }
+#if !defined(UDC_HSB1)
+ if (dev->otg_driver) {
+#ifdef UDC_IPBUG_3950_WORKAROUND
+ dev->otg_driver->notify = NULL;
+#endif
+ dev->otg_driver = NULL;
+ }
+#endif
+
+ /* set SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+ DBG( "unregistered uoc driver\n");
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_otg);
+
+/**
+ * shutdown requests and disconnect from gadget
+ */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+{
+ int tmp;
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue (&dev->ep [tmp]);
+ }
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock (&dev->lock);
+ driver->disconnect (&dev->gadget);
+ spin_lock (&dev->lock);
+ }
+ /* init */
+ udc_setup_endpoints (dev);
+}
+
+/**
+ * Called by gadget driver to unregister itself
+ *
+ * \param driver pointer to gadget driver struct
+ * \return 0 if success
+ */
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ unsigned long iflags;
+ u32 tmp;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver)
+ return -EINVAL;
+ if (gadget_bind_count) {
+ spin_lock_irqsave (&dev->lock, iflags);
+ shutdown(dev, driver);
+ spin_unlock_irqrestore (&dev->lock, iflags);
+ }
+
+ /* unbind from otg driver first */
+ if (dev->otg_transceiver) {
+ dev->otg_transceiver->set_peripheral(
+ dev->otg_transceiver, NULL);
+ }
+
+ if (gadget_bind_count) {
+ driver->unbind (&dev->gadget);
+ }
+
+ /* set SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+ gadget_bind_count = 0;
+ dev->driver = 0;
+
+ DBG( "%s: unregistered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+
+#ifdef UDC_IPBUG_3958_WORKAROUND
+/**
+ * Clear pending NAK bits
+ *
+ * \param dev pointer to UDC device object
+ * \return 0 if success
+ */
+static void udc_process_cnak_queue(struct udc* dev)
+{
+ u32 tmp;
+ u32 reg;
+ /* check epin's */
+ DBG("CNAK pending queue processing\n");
+ for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+ if (cnak_pending & (1 << tmp)) {
+ DBG("CNAK pending for ep%d\n", tmp);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+ }
+ }
+ /* ... and ep0out */
+ if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+ DBG("CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+ dev->ep[UDC_EP0OUT_IX].num);
+ }
+}
+#endif
+
+/**
+ * Enabling RX DMA after setup packet
+ *
+ * \param dev pointer to UDC device object
+ */
+static inline void udc_ep0_set_rde(struct udc* dev)
+{
+ if (use_dma) {
+#ifndef UDC_USE_TIMER
+ udc_set_rde(dev);
+#else
+ /* only enable RXDMA when no data endpoint enabled
+ or data is queued */
+ if (!dev->data_ep_enabled || dev->data_ep_queued) {
+ udc_set_rde(dev);
+ }
+ else {
+ /* setup timer for enabling RDE (to not enable
+ RXFIFO DMA for data endpoints to early) */
+ if (set_rde != 0 && !timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+#endif
+ }
+}
+
+
+/**
+ * Interrupt handler for data OUT traffic
+ *
+ * \param dev pointer to UDC device object
+ * \param ep_ix endpoint index
+ * \return 0 if success
+ */
+static inline int udc_data_out_isr(struct udc* dev, int ep_ix)
+{
+ int ret_val = 0;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned int count;
+ struct udc_data_dma *td = NULL;
+ unsigned dma_done;
+
+ VDBG("ep%d irq\n", ep_ix);
+ ep = &dev->ep [ep_ix];
+
+ tmp = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ ERR("BNA ep%dout occured - DESPTR = %lx \n", ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear BNA */
+ writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+ /* TODO no early return */
+ return 1;
+ }
+ }
+ /* HE event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+ ERR("HE ep%dout occured\n", ep->num);
+
+ /* clear HE */
+ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ /* TODO no early return */
+ return 1;
+ }
+
+ if (!list_empty (&ep->queue)) {
+
+ /* next request */
+ req = list_entry (ep->queue.next,
+ struct udc_request, queue);
+ }
+ else
+ {
+ req = 0;
+#ifdef UDC_DEBUG
+ no_req++;
+#endif
+ udc_rxfifo_pending = 1;
+ }
+ VDBG("req = %lx\n", (unsigned long) req);
+ /* fifo mode ****************/
+ if (!use_dma) {
+
+ /* read fifo */
+ if (req && udc_rxfifo_read(ep, req)) {
+ /* finish */
+ complete_req (ep, req, 0);
+ /* next request */
+ if (!list_empty (&ep->queue) && !ep->halted) {
+ req = list_entry (ep->queue.next,
+ struct udc_request, queue);
+ }
+ else
+ req = 0;
+ }
+
+ } /* DMA ********************/
+ else if (req) {
+
+ /* check for DMA done */
+ if (!use_dma_ppb) {
+ dma_done = AMD_GETBITS(req->td_data->status, UDC_DMA_OUT_STS_BS);
+ } /* packet per buffer mode - rx bytes */
+ else {
+ td = udc_get_last_dma_desc(req);
+ dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+ }
+ if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+ /* buffer fill mode - rx bytes */
+ if (!use_dma_ppb) {
+ /* received number bytes */
+ count = AMD_GETBITS(req->td_data->status, UDC_DMA_OUT_STS_RXBYTES);
+ VDBG("rx bytes=%lx\n", (unsigned long) count);
+ } /* packet per buffer mode - rx bytes */
+ else {
+ VDBG("req->td_data=%lx\n", (unsigned long) req->td_data);
+ VDBG("last desc = %lx\n", (unsigned long) td);
+ /* received number bytes */
+ if (use_dma_ppb_du) {
+ /* every desc. counts bytes */
+ count = udc_get_ppbdu_rxbytes(req);
+ }
+ else {
+ /* last desc. counts bytes */
+ count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+ if (!count) {
+ /* on 64k packets the RXBYTES field is zero */
+ if (req->req.length == UDC_DMA_MAXPACKET)
+ count = UDC_DMA_MAXPACKET;
+ }
+ }
+ VDBG("last desc rx bytes=%lx\n", (unsigned long) count);
+ }
+
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ if ((tmp % ep->ep.maxpacket) != 0) {
+ ERR( "%s: received %d bytes, rx-buffer space = %d bytes => buffer overrun\n",
+ ep->ep.name, count, tmp);
+ req->req.status = -EOVERFLOW;
+ }
+ count = tmp;
+ }
+ req->req.actual += count;
+
+ /* complete request */
+ complete_req(ep, req, 0);
+
+ /* next request */
+ if (!list_empty (&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+
+ /* next dma */
+ ret_val = prep_dma(ep, req);
+ if (ret_val != 0)
+ goto finished;
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* enable DMA */
+ udc_set_rde(dev);
+ }
+ else {
+#ifdef UDC_DEBUG
+ no_pref_req++;
+ VDBG("OUT queue empty\n");
+#endif
+ /* schedule timer for setting RDE if queue remains empty
+ * to allow ep0 packets pass through */
+#ifdef UDC_USE_TIMER
+ if (set_rde != 0 && !timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+#endif
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 0;
+ }
+
+ }
+ else {
+ /* RX DMA must be reenabled for each desc in PPBDU mode */
+ if (use_dma_ppb_du) {
+ udc_set_rde(dev);
+ }
+ }
+
+ }
+
+#ifdef UDC_IPBUG_3958_WORKAROUND
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+#endif
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_DATA_CLEAR, &ep->regs->sts);
+finished:
+ return ret_val;
+}
+
+/**
+ * Interrupt handler for data IN traffic
+ *
+ * \param dev pointer to UDC device object
+ * \param ep_ix endpoint index
+ * \return 0 if success
+ */
+static inline int udc_data_in_isr(struct udc* dev, int ep_ix)
+{
+ int ret_val = 0;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc_data_dma *td;
+ unsigned dma_done;
+ unsigned len;
+
+ ep = &dev->ep[ep_ix];
+
+ tmp = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ ERR("BNA ep%din occured - DESPTR = %08lx \n",
+ ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear BNA */
+ writel(tmp, &ep->regs->sts);
+ /* TODO no early return */
+
+ return 1;
+ }
+ }
+ /* HE event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+ ERR("HE ep%dn occured - DESPTR = %08lx \n",
+ ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear HE */
+ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ /* TODO no early return */
+ return 1;
+ }
+
+ tmp= readl(&ep->regs->sts);
+
+ /* DMA completion */
+ if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG("TDC set- completion\n");
+ if (!list_empty (&ep->queue)) {
+ req = list_entry (ep->queue.next,
+ struct udc_request, queue);
+ if (req) {
+ /* lengh bytes transfered */
+ /* check dma done of last desc. in PPBDU mode */
+ if (use_dma_ppb_du) {
+ td = udc_get_last_dma_desc(req);
+ if (td) {
+ /* RTL bug (Bugzilla #3672): the TDC */
+ /* irq is quicker */
+ /* than the desc. update in memory */
+ /* TDC is set, but DMA is busy */
+ dma_done =
+ AMD_GETBITS(td->status, UDC_DMA_IN_STS_BS);
+ /* don't care DMA done as long the above mentioned RTL bug is */
+ /* present, TODO check dma_done if this is fixed */
+ //if (dma_done == UDC_DMA_IN_STS_BS_DMA_DONE) {
+ req->req.actual = req->req.length;
+ //}
+ }
+ }
+ else {
+ /* assume all bytes transferred */
+ /* TODO check error status */
+ req->req.actual = req->req.length;
+ }
+
+ if (req->req.actual == req->req.length) {
+#ifdef UDC_IPBUG_2253_WORKAROUND
+ /* stop NAKing after small packet DMA */
+ if (ep->naking) {
+ /* clear NAK by writing CNAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+#endif
+ /* complete req */
+ complete_req(ep, req, 0);
+ req->dma_going = 0;
+#ifdef UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE
+ /* further request available ? */
+ if (list_empty (&ep->queue)) {
+ /* disable interrupt */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
+#endif
+
+ }
+ }
+ }
+
+
+ /* clear TDC bit */
+ writel(AMD_BIT(UDC_EPSTS_TDC),&ep->regs->sts);
+
+
+ } /* status reg has IN bit set ? */
+ else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+ if (!list_empty (&ep->queue))
+ {
+ /* next request */
+ req = list_entry (ep->queue.next,
+ struct udc_request, queue);
+ /* FIFO mode ********/
+ if (!use_dma) {
+ /* write fifo */
+ udc_txfifo_write(ep, &(req->req));
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ //&& (!req->req.zero || len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req (ep, req, 0);
+ }
+ } /* DMA *****************/
+ else if (req && !req->dma_going) {
+ VDBG("IN DMA : req=%lx req->td_data=%lx\n",
+ (unsigned long) req, (unsigned long) req->td_data);
+ if (req->td_data) {
+
+ req->dma_going = 1;
+
+ /* unset L bit of first desc. for chain */
+ if (use_dma_ppb && req->req.length > ep->ep.maxpacket) {
+ req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+ }
+
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ wb_flush();
+ /* set HOST READY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+
+ wb_flush();
+
+#ifdef UDC_IPBUG_2253_WORKAROUND
+ /* NAK if small packet until TDC interrupt */
+ if (req->req.length < UDC_SMALL_PACKET) {
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+ wb_flush();
+ }
+#endif
+ /* set poll demand bit */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+ }
+ }
+
+ }
+
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),&ep->regs->sts);
+ }
+
+ return ret_val;
+
+}
+
+/**
+ * Interrupt handler for Control OUT traffic
+ *
+ * \param dev pointer to UDC device object
+ * \return 0 if success
+ */
+static inline int udc_control_out_isr(struct udc* dev)
+{
+ int ret_val = 0;
+ u32 tmp;
+ int setup_supported;
+ u32 count;
+ int set = 0;
+ struct udc_ep *ep;
+ struct udc_ep *ep_tmp;
+
+ ep = &dev->ep[UDC_EP0OUT_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ /* check BNA and clear if set */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ VDBG("BNA set\n");
+ writel(AMD_BIT(UDC_EPSTS_BNA), &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ }
+
+ /* type of data: SETUP or DATA 0 bytes */
+ tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+ VDBG( "data_typ = %lx\n", (unsigned long) tmp);
+ /* setup data */
+ if (tmp == UDC_EPSTS_OUT_SETUP) {
+
+ ep->dev->stall_ep0in = 0;
+ dev->waiting_zlp_ack_ep0in = 0;
+
+ /* set NAK for EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 1;
+ /* get setup data */
+ if (use_dma) {
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_SETUP_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ setup_data.data[0] = dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+ setup_data.data[1] = dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+ /* set HOST READY */
+ writel(UDC_DMA_STP_STS_BS_HOST_READY,
+ &dev->ep[UDC_EP0OUT_IX].td_stp->status);
+ }
+ else {
+ /* read fifo */
+ udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+ }
+
+ /* determine direction of control data */
+ if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+ dev->gadget.ep0 = &dev->ep [UDC_EP0IN_IX].ep;
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ set = 0;
+ }
+ else {
+ dev->gadget.ep0 = &dev->ep [UDC_EP0OUT_IX].ep;
+#ifdef UDC_USE_TIMER
+ set = 1;
+ dev->ep[UDC_EP0OUT_IX].naking = 1;
+ /* setup timer for enabling RDE (to not enable
+ RXFIFO DMA for data to early) */
+ set_rde = 1;
+ if (!timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+#endif
+ }
+ /* mass storage reset must be processed here because
+ next packet may be a CLEAR_FEATURE HALT which would not
+ clear the stall bit when no STALL handshale was received before
+ (autostall can cause this) */
+ if (setup_data.data[0] == UDC_MSCRES_DWORD0 &&
+ setup_data.data[1] == UDC_MSCRES_DWORD1) {
+ DBG("MSC Reset\n");
+ /* clear stall bits */
+ /* TODO only one IN and OUT endpoints are handled */
+ ep_tmp = &udc->ep [UDC_EPIN_IX];
+ udc_set_halt (&ep_tmp->ep, 0);
+ ep_tmp = &udc->ep [UDC_EPOUT_IX];
+ udc_set_halt (&ep_tmp->ep, 0);
+ }
+
+ /* call gadget with setup data received */
+ spin_unlock (&dev->lock);
+ setup_supported = dev->driver->setup (&dev->gadget,
+ &setup_data.request);
+ spin_lock (&dev->lock);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ /* ep0 in returns data (not zlp) on IN phase */
+ if (setup_supported >= 0 && setup_supported < UDC_EP0IN_MAXPACKET) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+ }
+ else if (setup_supported < 0) {
+ /* if unsupported request then stall */
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ }
+ else
+ dev->waiting_zlp_ack_ep0in = 1;
+
+
+ /* clear NAK by writing CNAK in EP0_OUT */
+ if (!set) {
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+ }
+
+ if (!use_dma) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_SETUP_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ }
+
+ } /* data packet 0 bytes */
+ else if (tmp == UDC_EPSTS_OUT_DATA) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_DATA_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ /* get setup data: only 0 packet */
+ if (use_dma) {
+ /* no req if 0 packet, just reactivate */
+ if (list_empty (&dev->ep[UDC_EP0OUT_IX].queue)) {
+ VDBG("ZLP\n");
+
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td->status =
+ AMD_ADDBITS(dev->ep[UDC_EP0OUT_IX].td->status,
+ UDC_DMA_OUT_STS_BS_HOST_READY,
+ UDC_DMA_OUT_STS_BS);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ }
+ else {
+ /* control write */
+ udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ /* re-program desc. pointer for possible ZLPs */
+ writel(dev->ep [UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ }
+ }
+ else {
+
+ /* received number bytes */
+ count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+ /* FIXME disabled out data for fifo mode */
+ count = 0;
+
+ /* 0 packet or real data ? */
+ if (count != 0) {
+ udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ }
+ else {
+ /* dummy read confirm */
+ readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+ }
+ }
+ }
+
+#ifdef UDC_IPBUG_3958_WORKAROUND
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+#endif
+
+ return ret_val;
+}
+
+/**
+ * Interrupt handler for Control IN traffic
+ *
+ * \param dev pointer to UDC device object
+ * \return 0 if success
+ */
+static inline int udc_control_in_isr(struct udc* dev)
+{
+ int ret_val = 0;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned len;
+
+ ep = &dev->ep [UDC_EP0IN_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+ tmp= readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+ /* DMA completion */
+ if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG("isr: TDC clear \n");
+#ifdef UDC_IPBUG_2253_WORKAROUND
+ /* stop NAKing after small packet DMA */
+ if (ep->naking) {
+ /* clear NAK by writing CNAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+#endif
+ /* clear TDC bit */
+ writel(AMD_BIT(UDC_EPSTS_TDC),&dev->ep[UDC_EP0IN_IX].regs->sts);
+ } /* status reg has IN bit set ? */
+ else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+ if (ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),&dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ if (dev->stall_ep0in) {
+ DBG("stall ep0in\n");
+ /* halt ep0in */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ else {
+ if (!list_empty (&ep->queue))
+ {
+ /* next request */
+ req = list_entry (ep->queue.next,
+ struct udc_request, queue);
+
+ if (ep->dma) {
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+ /* set HOST READY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+ wb_flush();
+
+#ifdef UDC_IPBUG_2253_WORKAROUND
+ /* NAK if small packet until TDC interrupt */
+ if (req->req.length < UDC_SMALL_PACKET) {
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+ wb_flush();
+ }
+#endif
+ /* set poll demand bit */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* all bytes will be transferred */
+ req->req.actual = req->req.length;
+
+ /* complete req */
+ complete_req(ep, req, 0);
+
+ }
+ else {
+ /* write fifo */
+ udc_txfifo_write(ep, &(req->req));
+
+ /* lengh bytes transfered */
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ //&& (!req->req.zero || len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ }
+
+ }
+ }
+ ep->halted = 0;
+ dev->stall_ep0in = 0;
+ if (!ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),&dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ }
+
+ return ret_val;
+}
+
+
+/**
+ * Interrupt handler for global device events
+ *
+ * \param dev pointer to UDC device object
+ * \param dev_irq device interrupt bit of DEVINT register
+ * \return 0 if success
+ */
+static inline int udc_dev_isr(struct udc* dev, u32 dev_irq)
+{
+ int ret_val = 0;
+ u32 tmp;
+ u32 cfg;
+ struct udc_ep *ep;
+ u16 i;
+ u8 udc_csr_epix;
+
+ /* SET_CONFIG irq ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+
+ /* read config value */
+ tmp = readl(&dev->regs->sts);
+ cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+#ifdef UDC_DEBUG
+ /* this is needed for debug only */
+ if (cfg == dev->cur_config) {
+ same_cfg = 1;
+ }
+ else {
+ same_cfg = 0;
+ }
+ VDBG("same_cfg=%d\n", same_cfg);
+#endif
+ DBG("SET_CONFIG interrupt: config=%d\n", cfg);
+ dev->cur_config = cfg;
+ dev->set_cfg_not_acked = 1;
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.request.wValue = dev->cur_config;
+
+ /* programm the NE registers */
+ /* TODO - put this to extra function or use udc_setup_endpoints() or udc_enable() */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ } /* OUT ep */
+ else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep cfg */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ /* call gadget zero with setup data received */
+ spin_unlock (&dev->lock);
+ tmp = dev->driver->setup (&dev->gadget, &setup_data.request);
+ spin_lock (&dev->lock);
+
+ } /* SET_INTERFACE ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+ dev->set_cfg_not_acked = 1;
+ /* read interface and alt setting values */
+ tmp = readl(&dev->regs->sts);
+ dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+ dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+ setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+ setup_data.request.wValue = dev->cur_alt;
+ setup_data.request.wIndex = dev->cur_intf;
+
+ DBG("SET_INTERFACE interrupt: alt=%d intf=%d\n", dev->cur_alt, dev->cur_intf);
+
+ /* programm the NE registers */
+ /* TODO - put this to extra function or use udc_setup_endpoints() or udc_enable() */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ } /* OUT ep */
+ else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ /***** UDC CSR reg ****************************/
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+ //tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF);
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+ //tmp = AMD_ADDBITS(tmp, 1, UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+
+ /* call gadget zero with setup data received */
+ spin_unlock (&dev->lock);
+ tmp = dev->driver->setup (&dev->gadget, &setup_data.request);
+ spin_lock (&dev->lock);
+
+ } /* USB reset */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+ DBG("USB Reset interrupt\n");
+
+ /* allow soft reset when suspend occurs */
+ soft_reset_occured = 0;
+
+ dev->waiting_zlp_ack_ep0in = 0;
+ dev->set_cfg_not_acked = 0;
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* call gadget to reset configs etc. */
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue (&dev->ep [UDC_EP0IN_IX]);
+ ep_init(dev->regs,
+ &dev->ep [UDC_EP0IN_IX]);
+
+#ifdef UDC_IPBUG_3958_WORKAROUND_SOFT_RESET_ON_USBRESET
+ /* soft reset when rxfifo not empty */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) &&
+ !soft_reset_after_usbreset_occured) {
+ udc_soft_reset(dev);
+ soft_reset_after_usbreset_occured++;
+ }
+#endif
+
+ /* DMA reset to kill potential old DMA hw hang, */
+ /* POLL bit is already reset by ep_init() through */
+ /* disconnect() */
+ UDC_DMARST(tmp,dev);
+
+ /* put into initial config */
+ udc_basic_init (dev);
+
+#ifdef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH_ON_USBRESET
+ /* TODO this workaround hang sometimes */
+ {
+ u32 reg;
+ u32 val;
+ /* TODO outsource this */
+ /* take care of PCSBUG#1503, empty rxfifo to allow CNAK */
+ /* disable DMA */
+ tmp = readl(&dev->regs->ctl);
+ writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_MODE), &dev->regs->ctl);
+ /* empty rxfifo */
+ reg = readl(&dev->regs->sts);
+ while (!(reg & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))) {
+ DBG("RXFIFO not empty\n");
+ /* clear all OUT and BNA bits */
+ for (i = UDC_EPIN_NUM; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ reg = readl(&ep->regs->sts);
+ /* BNA clear */
+ if (reg & AMD_BIT(UDC_EPSTS_BNA)) {
+ ERR("BNA ep%d occured - ep sts = %08lx \n", ep->num, (unsigned long) reg);
+ /* clear BNA */
+ writel(reg | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+ }
+ if (reg & AMD_BIT(UDC_EPSTS_OUT_DATA) ||
+ reg & AMD_BIT(UDC_EPSTS_OUT_SETUP)) {
+ /* received number bytes */
+ val = readl(&ep->regs->sts);
+ val = AMD_GETBITS(val, UDC_EPSTS_RX_PKT_SIZE);
+ /* read rx fifo bytes */
+ DBG("Clear ep%d rxfifo bytes count=%d\n", ep->num, val);
+ udc_rxfifo_read_bytes(dev, udc_rxfifo_trash, val);
+ /* clear OUT/SETUP bits in ep status */
+ writel(reg | UDC_EPSTS_OUT_SETUP_CLEAR |
+ UDC_EPSTS_OUT_DATA_CLEAR, &ep->regs->sts);
+ }
+ }
+ reg = readl(&dev->regs->sts);
+ }
+ /* re-enable DMA if was active */
+ writel(tmp, &dev->regs->ctl);
+ }
+#endif
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ } /* USB suspend */
+#ifndef UDC_IPBUG_3943_WORKAROUND
+ if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+ DBG("USB Suspend interrupt\n");
+
+ } /* new speed ? */
+#endif
+ if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+ DBG("ENUM interrupt\n");
+#ifdef UDC_DEBUG
+ num_enums++;
+ DBG("%d enumerations !\n", num_enums);
+#endif
+ soft_reset_after_usbreset_occured = 0;
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue (&dev->ep [UDC_EP0IN_IX]);
+ ep_init (dev->regs,
+ &dev->ep [UDC_EP0IN_IX]);
+
+ /* link up all endpoints */
+ udc_setup_endpoints (dev);
+ if (dev->gadget.speed == USB_SPEED_HIGH) {
+ INFO("Connect: Speed = HIGH_SPEED\n");
+ }
+ else if (dev->gadget.speed == USB_SPEED_FULL) {
+ INFO("Connect: Speed = FULL_SPEED\n");
+ }
+
+ /* init ep 0 */
+ activate_control_endpoints(dev);
+
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ }
+#ifndef UDC_IPBUG_3950_WORKAROUND
+ /* session valid change interrupt */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+ DBG("USB SVC interrupt\n");
+
+ /* check that session is not valid to detect disconnect */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+ DBG("USB Disconnect (session valid low)\n");
+ /* cleanup on disconnect */
+ usb_disconnect(udc);
+ }
+
+ }
+#endif
+
+ return ret_val;
+}
+
+/**
+ * Interrupt Service Routine, see Linux Kernel Doc for parameters
+ *
+ * \param irq irq number
+ * \param pdev pointer to device object
+ * \param ptregs don't used
+ */
+static irqreturn_t udc_irq (int irq, void *pdev, struct pt_regs * ptregs)
+{
+ struct udc *dev = pdev;
+ u32 reg;
+ u16 i;
+ u32 ep_irq;
+
+
+#ifdef UDC_IPBUG_3943_WORKAROUND
+ /* If UDC is suspended, then don't touch any register, otherwise
+ system hangs in endless retry => possibly hang !!! */
+ if (dev->otg_driver && dev->otg_driver->query) {
+ if (dev->otg_driver->query(0) & OTG_FLAGS_UDC_SUSP) {
+ return IRQ_HANDLED;
+ }
+ }
+ else
+ return IRQ_HANDLED;
+#endif
+
+ if (dev->sys_suspended)
+ return IRQ_HANDLED;
+
+ spin_lock (&dev->lock);
+
+
+ /* check for ep irq */
+ reg = readl(&dev->regs->ep_irqsts);
+ if (reg)
+ {
+ /* EP0 OUT */
+ if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+ {
+ udc_control_out_isr(dev);
+ } /* EP0 IN */
+ if (reg & AMD_BIT(UDC_EPINT_IN_EP0)) {
+ udc_control_in_isr(dev);
+
+ }
+
+ /* data endpoint */
+ /* iterate ep's */
+ for (i = 1; i < UDC_EP_NUM; i++) {
+ ep_irq = 1 << i;
+ /* irq for out ep ? */
+ if ((reg & ep_irq) && i > UDC_EPIN_NUM) {
+ /* clear irq */
+ writel(ep_irq, &dev->regs->ep_irqsts);
+ udc_data_out_isr(dev,i);
+ } /* irq for in ep ? */
+ if ((reg & ep_irq) && i < UDC_EPIN_NUM && i > 0) {
+ /* clear irq */
+ writel(ep_irq, &dev->regs->ep_irqsts);
+ udc_data_in_isr(dev,i);
+ }
+
+ }
+
+ }
+
+
+ /* check for dev irq */
+ reg = readl(&dev->regs->irqsts);
+ if (reg) {
+ /* clear irq */
+ writel(reg, &dev->regs->irqsts);
+ udc_dev_isr(dev, reg);
+ }
+
+
+ spin_unlock (&dev->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * Tears down device
+ *
+ * \param pdev pointer to device struct
+ */
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+static void gadget_release (struct device *pdev)
+{
+ struct amd5536udc *dev = dev_get_drvdata(pdev);
+ kfree (dev);
+}
+#endif
+
+/**
+ * Reset all pci context
+ *
+ * \param pdev pointer to pci device struct
+ */
+static void udc_remove (struct pci_dev *pdev)
+{
+ struct udc *dev;
+
+#ifdef UDC_DEBUG
+ /* debug */
+ print_misc(udc);
+#endif
+ dev = pci_get_drvdata(pdev);
+ /* gadget driver registered ? */
+ if (dev->driver) {
+ WARN( "unregistering %s on pci remove\n", dev->driver->driver.name);
+ usb_gadget_unregister_driver (dev->driver);
+ }
+ /* otg driver registered ? */
+ if (dev->otg_transceiver) {
+ /* should have been done already by driver model core */
+ WARN( "uoc driver is still registered\n");
+ }
+ /* dma pool cleanup */
+ if (dev->data_requests) {
+ pci_pool_destroy (dev->data_requests);
+ }
+ if (dev->stp_requests) {
+ /* cleanup DMA desc's for ep0in */
+ pci_pool_free (dev->stp_requests,
+ dev->ep [UDC_EP0OUT_IX].td_stp,
+ dev->ep [UDC_EP0OUT_IX].td_stp_dma);
+ pci_pool_free (dev->stp_requests,
+ dev->ep [UDC_EP0OUT_IX].td,
+ dev->ep [UDC_EP0OUT_IX].td_phys);
+
+ pci_pool_destroy (dev->stp_requests);
+ }
+
+ /* init controller by soft reset */
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ if (dev->irq_registered)
+ free_irq (pdev->irq, dev);
+ if (dev->regs)
+ iounmap (dev->regs);
+ if (dev->mem_region)
+ release_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+ if (dev->active)
+ pci_disable_device (pdev);
+#endif
+
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifndef CONFIG_MIPS
+ /* FIXME TMP26: temporary disabled device file system usage until
+ * working for Au1200 */
+ //device_unregister (&dev->gadget.dev);
+ //device_remove_file (&pdev->dev, &dev_attr_registers);
+#endif
+#endif
+ pci_set_drvdata (pdev,0);
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+ {
+ u32 tmp;
+ /* disable UDC memory, DMA and clock */
+ tmp = readl((u32*) (USB_MSR_BASE + USB_MSR_MCFG));
+ tmp &= AMD_CLEAR_BIT(USBMSRMCFG_DMEMEN)
+ & AMD_CLEAR_BIT(USBMSRMCFG_DBMEN)
+ & AMD_CLEAR_BIT(USBMSRMCFG_UDCCLKEN);
+ writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+ }
+#endif
+
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL || defined(CONFIG_MIPS)
+ /* done by gadget.dev.release() in kernel 2.6.x
+ * TMP26: device registration currently disabled for Au1200 */
+ kfree (dev);
+#endif
+#ifdef UDC_USE_TIMER
+ /* remove timer */
+ stop_timer++;
+ if (timer_pending(&udc_timer))
+ wait_for_completion(&on_exit);
+ if (udc_timer.data)
+ del_timer_sync(&udc_timer);
+ /* remove pollstall timer */
+ stop_pollstall_timer++;
+ if (timer_pending(&udc_pollstall_timer))
+ wait_for_completion(&on_pollstall_exit);
+ if (udc_pollstall_timer.data)
+ del_timer_sync(&udc_pollstall_timer);
+#endif
+ udc = 0;
+}
+
+/**
+ * Called by pci bus driver to init pci context
+ *
+ * \param pdev pointer to pci device struct
+ * \param id pointer to pci device id
+ * \return 0 if success
+ */
+static int udc_probe (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct udc *dev;
+ char tmp[8];
+ char *tmpstr;
+ unsigned long resource;
+ unsigned long len;
+ void *start_addr = 0;
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td_data;
+ u32 reg;
+ int retval;
+
+ VDBG("udc_probe()\n");
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+ {
+ u32 tmp;
+ /*
+ * Fill in the dummy pci_dev
+ */
+ memset(pdev, 0, sizeof(struct pci_dev));
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+ strcpy(pdev->name, "non-PCI UDC");
+#endif
+ pdev->resource[0].name = "UDC Registers";
+ pdev->resource[0].start = USB_UDC_BASE;
+ pdev->resource[0].end = USB_UDC_BASE + USB_UDC_LEN - 1;
+ pdev->resource[0].flags = 0;
+ pdev->irq = AU1200_USB_INT;
+
+ tmp = readl((u32*) (USB_MSR_BASE + USB_MSR_MCFG));
+ if (tmp == 0) {
+ /* default value */
+ tmp = USBMSRMCFG_DEFAULT;
+ writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+ readl((u32*) USB_MSR_BASE + USB_MSR_MCFG);
+ udelay(1000);
+ }
+ /* enable UDC memory, DMA, clock, cacheable memory,
+ * read combining and prefetch enable */
+ tmp |= AMD_BIT(USBMSRMCFG_DMEMEN) | AMD_BIT(USBMSRMCFG_DBMEN)
+ | AMD_BIT(USBMSRMCFG_UDCCLKEN)
+ | AMD_BIT(USBMSRMCFG_PHYPLLEN)
+#ifdef CONFIG_DMA_COHERENT
+ | AMD_BIT(USBMSRMCFG_UCAM)
+#endif
+ | AMD_BIT(USBMSRMCFG_RDCOMB)
+ | AMD_BIT(USBMSRMCFG_PFEN);
+ writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+ }
+#endif
+ /* one udc only */
+ if (udc) {
+ WARN("already probed: %04x/%04x\n", UDC_PCI_VENID, UDC_PCI_DEVID);
+ return -EBUSY;
+ }
+
+ /* init */
+ dev = kmalloc (sizeof (struct udc), SLAB_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* mark timer as not initialized */
+ udc_timer.data = 0;
+ udc_pollstall_timer.data = 0;
+
+ /* device struct setup */
+ memset (dev, 0, sizeof(struct udc));
+ spin_lock_init(&dev->lock);
+ spin_lock_init(&udc_irq_spinlock);
+ spin_lock_init(&udc_stall_spinlock);
+ dev->pdev = pdev;
+ dev->gadget.ops = &udc_ops;
+
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ strcpy(dev->gadget.dev.bus_id, "gadget");
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = name;
+#else
+ dev->gadget.dev.bus_id = "gadget";
+#endif
+ dev->gadget.name = name;
+ dev->gadget.is_dualspeed = 1;
+
+ /* pci setup */
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+ if (pci_enable_device (pdev) < 0) {
+ retval = -ENODEV;
+ goto finished;
+ }
+#endif
+ dev->active = 1;
+
+ resource = pci_resource_start(pdev, 0);
+ len = pci_resource_len (pdev, 0);
+
+ if (!request_mem_region (resource, len, name)) {
+ DBG( "pci device used already\n");
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->mem_region = 1;
+
+ start_addr = ioremap_nocache(resource, len);
+ if (start_addr == NULL) {
+ DBG( "start address cannot be mapped\n");
+ retval = -EFAULT;
+ goto finished;
+ }
+
+ /* udc csr registers base */
+ dev->csr = (struct udc_csrs*) (start_addr + UDC_CSR_ADDR);
+ /* dev registers base */
+ dev->regs = (struct udc_regs *) (start_addr + UDC_DEVCFG_ADDR);
+ /* ep registers base */
+ dev->ep_regs = (struct udc_ep_regs *) (start_addr + UDC_EPREGS_ADDR);
+ /* fifo's base */
+ dev->rxfifo = (u32*) (start_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32*) (start_addr + UDC_TXFIFO_ADDR);
+
+ /* init registers, interrupts, ... */
+#ifndef UDC_IPBUG_3943_WORKAROUND
+ startup_registers(dev);
+#else
+ {
+ u32 tmp;
+
+ /* TODO put this to extra function,
+ * this all is extracted from usb_init() and
+ * udc_basic_init() but without register access */
+ dev->gadget.ep0 = &dev->ep [UDC_EP0IN_IX].ep;
+ dev->ep [UDC_EP0IN_IX].halted = 0;
+ INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+ dev->gadget.speed = USB_SPEED_HIGH;
+ make_ep_lists(dev);
+ /* basic endpoint init */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ struct udc_ep *ep = &dev->ep[tmp];
+
+ ep->ep.name = ep_string[tmp];
+ ep->dev = dev;
+ ep->num = tmp;
+ /* txfifo size is calculated at enable time */
+ ep->txfifo = dev->txfifo;
+
+ /* fifo size */
+ if (tmp < UDC_EPIN_NUM) {
+ ep->fifo_depth = UDC_TXFIFO_SIZE;
+ ep->in = 1;
+ }
+ else {
+ ep->fifo_depth = UDC_RXFIFO_SIZE;
+ ep->in = 0;
+
+ }
+
+ ep->regs = &dev->ep_regs [tmp];
+ if (!ep->desc) {
+ ep->desc = 0;
+ INIT_LIST_HEAD (&ep->queue);
+
+ ep->ep.maxpacket = ~0;
+ ep->ep.ops = &udc_ep_ops;
+ }
+ if (use_dma) {
+ /* TODO ep->dma is not really used, just to indicate that */
+ /* DMA is active: remove this */
+ /* dma regs = dev control regs */
+ ep->dma = (u32*) &dev->regs->ctl;
+ }
+ }
+ dev->ep [UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep [UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+ }
+#endif
+
+ if (!pdev->irq) {
+ ERR( "pdev->irq not set\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+
+ snprintf (tmp, sizeof tmp, "%d", pdev->irq);
+ tmpstr = tmp;
+
+ if (request_irq (pdev->irq, udc_irq, SA_SHIRQ, name, dev) != 0) {
+ ERR( "error on request_irq() with %s\n", tmpstr);
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->irq_registered = 1;
+
+ if (use_dma) {
+ /* consistent DMA mode setting ? */
+ if (use_dma_ppb) {
+ use_dma_bufferfill_mode = 0;
+ }
+ else {
+ use_dma_ppb_du = 0;
+ use_dma_bufferfill_mode = 1;
+ }
+ /* DMA setup */
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ dev->data_requests = pci_pool_create ("data_requests", pdev,
+ sizeof (struct udc_data_dma),
+ UDC_PCIPOOL_ALIGN,
+ UDC_PCIPOOL_CROSS);
+#else
+ dev->data_requests = pci_pool_create ("data_requests", pdev,
+ sizeof (struct udc_data_dma),
+ UDC_PCIPOOL_ALIGN,
+ UDC_PCIPOOL_CROSS,
+ SLAB_KERNEL /* 2.4 only */ );
+#endif
+ if (!dev->data_requests) {
+ DBG( "can't get request data pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* EP0 in dma regs = dev control regs */
+ dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+ /* dma desc for setup data */
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+ dev->stp_requests = pci_pool_create ("setup requests", pdev,
+ sizeof (struct udc_stp_dma),
+ UDC_PCIPOOL_ALIGN,
+ UDC_PCIPOOL_CROSS);
+#else
+ dev->stp_requests = pci_pool_create ("setup requests", pdev,
+ sizeof (struct udc_stp_dma),
+ UDC_PCIPOOL_ALIGN,
+ UDC_PCIPOOL_CROSS,
+ SLAB_KERNEL /* 2.4 only */ );
+#endif
+ if (!dev->stp_requests) {
+ DBG( "can't get stp request pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+ /* setup */
+ td_stp = pci_pool_alloc (dev->stp_requests, UDC_PCIPOOL_GFP_STP,
+ &dev->ep [UDC_EP0OUT_IX].td_stp_dma);
+ if (td_stp == NULL){
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep [UDC_EP0OUT_IX].td_stp = td_stp;
+ /* data: 0 packets !? */
+ td_data = pci_pool_alloc (dev->stp_requests, UDC_PCIPOOL_GFP_STP,
+ &dev->ep [UDC_EP0OUT_IX].td_phys);
+ if (td_data == NULL){
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep [UDC_EP0OUT_IX].td = td_data;
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ /* point to itself */
+ dev->ep [UDC_EP0OUT_IX].td->next = dev->ep [UDC_EP0OUT_IX].td_phys;
+#endif
+ }
+
+ dev->chiprev = 0;
+
+#ifndef CONFIG_USB_NON_PCI_OTGDEVICE
+ pci_set_master (pdev);
+#ifdef HAVE_PCI_SET_MWI
+ pci_set_mwi (pdev);
+#endif
+ /* chip rev for Hs AMD5536 */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, (u8*) &dev->chiprev);
+#else
+ /* chip rev for Au1200 */
+ dev->chiprev = (u16) read_c0_prid() & 0xff;
+#endif
+
+ pci_set_drvdata (pdev, dev);
+
+ INFO( "%s\n", mod_desc);
+
+ /* TODO make defines for rev. strings */
+#ifdef CONFIG_SOC_AU1200
+ INFO( "irq %s, mem %08lx, chip rev %02x (Au1200 %s)\n",
+ tmpstr, resource, dev->chiprev, (dev->chiprev == 0) ? "AB" : "AC");
+ tmpstr = UDC_DRIVER_VERSION_STRING;
+#ifdef CONFIG_DMA_COHERENT
+ /* coherent DMA not possible with AB silicon */
+ if (dev->chiprev == UDC_AUAB_REV) {
+ ERR("Your chip revision is %s, it must be at least %s to use coherent DMA. \nPlease change DMA_COHERENT to DMA_NONCOHERENT in arch/mips/Kconfig and re-compile .\n",
+ "AB", "AC");
+ retval = -ENODEV;
+ goto finished;
+ }
+#endif
+
+#ifdef UDC_AUA1
+ if (dev->chiprev < UDC_AUA1) {
+ ERR("Your chip revision is %s, it must be at least %s\n",
+ "AB", "AC");
+ retval = -ENODEV;
+ goto finished;
+ }
+ INFO("driver version: %s (for Au1200 AC)\n", tmpstr);
+#else
+ INFO("driver version: %s (for Au1200 AB)\n", tmpstr);
+#endif
+#ifdef CONFIG_DMA_COHERENT
+ INFO("Compiled for coherent memory.\n");
+#endif
+#ifdef CONFIG_DMA_NONCOHERENT
+ INFO("Compiled for non-coherent memory.\n");
+#endif
+#else
+ INFO("irq %s, pci mem %08lx, chip rev %02x (Geode5536 %s)\n",
+ tmpstr, resource, dev->chiprev, (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+ tmpstr = UDC_DRIVER_VERSION_STRING;
+#ifdef UDC_HSB1
+ if (dev->chiprev == UDC_HSA0_REV) {
+ ERR("Your chip revision is %s, it must be at least %s\n",
+ "A0", "B1");
+ retval = -ENODEV;
+ goto finished;
+ }
+ INFO("driver version: %s (for Geode5536 B1)\n", tmpstr);
+#else
+ INFO("driver version: %s (for Geode5536 A0)\n", tmpstr);
+#endif
+#endif
+ udc = dev;
+
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#ifndef CONFIG_MIPS
+ /* FIXME TMP26: temporary disabled device file system usage until
+ * working for Au1200 */
+ //device_register (&dev->gadget.dev);
+ //device_create_file (&pdev->dev, &dev_attr_registers);
+#endif
+#endif
+
+#ifdef UDC_USE_TIMER
+ /* timer init */
+ init_timer(&udc_timer);
+ udc_timer.function = udc_timer_function;
+ udc_timer.data = 1;
+ /* timer pollstall init */
+ init_timer(&udc_pollstall_timer);
+ udc_pollstall_timer.function = udc_pollstall_timer_function;
+ udc_pollstall_timer.data = 1;
+#endif
+
+ /* set SD */
+ reg = readl(&dev->regs->ctl);
+ reg |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(reg, &dev->regs->ctl);
+
+ /* print dev register info */
+ print_regs(dev);
+
+ return 0;
+
+finished:
+ if (dev)
+ udc_remove (pdev);
+ return retval;
+}
+
+
+/**
+ * Initiates a remote wakeup
+ *
+ * \return 0 if success
+ */
+/* initiate remote wakeup */
+static int udc_remote_wakeup(struct udc* dev)
+{
+ u32 tmp;
+
+ INFO("UDC initiates remote wakeup\n");
+
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+ /* wait 1ms before clear resume bit */
+ // udelay(1000);
+ tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+
+ return 0;
+}
+
+/* PM currently under debug */
+#ifdef UDC_DEBUG
+/**
+ * Suspends UDC
+ *
+ * \return 0 if success
+ */
+static int udc_suspend(struct udc* dev)
+{
+ int retval = 0;
+
+ INFO("UDC suspend\n");
+#ifdef CONFIG_MIPS
+ u32 tmp;
+ /* mask interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ if (dev->driver && dev->driver->disconnect) {
+ /* call gadget to reset context */
+ if (spin_is_locked(&dev->lock)) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect (&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ else
+ dev->driver->disconnect (&dev->gadget);
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue (&dev->ep [UDC_EP0IN_IX]);
+ ep_init (dev->regs,
+ &dev->ep [UDC_EP0IN_IX]);
+
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+
+ }
+ if (dev->otg_driver && dev->otg_transceiver
+ && dev->otg_transceiver->set_peripheral) {
+ /* if UDC is supended by Host or already disconnected then
+ don't force disconnect by unbind() */
+ if (dev->otg_driver->query) {
+ if (!(dev->otg_driver->query(0) & OTG_FLAGS_UDC_SUSP)) {
+ /* unbind from otg driver -> host disconnect */
+ dev->otg_transceiver->set_peripheral(dev->otg_transceiver, NULL);
+ dev->connected = 0;
+ }
+ }
+ else
+ {
+ /* unbind from otg driver -> host disconnect */
+ dev->otg_transceiver->set_peripheral (dev->otg_transceiver, NULL);
+ dev->connected = 0;
+ }
+ }
+
+ dev->sys_suspended = 1;
+
+ /* switch off UDC clock */
+ tmp = readl((u32*) (USB_MSR_BASE + USB_MSR_MCFG));
+ tmp &= AMD_CLEAR_BIT(USBMSRMCFG_UDCCLKEN);
+ writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+
+#endif
+
+ return retval;
+}
+
+/**
+ * Resumes UDC
+ *
+ * \return 0 if success
+ */
+static int udc_resume(struct udc* dev)
+{
+ int retval = 0;
+
+ INFO("UDC resume\n");
+#ifdef CONFIG_MIPS
+ u32 tmp;
+ /* switch on UDC clock */
+ tmp = readl((u32*) (USB_MSR_BASE + USB_MSR_MCFG));
+ tmp |= AMD_BIT(USBMSRMCFG_UDCCLKEN);
+ writel(tmp, USB_MSR_BASE + USB_MSR_MCFG);
+
+ dev->sys_suspended = 0;
+
+ usb_connect(dev);
+ if (dev->otg_transceiver && dev->otg_transceiver->set_peripheral) {
+ /* bind to otg driver */
+ dev->otg_transceiver->set_peripheral(dev->otg_transceiver, dev);
+ }
+
+#endif
+
+ return retval;
+}
+#endif
+
+#ifdef UDC_USE_DRIVER_REGISTER
+/* TODO we provide device_driver functions to attach
+ * to device system which allows power management and
+ * more. Currently we just call the PCI probe function.
+ * So later pci_dev dummy is to be removed */
+
+static int udc_au1xxx_drv_probe(struct device *dev)
+{
+ int retval;
+
+ DBG("udc_au1xxx_drv_probe()\n");
+ retval = udc_probe(pdev, pci_id);
+ if (retval == 0)
+ dev_set_drvdata(dev, (struct udc*) pci_get_drvdata(pdev));
+ return retval;
+}
+
+static int udc_au1xxx_drv_remove(struct device *dev)
+{
+ DBG("udc_au1xxx_drv_remove()\n");
+ udc_remove(pdev);
+ dev_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static int udc_au1xxx_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+ struct udc *udc_dev = dev_get_drvdata(dev);
+ return udc_suspend(udc_dev);
+}
+
+static int udc_au1xxx_drv_resume(struct device *dev, u32 level)
+{
+ struct udc *udc_dev = dev_get_drvdata(dev);
+ return udc_resume(udc_dev);
+}
+
+static struct device_driver udc_au1xxx_driver = {
+ .name = "au1xxx-udc",
+ .bus = &platform_bus_type,
+ .probe = udc_au1xxx_drv_probe,
+ .remove = udc_au1xxx_drv_remove,
+ .suspend = udc_au1xxx_drv_suspend,
+ .resume = udc_au1xxx_drv_resume,
+};
+#endif
+
+
+/**
+ * Inits driver
+ *
+ * \return 0 if success
+ */
+static int __init init(void)
+{
+ int rc;
+
+#ifdef UDC_DEBUG
+ /* register char device */
+ rc = register_chrdev(UDC_MAJOR_NUM, UDC_DEVICE_NAME, &udc_fops);
+ if (rc < 0)
+ {
+ printk("Error registering udc char device");
+ }
+#endif
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL && defined(UDC_USE_DRIVER_REGISTER)
+
+ /* probe by device system */
+ rc = driver_register(&udc_au1xxx_driver);
+#else
+ /* manual probe */
+ rc = udc_probe(pdev, pci_id);
+#endif
+#else
+ /* probe by PCI bus driver */
+ rc = pci_module_init (&udc_pci_driver);
+#endif
+
+ return rc;
+}
+module_init (init);
+
+/**
+ * Cleans driver
+ */
+static void __exit cleanup(void)
+{
+#ifdef UDC_DEBUG
+ /* unregister char device */
+ unregister_chrdev(UDC_MAJOR_NUM, UDC_DEVICE_NAME);
+#endif
+
+#ifdef CONFIG_USB_NON_PCI_OTGDEVICE
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL && defined(UDC_USE_DRIVER_REGISTER)
+ /* unregister at device system */
+ driver_unregister(&udc_au1xxx_driver);
+#else
+ /* manual remove */
+ udc_remove(pdev);
+#endif
+#else
+ /* unregister at PCI bus driver */
+ pci_unregister_driver (&udc_pci_driver);
+#endif
+
+}
+module_exit (cleanup);
+
Index: linux-2.6.11/drivers/usb/gadget/amd5536udc.h
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,989 @@
+/*
+ * Header for driver for AMD 5536 UDC high/full speed USB device controller
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/*****************************************************************************
+* Constants
+*****************************************************************************/
+
+/* Driver constants -------------------------------------------------------*/
+#define DRIVER_NAME_FOR_PRINT "amd5536udc"
+
+/* PCI constants -----------------------------------------------------------*/
+#define UDC_PCI_VENID 0x1022
+#define UDC_PCI_DEVID 0x2096
+#define UDC_PCI_CLASS ((PCI_CLASS_SERIAL_USB << 8) | 0xfe)
+#define UDC_PCI_CLASS_MASK 0xffffffff
+
+/* Platform specific -------------------------------------------------------*/
+#if defined(CONFIG_MIPS)
+#define UDC_PCIPOOL_ALIGN 32
+#define UDC_PCIPOOL_CROSS 4096
+#define UDC_PCIPOOL_GFP_STP (GFP_ATOMIC | GFP_DMA)
+#else
+#define UDC_PCIPOOL_ALIGN 0
+#define UDC_PCIPOOL_CROSS 0
+#define UDC_PCIPOOL_GFP_STP (GFP_KERNEL)
+#endif
+
+/* temp define for AU1200, will live in au1000.h normally */
+#ifndef USB_UDC_BASE
+#define USB_UDC_BASE 0x14022000
+#define USB_UDC_LEN 0x2000
+#define USB_MSR_BASE 0xB4020000
+#define USB_MSR_MCFG 4
+#define USBMSRMCFG_DMEMEN 4
+#define USBMSRMCFG_DBMEN 5
+#define USBMSRMCFG_UDCCLKEN 18
+#define USBMSRMCFG_PHYPLLEN 19
+#define AU1200_USB_INT 29
+#endif
+#ifndef USBMSRMCFG_UCAM
+#define USBMSRMCFG_UCAM 7
+#endif
+#define USBMSRMCFG_DEFAULT 0x00d02000
+
+/* other constants */
+#define UDC_RDE_TIMER_SECONDS 1
+#define UDC_RDE_TIMER_DIV 10
+#define UDC_POLLSTALL_TIMER_USECONDS 500
+
+/* Special optimization for certain gadgets ------------------------------- */
+/* use hardware NAK if IN queue empty, this can be used to
+* avoid interrupt flood as for the ethernet gadget where host side
+* sends IN tokens permamently */
+#define UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE
+/*#undef UDC_DISABLE_IRQ_IF_EMPTY_IN_QUEUE*/
+
+/* IP core defect/bug/case workarounds ---------------------------------------- */
+/* Hs AMD5536 A0 workarounds */
+/* Description: "Last descriptor loop */
+#define UDC_IPDEFECT_9000004946_WORKAROUND
+/* Description: "DMA machine not restartable" */
+#define UDC_IPCASE_8000018724_WORKAROUND
+/* Description: "UDC not accessible when phy is suspended */
+#define UDC_IPBUG_3943_WORKAROUND
+/* Description: "USB device needs session-valid status information */
+#define UDC_IPBUG_3950_WORKAROUND
+/* Description: "Clearing endpoint NAK bits not possible if RxFIFO
+ not empty (PCS#1503) */
+#define UDC_IPBUG_3958_WORKAROUND
+#ifdef UDC_IPBUG_3958_WORKAROUND
+/* option 1: flush rxfifo on USB reset */
+#undef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH_ON_USBRESET
+/* option 2: soft reset on USB reset */
+#ifndef UDC_IPBUG_3958_WORKAROUND_RXFIFO_FLUSH_ON_USBRESET
+#define UDC_IPBUG_3958_WORKAROUND_SOFT_RESET_ON_USBRESET
+#endif
+#endif
+/* UDC data errors during loop test (DMA)
+ - found only with Au1200 but used for Hs too, bug entry
+ is in Au1200 bugzilla
+ - the workaround applies only for small packets */
+#define UDC_IPBUG_2253_WORKAROUND
+#define UDC_SMALL_PACKET 32
+
+/* Disable workarounds which don't apply to Hs AMD5536 B1/ Au1200 A1 */
+/* And enable new features */
+
+/* Hs AMD5536 A0 flag */
+/* #define UDC_HSA0 */
+/* Hs AMD5536 B1 flag */
+#define UDC_HSB1
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/* consistency */
+#ifdef UDC_HSB1
+#undef UDC_HSA0
+#endif
+
+/* Au1200 rev. */
+#if defined(CONFIG_MIPS)
+#undef UDC_HSB1
+#undef UDC_HSA0
+/* revision value */
+#define UDC_AUAB_REV 0
+#define UDC_AUAC_REV 1
+#define UDC_AUA0 0
+/* Au1200 AC flag */
+//#define UDC_AUA1 1
+#endif
+
+/* disable workarounds for newer chip revisions */
+#ifdef UDC_HSB1
+#undef UDC_IPBUG_3943_WORKAROUND
+#undef UDC_IPBUG_3950_WORKAROUND
+#define UDC_DMARST_AVAIL
+#endif
+#ifdef UDC_AUA1
+#undef UDC_IPBUG_3943_WORKAROUND
+#endif
+
+/* SETUP usb commands
+* needed, because some SETUP's are handled in hw, but must be passed to
+* gadget driver above -----------------------------------------------------*/
+/* SET_CONFIG */
+#define UDC_SETCONFIG_DWORD0 0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16
+
+#define UDC_SETCONFIG_DWORD1 0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0 0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS 16
+
+#define UDC_SETINTF_DWORD1 0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS 0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0 0x0000ff21
+#define UDC_MSCRES_DWORD1 0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+/* UDC CSR's */
+#define UDC_CSR_ADDR 0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_NUM_OFS 0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_DIR_OFS 4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_TYPE_OFS 5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_CFG_OFS 7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_INTF_OFS 11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_ALT_OFS 15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR 0x400
+
+#define UDC_DEVCFG_SOFTRESET 31
+#define UDC_DEVCFG_HNPSFEN 30
+#define UDC_DEVCFG_DMARST 29
+#define UDC_DEVCFG_SET_DESC 18
+#define UDC_DEVCFG_CSR_PRG 17
+#define UDC_DEVCFG_STATUS 7
+#define UDC_DEVCFG_DIR 6
+#define UDC_DEVCFG_PI 5
+#define UDC_DEVCFG_SS 4
+#define UDC_DEVCFG_SP 3
+#define UDC_DEVCFG_RWKP 2
+
+#define UDC_DEVCFG_SPD_MASK 0x3
+#define UDC_DEVCFG_SPD_OFS 0
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+/*#define UDC_DEVCFG_SPD_FS 0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR 0x404
+
+#define UDC_DEVCTL_THLEN_MASK 0xff000000
+#define UDC_DEVCTL_THLEN_OFS 24
+
+#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS 16
+
+#define UDC_DEVCTL_CSR_DONE 13
+#define UDC_DEVCTL_DEVNAK 12
+#define UDC_DEVCTL_SD 10
+#define UDC_DEVCTL_MODE 9
+#define UDC_DEVCTL_BREN 8
+#define UDC_DEVCTL_THE 7
+#define UDC_DEVCTL_BF 6
+#define UDC_DEVCTL_BE 5
+#define UDC_DEVCTL_DU 4
+#define UDC_DEVCTL_TDE 3
+#define UDC_DEVCTL_RDE 2
+#define UDC_DEVCTL_RES 0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR 0x408
+
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_TS_OFS 18
+
+#define UDC_DEVSTS_SESSVLD 17
+#define UDC_DEVSTS_PHY_ERROR 16
+#define UDC_DEVSTS_RXFIFO_EMPTY 15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS 13
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+
+#define UDC_DEVSTS_SUSP 12
+
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_ALT_OFS 8
+
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_INTF_OFS 4
+
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+#define UDC_DEVSTS_CFG_OFS 0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR 0x40c
+
+#define UDC_DEVINT_SVC 7
+#define UDC_DEVINT_ENUM 6
+#define UDC_DEVINT_SOF 5
+#define UDC_DEVINT_US 4
+#define UDC_DEVINT_UR 3
+#define UDC_DEVINT_ES 2
+#define UDC_DEVINT_SI 1
+#define UDC_DEVINT_SC 0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR 0x410
+
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR 0x414
+
+#define UDC_EPINT_OUT_MASK 0xffff0000
+#define UDC_EPINT_OUT_OFS 16
+#define UDC_EPINT_IN_MASK 0x0000ffff
+#define UDC_EPINT_IN_OFS 0
+
+#define UDC_EPINT_IN_EP0 0
+#define UDC_EPINT_IN_EP1 1
+#define UDC_EPINT_IN_EP2 2
+#define UDC_EPINT_IN_EP3 3
+#define UDC_EPINT_OUT_EP0 16
+#define UDC_EPINT_OUT_EP1 17
+#define UDC_EPINT_OUT_EP2 18
+#define UDC_EPINT_OUT_EP3 19
+
+#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR 0x418
+
+#define UDC_EPINT_OUT_MSK_MASK 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS 16
+#define UDC_EPINT_IN_MSK_MASK 0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS 0
+
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE 0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+/* Endpoint Control Registers -----------------------------------------------*/
+#define UDC_EPREGS_ADDR 0x0
+#define UDC_EPIN_REGS_ADDR 0x0
+#define UDC_EPOUT_REGS_ADDR 0x200
+
+#define UDC_EPCTL_ADDR 0x0
+
+#define UDC_EPCTL_RRDY 9
+#define UDC_EPCTL_CNAK 8
+#define UDC_EPCTL_SNAK 7
+#define UDC_EPCTL_NAK 6
+
+#define UDC_EPCTL_ET_MASK 0x00000030
+#define UDC_EPCTL_ET_OFS 4
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+#define UDC_EPCTL_P 3
+#define UDC_EPCTL_SN 2
+#define UDC_EPCTL_F 1
+#define UDC_EPCTL_S 0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR 0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS 11
+
+#define UDC_EPSTS_TDC 10
+#define UDC_EPSTS_HE 9
+#define UDC_EPSTS_BNA 7
+#define UDC_EPSTS_IN 6
+
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_OUT_OFS 4
+#define UDC_EPSTS_OUT_DATA 1
+#define UDC_EPSTS_OUT_DATA_CLEAR 0x10
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR 0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE 32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT 2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE 256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE 32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE 32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS 0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS 16
+#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS 0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE 64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64
+
+/* Endpoint dma descriptors ------------------------------------------------*/
+/* Setup data */
+/* Status dword */
+#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS 16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS 16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS 20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS 24
+#define UDC_DMA_STP_STS_RX_MASK 0x30000000
+#define UDC_DMA_STP_STS_RX_OFS 28
+#define UDC_DMA_STP_STS_BS_MASK 0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS 30
+#define UDC_DMA_STP_STS_BS_HOST_READY 0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY 1
+#define UDC_DMA_STP_STS_BS_DMA_DONE 2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY 3
+/* IN data */
+/* Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS 0
+#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS 0
+#define UDC_DMA_IN_STS_L 27
+#define UDC_DMA_IN_STS_TX_MASK 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS 28
+#define UDC_DMA_IN_STS_BS_MASK 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS 30
+#define UDC_DMA_IN_STS_BS_HOST_READY 0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY 1
+#define UDC_DMA_IN_STS_BS_DMA_DONE 2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY 3
+/* OUT data */
+/* Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS 0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0
+#define UDC_DMA_OUT_STS_L 27
+#define UDC_DMA_OUT_STS_RX_MASK 0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS 28
+#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY 0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE 2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3
+/* other constants */
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET 1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET 65536
+/* DMA buffer len for temp request, should be the same as the upper
+layer gadget is using => TODO replace follwing constant */
+#define UDC_DMA_TEMP_BUFFER_LEN 4096
+/* un-usable DMA address */
+#define DMA_DONT_USE (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR 0x10
+#define UDC_EP_DESPTR_ADDR 0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM 32
+#define UDC_EPIN_NUM 16
+#define UDC_EPIN_NUM_USED 5
+#define UDC_EPOUT_NUM 16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM 9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS 12
+
+#define UDC_EP0OUT_IX 16
+#define UDC_EP0IN_IX 0
+
+/* max packet */
+#define UDC_HS_BULK_MAXPKT 512
+//DISABLEDamd #define UDC_EP0_MAXPKT 64
+/* max packet fullspeed */
+//DISABLEDamd #define UDC_FS_EP0_MAXPKT 8
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR 0x800
+#define UDC_RXFIFO_SIZE 0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR 0xc00
+#define UDC_TXFIFO_SIZE 0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX 1
+#define UDC_EPIN_IX 2
+#define UDC_EPOUT_IX 18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES 4
+#define UDC_BITS_PER_BYTE_SHIFT 3
+#define UDC_BYTE_MASK 0xff
+#define UDC_BITS_PER_BYTE 8
+
+/* char device constants ---------------------------------------------------*/
+/* names */
+#ifdef UDC_DEBUG
+#ifdef UDC_DRIVER_NAME
+#define UDC_DEVICE_NAME UDC_DRIVER_NAME
+#else
+#define UDC_DEVICE_NAME "amd5536udc"
+#endif
+#define UDC_DEVICE_FILE_NAME "amd5536udc_dev"
+#define UDC_DEVICE_FILE_INODE "/dev/amd5536udc_dev"
+/* major number */
+#define UDC_MAJOR_NUM 240
+#endif
+
+#ifdef __KERNEL__
+/* kernel wrappers */
+#define device_create_file(x,y) do {} while (0)
+#define device_remove_file device_create_file
+
+#ifndef WARN_ON
+#define WARN_ON(a) do {} while (0)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(cond)do {if (unlikely((cond) != 0)) BUG();} while(0)
+#endif
+
+#ifndef likely
+#define likely(a) (a)
+#define unlikely(a) (a)
+#endif
+
+#ifndef container_of
+#define container_of list_entry
+#endif
+
+#ifndef IRQ_NONE
+typedef void irqreturn_t;
+#define IRQ_HANDLED
+#define IRQ_NONE
+#define IRQ_RETVAL(a)
+#endif
+#endif
+
+/* MIPS specific -----------------------------------------------------------*/
+#if defined(CONFIG_MIPS)
+/* sync does it without refilling the pipe,
+ so read after write can bypass write */
+#define au1200_sync_delay() {\
+ asm(".set noreorder"); \
+ asm("b l1");\
+ asm("l1:");\
+ asm("sync");\
+ asm("nop");\
+ asm("nop");\
+ asm("nop");\
+ asm("nop");\
+ asm("b l2");\
+ asm("l2:");\
+ asm("nop");\
+ asm("nop");\
+ asm(".set reorder");\
+}
+
+//DISABLEDamd #define wb_flush() au1200_sync()
+#define wb_flush() __asm__ volatile ("sync")
+
+/* special write functions for MIPS (with write buffer flush) */
+#undef writel
+#undef writeb
+#if LINUX_VERSION_CODE < UDC_NEW_GADGET_KERNEL
+#define writel(d,a) {((*(volatile unsigned int *)(a))=(__ioswab32(d)));wb_flush();}
+#else
+#define writel(d,a) {((*(volatile unsigned int *)(a))=(d));wb_flush();}
+#endif
+#define writeb(d,a) {((*(volatile unsigned char *)(a))=(d));wb_flush();}
+
+/* dma pool alloc wrapper */
+#if LINUX_VERSION_CODE >= UDC_NEW_GADGET_KERNEL
+#undef pci_pool
+#undef pci_pool_create
+#undef pci_pool_destroy
+#undef pci_pool_alloc
+#undef pci_pool_free
+#define pci_pool dma_pool
+/* FIXME TMP26: use "struct device*" if device file system works */
+/* #define pci_pool_create(name, pdev, size, align, allocation) \
+ dma_pool_create(name, &pdev->dev, size, align, allocation) */
+#define pci_pool_create(name, pdev, size, align, allocation) \
+ dma_pool_create(name, NULL, size, align, allocation)
+#define pci_pool_destroy(pool) dma_pool_destroy(pool)
+#define pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle)
+#define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
+#endif
+#else
+#define wb_flush() {}
+#endif
+
+/*****************************************************************************
+* Includes
+*****************************************************************************/
+
+#if !defined(UDC_HSB1)
+#include "amd5536otg.h"
+#endif
+
+/*****************************************************************************
+* Types
+*****************************************************************************/
+
+/* UDC CSR's */
+struct udc_csrs {
+
+ /* sca - setup command address */
+ u32 sca;
+
+ /* ep ne's */
+ u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+ /* device configuration */
+ u32 cfg;
+
+ /* device control */
+ u32 ctl;
+
+ /* device status */
+ u32 sts;
+
+ /* device interrupt */
+ u32 irqsts;
+
+ /* device interrupt mask */
+ u32 irqmsk;
+
+ /* endpoint interrupt */
+ u32 ep_irqsts;
+
+ /* endpoint interrupt mask */
+ u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+ /* endpoint control */
+ u32 ctl;
+
+ /* endpoint status */
+ u32 sts;
+
+ /* endpoint buffer size in/ receive packet frame number out */
+ u32 bufin_framenum;
+
+ /* endpoint buffer size out/max packet size */
+ u32 bufout_maxpkt;
+
+ /* endpoint setup buffer pointer */
+ u32 subptr;
+
+ /* endpoint data descriptor pointer */
+ u32 desptr;
+
+ /* reserverd */
+ u32 reserved;
+
+ /* write/read confirmation */
+ u32 confirm;
+
+} __attribute__ ((packed));
+
+#ifdef __KERNEL__
+/* control data DMA desc */
+struct udc_stp_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* first setup word */
+ u32 data12;
+ /* second setup word */
+ u32 data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* buffer pointer */
+ u32 bufptr;
+ /* next descriptor pointer */
+ u32 next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+ /* embedded gadget ep */
+ struct usb_request req;
+
+ /* flags */
+ unsigned dma_going : 1,
+ dma_mapping : 1,
+ dma_done : 1;
+ /* phys. address */
+ dma_addr_t td_phys;
+ /* first dma desc. of chain */
+ struct udc_data_dma *td_data;
+ /* last dma desc. of chain */
+ struct udc_data_dma *td_data_last;
+#ifdef UDC_IPDEFECT_9000004946_WORKAROUND
+ /* next pointer of broken chain */
+ dma_addr_t td_data_last_next;
+#endif
+
+ struct list_head queue;
+
+ /* chain length */
+ unsigned chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+ struct usb_ep ep;
+ struct udc_ep_regs *regs;
+ u32 *txfifo;
+ u32* dma;
+ dma_addr_t td_phys;
+ dma_addr_t td_stp_dma;
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td;
+ /* temp request */
+ struct udc_request *req;
+ unsigned req_used;
+ unsigned req_completed;
+ /* NAK state */
+ unsigned naking;
+
+ struct udc *dev;
+
+ /* queue for requests */
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned halted;
+ unsigned num : 5,
+ fifo_depth : 14,
+ in : 1;
+};
+
+/* device struct */
+struct udc {
+ struct usb_gadget gadget;
+ spinlock_t lock;
+ /* all endpoints */
+ struct udc_ep ep[UDC_EP_NUM];
+ struct usb_gadget_driver *driver;
+ struct otg_transceiver *otg_transceiver;
+#if !defined(UDC_HSB1)
+ struct usb_otg_gadget_extension *otg_driver;
+#endif
+ /* operational flags */
+ unsigned active : 1,
+ stall_ep0in : 1,
+ waiting_zlp_ack_ep0in : 1,
+ set_cfg_not_acked : 1,
+ irq_registered : 1,
+ otg_supported : 1,
+ data_ep_enabled : 1,
+ data_ep_queued : 1,
+ mem_region : 1,
+ selfpowered : 1,
+ sys_suspended : 1,
+ connected;
+
+ u16 chiprev;
+
+ /* registers */
+ struct pci_dev *pdev;
+ struct udc_csrs *csr;
+ struct udc_regs *regs;
+ struct udc_ep_regs *ep_regs;
+ u32* rxfifo;
+ u32* txfifo;
+
+ /* DMA desc pools */
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+
+ /* states */
+ u16 cur_config;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+ u32 data[2];
+ struct usb_ctrlrequest request;
+};
+#endif /*__KERNEL__*/
+
+/*****************************************************************************
+* Macros
+*****************************************************************************/
+
+/***************************************
+* SET and GET bitfields in u32 values
+* via constants for mask/offset:
+* is the text between
+* UDC_ and _MASK|_OFS of appropiate
+* constant
+****************************************/
+/* set bitfield value in u32 u32Val */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name)\
+ (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK))))\
+ |(((bitfield_val) << ((u32) bitfield_stub_name##_OFS))\
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/* set bitfield value in zero-initialized u32 u32Val */
+/* => bitfield bits in u32Val are all zero */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name)\
+ ((u32Val)\
+ |(((bitfield_val) << ((u32) bitfield_stub_name##_OFS))\
+ &((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name)\
+ ((u32Val & ((u32) bitfield_stub_name##_MASK))\
+ >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* misc --------------------------------------------------------------------*/
+#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+/* UDC specific macros -----------------------------------------------------*/
+#ifdef UDC_DMARST_AVAIL
+#define UDC_DMARST(tmp, dev) \
+ DBG("DMA machine reset\n"); \
+ tmp = readl(&dev->regs->cfg); \
+ writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg); \
+ writel(tmp, &dev->regs->cfg);
+#else
+#define UDC_DMARST(tmp, dev) {}
+#endif
+
+/* print macros ------------------------------------------------------------*/
+
+#ifdef UDC_VERBOSE
+#ifndef UDC_DEBUG
+#define UDC_DEBUG
+#endif
+#endif
+
+/* Driver name for printing messages, this should be defined by driver */
+#ifndef DRIVER_NAME_FOR_PRINT
+//#define DRIVER_NAME_FOR_PRINT "amd5536"
+#endif
+
+/**
+ * \brief
+ * Macro for printing information in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code.
+ * It should be used for printing useful information about states and called
+ * functions for normal operation (not for errors and warnings).
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on )
+ * \return code from printk
+ */
+#define INFO(args...) \
+ printk(KERN_INFO DRIVER_NAME_FOR_PRINT ": " args)
+
+/**
+ * \brief
+ * Macro for printing warnings in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code.
+ * It should be used for printing warnings.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on )
+ * \return code from printk
+ */
+#define WARN(args...) \
+ printk(KERN_WARNING DRIVER_NAME_FOR_PRINT " warning: " args)
+
+/**
+ * \brief
+ * Macro for printing errors in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code.
+ * It should be used for printing errors.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on )
+ * \return code from printk
+ */
+#define ERR(args...) \
+ printk(KERN_ERR DRIVER_NAME_FOR_PRINT " error: " args)
+
+/**
+ * \brief
+ * Macro for printing debug messages in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code
+ * when UDC_DEBUG is defined
+ * It should be used for printing debug messages.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on )
+ * \return code from printk
+ */
+#ifdef UDC_DEBUG
+#define DBG(args...) \
+ printk(KERN_DEBUG DRIVER_NAME_FOR_PRINT " debug: " args)
+#else
+
+#define DBG(args...) \
+ do {} while (0)
+#endif
+
+/**
+ * \brief
+ * Macro for printing verbose debug messages in drivers
+ *
+ * This macro is used for printing kernel messages in driver source code
+ * when UDC_DEBUG and UDC_VERBOSE is defined
+ * It should be used for printing debug messages.
+ *
+ * \param fmt is format string for printk
+ * \param args... are arguments given to printk (number depends on )
+ * \return code from printk
+ */
+#ifdef UDC_VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(args...) \
+ do {} while (0)
+#endif
+
+/*****************************************************************************
+* Data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/*****************************************************************************
+* Functions
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/*****************************************************************************
+* Inline Functions
+*****************************************************************************/
+
+#endif /* #ifdef AMD5536UDC_H */
Index: linux-2.6.11/drivers/usb/gadget/amd5536uoc.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/usb/gadget/amd5536uoc.c
@@ -0,0 +1,454 @@
+/*
+ * AMD 5536 USB UOC controller driver
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Karsten Boge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*****************************************************************************
+ * Defines
+ *****************************************************************************/
+
+/* #define DEBUG */
+/* #define VERBOSE */
+
+#define DRIVER_DESC "AMD 5536 USB UOC Controller"
+#define DRIVER_VERSION "01.00.0204 - $Revision: #8 $"
+#define DRIVER_NAME_FOR_PRINT UOC_DRIVER_NAME
+
+/*****************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "amd5536uoc.h"
+
+
+/*****************************************************************************
+ * Function Declarations
+ *****************************************************************************/
+
+static int uoc5536_set_peripheral (struct otg_transceiver *,
+ struct usb_gadget *);
+
+
+/*****************************************************************************
+ * Data
+ *****************************************************************************/
+
+static const char driver_name [] = UOC_DRIVER_NAME;
+static const char driver_desc [] = DRIVER_DESC;
+
+static struct uoc *the_controller;
+static const char *transceiver_label = "cs5536_uoc";
+
+/*****************************************************************************
+ * Function Definitions
+ *****************************************************************************/
+
+/**
+ * \brief
+ * fill UOC transceiver struct
+ *
+ * \param transceiver UOC transceiver
+ *
+ * \return void
+ */
+static inline void uoc_init_transceiver (struct otg_transceiver *transceiver)
+{
+ transceiver->dev = NULL;
+ transceiver->label = transceiver_label;
+ transceiver->default_a = 0;
+ transceiver->state = 0;
+ transceiver->host = NULL;
+ transceiver->gadget = NULL;
+ transceiver->port_status = 0;
+ transceiver->port_change = 0;
+ transceiver->set_host = NULL;
+ transceiver->set_peripheral = uoc5536_set_peripheral;
+ transceiver->set_power = NULL;
+ transceiver->start_srp = NULL;
+ transceiver->start_hnp = NULL;
+}
+
+/**
+ * \brief
+ * OTG get transceiver: provide info to others
+ *
+ * \param void
+ *
+ * \return pointer to transceiver struct
+ */
+struct otg_transceiver * otg_get_transceiver (void)
+{
+ return uoc_to_transceiver (the_controller);
+}
+
+/**
+ * \brief
+ * Bind/unbind the UOC controller to/from usb gadget
+ *
+ * \param transceiver this transceiver
+ * \param gadget usb gadget info
+ *
+ * \return error code
+ */
+static int uoc5536_set_peripheral (struct otg_transceiver *transceiver,
+ struct usb_gadget *gadget)
+{
+ struct uoc *uoc = the_controller;
+
+ if (unlikely (transceiver != uoc_to_transceiver (uoc))) {
+ ERR ("USB UOC: unknown transceiver\n");
+ return -EINVAL;
+ }
+ if (gadget) {
+ if (transceiver->gadget) {
+ ERR ("USB gadget: UOC driver already registered\n");
+ return -EBUSY;
+ }
+ DBG ("bind UOC driver to USB gadget\n");
+ transceiver->gadget = gadget;
+
+ /* Enable UOC hardware (incl. auto pull-up enable) */
+ writel ((readl (&uoc->regs->cap) | UOC_CAP_APU), &uoc->regs->cap);
+
+ return 0;
+ }
+ else {
+ DBG ("unbind UOC driver from USB gadget\n");
+
+ /* Reset auto pull-up (does not reset pull-up) */
+ writel ((readl (&uoc->regs->cap) & ~((u32) UOC_CAP_APU)),
+ &uoc->regs->cap);
+
+ /* Reset pull-up */
+ writel ((readl (&uoc->regs->mux) & ~((u32) UOC_MUX_PUEN)),
+ &uoc->regs->mux);
+
+ transceiver->gadget = NULL;
+ return 0;
+ }
+}
+
+/**
+ * \brief
+ * UOC probe: init hardware, register the driver
+ *
+ * \param uoc uoc controller info
+ *
+ * \return success
+ */
+static inline int __init uoc_probe (struct uoc *uoc)
+{
+ int retval;
+ u32 port_mux;
+
+ /* initialize the UOC controller */
+
+ VDBG ("UOC init ...\n");
+
+#ifdef VERBOSE
+ /* print regs */
+ print_regs (uoc);
+#endif
+
+ /* Make sure the port mux setting corresponds to .config to avoid bug 5190 */
+ port_mux = readl (&uoc->regs->ctl) & UOC_CTL_MUX_MASK;
+ if (port_mux != UOC_CTL_ENABLE_UDC) {
+ ERR("Your USB port is assigned to %s, it must be assigned to %s within the BIOS setup\n",
+ (port_mux == UOC_CTL_ENABLE_UHC ? "Host" : "Not used"), "Device");
+ retval = -ENODEV;
+ goto err1;
+ }
+
+ /* turn on the UOC controller */
+ writel ((readl (&uoc->regs->ctl) | UOC_CTL_PADEN), &uoc->regs->ctl);
+
+ INFO ("Port is assigned to device\n");
+
+ VDBG ("UOC init done\n");
+
+ /* registering to the device driver */
+ if (usb_gadget_register_otg (otg_get_transceiver)) {
+ ERR ("gadget driver registration failed\n");
+ retval = -ENODEV;
+ goto err1;
+ }
+
+ return 0;
+
+err1:
+
+ return retval;
+}
+
+/**
+ * \brief
+ * UOC remove: deregister the driver, clean-up hardware
+ *
+ * \param uoc uoc controller info
+ *
+ * \return void
+ */
+static inline void __exit uoc_remove (struct uoc *uoc)
+{
+
+ /* unregistering from the usb gadget */
+ usb_gadget_unregister_otg ();
+
+ /* Disable UOC hardware (incl. auto pull-up disable) */
+ writel ((readl (&uoc->regs->ctl) & ~((u32) UOC_CTL_PADEN)),
+ &uoc->regs->ctl);
+
+ VDBG ("UOC exit: UOC-HW disabled\n");
+
+}
+
+
+#ifdef CONFIG_PCI
+
+/**
+ * \brief
+ * UOC PCI probe: enable, init controller hardware
+ *
+ * \param pdev pci device info
+ * \param id pci ids
+ *
+ * \return success
+ */
+static int __init uoc_pci_probe (struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct uoc *uoc;
+ u32 resource, len;
+ void *base;
+ int retval;
+ char buf [8] = {0,0,0,0,0,0,0,0}, *bufp;
+
+ /* alloc, and start init */
+ uoc = (struct uoc *) kmalloc (sizeof(struct uoc), SLAB_KERNEL);
+ if (!uoc) {
+ ERR ("couldn't allocate memory for UOC driver\n");
+ retval = -ENOMEM;
+ goto err1;
+ }
+ DBG ( "kmalloc: UOC driver: %p\n", uoc);
+
+ /* hold global device pointer */
+ the_controller = uoc;
+
+ memset (uoc, 0, sizeof(struct uoc));
+ spin_lock_init (&uoc->lock);
+
+ uoc->pdev = pdev;
+
+ /* now all the pci goodies ... */
+ if (pci_enable_device (pdev) < 0) {
+ ERR ("couldn't enable PCI device\n");
+ retval = -ENODEV;
+ goto err2;
+ }
+ uoc->enabled = 1;
+
+ resource = pci_resource_start (pdev, 0);
+ len = pci_resource_len (pdev, 0);
+
+ if (!request_mem_region (resource, len, driver_name)) {
+ ERR ("controller already in use\n");
+ retval = -EBUSY;
+ goto err3;
+ }
+ uoc->region = 1;
+
+ base = ioremap_nocache (resource, len);
+ if (!base) {
+ ERR ("couldn't map memory\n");
+ retval = -EFAULT;
+ goto err4;
+ }
+ uoc->regs = (struct uoc_regs *) base;
+ bufp = buf;
+
+ pci_read_config_byte (pdev, PCI_REVISION_ID, (u8*) &uoc->chiprev);
+
+ /* chip rev >= "B1" supported */
+ if (uoc->chiprev == A0_REV) {
+ ERR("Your chip revision is %s, it must be at least %s\n",
+ "A0", "B1");
+ retval = -ENODEV;
+ goto err5;
+ }
+
+ /* UOC transceiver info */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
+ uoc->transceiver.dev = NULL;
+#else
+ uoc->transceiver.dev = &pdev->dev;
+#endif
+ uoc_init_transceiver (uoc_to_transceiver (uoc));
+
+ /* done */
+ INFO ("%s\n", driver_desc);
+ INFO ("pci mem %08x, chip rev %02x (Geode5536 %s)\n",
+ resource, uoc->chiprev, (uoc->chiprev == A0_REV ? "A0" : "B1"));
+
+ bufp = DRIVER_VERSION;
+ INFO ("driver version: %s\n", bufp);
+
+ if ((retval = uoc_probe (uoc)) == 0) {
+ pci_set_drvdata (pdev, uoc);
+ return 0;
+ }
+
+ /* something went wrong */
+
+err5:
+ uoc->regs = NULL;
+ iounmap (base);
+err4:
+ uoc->region = 0;
+ release_mem_region (resource, len);
+err3:
+ uoc->enabled = 0;
+ pci_disable_device (pdev);
+err2:
+ uoc->pdev = NULL;
+ the_controller = NULL;
+ DBG ( "kfree: UOC driver: %p\n", uoc);
+ kfree (uoc);
+err1:
+ uoc = NULL;
+ return retval;
+}
+
+/**
+ * \brief
+ * UOC PCI remove: clean-up, disable controller hardware
+ *
+ * \param pdev pci device info
+ *
+ * \return void
+ */
+static void __exit uoc_pci_remove (struct pci_dev *pdev)
+{
+ struct uoc *uoc = pci_get_drvdata (pdev);
+
+ uoc_remove (uoc);
+
+ iounmap (uoc->regs);
+ uoc->regs = NULL;
+ uoc->region = 0;
+ release_mem_region (pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ uoc->enabled = 0;
+ pci_disable_device (pdev);
+ uoc->pdev = NULL;
+ the_controller = NULL;
+ DBG ( "kfree: UOC driver: %p\n", uoc);
+ kfree (uoc);
+ uoc = NULL;
+ pci_set_drvdata(pdev, NULL);
+}
+#endif
+
+
+/*****************************************************************************
+ * More data
+ *****************************************************************************/
+
+#ifdef CONFIG_PCI
+/**
+ * \brief
+ * PCI ID table
+ *
+ */
+static struct pci_device_id pci_ids [] = { {
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = PCI_DEVICE_ID_AMD_CS5536_UOC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+
+}, { /* end: all zeroes */ }
+};
+
+/**
+ * \brief
+ * PCI driver struct to be used for driver registration
+ * ( this is a "new style" PCI driver module )
+ *
+ */
+static struct pci_driver uoc_pci_driver = {
+ .name = (char *) driver_name,
+ .id_table = pci_ids,
+ .probe = uoc_pci_probe,
+ .remove = uoc_pci_remove,
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+#endif
+/* This comment closes the module definition from above. There can be multiple
+ definitions of this kind in a file. See the doxygen documentation for more
+ information. */
+/** \}*/
+
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_AUTHOR ("Karsten Boge");
+MODULE_LICENSE ("GPL");
+
+#ifdef CONFIG_PCI
+
+static int __init init (void)
+{
+ return (pci_module_init (&uoc_pci_driver));
+}
+static void __exit cleanup (void)
+{
+ pci_unregister_driver (&uoc_pci_driver);
+}
+#endif
+module_init (init);
+module_exit (cleanup);
Index: linux-2.6.11/drivers/usb/gadget/amd5536uoc.h
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/usb/gadget/amd5536uoc.h
@@ -0,0 +1,304 @@
+/*
+ * AMD 5536 USB UOC controller driver
+ */
+
+/*
+ * Copyright (C) 2005 AMD (http://www.amd.com)
+ * Author: Karsten Boge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef AMD5536UOC_H
+#define AMD5536UOC_H
+
+
+/*****************************************************************************
+* Config options
+*****************************************************************************/
+
+#ifdef VERBOSE
+#ifndef DEBUG
+#define DEBUG
+#endif
+#endif
+
+
+/*****************************************************************************
+* Constants
+*****************************************************************************/
+
+#define UOC_DRIVER_NAME "amd5536uoc"
+
+#ifdef CONFIG_PCI
+#ifndef PCI_VENDOR_ID_AMD
+#define PCI_VENDOR_ID_AMD 0x1022
+#endif
+#ifndef PCI_DEVICE_ID_AMD_CS5536_UOC
+#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
+#endif
+#else
+#error "!!! UNKNOWN SYSTEM BUS TYPE !!!"
+#endif
+
+/* AMD5536 chip rev. */
+#define A0_REV 1
+#define B1_REV 2
+
+/**********************************
+* CS5536UOC Register definitions
+**********************************/
+
+/* capabilities */
+#define UOC_CAP_APU (1<<15) /* automatic pull-up enable */
+
+/* multiplexer */
+#define UOC_MUX_DISABLE_ALL 0 /* not assigned */
+#define UOC_MUX_ENABLE_UHC (2<<0) /* assigned to host */
+#define UOC_MUX_ENABLE_UDC (3<<0) /* assigned to device */
+#define UOC_MUX_PUEN (1<<2) /* pull-up enable */
+#define UOC_MUX_VBUSVLD (1<<8) /* VBus valid */
+
+/* status */
+#define UOC_STS_ID (1<<0) /* ID pin status */
+#define UOC_STS_VBUSVLD (1<<1) /* VBus valid */
+#define UOC_STS_SESSVLD (1<<2) /* Session valid */
+#define UOC_STS_SESSEND (1<<3) /* Session end */
+#define UOC_STS_LST (3<<4) /* Line state */
+#define UOC_STS_LST_J (1<<4) /* Line state */
+#define UOC_STS_LST_K (2<<4) /* Line state */
+#define UOC_STS_PSPD (3<<6) /* Port speed */
+#define UOC_STS_PSPD_LS (2<<6) /* Port speed */
+#define UOC_STS_PSPD_FS (1<<6) /* Port speed */
+#define UOC_STS_FSOE (1<<8) /* FS output enable (OHC) */
+#define UOC_STS_PCON (1<<9) /* Port connected */
+#define UOC_STS_PSUS (1<<10) /* Port suspended */
+#define UOC_STS_TMH (1<<11) /* Timer halted */
+#define UOC_STS_HNP_EN (1<<12) /* HNP enabled for B-dev */
+#define UOC_STS_HNP_SUPP (1<<13) /* A-host supports HNP */
+#define UOC_STS_HNP_ALTSUPP (1<<14) /* A-host supports alt. HNP */
+#define UOC_STS_HNPSTS (UOC_STS_HNP_EN | UOC_STS_HNP_SUPP | \
+ UOC_STS_HNP_ALTSUPP)
+#define UOC_STS_OC (1<<15) /* over-current */
+#define UOC_STS_DPR (1<<16) /* Downstream port reset */
+
+/* control */
+#define UOC_CTL_DISABLE_ALL 0 /* not assigned */
+#define UOC_CTL_ENABLE_UHC (2<<0) /* assigned to host */
+#define UOC_CTL_ENABLE_UDC (3<<0) /* assigned to device */
+#define UOC_CTL_MUX_MASK (3<<0) /* port mux mask */
+#define UOC_CTL_PPWR (1<<2) /* port power switch */
+#define UOC_CTL_PPO (1<<3) /* port power override */
+#define UOC_CTL_CHRG (1<<4) /* charge VBus */
+#define UOC_CTL_DISCHRG (1<<5) /* discharge VBus */
+#define UOC_CTL_IDSNSEN (1<<6) /* ID sense enable, ID-PU */
+#define UOC_CTL_PADEN (1<<7)
+#define UOC_CTL_PUEN (1<<8) /* pull-up enable */
+#define UOC_CTL_DMPDEN (1<<9) /* pull-down enable */
+#define UOC_CTL_HNPSFEN (1<<10) /* HNP SET_FEATURE enable */
+#define UOC_CTL_WPCS_DEAS (2<<16) /* deassert port connect */
+#define UOC_CTL_WPCS_ASRT (3<<16) /* assert port connect */
+#define UOC_CTL_WPSS_DEAS (2<<18) /* deassert port suspend */
+#define UOC_CTL_WPSS_ASRT (3<<18) /* assert port suspend */
+/* timer conditions */
+#define UOC_CTL_TMR_RLP (1<<28) /* timer reload policy */
+#define UOC_CTL_TMR_ALL (0xf<<24) /* stop timer */
+#define UOC_CTL_TMR_STOP 0 /* timer disabled */
+#define UOC_CTL_TMR_UNCOND (1<<24) /* count unconditionally */
+#define UOC_CTL_TMR_SE0 (2<<24) /* count if LSt = FS-SE0 */
+#define UOC_CTL_TMR_FSJ (3<<24) /* count if LSt = FS-J */
+#define UOC_CTL_TMR_FSK (4<<24) /* count if LSt = FS-K */
+#define UOC_CTL_TMR_NOSE0 (5<<24) /* count if LSt <> FS-SE0 */
+#define UOC_CTL_TMR_NORX (6<<24) /* count if Rx inactiv */
+#define UOC_CTL_TMR_ID (7<<24) /* count if ID = 0 */
+
+/* interrupts */
+#define UOC_INT_GLOBAL (1<<31) /* global interrupt enable */
+#define UOC_INT_ENALL 0x7fff /* enable all */
+#define UOC_INT_DISALL 0 /* disable all */
+#define UOC_INT_IDC (1<<0) /* ID pin change */
+#define UOC_INT_VBVC (1<<1) /* VBUS valid change */
+#define UOC_INT_SVC (1<<2) /* Session valid change */
+#define UOC_INT_SEC (1<<3) /* Session end change */
+#define UOC_INT_LSTC (1<<4) /* Line state change */
+#define UOC_INT_PSPDC (1<<5) /* Port speed change */
+#define UOC_INT_FSOEC (1<<6) /* FS/LS OE change */
+#define UOC_INT_HSDD (1<<7) /* HS disconnect detected */
+#define UOC_INT_RXACT (1<<8) /* Rx activity detected */
+#define UOC_INT_PCC (1<<9) /* Port connect change */
+#define UOC_INT_PSC (1<<10) /* Port suspend change */
+#define UOC_INT_TMX (1<<11) /* Timer expired */
+#define UOC_INT_HNPFC (1<<12) /* HNP feature change */
+#define UOC_INT_OCD (1<<13) /* over current detected */
+#define UOC_INT_DPRC (1<<14) /* Downstream port reset change */
+
+
+/*****************************************************************************
+* Types
+*****************************************************************************/
+
+
+/*****************************************************************************
+* Macros
+*****************************************************************************/
+
+/* printing messages */
+
+#define INFO(args...) \
+ printk(KERN_INFO DRIVER_NAME_FOR_PRINT ": " args)
+
+#define WARN(args...) \
+ printk(KERN_WARNING DRIVER_NAME_FOR_PRINT " warning: " args)
+
+#define ERR(args...) \
+ printk(KERN_ERR DRIVER_NAME_FOR_PRINT " error: " args)
+
+#ifdef DEBUG
+#define DBG(args...) \
+ printk(KERN_DEBUG DRIVER_NAME_FOR_PRINT " debug: " args)
+#else
+#define DBG(args...) \
+ do {} while (0)
+#endif
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(args...) \
+ do { } while (0)
+#endif
+
+/****************************************************************************/
+
+/* this should always return "1" and print something in verbose mode */
+#ifdef VERBOSE
+#define VDBG_SPC(fmt,args...) \
+ (VDBG (fmt, args) ? 1 : 1)
+#else
+#define VDBG_SPC(fmt,args...) 1
+#endif
+
+/*****************************************************************************
+* Data
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct uoc_regs {
+ u32 cap; /* capabilities */
+ u32 mux; /* mux */
+ u32 sts; /* status */
+ u32 ctl; /* control */
+ u32 tmr; /* timer */
+ u32 intr; /* interrupt request */
+ u32 inten; /* interrupt enable */
+} __attribute__ ((packed));
+
+
+struct uoc {
+ spinlock_t lock;
+ unsigned enabled : 1,
+ got_irq : 1,
+ region : 1;
+ u16 chiprev;
+
+ struct pci_dev *pdev;
+ struct uoc_regs *regs;
+ struct otg_transceiver transceiver;
+};
+#define uoc_transceiver_to_uoc(pTransceiver) \
+ container_of (uoc, struct uoc, pTransceiver)
+#define uoc_to_transceiver(pUoc) \
+ &pUoc->transceiver
+
+#ifdef __KERNEL__
+
+/* 2.5 and 2.4.older portability changes ... */
+
+#ifndef container_of
+#define container_of list_entry
+#endif
+
+#ifndef likely
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef WARN_ON
+#define WARN_ON(x) do { } while (0)
+#endif
+
+#endif /* __KERNEL__ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+/*****************************************************************************
+* Functions
+*****************************************************************************/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern int usb_gadget_register_otg (struct otg_transceiver * (
+ *get_transceiver)(void));
+extern int usb_gadget_unregister_otg (void);
+
+
+#ifdef DEBUG
+static void print_regs (struct uoc *);
+#endif /* DEBUG */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+/*****************************************************************************
+* Inline Functions
+*****************************************************************************/
+
+#ifdef DEBUG
+/**
+ * \brief
+ * Print UOC controller registers (debug mode only)
+ *
+ * \param dev UOC controller info
+ *
+ * \return void
+ */
+static inline void print_regs (struct uoc *dev)
+{
+ DBG( "-- UOC registers ---\n");
+ DBG( "uoc cap = %08x\n", readl (&dev->regs->cap));
+ DBG( "uoc mux = %08x\n", readl (&dev->regs->mux));
+ DBG( "uoc sts = %08x\n", readl (&dev->regs->sts));
+ DBG( "uoc ctl = %08x\n", readl (&dev->regs->ctl));
+ DBG( "uoc tmr = %08x\n", readl (&dev->regs->tmr));
+ DBG( "uoc intr = %08x\n", readl (&dev->regs->intr));
+ DBG( "uoc inten = %08x\n", readl (&dev->regs->inten));
+ DBG( "--------------------\n");
+}
+#endif /* DEBUG */
+
+#endif /* AMD5536UOC_H */
Index: linux-2.6.11/drivers/usb/gadget/ether.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/ether.c
+++ linux-2.6.11/drivers/usb/gadget/ether.c
@@ -90,6 +90,14 @@ static const char driver_desc [] = DRIVE
#define RX_EXTRA 20 /* guard against rx overflows */
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+/*
+ * AMD UDC supports dword aligned DMA buffers only, so skbuf buffers
+ * from network layer must be copied
+ */
+#define UDC_MAX_BUFLEN 2048 /* size of dword aligned buffer */
+#endif
+
#ifdef CONFIG_USB_ETH_RNDIS
#include "rndis.h"
#else
@@ -144,8 +152,13 @@ static const char *EP_STATUS_NAME;
/* Thanks to NetChip Technologies for donating this product ID.
* It's for devices with only CDC Ethernet configurations.
*/
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define CDC_VENDOR_NUM 0x0438 /* AMD */
+#define CDC_PRODUCT_NUM 0xdc01 /* AMD Linux-USB Ethernet Gadget (temporary) */
+#else
#define CDC_VENDOR_NUM 0x0525 /* NetChip */
#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
+#endif
/* For hardware that can't talk CDC, we use the same vendor ID that
* ARM Linux has used for ethernet-over-usb, both with sa1100 and
@@ -242,6 +255,9 @@ MODULE_PARM_DESC(host_addr, "Host Ethern
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DEV_CONFIG_CDC
+#endif
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@@ -1144,6 +1160,10 @@ static void eth_reset_config (struct eth
req = container_of (dev->tx_reqs.next,
struct usb_request, list);
list_del (&req->list);
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+ if (req->buf)
+ usb_ep_free_buffer (dev->in_ep, req->buf, req->dma, UDC_MAX_BUFLEN);
+#endif
usb_ep_free_request (dev->in_ep, req);
}
dev->in_ep = NULL;
@@ -1154,6 +1174,10 @@ static void eth_reset_config (struct eth
req = container_of (dev->rx_reqs.next,
struct usb_request, list);
list_del (&req->list);
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+ if (req->buf)
+ usb_ep_free_buffer (dev->out_ep, req->buf, req->dma, UDC_MAX_BUFLEN);
+#endif
usb_ep_free_request (dev->out_ep, req);
}
dev->out_ep = NULL;
@@ -1322,8 +1346,10 @@ static void issue_start_status (struct e
DEBUG (dev, "status ENOMEM\n");
return;
}
+//DISABLEDamd req->buf = usb_ep_alloc_buffer (dev->status_ep, 16,
+//DISABLEDamd &dev->req->dma, GFP_ATOMIC);
req->buf = usb_ep_alloc_buffer (dev->status_ep, 16,
- &dev->req->dma, GFP_ATOMIC);
+ &req->dma, GFP_ATOMIC);
if (req->buf == 0) {
DEBUG (dev, "status buf ENOMEM\n");
free_req:
@@ -1766,7 +1792,9 @@ rx_submit (struct eth_dev *dev, struct u
goto enomem;
}
+#ifndef CONFIG_USB_GADGET_AMD5536UDC
req->buf = skb->data;
+#endif
req->length = size;
req->complete = rx_complete;
req->context = skb;
@@ -1808,6 +1836,16 @@ static void rx_complete (struct usb_ep *
break;
}
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+ /* we need to copy here because AMD UDC needs dword aligned buffers */
+ VDEBUG(dev, "memcpy( skb->data %lx,req->buf %lx,req->actual %d)\n", skb->data,req->buf,req->actual);
+ if (req->actual <= UDC_MAX_BUFLEN) {
+ memcpy(skb->data, req->buf, req->actual);
+ }
+ else {
+ ERROR(dev, "memcpy of %d bytes bigger than max %d\n", req->actual, UDC_MAX_BUFLEN);
+ }
+#endif
skb->dev = dev->net;
skb->protocol = eth_type_trans (skb, dev->net);
dev->stats.rx_packets++;
@@ -1876,6 +1914,15 @@ static int prealloc (struct list_head *l
req = usb_ep_alloc_request (ep, gfp_flags);
if (!req)
return list_empty (list) ? -ENOMEM : 0;
+
+
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+ /* allocate buffer which must be dword aligned for AMD UDC */
+ req->buf = usb_ep_alloc_buffer (ep, UDC_MAX_BUFLEN,
+ &req->dma, GFP_ATOMIC);
+#endif
+
+
list_add (&req->list, list);
}
return 0;
@@ -1887,6 +1934,10 @@ extra:
next = req->list.next;
list_del (&req->list);
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+ if (req->buf)
+ usb_ep_free_buffer (ep, req->buf, req->dma, UDC_MAX_BUFLEN);
+#endif
usb_ep_free_request (ep, req);
if (next == list)
@@ -2020,7 +2071,19 @@ static int eth_start_xmit (struct sk_buf
length = skb->len;
}
#endif
- req->buf = skb->data;
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+ /* we need to copy here because AMD UDC needs dword aligned buffers */
+ VDEBUG(dev, "memcpy(req->buf %lx, skb->data %lx, length %d)", req->buf, skb->data, length);
+ if (length <= UDC_MAX_BUFLEN) {
+ memcpy(req->buf, skb->data, length);
+ }
+ else {
+ ERROR(dev, "memcpy of %d bytes bigger than max %d\n", length, UDC_MAX_BUFLEN);
+ }
+ VDEBUG(dev, "past memcpy(req->buf %lx, skb->data %lx, length %d)", req->buf, skb->data, length);
+#else
+ req->buf = skb->data;
+#endif
req->context = skb;
req->complete = tx_complete;
@@ -2326,6 +2389,9 @@ eth_bind (struct usb_gadget *gadget)
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
} else if (gadget_is_pxa27x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+ } else if (gadget_is_amd5536udc(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
+ rndis = 0;
} else {
/* can't assume CDC works. don't want to default to
* anything less functional on CDC-capable hardware,
@@ -2457,10 +2523,16 @@ autoconf_fail:
if (gadget->is_otg) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
+#ifndef CONFIG_USB_GADGET_AMD5536UDC
+ /* FIXME disabled remote wake feature to pass USBCV */
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+#endif
eth_config.bMaxPower = 4;
#ifdef CONFIG_USB_ETH_RNDIS
+#ifndef CONFIG_USB_GADGET_AMD5536UDC
+ /* FIXME disabled remote wake feature to pass USBCV */
rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+#endif
rndis_config.bMaxPower = 4;
#endif
}
Index: linux-2.6.11/drivers/usb/gadget/file_storage.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/file_storage.c
+++ linux-2.6.11/drivers/usb/gadget/file_storage.c
@@ -262,8 +262,14 @@ MODULE_LICENSE("Dual BSD/GPL");
*
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures. */
+
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DRIVER_VENDOR_ID 0x0438 // AMD
+#define DRIVER_PRODUCT_ID 0xdc02 // AMD Linux-USB File-backed Storage Gadget (temporary)
+#else
#define DRIVER_VENDOR_ID 0x0525 // NetChip
#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget
+#endif
/*
@@ -640,6 +646,7 @@ struct fsg_dev {
unsigned int bulk_out_maxpacket;
enum fsg_state state; // For exception handling
+ int sync_active;
unsigned int exception_req_tag;
u8 config, new_config;
@@ -1083,12 +1090,14 @@ static void raise_exception(struct fsg_d
* If a lower-or-equal priority exception is in progress, preempt it
* and notify the main thread by sending it a signal. */
spin_lock_irqsave(&fsg->lock, flags);
- if (fsg->state <= new_state) {
+ if ((fsg->state <= new_state && (fsg->state != FSG_STATE_DISCONNECT || new_state != FSG_STATE_DISCONNECT))
+ || (fsg->state == FSG_STATE_DISCONNECT && new_state == FSG_STATE_CONFIG_CHANGE && fsg->sync_active)) {
fsg->exception_req_tag = fsg->ep0_req_tag;
fsg->state = new_state;
thread_task = fsg->thread_task;
if (thread_task)
send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task);
+ fsg->sync_active = 0;
}
spin_unlock_irqrestore(&fsg->lock, flags);
}
@@ -1282,7 +1291,8 @@ static int class_setup_req(struct fsg_de
if (ctrl->bRequestType != (USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (ctrl->wIndex != 0) {
+ if (ctrl->wIndex != 0 || ctrl->wValue != 0
+ || ctrl->wLength != 0) {
value = -EDOM;
break;
}
@@ -1298,7 +1308,8 @@ static int class_setup_req(struct fsg_de
if (ctrl->bRequestType != (USB_DIR_IN |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (ctrl->wIndex != 0) {
+ if (ctrl->wIndex != 0 || ctrl->wValue != 0
+ || ctrl->wLength != 1) {
value = -EDOM;
break;
}
@@ -1708,8 +1719,11 @@ static int do_write(struct fsg_dev *fsg)
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
}
- if (fsg->cmnd[1] & 0x08) // FUA
- curlun->filp->f_flags |= O_SYNC;
+ /* FUA avoids cache -> slow */
+ /* FIXME make sure that device is self powered otherwise
+ * cached data may be lost on disconnect */
+ /* if (fsg->cmnd[1] & 0x08) // FUA
+ curlun->filp->f_flags |= O_SYNC; */
}
if (lba >= curlun->num_sectors) {
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
@@ -2444,13 +2458,21 @@ static int finish_reply(struct fsg_dev *
* short packet and halt the bulk-in endpoint. If we can't
* stall, pad out the remaining data with 0's. */
else {
- if (mod_data.can_stall) {
- bh->inreq->zero = 1;
- start_transfer(fsg, fsg->bulk_in, bh->inreq,
- &bh->inreq_busy, &bh->state);
- fsg->next_buffhd_to_fill = bh->next;
- rc = halt_bulk_in_endpoint(fsg);
- } else
+ /* normal windows host mass storage would cause a stall
+ here, when then host sends CLEAR_FEATURE the
+ halt condition is not allowed to be cleared
+ according to USB-IF MSC compliance specification.
+ This would cause the windows host to re-enumerate
+ again and again. This was found after the controller
+ driver was made compliant to the MSC compliance
+ test (see test TD.1.4) */
+ //if (mod_data.can_stall) {
+ // bh->inreq->zero = 1;
+ // start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ // &bh->inreq_busy, &bh->state);
+ // fsg->next_buffhd_to_fill = bh->next;
+ // rc = halt_bulk_in_endpoint(fsg);
+ //} else
rc = pad_with_zeros(fsg);
}
break;
@@ -3320,6 +3342,8 @@ static void handle_exception(struct fsg_
usb_ep_clear_halt(fsg->bulk_out);
}
+ fsync_all(fsg);
+
if (transport_is_bbb()) {
if (fsg->ep0_req_tag == exception_req_tag)
ep0_queue(fsg); // Complete the status stage
@@ -3355,8 +3379,13 @@ static void handle_exception(struct fsg_
break;
case FSG_STATE_DISCONNECT:
+ fsg->sync_active = 1;
fsync_all(fsg);
- do_set_config(fsg, 0); // Unconfigured state
+ fsg->sync_active++;
+ spin_lock_irq(&fsg->lock);
+ if (fsg->state != FSG_STATE_CONFIG_CHANGE)
+ do_set_config(fsg, 0); // Unconfigured state
+ spin_unlock_irq(&fsg->lock);
break;
case FSG_STATE_EXIT:
@@ -3664,13 +3693,18 @@ static void fsg_unbind(struct usb_gadget
init_completion(&fsg->lun_released);
for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i];
- if (curlun->registered) {
- device_remove_file(&curlun->dev, &dev_attr_ro);
- device_remove_file(&curlun->dev, &dev_attr_file);
- device_unregister(&curlun->dev);
- wait_for_completion(&fsg->lun_released);
- curlun->registered = 0;
- }
+
+ /* FIXME temporary disabled device file system usage until
+ * working for Au1200 */
+ if (!gadget_is_amd5536udc(fsg->gadget)) {
+ if (curlun->registered) {
+ device_remove_file(&curlun->dev, &dev_attr_ro);
+ device_remove_file(&curlun->dev, &dev_attr_file);
+ device_unregister(&curlun->dev);
+ wait_for_completion(&fsg->lun_released);
+ curlun->registered = 0;
+ }
+ }
}
/* If the thread isn't already dead, tell it to exit now */
@@ -3740,6 +3774,8 @@ static int __init check_parameters(struc
mod_data.release = 0x0310;
else if (gadget_is_pxa27x(fsg->gadget))
mod_data.release = 0x0311;
+ else if (gadget_is_amd5536udc(fsg->gadget))
+ mod_data.release = 0x0312;
else {
WARN(fsg, "controller '%s' not recognized\n",
fsg->gadget->name);
@@ -3817,6 +3853,9 @@ static int __init fsg_bind(struct usb_ga
set_gadget_data(gadget, fsg);
fsg->ep0 = gadget->ep0;
fsg->ep0->driver_data = fsg;
+ fsg->sync_active = 0;
+
+
if ((rc = check_parameters(fsg)) != 0)
goto out;
@@ -3856,14 +3895,18 @@ static int __init fsg_bind(struct usb_ga
snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
"%s-lun%d", gadget->dev.bus_id, i);
- if ((rc = device_register(&curlun->dev)) != 0)
- INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
- else {
- curlun->registered = 1;
- curlun->dev.release = lun_release;
- device_create_file(&curlun->dev, &dev_attr_ro);
- device_create_file(&curlun->dev, &dev_attr_file);
- }
+ /* FIXME temporary disabled device file system usage until
+ * working for Au1200 */
+ if (!gadget_is_amd5536udc(fsg->gadget)) {
+ if ((rc = device_register(&curlun->dev)) != 0)
+ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
+ else {
+ curlun->registered = 1;
+ curlun->dev.release = lun_release;
+ device_create_file(&curlun->dev, &dev_attr_ro);
+ device_create_file(&curlun->dev, &dev_attr_file);
+ }
+ }
if (file[i] && *file[i]) {
if ((rc = open_backing_file(curlun, file[i])) != 0)
@@ -3922,8 +3965,12 @@ static int __init fsg_bind(struct usb_ga
#endif
if (gadget->is_otg) {
- otg_desc.bmAttributes |= USB_OTG_HNP,
+ otg_desc.bmAttributes |= USB_OTG_HNP;
+
+#ifndef CONFIG_USB_GADGET_AMD5536UDC
+ /* FIXME disabled remote wake feature to pass USBCV */
config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+#endif
}
rc = -ENOMEM;
Index: linux-2.6.11/drivers/usb/gadget/gadget_chips.h
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/gadget_chips.h
+++ linux-2.6.11/drivers/usb/gadget/gadget_chips.h
@@ -14,6 +14,12 @@
#define gadget_is_net2280(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define gadget_is_amd5536udc(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
#else
Index: linux-2.6.11/drivers/usb/gadget/inode.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/inode.c
+++ linux-2.6.11/drivers/usb/gadget/inode.c
@@ -20,8 +20,9 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
-// #define VERBOSE /* extra debug messages (success too) */
+//DISABLEDamd #define DEBUG /* data to help fault diagnosis */
+//DISABLEDamd #define VERBOSE /* extra debug messages (success too) */
+#define HIGHSPEED
#include
#include
@@ -39,6 +40,8 @@
#include
#include
+#include
+#include
/*
* The gadgetfs API maps each endpoint to a file descriptor so that you
@@ -134,7 +137,8 @@ struct dev_data {
setup_can_stall : 1,
setup_out_ready : 1,
setup_out_error : 1,
- setup_abort : 1;
+ setup_abort : 1,
+ control_out_ready : 1;
/* the rest is basically write-once */
struct usb_config_descriptor *config, *hs_config;
@@ -148,7 +152,16 @@ struct dev_data {
struct dentry *dentry;
/* except this scratch i/o buffer for ep0 */
- u8 rbuf [256];
+ //u8 rbuf [256];
+ u8* rbuf;
+ dma_addr_t dma_rbuf;
+ u8 control_out_data[4096];
+ unsigned int control_out_data_len;
+
+ u32 len;
+ dma_addr_t dma;
+ void* dma_buf;
+
};
static inline void get_dev (struct dev_data *data)
@@ -162,6 +175,7 @@ static void put_dev (struct dev_data *da
return;
/* needs no more cleanup */
BUG_ON (waitqueue_active (&data->wait));
+ dma_free_coherent (NULL, 4096, data->rbuf, data->dma_rbuf);
kfree (data);
}
@@ -178,6 +192,10 @@ static struct dev_data *dev_new (void)
spin_lock_init (&dev->lock);
INIT_LIST_HEAD (&dev->epfiles);
init_waitqueue_head (&dev->wait);
+
+ dev->rbuf = dma_alloc_coherent (NULL,
+ 4096, &dev->dma_rbuf, GFP_ATOMIC | GFP_DMA);
+
return dev;
}
@@ -412,7 +430,10 @@ ep_read (struct file *fd, char __user *b
/* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
value = -ENOMEM;
- kbuf = kmalloc (len, SLAB_KERNEL);
+ //kbuf = kmalloc (len, SLAB_KERNEL);
+ kbuf = dma_alloc_coherent (NULL,
+ len, &data->req->dma, GFP_ATOMIC | GFP_DMA);
+
if (unlikely (!kbuf))
goto free1;
@@ -424,7 +445,8 @@ ep_read (struct file *fd, char __user *b
free1:
up (&data->lock);
- kfree (kbuf);
+ //kfree (kbuf);
+ dma_free_coherent (NULL, len, kbuf, data->req->dma);
return value;
}
@@ -456,7 +478,9 @@ ep_write (struct file *fd, const char __
/* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
value = -ENOMEM;
- kbuf = kmalloc (len, SLAB_KERNEL);
+ //kbuf = kmalloc (len, SLAB_KERNEL);
+ kbuf = dma_alloc_coherent (NULL,
+ len, &data->req->dma, GFP_ATOMIC | GFP_DMA);
if (!kbuf)
goto free1;
if (copy_from_user (kbuf, buf, len)) {
@@ -469,7 +493,8 @@ ep_write (struct file *fd, const char __
data->name, len, value);
free1:
up (&data->lock);
- kfree (kbuf);
+ //kfree (kbuf);
+ dma_free_coherent (NULL, len, kbuf, data->req->dma);
return value;
}
@@ -902,6 +927,7 @@ static void clean_req (struct usb_ep *ep
}
req->complete = epio_complete;
dev->setup_out_ready = 0;
+ dev->control_out_ready = 0;
}
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
@@ -912,8 +938,16 @@ static void ep0_complete (struct usb_ep
/* for control OUT, data must still get to userspace */
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
- if (!dev->setup_out_error)
+ if (!dev->setup_out_error) {
+ if (req->actual) {
+ dev->control_out_data_len = min((unsigned) 4096, req->actual);
+ memcpy(dev->control_out_data, req->buf,
+ dev->control_out_data_len);
+ dev->state = STATE_CONNECTED;
+ dev->control_out_ready = 1;
+ }
free = 0;
+ }
dev->setup_out_ready = 1;
ep0_readable (dev);
} else if (dev->state == STATE_SETUP)
@@ -933,8 +967,13 @@ static int setup_req (struct usb_ep *ep,
DBG (dev, "ep0 request busy!\n");
return -EBUSY;
}
- if (len > sizeof (dev->rbuf))
+ /* FIXME replace magic number */
+ if (len > 4096)
req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC);
+ else {
+ req->buf = dev->rbuf;
+ req->dma = dev->dma_rbuf;
+ }
if (req->buf == 0) {
req->buf = dev->rbuf;
return -ENOMEM;
@@ -948,11 +987,11 @@ static ssize_t
ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
struct dev_data *dev = fd->private_data;
- ssize_t retval;
+ ssize_t retval = 0;
enum ep0_state state;
+ int value = -EOPNOTSUPP;
spin_lock_irq (&dev->lock);
-
/* report fd mode change before acting on it */
if (dev->setup_abort) {
dev->setup_abort = 0;
@@ -995,24 +1034,48 @@ ep0_read (struct file *fd, char __user *
retval = -EAGAIN;
goto done;
}
- spin_unlock_irq (&dev->lock);
- retval = wait_event_interruptible (dev->wait,
- dev->setup_out_ready != 0);
+ /* TDB */
+ /* read DATA stage for OUT right away */
+ if (unlikely (!dev->setup_in && dev->event[0].u.setup.wLength)) {
- /* FIXME state could change from under us */
- spin_lock_irq (&dev->lock);
- if (retval)
- goto done;
- if (dev->setup_out_error)
- retval = -EIO;
- else {
- len = min (len, (size_t)dev->req->actual);
-// FIXME don't call this with the spinlock held ...
- if (copy_to_user (buf, &dev->req->buf, len))
- retval = -EFAULT;
- clean_req (dev->gadget->ep0, dev->req);
- /* NOTE userspace can't yet choose to stall */
- }
+ value = setup_req (dev->gadget->ep0, dev->req,
+ dev->event[0].u.setup.wLength);
+ if (value >= 0) {
+ value = usb_ep_queue (dev->gadget->ep0, dev->req,
+ GFP_ATOMIC);
+ if (value < 0) {
+ clean_req (dev->gadget->ep0, dev->req);
+ }
+ else {
+ dev->control_out_ready = 0;
+ /* we can't currently stall these */
+ dev->setup_can_stall = 0;
+ }
+ }
+ } /* end TDB */
+
+ spin_unlock_irq (&dev->lock);
+ if (!dev->control_out_ready ) {
+ retval = wait_event_interruptible_timeout(dev->wait,
+ dev->control_out_ready != 0,
+ HZ);
+ }
+ spin_lock_irq (&dev->lock);
+ if (dev->control_out_ready) {
+ /* FIXME state could change from under us */
+ /* TDB wait with timeout has pos. retval */
+ //if (retval)
+ // goto done;
+ if (dev->setup_out_error)
+ retval = -EIO;
+ else {
+ len = min (len, (size_t)dev->control_out_data_len);
+ if (copy_to_user (buf, dev->control_out_data, len))
+ retval = -EFAULT;
+ clean_req (dev->gadget->ep0, dev->req);
+ /* NOTE userspace can't yet choose to stall */
+ }
+ }
}
goto done;
}
@@ -1048,6 +1111,7 @@ scan:
retval = -EFAULT;
else
retval = len;
+//
if (len > 0) {
len /= sizeof (struct usb_gadgetfs_event);
@@ -1216,7 +1280,8 @@ dev_release (struct inode *inode, struct
*/
fasync_helper (-1, fd, 0, &dev->fasync);
- kfree (dev->buf);
+ //kfree (dev->buf);
+ dma_free_coherent (NULL, dev->len, dev->buf, dev->dma);
dev->buf = NULL;
put_dev (dev);
@@ -1370,7 +1435,8 @@ gadgetfs_setup (struct usb_gadget *gadge
dev->setup_abort = 1;
req->buf = dev->rbuf;
- req->dma = DMA_ADDR_INVALID;
+ //req->dma = DMA_ADDR_INVALID;
+ req->dma = dev->dma_rbuf;
req->context = NULL;
value = -EOPNOTSUPP;
switch (ctrl->bRequest) {
@@ -1484,27 +1550,29 @@ delegate:
dev->setup_out_error = 0;
value = 0;
- /* read DATA stage for OUT right away */
- if (unlikely (!dev->setup_in && ctrl->wLength)) {
- value = setup_req (gadget->ep0, dev->req,
- ctrl->wLength);
- if (value < 0)
- break;
- value = usb_ep_queue (gadget->ep0, dev->req,
- GFP_ATOMIC);
- if (value < 0) {
- clean_req (gadget->ep0, dev->req);
- break;
- }
-
- /* we can't currently stall these */
- dev->setup_can_stall = 0;
- }
+//DISABLEDamd /* read DATA stage for OUT right away */
+//DISABLEDamd if (unlikely (!dev->setup_in && ctrl->wLength)) {
+//DISABLEDamd
+//DISABLEDamd value = setup_req (gadget->ep0, dev->req,
+//DISABLEDamd ctrl->wLength);
+//DISABLEDamd if (value < 0)
+//DISABLEDamd break;
+//DISABLEDamd value = usb_ep_queue (gadget->ep0, dev->req,
+//DISABLEDamd GFP_ATOMIC);
+//DISABLEDamd if (value < 0) {
+//DISABLEDamd clean_req (gadget->ep0, dev->req);
+//DISABLEDamd break;
+//DISABLEDamd }
+//DISABLEDamd
+//DISABLEDamd /* we can't currently stall these */
+//DISABLEDamd dev->setup_can_stall = 0;
+//DISABLEDamd }
/* state changes when reader collects event */
event = next_event (dev, GADGETFS_SETUP);
event->u.setup = *ctrl;
ep0_readable (dev);
+
spin_unlock (&dev->lock);
return 0;
}
@@ -1515,6 +1583,9 @@ delegate:
req->length = value;
req->zero = value < ctrl->wLength
&& (value % gadget->ep0->maxpacket) == 0;
+ memcpy(dev->dma_buf, req->buf, req->length);
+ req->buf=dev->dma_buf;
+ req->dma = dev->dma;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG (dev, "ep_queue --> %d\n", value);
@@ -1633,6 +1704,7 @@ gadgetfs_unbind (struct usb_gadget *gadg
spin_unlock_irq (&dev->lock);
destroy_ep_files (dev);
+ usb_ep_free_buffer (gadget->ep0, dev->dma_buf, dev->dma, 4096);
gadget->ep0->driver_data = NULL;
set_gadget_data (gadget, NULL);
@@ -1667,6 +1739,8 @@ gadgetfs_bind (struct usb_gadget *gadget
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
+ dev->dma_buf = usb_ep_alloc_buffer(gadget->ep0, 4096, &dev->dma, GFP_DMA | GFP_ATOMIC);
+
dev->req->context = NULL;
dev->req->complete = epio_complete;
@@ -1827,11 +1901,15 @@ dev_config (struct file *fd, const char
buf += 4;
length -= 4;
- kbuf = kmalloc (length, SLAB_KERNEL);
+ //kbuf = kmalloc (length, SLAB_KERNEL);
+ kbuf = dma_alloc_coherent (NULL,
+ length, &dev->dma, GFP_ATOMIC | GFP_DMA);
+ dev->len = length;
if (!kbuf)
return -ENOMEM;
if (copy_from_user (kbuf, buf, length)) {
- kfree (kbuf);
+ //kfree (kbuf);
+ dma_free_coherent (NULL, length, kbuf, dev->dma);
return -EFAULT;
}
@@ -1876,7 +1954,8 @@ dev_config (struct file *fd, const char
spin_unlock_irq (&dev->lock);
value = usb_gadget_register_driver (&gadgetfs_driver);
if (value != 0) {
- kfree (dev->buf);
+ //kfree (dev->buf);
+ dma_free_coherent (NULL, length, kbuf, dev->dma);
dev->buf = NULL;
} else {
/* at this point "good" hardware has for the first time
@@ -1896,7 +1975,8 @@ dev_config (struct file *fd, const char
fail:
spin_unlock_irq (&dev->lock);
pr_debug ("%s: %s fail %Zd, %p\n", shortname, __FUNCTION__, value, dev);
- kfree (dev->buf);
+ //kfree (dev->buf);
+ dma_free_coherent (NULL, length, kbuf, dev->dma);
dev->buf = NULL;
return value;
}
Index: linux-2.6.11/drivers/usb/gadget/zero.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/gadget/zero.c
+++ linux-2.6.11/drivers/usb/gadget/zero.c
@@ -60,7 +60,7 @@
*/
#define DEBUG 1
-// #define VERBOSE
+//#define VERBOSE
#include
#include
@@ -193,6 +193,10 @@ module_param (loopdefault, bool, S_IRUGO
* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures.
*/
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DRIVER_VENDOR_NUM 0x0438 /* AMD */
+#define DRIVER_PRODUCT_NUM 0xdc00 /* AMD Linux-USB "Gadget Zero" (temporary) */
+#else
#ifndef CONFIG_USB_ZERO_HNPTEST
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
@@ -200,6 +204,7 @@ module_param (loopdefault, bool, S_IRUGO
#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
#define DRIVER_PRODUCT_NUM 0xbadd
#endif
+#endif
/*-------------------------------------------------------------------------*/
@@ -219,7 +224,11 @@ module_param (loopdefault, bool, S_IRUGO
* on a pxa250 as well as more flexible hardware.
*/
#define CONFIG_SOURCE_SINK 3
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define CONFIG_LOOPBACK 1
+#else
#define CONFIG_LOOPBACK 2
+#endif
static struct usb_device_descriptor
device_desc = {
@@ -1125,8 +1134,11 @@ zero_unbind (struct usb_gadget *gadget)
DBG (dev, "unbind\n");
/* we've already been disconnected ... no i/o is active */
- if (dev->req)
+ if (dev->req) {
+ /* free with original length */
+ dev->req->length = USB_BUFSIZ;
free_ep_req (gadget->ep0, dev->req);
+ }
del_timer_sync (&dev->resume);
kfree (dev);
set_gadget_data (gadget, NULL);
@@ -1191,6 +1203,9 @@ autoconf_fail:
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
} else if (gadget_is_pxa27x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+ } else if (gadget_is_amd5536udc(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
+ loopdefault = 1;
} else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
@@ -1237,15 +1252,21 @@ autoconf_fail:
#endif
if (gadget->is_otg) {
- otg_descriptor.bmAttributes |= USB_OTG_HNP,
+ otg_descriptor.bmAttributes |= USB_OTG_HNP;
+#ifndef CONFIG_USB_GADGET_AMD5536UDC
+ /* FIXME disabled remote wake feature to pass USBCV */
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+#endif
}
if (gadget->is_otg) {
- otg_descriptor.bmAttributes |= USB_OTG_HNP,
+ otg_descriptor.bmAttributes |= USB_OTG_HNP;
+#ifndef CONFIG_USB_GADGET_AMD5536UDC
+ /* FIXME disabled remote wake feature to pass USBCV */
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+#endif
}
usb_gadget_set_selfpowered (gadget);
Index: linux-2.6.11/drivers/usb/host/ehci-hcd.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/host/ehci-hcd.c
+++ linux-2.6.11/drivers/usb/host/ehci-hcd.c
@@ -722,7 +722,7 @@ static int ehci_suspend (struct usb_hcd
static int ehci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- unsigned port;
+ int port;
struct usb_device *root = hcd->self.root_hub;
int retval = -EINVAL;
int powerup = 0;
@@ -733,11 +733,11 @@ static int ehci_resume (struct usb_hcd *
msleep (100);
/* If any port is suspended, we know we can/must resume the HC. */
- for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
+ for (port = HCS_N_PORTS (ehci->hcs_params); --port >= 0; ) {
u32 status;
- port--;
status = readl (&ehci->regs->port_status [port]);
- if (status & PORT_SUSPEND) {
+ if ( (status & PORT_SUSPEND) != 0 ||
+ ((status & PORT_OWNER) != 0 && (status & PORT_POWER) != 0) ) {
down (&hcd->self.root_hub->serialize);
retval = ehci_hub_resume (hcd);
up (&hcd->self.root_hub->serialize);
@@ -755,7 +755,7 @@ static int ehci_resume (struct usb_hcd *
/* Else reset, to cope with power loss or flush-to-storage
* style "resume" having activated BIOS during reboot.
*/
- if (port == 0) {
+ if (port < 0) {
(void) ehci_halt (ehci);
(void) ehci_reset (ehci);
(void) ehci_hc_reset (hcd);
Index: linux-2.6.11/drivers/usb/host/ehci-hub.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/host/ehci-hub.c
+++ linux-2.6.11/drivers/usb/host/ehci-hub.c
@@ -232,7 +232,8 @@ ehci_hub_status_data (struct usb_hcd *hc
if (temp & PORT_OWNER) {
/* don't report this in GetPortStatus */
if (temp & PORT_CSC) {
- temp &= ~PORT_CSC;
+ temp &= ~PORT_RWC_BITS;
+ temp |= PORT_CSC;
writel (temp, &ehci->regs->port_status [i]);
}
continue;
Index: linux-2.6.11/drivers/usb/host/ehci.h
===================================================================
--- linux-2.6.11.orig/drivers/usb/host/ehci.h
+++ linux-2.6.11/drivers/usb/host/ehci.h
@@ -262,6 +262,7 @@ struct ehci_regs {
#define PORT_PE (1<<2) /* port enable */
#define PORT_CSC (1<<1) /* connect status change */
#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
} __attribute__ ((packed));
/* Appendix C, Debug port ... intended for use with special "debug devices"
Index: linux-2.6.11/drivers/usb/host/ohci-hcd.c
===================================================================
--- linux-2.6.11.orig/drivers/usb/host/ohci-hcd.c
+++ linux-2.6.11/drivers/usb/host/ohci-hcd.c
@@ -720,6 +720,7 @@ static irqreturn_t ohci_irq (struct usb_
if (ints & OHCI_INTR_RD) {
ohci_vdbg (ohci, "resume detect\n");
+ ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus);
schedule_work(&ohci->rh_resume);
}
Index: linux-2.6.11/drivers/video/Kconfig
===================================================================
--- linux-2.6.11.orig/drivers/video/Kconfig
+++ linux-2.6.11/drivers/video/Kconfig
@@ -811,6 +811,33 @@ config FB_SAVAGE_ACCEL
the resulting framebuffer console has bothersome glitches, then
choose N here.
+config FB_GEODE
+ tristate "AMD Geode generic framebuffer support"
+ depends on FB
+
+config FB_GEODE_LX
+ bool "AMD Geode LX framebuffer"
+ depends on FB_GEODE && PC && MGEODE_LX
+ select CIMARRON
+ help
+ This is the framebuffer device driver for the AMD Geode LX processor.
+ Select this option to enable accelerated console support. To compile
+ this driver as a module, chose 'M' here; the module will be called
+ geodefb
+
+config FB_GEODE_ACCEL
+ bool "AMD Geode LX console acceleration"
+ depends on FB_GEODE_LX
+ help
+ Say y here to enable accelerated drawing for the Geode framebuffer
+
+config FB_GEODE_PANEL
+ bool "AMD Geode Framebuffer panel support"
+ depends on FB_GEODE_LX
+ help
+ Say y here to enable flatpanel support in the Geode framebuffer
+ driver
+
config FB_SIS
tristate "SiS acceleration"
depends on FB && PCI
Index: linux-2.6.11/drivers/video/Makefile
===================================================================
--- linux-2.6.11.orig/drivers/video/Makefile
+++ linux-2.6.11/drivers/video/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb
obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_GEODE) += geode/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
Index: linux-2.6.11/drivers/video/console/vgacon.c
===================================================================
--- linux-2.6.11.orig/drivers/video/console/vgacon.c
+++ linux-2.6.11/drivers/video/console/vgacon.c
@@ -95,6 +95,7 @@ static unsigned long vgacon_uni_pagedir[
/* Description of the hardware situation */
static unsigned long vga_vram_base; /* Base of video memory */
static unsigned long vga_vram_end; /* End of video memory */
+static int vga_vram_size; /* Size of video memory */
static u16 vga_video_port_reg; /* Video register select port */
static u16 vga_video_port_val; /* Video register value port */
static unsigned int vga_video_num_columns; /* Number of text columns */
@@ -288,6 +289,7 @@ static const char __init *vgacon_startup
vga_vram_base = VGA_MAP_MEM(vga_vram_base);
vga_vram_end = VGA_MAP_MEM(vga_vram_end);
+ vga_vram_size = vga_vram_end - vga_vram_base;
/*
* Find out if there is a graphics card present.
@@ -502,9 +504,13 @@ static int vgacon_switch(struct vc_data
*/
vga_video_num_columns = c->vc_cols;
vga_video_num_lines = c->vc_rows;
+
+ /* We can only copy out the size of the video buffer here,
+ * otherwise we get into VGA BIOS */
+
if (!vga_is_gfx)
scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
- c->vc_screenbuf_size);
+ c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
return 0; /* Redrawing not needed */
}
@@ -959,7 +965,6 @@ static int vgacon_scrolldelta(struct vc_
if (!lines) /* Turn scrollback off */
c->vc_visible_origin = c->vc_origin;
else {
- int vram_size = vga_vram_end - vga_vram_base;
int margin = c->vc_size_row * 4;
int ul, we, p, st;
@@ -969,7 +974,7 @@ static int vgacon_scrolldelta(struct vc_
we = vga_rolled_over + c->vc_size_row;
} else {
ul = 0;
- we = vram_size;
+ we = vga_vram_size;
}
p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
lines * c->vc_size_row;
@@ -1010,9 +1015,13 @@ static void vgacon_save_screen(struct vc
c->vc_x = ORIG_X;
c->vc_y = ORIG_Y;
}
+
+ /* We can't copy in more then the size of the video buffer,
+ * or we'll be copying in VGA BIOS */
+
if (!vga_is_gfx)
scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
- c->vc_screenbuf_size);
+ c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
}
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
Index: linux-2.6.11/drivers/video/geode/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/Makefile
@@ -0,0 +1,8 @@
+# Makefile for the Geode framebuffer
+
+EXTRA_CFLAGS += -Ilib/cimarron/ -DREAL_SILICON
+
+my-obj-$(CONFIG_FB_GEODE_LX) += geodefb_lx.o
+my-obj-$(CONFIG_FB_GEODE_ACCEL) += geodefb_lx_accel.o
+
+obj-$(CONFIG_FB_GEODE) += geodefb.o geodefb_modes.o geodefb_hw.o $(my-obj-y)
Index: linux-2.6.11/drivers/video/geode/build_num.h
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/build_num.h
@@ -0,0 +1,36 @@
+#ifndef BUILD_NUM_H
+#define BUILD_NUM_H
+
+#ifdef AMD_BUILDNUM_DEFINED
+#error "Caution: You have muliple version files in your path. Please correct this."
+#endif
+
+#define AMD_BUILDNUM_DEFINED
+
+/* Define the following for your driver */
+
+#define _NAME "AMD Geode LX Accelerated Framebuffer driver"
+#define _MAJOR 01
+#define _MINOR 03
+
+/* This defines the current buildlevel and revision of the code */
+#define _BL 01
+#define _BLREV 00
+
+#ifdef _BLREV
+#define _BUILDLEVEL _x(_BL)_x(_BLREV)
+#else
+#define _BUILDLEVEL _x(_BL)
+#endif
+
+/* Use this macro to get the version string */
+
+#define _VERSION_NUMBER _x(_MAJOR) "." _x(_MINOR) "." _BUILDLEVEL
+#define AMD_VERSION _NAME " " _VERSION_NUMBER
+
+/* Syntatic sugar for use above - you probably don't have to touch this */
+
+#define _x(s) _s(s)
+#define _s(s) #s
+
+#endif
Index: linux-2.6.11/drivers/video/geode/geodefb.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode framebuffer driver
+ * */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+/* module and KFB options */
+
+char vmode[15] = {0};
+int compression = 0; /* Compression support default off */
+int vfreq = 60; /* vertical refresh default 60 */
+int maxmem = (720 * 2 * 8192) / 1024; /* 12288K */
+int accel = 1;
+
+#ifdef CONFIG_FB_GEODE_PANEL
+int flatpanel = 1; /* Flatpanel support default off when FP is enabled */
+int fphwscale = 1; /* HW scaling default on when FP is enabled*/
+#endif
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc.");
+MODULE_DESCRIPTION("Accelerated Framebuffer driver for AMD Geode devices");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(vfreq, "i");
+MODULE_PARM_DESC(vfreq, "Set default video refresh rate");
+
+MODULE_PARM(vmode, "s");
+MODULE_PARM_DESC(vmode, "Set inital mode to x@refresh-bpp");
+
+MODULE_PARM(compression, "i");
+MODULE_PARM_DESC(compression, "Compression support (0=disabled or 1=enabled)");
+
+MODULE_PARM(maxmem, "i");
+MODULE_PARM_DESC(maxmem, "Maximum amount of memory to use for the FB (in K)");
+
+MODULE_PARM(accel, "i");
+MODULE_PARM_DESC(accel, "HW accleration support (0=disabled or 1=enabled)");
+
+#ifdef CONFIG_FB_GEODE_PANEL
+MODULE_PARM(flatpanel, "i");
+MODULE_PARM_DESC(flatpanel, "Flatpanel support (0=disabled or 1=enabled)");
+
+MODULE_PARM(fphwscale, "i");
+MODULE_PARM_DESC(fphwscale, "FP Hardware Scaling (0=disabled or 1=enabled)");
+#endif
+
+#endif
+
+#ifdef CONFIG_FB_GEODE_LX
+extern int lxfb_init(struct device *);
+extern void lxfb_cleanup(void);
+extern int lxfb_suspend(struct device *dev, u32 state, u32 level);
+extern int lxfb_resume(struct device *dev, u32 level);
+#endif
+
+struct geodefb_funcs {
+ int cpu;
+ int (*init)(struct device *);
+ void (*cleanup)(void);
+ int (*suspend)(struct device *, u32, u32);
+ int (*resume)(struct device *, u32);
+};
+
+static struct geodefb_funcs geode_cpus[] = {
+#ifdef CONFIG_FB_GEODE_LX
+ { CIM_CPU_GEODELX,
+ lxfb_init,
+ lxfb_cleanup,
+ lxfb_suspend,
+ lxfb_resume },
+#endif
+ { 0, NULL, NULL }
+};
+
+static struct geodefb_funcs *geodefb_cpu = 0;
+
+/* FIXME: __init? */
+
+static int detect_geode_cpu(void) {
+ unsigned long cpu, companion;
+ int f = 0;
+
+ /* This returns both the CPU and the companion chip */
+ init_detect_cpu(&cpu, &companion);
+
+ while(geode_cpus[f].cpu) {
+ if (geode_cpus[f].cpu == (cpu & 0xFF)) {
+ geodefb_cpu = &geode_cpus[f];
+ break;
+ }
+ f++;
+ }
+
+ if (!geodefb_cpu) {
+ printk(KERN_ERR "GEODEFB: Unknown CPU detected (%lx)n", cpu);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* FIXME: Don't build if we aren't a module? */
+
+#define TYPE_INT 0x1
+#define TYPE_STRING 0x2
+#define TYPE_FLAG 0x3
+
+struct geodefb_opts_t {
+ char *option;
+ int type;
+ void *ptr;
+ int size;
+};
+
+static struct geodefb_opts_t geodefb_options[] __initdata = {
+ { "vfreq", TYPE_INT, &vfreq, sizeof(vfreq) },
+ { "vmode", TYPE_STRING, vmode, sizeof(vmode) },
+ { "compression", TYPE_FLAG, &compression, 0 },
+ { "maxmem", TYPE_INT, &maxmem, sizeof(maxmem) },
+ { "accel", TYPE_FLAG, &accel, 0 },
+#ifdef CONFIG_FB_GEODE_PANEL
+ { "flatpanel", TYPE_FLAG, &flatpanel, 0 },
+ { "fphwscale", TYPE_FLAG, &fphwscale, 0 },
+#endif
+ { "", 0, 0 }
+};
+
+int __init
+geodefb_setup(char *options) {
+
+ char *opt;
+ int o;
+
+ if (!options || !*options)
+ return 0;
+
+ while((opt = strsep(&options, ","))) {
+ if (!*opt) continue;
+
+ for(o = 0; geodefb_options[o].type; o++) {
+ struct geodefb_opts_t *p = &geodefb_options[o];
+
+ if (p->type == TYPE_FLAG) {
+ int flag = 1;
+ char *ptr = opt;
+
+ /* Allow them to say "no */
+ if (!strncmp(ptr, "no", 2)) {
+ flag = 0;
+ ptr += 2;
+ }
+
+ if (!strcmp(ptr,p->option)) {
+ *((int *) p->ptr) = flag;
+ break;
+ }
+
+ } else {
+ if (strncmp(opt, p->option, strlen(p->option)))
+ continue;
+
+ if (*(opt + strlen(p->option)) != '=')
+ continue;
+
+ if (p->type == TYPE_INT) {
+ *((int *) p->ptr) =
+ simple_strtoul(opt + strlen(p->option) + 1, NULL, 0);
+ }
+ else if (p->type == TYPE_STRING) {
+ strncpy((char *) p->ptr, opt + strlen(p->option) + 1, p->size);
+ }
+
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int geodefb_suspend(struct device *dev, u32 state, u32 level) {
+ if (geodefb_cpu)
+ return geodefb_cpu->suspend(dev, state, level);
+ return 0;
+}
+
+static int geodefb_resume(struct device *dev, u32 level) {
+ if (geodefb_cpu)
+ return geodefb_cpu->resume(dev, level);
+ return 0;
+}
+
+static int __init
+geodefb_probe(struct device *device) {
+
+ if (detect_geode_cpu()) return -ENODEV;
+ return geodefb_cpu->init(device);
+}
+
+static struct device_driver geodefb_driver = {
+ .name = "geodefb",
+ .bus = &platform_bus_type,
+ .probe = geodefb_probe,
+ .suspend = geodefb_suspend,
+ .resume = geodefb_resume
+};
+
+static struct platform_device geodefb_device = {
+ .name = "geodefb",
+};
+
+
+int __init
+geodefb_init(void)
+{
+ char *option = NULL;
+ int ret;
+
+ if (fb_get_options("geodefb", &option))
+ return -ENODEV;
+
+ geodefb_setup(option);
+
+ ret = driver_register(&geodefb_driver);
+
+ if (!ret) {
+ ret = platform_device_register(&geodefb_device);
+
+ if (ret)
+ driver_unregister(&geodefb_driver);
+ }
+
+ return ret;
+}
+
+#ifdef MODULE
+void __exit
+geodefb_exit(void)
+{
+ if (geodefb_cpu)
+ geodefb_cpu->cleanup();
+}
+#endif
+
+module_init(geodefb_init);
+
+#ifdef MODULE
+module_exit(geodefb_exit);
+#endif
Index: linux-2.6.11/drivers/video/geode/geodefb.h
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode framebuffer header file
+ * */
+
+
+#ifndef GEODEFB_H_
+#define GEODEFB_H_
+
+#include
+
+#define GEODEFB_CRT_DEV 0x01
+#define GEODEFB_PANEL_DEV 0x02
+
+struct geodefb_panel_info {
+ int refresh;
+ int xres;
+ int yres;
+};
+
+
+struct geodefb_mode {
+ int xres;
+ int yres;
+ int refresh;
+ int depth;
+};
+
+#define FB_HZ 0
+#define FB_HTOTAL 1
+#define FB_VTOTAL 2
+#define FB_FREQ 3
+
+#define GEODEFB_GET_HZ(var) geodefb_get_timings(var, 0, FB_HZ)
+#define GEODEFB_GET_HTOTAL(var) geodefb_get_timings(var, 0, FB_HTOTAL)
+#define GEODEFB_GET_VTOTAL(var) geodefb_get_timings(var, 0, FB_VTOTAL)
+#define GEODEFB_GET_FREQ(var, hz) geodefb_get_timings(var, hz, FB_FREQ)
+
+unsigned int geodefb_get_devices(void);
+int geodefb_get_panel_info(struct geodefb_panel_info *);
+void geodefb_parse_mode(const char *, struct geodefb_mode *);
+int geodefb_get_timings(struct fb_var_screeninfo *var, int hz, int flag);
+
+#endif
Index: linux-2.6.11/drivers/video/geode/geodefb_hw.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb_hw.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode hardware specific routines
+ * */
+
+#include "geodefb.h"
+
+/* Device specific stuff */
+/* Each platform should define READ_VG */
+
+#ifdef CONFIG_FB_GEODE_LX
+
+#define READ_VG(reg) lx_read_vg(reg)
+
+extern void cim_outw(unsigned short port, unsigned short data);
+extern unsigned short cim_inw(unsigned short port);
+
+unsigned short lx_read_vg(unsigned char reg) {
+
+ unsigned short out;
+
+ cim_outw(0xAC1C, 0xFC53);
+ cim_outw(0xAC1C, 0x0200 | reg);
+
+ out = cim_inw(0xAC1E);
+
+ return out;
+}
+
+#endif
+
+#ifndef READ_VG
+#error "geodefb: No processor was selected - probably due to a corrupted config"
+#endif
+
+/* List of refresh values from the FP config register */
+
+static int geodefb_panel_refresh[7] =
+ { 60, 70, 72, 75, 85, 90, 100 };
+
+/* List of panel resolutiosn from the FP config register */
+
+static struct {
+ int xres;
+ int yres;
+} geodefb_panel_res[] = {
+ { 320, 240 },
+ { 640, 480 },
+ { 800, 600 },
+ { 1024, 768 },
+ { 1152, 864 },
+ { 1280, 1024 },
+ { 1600, 1200 }
+};
+
+int geodefb_get_panel_info(struct geodefb_panel_info *info) {
+
+ unsigned short reg = READ_VG(0x02);
+
+ /* refresh rate */
+
+ info->refresh = geodefb_panel_refresh[(reg >> 13) & 0x7];
+ info->xres = geodefb_panel_res[(reg >> 3) & 0x07].xres;
+ info->yres = geodefb_panel_res[(reg >> 3) & 0x07].yres;
+
+ return 0;
+}
+
+unsigned int geodefb_get_devices(void) {
+ unsigned short reg = READ_VG(0x0);
+
+ switch((reg >> 8) & 0x7) {
+ case 0:
+ return GEODEFB_CRT_DEV;
+
+ case 1:
+ return GEODEFB_PANEL_DEV;
+
+ case 5:
+ return GEODEFB_CRT_DEV | GEODEFB_PANEL_DEV;
+ }
+
+ return 0;
+}
Index: linux-2.6.11/drivers/video/geode/geodefb_lx.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb_lx.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode LX framebuffer driver
+ * */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* For the console notifier */
+#include
+
+#include
+
+#include
+#include
+
+#include "geodefb.h"
+#include "geodefb_lx.h"
+
+#include "build_num.h"
+
+extern char vmode[15];
+extern int compression;
+extern int vfreq;
+extern int maxmem;
+extern int accel;
+
+#ifdef CONFIG_FB_GEODE_PANEL
+extern int flatpanel;
+extern int fphwscale;
+static struct geodefb_panel_info panel_info;
+#endif
+
+/* Cimarron */
+
+extern void cim_outb(unsigned short port, unsigned char data);
+extern unsigned char cim_inb(unsigned short port);
+extern void cim_outw(unsigned short port, unsigned short data);
+
+extern struct notifier_block *console_notifier_list;
+
+/* Macros */
+
+#define LXFB_FBINFO_FLAGS (FBINFO_DEFAULT | \
+ FBINFO_HWACCEL_COPYAREA | \
+ FBINFO_HWACCEL_FILLRECT | \
+ FBINFO_HWACCEL_IMAGEBLIT | \
+ FBINFO_HWACCEL_XPAN | \
+ FBINFO_HWACCEL_YPAN)
+
+#define GEODEFB_DEFAULT_XRES 640
+#define GEODEFB_DEFAULT_YRES 480
+#define GEODEFB_DEFAULT_DEPTH 16
+
+/* Local variables */
+static struct fb_info *fbinfo;
+static int lxfb_palette[16];
+
+static int active_devices;
+
+static struct geodefb_mode initial_mode = {
+ xres: GEODEFB_DEFAULT_XRES,
+ yres: GEODEFB_DEFAULT_YRES,
+ depth: GEODEFB_DEFAULT_DEPTH
+};
+static struct geodefb_mode initial_mode;
+
+struct fb_fix_screeninfo lxfb_fix = {
+ id: "AMD LX",
+ type: FB_TYPE_PACKED_PIXELS,
+ visual: FB_VISUAL_TRUECOLOR,
+ xpanstep: 8,
+ ywrapstep: 1,
+ ypanstep: 0,
+ accel: FB_ACCEL_NONE
+};
+
+/* ======= Utility variables ======= */
+
+int
+lxfb_get_pitch(int xres, int bpp)
+{
+ int d = xres * (bpp >> 3);
+
+ if (d > 4096) return 8192;
+ if (d > 2048) return 4096;
+ if (d > 1024) return 2048;
+
+ return 1024;
+}
+
+static int
+lxfb_get_refresh(VG_DISPLAY_MODE *mode) {
+ switch(mode->internal_flags & VG_SUPPORTFLAG_HZMASK) {
+ case VG_SUPPORTFLAG_56HZ: return 56;
+ case VG_SUPPORTFLAG_60HZ: return 60;
+ case VG_SUPPORTFLAG_70HZ: return 70;
+ case VG_SUPPORTFLAG_72HZ: return 72;
+ case VG_SUPPORTFLAG_75HZ: return 75;
+ case VG_SUPPORTFLAG_85HZ: return 85;
+ case VG_SUPPORTFLAG_90HZ: return 90;
+ case VG_SUPPORTFLAG_100HZ: return 100;
+ }
+ return 60;
+}
+
+void
+lxfb_clear_active(struct lxfb_par *par, int xres, int yres, int bpp)
+{
+ int pitch = lxfb_get_pitch(xres,bpp);
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+ if (par->accel == ACCEL_ACTIVE) {
+ gp_declare_blt(0);
+ gp_set_raster_operation(0xF0);
+ gp_set_solid_pattern(0);
+ gp_set_strides(pitch, 0);
+
+ gp_pattern_fill(0, xres, yres);
+ gp_wait_blt_pending();
+ } else
+#endif
+ {
+ memset(par->fbvirt, 0, yres * pitch);
+ }
+}
+
+/* From 2.4 - check to see if the timings have changed */
+/* AUDIT: Is this still needed? */
+
+static int lxfb_timings_changed(struct fb_var_screeninfo *old,
+ struct fb_var_screeninfo *new) {
+
+ if (old->pixclock != new->pixclock) return 1;
+ if (old->left_margin != new->left_margin) return 1;
+ if (old->right_margin != new->right_margin) return 1;
+ if (old->upper_margin != new->upper_margin) return 1;
+ if (old->lower_margin != new->lower_margin) return 1;
+ if (old->hsync_len != new->hsync_len) return 1;
+ if (old->vsync_len != new->vsync_len) return 1;
+
+ return 0;
+}
+
+
+/* Not just timings - this should result in a fairly sane var structure */
+
+static void
+lxfb_set_timings(struct fb_var_screeninfo *var, int mnum) {
+
+ VG_DISPLAY_MODE mode;
+ vg_get_display_mode_information(mnum, &mode);
+
+ var->hsync_len = mode.hsyncend - mode.hsyncstart;
+ var->vsync_len = mode.vsyncend - mode.vsyncstart;
+
+ var->right_margin = var->left_margin =
+ (mode.htotal - mode.hactive - var->hsync_len) / 2;
+ var->upper_margin = var->lower_margin =
+ (mode.vtotal - mode.vactive - var->vsync_len) / 2;
+
+ var->pixclock = GEODEFB_GET_FREQ(var, lxfb_get_refresh(&mode));
+
+ var->sync = 0;
+
+ if (!(mode.flags & VG_MODEFLAG_NEG_HSYNC))
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ if (!(mode.flags & VG_MODEFLAG_NEG_VSYNC))
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if (mode.flags & VG_MODEFLAG_INTERLACED) {
+ var->vmode = FB_VMODE_INTERLACED;
+
+ if (mode.flags & VG_MODEFLAG_INT_LINEDOUBLE)
+ var->vmode |= FB_VMODE_DOUBLE;
+ }
+ else
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ var->width = var->height = -1;
+
+ switch (var->bits_per_pixel) {
+
+ case 8:
+ var->red.offset = 0;
+ var->red.length = 6;
+ var->red.msb_right = 0;
+ var->blue = var->green = var->red;
+ break;
+
+ case 16: /* 5-6-5 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+
+ case 32: /* A-8-8-8 */
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ break;
+ }
+
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ if (var->xoffset < 0) var->xoffset = 0;
+ if (var->yoffset < 0) var->yoffset = 0;
+
+ if (var->xoffset > var->xres_virtual - var->xres)
+ var->xoffset = var->xres_virtual - var->xres;
+
+ if (var->yoffset > var->yres_virtual - var->yres)
+ var->yoffset = var->yres_virtual - var->yres;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+}
+
+static void
+lxfb_set_mode(struct lxfb_par *par, struct fb_var_screeninfo *var) {
+
+ int bpp = var->bits_per_pixel;
+ int hz = GEODEFB_GET_HZ(var);
+
+ if (compression)
+ vg_set_compression_enable(0);
+
+#ifdef CONFIG_FB_GEODE_PANEL
+ if (active_devices & GEODEFB_PANEL_DEV) {
+ int axres = var->xres, ayres = var->yres;
+ int flags = (active_devices & GEODEFB_CRT_DEV) ? VG_MODEFLAG_CRT_AND_FP : 0;
+
+ if (fphwscale && panel_info.xres >= var->xres && var->xres <= 1024) {
+ axres = panel_info.xres;
+ ayres = panel_info.yres;
+ }
+
+ vg_set_panel_mode(var->xres, var->yres, axres, ayres,
+ panel_info.xres, panel_info.yres, bpp, flags);
+
+ vg_set_border_color(0x0); /* Make sure the border is clear */
+ }
+ else if (active_devices & GEODEFB_CRT_DEV)
+#endif
+ {
+ vg_set_display_mode(var->xres, var->yres,
+ var->xres, var->yres, bpp, hz, 0);
+
+ }
+
+ if (var->xres_virtual > var->xres)
+ vg_set_display_pitch(lxfb_get_pitch(var->xres_virtual, bpp));
+
+ df_set_crt_enable(DF_CRT_ENABLE);
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+ gp_set_bpp(bpp);
+#endif
+
+ lxfb_clear_active(par, var->xres_virtual, var->yres_virtual, bpp);
+
+ /* Try to turn on compression if we can */
+ /* We do not enable compresssion if panning is even possible */
+
+ if (compression && var->xres_virtual == var->xres &&
+ var->yres_virtual == var->yres) {
+ VG_COMPRESSION_DATA data;
+
+ data.pitch = 544;
+ data.size = 544;
+ data.compression_offset = var->yres * lxfb_get_pitch(var->xres, bpp);
+ vg_configure_compression(&data);
+
+ vg_set_compression_enable(1);
+ }
+
+ par->vfreq = hz;
+};
+
+static int
+lxfb_find_mode(struct lxfb_par *par, struct fb_var_screeninfo *var,
+ struct geodefb_mode *mode) {
+
+ VG_QUERY_MODE query;
+ int mnum = 0;
+
+ query.query_flags = VG_QUERYFLAG_BPP | VG_QUERYFLAG_REFRESH;
+ query.bpp = mode->depth;
+
+#ifdef CONFIG_FB_GEODE_PANEL
+ if (active_devices & GEODEFB_PANEL_DEV) {
+ query.query_flags |= VG_QUERYFLAG_PANEL;
+ query.query_flags |= VG_QUERYFLAG_PANELWIDTH | VG_QUERYFLAG_PANELHEIGHT;
+ query.panel_width = panel_info.xres;
+ query.panel_height = panel_info.yres;
+
+ query.hz = panel_info.refresh;
+ } else
+#endif
+ {
+ query.query_flags |= VG_QUERYFLAG_ACTIVEWIDTH | VG_QUERYFLAG_ACTIVEHEIGHT;
+
+ query.active_width = mode->xres;
+ query.active_height = mode->yres;
+ query.hz = mode->refresh;
+ }
+
+ mnum = vg_get_display_mode_index(&query);
+ if (mnum < 0) return -EINVAL;
+
+ var->xres_virtual = var->xres = mode->xres;
+ var->yres_virtual = var->yres = mode->yres;
+
+ if (mode->depth <= 8)
+ var->bits_per_pixel = 8;
+ else if (mode->depth <= 16)
+ var->bits_per_pixel = 16;
+ else if (mode->depth <= 32)
+ var->bits_per_pixel = 32;
+
+ lxfb_set_timings(var, mnum);
+
+ if (par->accel & ACCEL_AVAILABLE_MASK)
+ var->accel_flags = 1;
+
+ return 0;
+}
+
+/* ======= FB Functions ======= */
+
+static int
+lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) {
+
+ struct lxfb_par *par = (struct lxfb_par *) info->par;
+ VG_QUERY_MODE query;
+ int mode;
+ unsigned int mem;
+
+ /* Adjust the bpp if it comes in screwy */
+
+ if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel <= 32)
+ var->bits_per_pixel = 32;
+
+ /* See if we have enough room for this mode */
+
+ mem = lxfb_get_pitch(var->xres, var->bits_per_pixel) * var->yres;
+
+ if (mem > par->fbsize)
+ return -EINVAL;
+
+ query.query_flags = VG_QUERYFLAG_BPP | VG_QUERYFLAG_REFRESH;
+ query.bpp = var->bits_per_pixel;
+
+#ifdef CONFIG_FB_GEODE_PANEL
+ if (active_devices & GEODEFB_PANEL_DEV) {
+ query.query_flags |= VG_QUERYFLAG_PANEL;
+ query.query_flags |= VG_QUERYFLAG_PANELWIDTH | VG_QUERYFLAG_PANELHEIGHT;
+ query.panel_width = panel_info.xres;
+ query.panel_height = panel_info.yres;
+ query.hz = panel_info.refresh;
+ }
+ else if (active_devices & GEODEFB_CRT_DEV)
+#endif
+ {
+ query.query_flags |= VG_QUERYFLAG_ACTIVEWIDTH | VG_QUERYFLAG_ACTIVEHEIGHT;
+
+ query.active_width = var->xres;
+ query.active_height = var->yres;
+
+ if (lxfb_timings_changed(&info->var, var))
+ query.hz = GEODEFB_GET_HZ(var);
+ else
+ query.hz = par->vfreq;
+ }
+
+ mode = vg_get_display_mode_index(&query);
+
+ if (mode < 0)
+ return -EINVAL;
+
+ /* Set up the timing tables correctly for the given mode */
+ lxfb_set_timings(var, mode);
+
+ /* Don't allow acceleration, even if the user asks for it */
+
+ if (!(par->accel & ACCEL_AVAILABLE_MASK))
+ var->accel_flags = 0;
+
+ return 0;
+}
+
+static int
+lxfb_set_par(struct fb_info *info) {
+
+ struct lxfb_par *par = (struct lxfb_par *) info->par;
+
+ if (par->accel & ACCEL_ACTIVE_MASK)
+ par->accel = ACCEL_NOT_READY;
+
+ /* Set up the pointers before we try to set the mode */
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+ if (info->var.accel_flags && (par->accel & ACCEL_AVAILABLE_MASK)) {
+ gp_set_frame_buffer_base (par->fbphys, par->fbsize);
+ gp_set_command_buffer_base(par->gpphys, 0, par->gpsize);
+ }
+#endif
+
+ lxfb_set_mode(par, &info->var);
+
+ info->fix.line_length = lxfb_get_pitch(info->var.xres_virtual,
+ info->var.bits_per_pixel);
+ info->fix.visual = (info->var.bits_per_pixel == 8)
+ ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+ info->cmap.len = (info->var.bits_per_pixel == 8) ? 256 : 16;
+
+ if (info->var.accel_flags) {
+ if (par->accel == ACCEL_NOT_READY || par->accel == ACCEL_USER_DISABLED)
+ par->accel = ACCEL_ACTIVE;
+ }
+ else {
+ if (par->accel == ACCEL_NOT_READY)
+ par->accel = ACCEL_USER_DISABLED;
+ }
+
+ return 0;
+}
+
+static int
+lxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info) {
+
+ if ((info->var.bits_per_pixel == 8 && regno > 255) || regno > 15)
+ return 1;
+
+ switch(info->var.bits_per_pixel) {
+ case 8: {
+ u32 color = ((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ vg_set_display_palette_entry(regno, color);
+ vg_set_display_palette_entry(regno ^ 0xFF, color ^ 0xFFFFFF);
+ }
+ break;
+
+ case 16:
+ ((u32*)info->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ break;
+
+ case 32:
+ ((u32*)info->pseudo_palette)[regno] =
+ ((transp & 0xFF00) <<16) |
+ ((red & 0xFF00) << 8) |
+ ((green & 0xFF00)) |
+ ((blue & 0xFF00)>>8);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+lxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) {
+
+ u32 offset = 0;
+
+ if (var->xoffset < 0 || var->xres + var->xoffset > var->xres_virtual)
+ return -EINVAL;
+
+ if (var->xoffset < 0 || var->yres + var->yoffset > var->yres_virtual)
+ return -EINVAL;
+
+ /* Calculate the fb offset */
+
+ offset = (var->yoffset * vg_get_display_pitch()) +
+ (var->xoffset * (var->bits_per_pixel >> 3));
+
+ vg_set_display_offset(offset);
+ return 0;
+}
+
+static int
+lxfb_blank(int blank_mode, struct fb_info *info) {
+
+#ifdef CONFIG_FB_GEODE_PANEL
+ /* Blank the panel if we have one attached */
+
+ if (active_devices & GEODEFB_PANEL_DEV)
+ df_set_panel_enable( (blank_mode) ? 0 : 1);
+#endif
+
+ switch(blank_mode) {
+ case VESA_POWERDOWN:
+ df_set_crt_enable(DF_CRT_DISABLE);
+ break;
+
+ case VESA_VSYNC_SUSPEND:
+ df_set_crt_enable(DF_CRT_SUSPEND);
+ break;
+
+ case VESA_HSYNC_SUSPEND:
+ df_set_crt_enable(DF_CRT_STANDBY);
+ break;
+
+ default:
+ df_set_crt_enable(DF_CRT_ENABLE);
+ break;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+
+int lxfb_sync(struct fb_info *info) {
+ struct lxfb_par *par = (struct lxfb_par *) info->par;
+
+ if (par->accel == ACCEL_ACTIVE)
+ gp_wait_blt_pending();
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+void lxfb_imageblit(struct fb_info *, const struct fb_image *);
+void lxfb_copyarea(struct fb_info *, const struct fb_copyarea *);
+void lxfb_fillrect(struct fb_info *, const struct fb_fillrect *);
+#endif
+
+static struct fb_ops lxfb_fb_ops = {
+ owner: THIS_MODULE,
+
+ fb_setcolreg: lxfb_setcolreg,
+ fb_check_var: lxfb_check_var,
+ fb_set_par: lxfb_set_par,
+ fb_pan_display: lxfb_pan_display,
+ fb_blank: lxfb_blank,
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+ fb_fillrect: lxfb_fillrect,
+ fb_copyarea: lxfb_copyarea,
+ fb_imageblit: lxfb_imageblit,
+ fb_sync: lxfb_sync,
+#else
+ fb_fillrect: cfb_fillrect,
+ fb_copyarea: cfb_copyarea,
+ fb_imageblit: cfb_imageblit,
+#endif
+
+ fb_cursor: soft_cursor,
+};
+
+static int
+lxfb_mem_init(struct lxfb_par *par)
+{
+ int ret;
+
+ par->fbsize = (maxmem * 1024);
+ if (par->fbsize > cim_get_fb_active())
+ par->fbsize = cim_get_fb_active();
+
+ KWRN("Allocating %dK of framebuffer memory\n", par->fbsize / 1024);
+
+ par->fbphys = cim_get_fb_base();
+ par->fbvirt = cim_get_fb_ptr();
+
+ ret = cim_get_memory("geodefb", "framebuffer", par->fbsize, CIM_F_PUBLIC);
+ if (!ret) return -ENOMEM;
+
+ /* Set up acceleration - if this fails, its not fatal */
+
+#ifdef CONFIG_FB_GEODE_ACCEL
+ if (accel) {
+ par->gpphys = cim_get_cmd_base();
+ par->gpsize = cim_get_cmd_size();
+
+ if (par->gpphys)
+ par->accel = ACCEL_NOT_READY;
+ }
+#endif
+
+ return 0;
+}
+
+static GP_SAVE_RESTORE gpsave;
+static VG_SAVE_RESTORE vgsave;
+static DF_SAVE_RESTORE dfsave;
+
+int lxfb_suspend(struct device *dev, u32 state, u32 level) {
+
+ if (level == SUSPEND_POWER_DOWN) {
+#ifdef CONFIG_FB_GEODE_PANEL
+ if (active_devices & GEODEFB_PANEL_DEV)
+ df_set_panel_enable(0);
+#endif
+ df_set_crt_enable(DF_CRT_DISABLE);
+
+ gp_save_state(&gpsave);
+ vg_save_state(&vgsave);
+ df_save_state(&dfsave);
+ }
+
+ return 0;
+}
+
+int lxfb_resume(struct device *dev, u32 level) {
+
+ if (level == RESUME_ENABLE) {
+ vg_restore_state(&vgsave);
+ gp_restore_state(&gpsave);
+ df_restore_state(&dfsave);
+
+ df_set_crt_enable(DF_CRT_ENABLE);
+
+#ifdef CONFIG_FB_GEODE_PANEL
+ if (active_devices & GEODEFB_PANEL_DEV)
+ df_set_panel_enable(1);
+#endif
+ }
+
+ return 0;
+}
+
+static int
+lxfb_console_notify(struct notifier_block *self,
+ unsigned long action, void *data) {
+
+ struct lxfb_par *par = (struct lxfb_par *) fbinfo->par;
+
+ if (action == CONSOLE_EVENT_SWITCH_TEXT) {
+
+ if (par->accel == ACCEL_KERNEL_DISABLED) {
+ gp_set_frame_buffer_base (par->fbphys, par->fbsize);
+ gp_set_command_buffer_base(par->gpphys, 0, par->gpsize);
+
+ par->accel = ACCEL_ACTIVE;
+ }
+ }
+ else if (action == CONSOLE_EVENT_SWITCH_GRAPHICS) {
+ if (par->accel == ACCEL_ACTIVE) {
+ gp_wait_blt_pending();
+ par->accel = ACCEL_KERNEL_DISABLED;
+ }
+ }
+
+ return 0;
+}
+
+static struct notifier_block lxfb_console_notifier = {
+ .notifier_call = lxfb_console_notify,
+};
+
+int __init
+lxfb_init(struct device *device)
+{
+ int ret, parsed = 0;
+ struct platform_device *dev = to_platform_device(device);
+
+ fbinfo = framebuffer_alloc(sizeof(struct lxfb_par), &dev->dev);
+
+ if (!fbinfo) {
+ KERR("Unable to allocatethe framebuffer memory.\n");
+ return -ENOMEM;
+ }
+
+ active_devices = geodefb_get_devices();
+
+ initial_mode.refresh = vfreq;
+
+ if (vmode[0] != 0) {
+ geodefb_parse_mode(vmode, &initial_mode);
+ parsed = 1;
+ }
+
+#ifdef CONFIG_FB_GEODE_PANEL
+ if (active_devices & GEODEFB_PANEL_DEV) {
+
+ if (flatpanel) {
+ geodefb_get_panel_info(&panel_info);
+ if (!parsed) {
+ initial_mode.xres = panel_info.xres;
+ initial_mode.yres = panel_info.yres;
+ }
+ initial_mode.refresh = panel_info.refresh;
+ KWRN("TFT support enabled.");
+ }
+ else
+ active_devices &= ~GEODEFB_PANEL_DEV;
+ }
+#endif
+
+ if (lxfb_mem_init((struct lxfb_par *) fbinfo->par)) {
+ KERR("Unable to initialize the graphics engine.\n");
+ kfree(fbinfo);
+ return -ENODEV;
+ }
+
+ fbinfo->screen_base = ((struct lxfb_par *) fbinfo->par)->fbvirt;
+ fbinfo->fbops = &lxfb_fb_ops;
+ fbinfo->fix = lxfb_fix;
+ fbinfo->pseudo_palette = lxfb_palette;
+
+ /* Since we have a nifty screen to screen blit, we use that for
+ scrolling - look ma, no bus!
+ */
+
+ fbinfo->flags = LXFB_FBINFO_FLAGS | FBINFO_READS_FAST;
+
+ ret = lxfb_find_mode(fbinfo->par, &fbinfo->var, &initial_mode);
+
+ if (ret < 0) {
+ KERR("Invalid mode %dx%d@%d-%d\n", initial_mode.xres, initial_mode.yres,
+ initial_mode.refresh, initial_mode.depth);
+
+ return -EINVAL;
+ }
+
+ KWRN("Initial mode: %dx%d@%d-%d\n",
+ initial_mode.xres, initial_mode.yres,
+ initial_mode.refresh, initial_mode.depth);
+
+ fbinfo->var.activate |= FB_ACTIVATE_NOW;
+
+ fb_alloc_cmap(&fbinfo->cmap, 256, 0);
+
+ /* ==== register ==== */
+
+ notifier_chain_register(&console_notifier_list,
+ &lxfb_console_notifier);
+
+ if (register_framebuffer(fbinfo) < 0) {
+ framebuffer_release(fbinfo);
+ KERR("Unable to register the framebuffer\n");
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s\n", AMD_VERSION);
+ return 0;
+}
+
+void __exit
+lxfb_cleanup(void) {
+ notifier_chain_unregister(&console_notifier_list,
+ &lxfb_console_notifier);
+
+ unregister_framebuffer((struct fb_info *) fbinfo);
+ framebuffer_release(fbinfo);
+}
+
+
Index: linux-2.6.11/drivers/video/geode/geodefb_lx.h
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb_lx.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode LX framebuffer header file
+ * */
+
+#ifndef GEODEFB_LX_H_
+#define GEODEFB_LX_H_
+
+#define KERR(str, args...) printk(KERN_ERR "geodefb-lx: " str, ##args)
+#define KWRN(str, args...) printk(KERN_INFO "geodefb-lx: " str, ##args)
+
+/* bit 0: acceleration available
+ bit 1: acceleration active
+ bit 2: acceleration suspended by kernel
+ bit 3: acceleration suspended by user
+*/
+
+#define ACCEL_OFF 0x0 /* Accleration not available */
+#define ACCEL_NOT_READY 0x1 /* Acceleration is available but the engine isn't set up yet */
+#define ACCEL_ACTIVE 0x3 /* Accleration is active */
+#define ACCEL_KERNEL_DISABLED 0x5 /* Acceleration has been turned off by the kernel */
+#define ACCEL_USER_DISABLED 0x9 /* Acceleration has been turned off by the user */
+
+#define ACCEL_AVAILABLE_MASK 0x1
+#define ACCEL_ACTIVE_MASK 0x2
+
+struct lxfb_par {
+ int accel;
+ unsigned long fbphys; /* The physical address of the FB */
+ char *fbvirt; /* The virtual address of the FB */
+ int fbsize; /* The size of the FB */
+
+ unsigned long gpphys; /* The physical address of the GP */
+ int gpsize; /* The size of the GP */
+
+ int vfreq;
+};
+
+#endif
Index: linux-2.6.11/drivers/video/geode/geodefb_lx_accel.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb_lx_accel.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode LX acceleration routines
+ * */
+
+#include
+#include
+#include
+
+#include
+
+#include "geodefb.h"
+#include "geodefb_lx.h"
+
+extern int lxfb_get_pitch(int, int);
+
+/* Matches ROP_ defines in fb.h */
+static unsigned char lx_rops[] = { 0xF0, 0x55 };
+
+void
+lxfb_imageblit(struct fb_info *info, const struct fb_image *image) {
+
+ struct lxfb_par *par = (struct lxfb_par *) info->par;
+ int pitch = lxfb_get_pitch(info->var.xres_virtual, info->var.bits_per_pixel);
+ u32 dst = (image->dy * pitch) + (image->dx * (info->var.bits_per_pixel >> 3));
+
+ if (par->accel != ACCEL_ACTIVE) {
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ if (image->depth == 1) {
+ u32 fg = 0, bg = 0;
+
+ switch(info->var.bits_per_pixel) {
+ case 8:
+ bg = image->bg_color;
+ fg = image->fg_color;
+ break;
+
+ case 16:
+ case 32:
+ bg = ((u32 *) info->pseudo_palette)[image->bg_color];
+ fg = ((u32 *) info->pseudo_palette)[image->fg_color];
+ break;
+ }
+
+ gp_declare_blt(0);
+ gp_set_raster_operation(0xCC);
+ gp_set_strides(pitch, 0);
+ gp_set_mono_source(bg, fg, 0);
+
+ gp_mono_bitmap_to_screen_blt(dst, 0,
+ image->width, image->height,
+ (unsigned char *) image->data,
+ image->width / 8);
+ } else if (image->depth == info->var.bits_per_pixel) {
+
+ gp_declare_blt(0);
+ gp_set_raster_operation(0xCC);
+ gp_set_strides(pitch, 0);
+
+ gp_color_bitmap_to_screen_blt(dst, 0, image->width, image->height,
+ (unsigned char *) image->data,
+ image->width * (image->depth >> 3));
+ }
+ else {
+ int flags = 0;
+
+ if (image->depth == 8) {
+ u32 colors[256];
+ memcpy(colors, (u32 *) info->pseudo_palette, 256 * sizeof(u32));
+
+ gp_program_lut((unsigned long *) colors, 1);
+ flags = CIMGP_BLTFLAGS_PRES_LUT;
+ }
+
+ gp_declare_blt(flags);
+ gp_set_raster_operation(0xCC);
+ gp_set_strides(pitch, 0);
+
+ switch(image->depth) {
+ case 8:
+ gp_set_source_format(CIMGP_SOURCE_FMT_8BPP_INDEXED);
+ break;
+ case 16:
+ gp_set_source_format(CIMGP_SOURCE_FMT_0_5_6_5);
+ break;
+ case 32:
+ gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
+ break;
+ }
+
+ gp_color_convert_blt(dst, 0, image->width, image->height,
+ (unsigned char *) image->data,
+ image->width * (image->depth >> 3));
+ }
+}
+
+void
+lxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) {
+
+ struct lxfb_par *par = (struct lxfb_par *) info->par;
+ int pitch = lxfb_get_pitch(info->var.xres_virtual, info->var.bits_per_pixel);
+ int flags = 0;
+
+ u32 src = (area->sy * pitch) + (area->sx * (info->var.bits_per_pixel >> 3));
+ u32 dst = (area->dy * pitch) + (area->dx * (info->var.bits_per_pixel >> 3));
+
+ if (par->accel != ACCEL_ACTIVE) {
+ cfb_copyarea(info, area);
+ return;
+ }
+
+ gp_declare_blt(0);
+ gp_set_raster_operation(0xCC);
+ gp_set_strides(pitch, pitch);
+ gp_set_solid_pattern(0);
+
+ if (area->dx > area->sx) flags |= CIMGP_NEGXDIR;
+ if (area->dy > area->sy) flags |= CIMGP_NEGYDIR;
+
+ gp_screen_to_screen_blt(dst, src, area->width, area->height, flags);
+}
+
+void
+lxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) {
+
+ struct lxfb_par *par = (struct lxfb_par *) info->par;
+ int pitch = lxfb_get_pitch(info->var.xres_virtual, info->var.bits_per_pixel);
+ u32 dst = (rect->dy * pitch) + (rect->dx * (info->var.bits_per_pixel >> 3));
+
+ if (par->accel != ACCEL_ACTIVE) {
+ cfb_fillrect(info, rect);
+ return;
+ }
+
+ gp_declare_blt(0);
+ gp_set_raster_operation(lx_rops[rect->rop]);
+
+ if (lx_rops[rect->rop] != 0x55)
+ gp_set_solid_pattern(rect->color);
+
+ gp_set_strides(pitch, 0);
+
+ gp_pattern_fill(dst, rect->width, rect->height);
+}
Index: linux-2.6.11/drivers/video/geode/geodefb_modes.c
===================================================================
--- /dev/null
+++ linux-2.6.11/drivers/video/geode/geodefb_modes.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING
+ * */
+/*
+ * */
+/*
+ * Geode framebuffer header file
+ * */
+
+#include
+#include "geodefb.h"
+
+void geodefb_parse_mode(const char *string, struct geodefb_mode *mode) {
+
+ char *next, *ptr = (char *) string;
+ int values[4] = { -1, -1, -1, -1 };
+ int flag = 0;
+
+ while(*ptr) {
+ switch(*ptr) {
+ case 'x':
+ flag = 1;
+ ptr++;
+ break;
+ case '@':
+ flag = 2;
+ ptr++;
+ break;
+ case '-':
+ flag = 3;
+ ptr++;
+ break;
+ case '0'...'9':
+ values[flag] = simple_strtoul(ptr, &next, 0);
+ ptr = next;
+ break;
+ }
+ }
+
+ if (values[0] != -1) mode->xres = values[0];
+ if (values[1] != -1) mode->yres = values[1];
+ if (values[2] != -1) mode->refresh = values[2];
+ if (values[3] != -1) mode->depth = values[3];
+}
+
+/* from fb.modes:
+ P = 1E12 / (V*F*H)
+ F = 1E12 / (V*P*H)
+
+ where P=pixclock, F=frequency, V=vtotal, H=htotal
+*/
+
+/* We can only use 32 bit integers, so we split 1E12 into something
+ more manageable */
+
+static inline int VAR2FREQ(int htotal, int vtotal, int refresh) {
+ unsigned long h;
+
+ h = 1953125000 / htotal;
+ h = h * 512 / refresh;
+ return (int) (h / vtotal);
+}
+
+static inline int VAR2HZ(int htotal, int vtotal, int pixclock) {
+ unsigned long v;
+
+ v = 488281250 / htotal;
+ v = v * 2048 / vtotal;
+ return (int) ((((v * 100) / pixclock) + 50) / 100);
+}
+
+static int HTOTAL(struct fb_var_screeninfo *var) {
+ return (var->left_margin + var->xres + var->right_margin + var->hsync_len);
+}
+
+static int VTOTAL(struct fb_var_screeninfo *var) {
+ return (var->upper_margin + var->yres + var->lower_margin + var->vsync_len);
+}
+
+int geodefb_get_timings(struct fb_var_screeninfo *var, int hz, int flag) {
+
+ unsigned int htotal = HTOTAL(var);
+ unsigned int vtotal = VTOTAL(var);
+
+ switch(flag) {
+ case FB_HTOTAL: return htotal;
+ case FB_VTOTAL: return vtotal;
+ case FB_HZ: return VAR2HZ(htotal, vtotal, var->pixclock);
+ case FB_FREQ: return VAR2FREQ(htotal, vtotal, hz);
+ }
+
+ return -1;
+}
Index: linux-2.6.11/include/asm-i386/module.h
===================================================================
--- linux-2.6.11.orig/include/asm-i386/module.h
+++ linux-2.6.11/include/asm-i386/module.h
@@ -36,6 +36,10 @@ struct mod_arch_specific
#define MODULE_PROC_FAMILY "K7 "
#elif defined CONFIG_MK8
#define MODULE_PROC_FAMILY "K8 "
+#elif defined CONFIG_MGEODE_GX
+#define MODULE_PROC_FAMILY "GEODE_GX "
+#elif defined CONFIG_MGEODE_LX
+#define MODULE_PROC_FAMILY "GEODE_GX "
#elif defined CONFIG_X86_ELAN
#define MODULE_PROC_FAMILY "ELAN "
#elif defined CONFIG_MCRUSOE
Index: linux-2.6.11/include/linux/i2c.h
===================================================================
--- linux-2.6.11.orig/include/linux/i2c.h
+++ linux-2.6.11/include/linux/i2c.h
@@ -55,7 +55,7 @@ extern int i2c_master_recv(struct i2c_cl
/* Transfer num messages.
*/
-extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num);
+extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,int num);
/*
* Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor.
@@ -194,7 +194,7 @@ struct i2c_algorithm {
to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
using common I2C messages */
- int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[],
+ int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
Index: linux-2.6.11/include/linux/pci_ids.h
===================================================================
--- linux-2.6.11.orig/include/linux/pci_ids.h
+++ linux-2.6.11/include/linux/pci_ids.h
@@ -388,6 +388,13 @@
#define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510
#define PCI_DEVICE_ID_NS_87410 0xd001
+#define PCI_DEVICE_ID_NS_CS5535_HOST_BRIDGE 0x0028
+#define PCI_DEVICE_ID_NS_CS5535_ISA_BRIDGE 0x002b
+#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d
+#define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e
+#define PCI_DEVICE_ID_NS_CS5535_USB 0x002f
+#define PCI_DEVICE_ID_NS_CS5535_VIDEO 0x0030
+
#define PCI_VENDOR_ID_TSENG 0x100c
#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202
#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205
@@ -513,6 +520,18 @@
#define PCI_DEVICE_ID_AMD_8151_0 0x7454
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7450
+#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
+#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
+
+#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
+#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
+#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
+#define PCI_DEVICE_ID_AMD_CS5536_OHC 0x2094
+#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095
+#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
+#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
+
#define PCI_VENDOR_ID_TRIDENT 0x1023
#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
Index: linux-2.6.11/include/linux/vt_kern.h
===================================================================
--- linux-2.6.11.orig/include/linux/vt_kern.h
+++ linux-2.6.11/include/linux/vt_kern.h
@@ -97,4 +97,10 @@ void reset_vc(unsigned int new_console);
extern char con_buf[CON_BUF_SIZE];
extern struct semaphore con_buf_sem;
+/* Called when we switch KD_TEXT in vt_ioctl */
+#define CONSOLE_EVENT_SWITCH_TEXT 0x01
+
+/* Called when we switch to KD_GRaPHICS in vt_ioctl */
+#define CONSOLE_EVENT_SWITCH_GRAPHICS 0x02
+
#endif /* _VT_KERN_H */
Index: linux-2.6.11/lib/Kconfig
===================================================================
--- linux-2.6.11.orig/lib/Kconfig
+++ linux-2.6.11/lib/Kconfig
@@ -30,6 +30,15 @@ config LIBCRC32C
require M here. See Castagnoli93.
Module will be libcrc32c.
+config CIMARRON
+ tristate "AMD LX graphics abstraction layer (Cimarron)"
+ depends on MGEODE_LX
+ default n
+ help
+ This option is provided for the case where no in-kernel-tree
+ modules require the AMD LX graphics HAL, but a module built
+ ouside of the kernel does.
+
#
# compression support is select'ed if needed
#
Index: linux-2.6.11/lib/Makefile
===================================================================
--- linux-2.6.11.orig/lib/Makefile
+++ linux-2.6.11/lib/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
+obj-$(CONFIG_CIMARRON) += cimarron/
hostprogs-y := gen_crc32table
clean-files := crc32table.h
Index: linux-2.6.11/lib/cimarron/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.11/lib/cimarron/Makefile
@@ -0,0 +1,5 @@
+EXTRA_CFLAGS += -Ilib/cimarron/cim -DREAL_SILICON
+
+obj-$(CONFIG_CIMARRON) := cimarron.o
+cimarron-objs := cim_mod.o cim_dev.o cim_mem.o cimapi.o
+
Index: linux-2.6.11/lib/cimarron/build_num.h
===================================================================
--- /dev/null
+++ linux-2.6.11/lib/cimarron/build_num.h
@@ -0,0 +1,36 @@
+#ifndef BUILD_NUM_H
+#define BUILD_NUM_H
+
+#ifdef AMD_BUILDNUM_DEFINED
+#error "Caution: You have muliple version files in your path. Please correct this."
+#endif
+
+#define AMD_BUILDNUM_DEFINED
+
+/* Define the following for your driver */
+
+#define _NAME "AMD LX Cimarron Support Module"
+#define _MAJOR 01
+#define _MINOR 03
+
+/* This defines the current buildlevel and revision of the code */
+#define _BL 01
+#define _BLREV 00
+
+#ifdef _BLREV
+#define _BUILDLEVEL _x(_BL)_x(_BLREV)
+#else
+#define _BUILDLEVEL _x(_BL)
+#endif
+
+/* Use this macro to get the version string */
+
+#define _VERSION_NUMBER _x(_MAJOR) "." _x(_MINOR) "." _BUILDLEVEL
+#define AMD_VERSION _NAME " " _VERSION_NUMBER
+
+/* Syntatic sugar for use above - you probably don't have to touch this */
+
+#define _x(s) _s(s)
+#define _s(s) #s
+
+#endif
Index: linux-2.6.11/lib/cimarron/cim/cim_defs.h
===================================================================
--- /dev/null
+++ linux-2.6.11/lib/cimarron/cim/cim_defs.h
@@ -0,0 +1,717 @@
+ /*
+ *
+ * Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ *
+ *
+ *
+ *
+ *
+ * Cimarron hardware access macros.
+ *
+ *
+ */
+
+#ifndef _cim_defs_h
+#define _cim_defs_h
+
+/*-----------------------------------------*/
+/* MEMORY ACCESS MACROS */
+/*-----------------------------------------*/
+
+#ifndef CIMARRON_EXCLUDE_REGISTER_ACCESS_MACROS
+
+#define READ_GP32(offset) \
+ (*(volatile unsigned long *)(cim_gp_ptr + (offset)))
+
+#define READ_REG32(offset) \
+ (*(volatile unsigned long *)(cim_vg_ptr + (offset)))
+
+#define READ_FB32(offset) \
+ (*(volatile unsigned long *)(cim_fb_ptr + (offset)))
+
+#define WRITE_GP32(offset, value) \
+ (*(volatile unsigned long *)(cim_gp_ptr + (offset))) = (value)
+
+#define WRITE_REG32(offset, value) \
+ (*(volatile unsigned long *)(cim_vg_ptr + (offset))) = (value)
+
+#define WRITE_COMMAND32(offset, value) \
+ (*(unsigned long *)(cim_cmd_ptr + (offset))) = (value)
+
+#define WRITE_COMMAND8(offset, value) \
+ (*(unsigned char *)(cim_cmd_ptr + (offset))) = (value)
+
+#define WRITE_FB32(offset, value) \
+ (*(unsigned long *)(cim_fb_ptr + (offset))) = (value)
+
+#define READ_VID32(offset) \
+ (*(volatile unsigned long *)(cim_vid_ptr + (offset)))
+
+#define WRITE_VID32(offset, value) \
+ (*(volatile unsigned long *)(cim_vid_ptr + (offset))) = (value)
+
+#define READ_VIP32(offset) \
+ (*(volatile unsigned long *)(cim_vip_ptr + (offset)))
+
+#define WRITE_VIP32(offset, value) \
+ (*(volatile unsigned long *)(cim_vip_ptr + (offset))) = (value)
+
+#define READ_VOP32(offset) \
+ (*(volatile unsigned long *)(cim_vid_ptr + (offset)))
+
+#define WRITE_VOP32(offset, value) \
+ (*(volatile unsigned long *)(cim_vid_ptr + (offset))) = (value)
+
+#endif
+
+/*-----------------------------------------*/
+/* GP POLLING MACROS */
+/*-----------------------------------------*/
+
+#define GP3_WAIT_WRAP(variable) \
+ while(((variable = READ_GP32 (GP3_CMD_READ)) > gp3_cmd_current) || \
+ (variable <= (gp3_cmd_top + GP3_BLT_COMMAND_SIZE + GP3_BLT_COMMAND_SIZE + 96)))
+
+#define GP3_WAIT_PRIMITIVE(variable) \
+ while (((variable = READ_GP32 (GP3_CMD_READ)) > gp3_cmd_current) && \
+ (variable <= (gp3_cmd_next + 96)))
+
+#define GP3_WAIT_BUSY \
+ while(READ_GP32 (GP3_BLT_STATUS) & GP3_BS_BLT_BUSY)
+
+#define GP3_WAIT_PENDING \
+ while(READ_GP32 (GP3_BLT_STATUS) & GP3_BS_BLT_PENDING)
+
+/*-----------------------------------------------------------------*/
+/* MSR MACROS */
+/* These macros facilitate interaction with the model specific */
+/* registers in GeodeLX. There are two included methods, direct */
+/* access using the rdmsr and wrmsr opcodes and an indirect method */
+/* using VSAII. */
+/*-----------------------------------------------------------------*/
+
+#ifdef CIMARRON_INCLUDE_MSR_MACROS
+
+#if CIMARRON_MSR_DIRECT_ASM
+
+/*-----------------------------------------------------------------
+ * MSR_READ
+ * Read the contents of a 64 bit MSR into a data structure
+ *-----------------------------------------------------------------*/
+
+#define MSR_READ(msr_reg, device_add, data64_ptr) \
+{ \
+ unsigned long msr_add = (unsigned long)(msr_reg) | (unsigned long)(device_add); \
+ unsigned long data_high, data_low; \
+ _asm { mov ecx, msr_add } \
+ _asm { rdmsr } \
+ _asm { mov data_high, edx } \
+ _asm { mov data_low, eax } \
+ \
+ ((Q_WORD *)(data64_ptr))->high = data_high; \
+ ((Q_WORD *)(data64_ptr))->low = data_low; \
+}
+
+/*-----------------------------------------------------------------
+ * MSR_WRITE
+ * Write the contents of a 64 bit data structure to a MSR.
+ *-----------------------------------------------------------------*/
+
+#define MSR_WRITE(msr_reg, device_add, data64_ptr) \
+{ \
+ unsigned long msr_add = (unsigned long)(msr_reg) | (unsigned long)(device_add); \
+ unsigned long data_high, data_low; \
+ \
+ data_high = ((Q_WORD *)(data64_ptr))->high; \
+ data_low = ((Q_WORD *)(data64_ptr))->low; \
+ \
+ _asm { mov ecx, msr_add } \
+ _asm { mov edx, data_high } \
+ _asm { mov eax, data_low } \
+ _asm { wrmsr } \
+}
+
+#elif CIMARRON_MSR_VSA_IO
+
+/*-----------------------------------------------------------------
+ * MSR_READ
+ * Read the contents of a 64 bit MSR into a data structure
+ *-----------------------------------------------------------------*/
+
+#define MSR_READ(msr_reg, device_add, data64_ptr) \
+{ \
+ unsigned long msr_add = (unsigned long)(msr_reg) | (unsigned long)(device_add); \
+ unsigned long data_high, data_low; \
+ \
+ _asm { mov dx, 0x0AC1C } \
+ _asm { mov eax, 0x0FC530007 } \
+ _asm { out dx, eax } \
+ \
+ _asm { add dl, 2 } \
+ _asm { mov ecx, msr_add } \
+ _asm { in ax, dx } \
+ _asm { mov data_high, edx } \
+ _asm { mov data_low, eax } \
+ \
+ ((Q_WORD *)(data64_ptr))->high = data_high; \
+ ((Q_WORD *)(data64_ptr))->low = data_low; \
+}
+
+/*-----------------------------------------------------------------
+ * MSR_WRITE
+ * Write the contents of a 64 bit data structure to a MSR.
+ *-----------------------------------------------------------------*/
+
+#define MSR_WRITE(msr_reg, device_add, data64_ptr) \
+{ \
+ unsigned long msr_add = (unsigned long)(msr_reg) | (unsigned long)(device_add); \
+ unsigned long data_high, data_low; \
+ \
+ data_high = ((Q_WORD *)(data64_ptr))->high; \
+ data_low = ((Q_WORD *)(data64_ptr))->low; \
+ \
+ _asm { mov dx, 0x0AC1C } \
+ _asm { mov eax, 0x0FC530007 } \
+ _asm { out dx, eax } \
+ \
+ _asm { add dl, 2 } \
+ _asm { mov ecx, msr_add } \
+ _asm { mov ebx, data_high } \
+ _asm { mov eax, data_low } \
+ \
+ _asm { mov esi, 0 } \
+ _asm { mov edi, 0 } \
+ _asm { out dx, ax } \
+}
+
+#elif CIMARRON_MSR_ABSTRACTED_ASM
+
+/*-----------------------------------------------------------------
+ * MSR_READ
+ * Read the contents of a 64 bit MSR into a data structure
+ *-----------------------------------------------------------------*/
+
+#define MSR_READ(msr,adr,val) \
+ __asm__ __volatile__( \
+ " mov $0x0AC1C, %%edx\n" \
+ " mov $0xFC530007, %%eax\n" \
+ " out %%eax,%%dx\n" \
+ " add $2,%%dl\n" \
+ " in %%dx, %%ax" \
+ : "=a" ((val)->low), "=d" ((val)->high) \
+ : "c" (msr | adr))
+
+/*-----------------------------------------------------------------
+ * MSR_WRITE
+ * Write the contents of a 64 bit data structure to a MSR.
+ *-----------------------------------------------------------------*/
+
+#define MSR_WRITE(msr,adr,val) \
+ { int d0, d1, d2, d3, d4; \
+ __asm__ __volatile__( \
+ " mov $0x0AC1C, %%edx\n" \
+ " mov $0xFC530007, %%eax\n" \
+ " out %%eax,%%dx\n" \
+ " add $2,%%dl\n" \
+ " mov %5, %4\n" \
+ " mov 0(%6), %1\n" \
+ " mov 4(%6), %0\n" \
+ " xor %3, %3\n" \
+ " xor %2, %2\n" \
+ " out %%ax, %%dx" \
+ : "=a" (d0), "=b" (d1), "=&D" (d2), "=&S" (d3), "=c" (d4) \
+ : "2" (msr | adr), "3" (val)); \
+ }
+
+#elif CIMARRON_MSR_KERNEL_ROUTINE
+
+#include "asm/msr.h"
+
+/*-----------------------------------------------------------------
+ * MSR_READ
+ * Read the contents of a 64 bit MSR into a data structure
+ *-----------------------------------------------------------------*/
+
+#define MSR_READ(msr_reg, device_add, data64_ptr) \
+{ \
+ unsigned long addr, val1, val2; \
+ \
+ addr = device_add | msr_reg; \
+ rdmsr (addr, val1, val2); \
+ \
+ ((Q_WORD *)(data64_ptr))->high = val2; \
+ ((Q_WORD *)(data64_ptr))->low = val1; \
+}
+
+/*-----------------------------------------------------------------
+ * MSR_WRITE
+ * Read the contents of a 64 bit data structure to a MSR.
+ *-----------------------------------------------------------------*/
+
+#define MSR_WRITE(msr_reg, device_add, data64_ptr) \
+{ \
+ unsigned long addr, val1, val2; \
+ \
+ val2 = ((Q_WORD *)(data64_ptr))->high; \
+ val1 = ((Q_WORD *)(data64_ptr))->low; \
+ \
+ addr = (device_add & 0xFFFF0000) | (unsigned long)msr_reg; \
+ wrmsr(addr, val1, val2); \
+}
+
+#endif
+
+#endif /* #ifdef CIMARRON_INCLUDE_MSR_MACROS */
+
+/*-----------------------------------------------------------------*/
+/* STRING MACROS */
+/* These macros are included to facilitate the optimization of */
+/* routines that write or copy large amounts of data. Two vesions */
+/* of these macros are included. One is intended for operating */
+/* systems that allow the use of inline assembly, while the other */
+/* is a pure C implementation for stricter operating systems. */
+/*-----------------------------------------------------------------*/
+
+#ifdef CIMARRON_INCLUDE_STRING_MACROS
+
+#if CIMARRON_OPTIMIZE_ASSEMBLY
+
+/*-----------------------------------------------------------------
+ * WRITE_COMMAND_STRING32
+ * Write a series of DWORDs to the current command buffer offset
+ *-----------------------------------------------------------------*/
+
+#define WRITE_COMMAND_STRING32(offset, dataptr, dataoffset, dword_count) \
+{ \
+ _asm { cld } \
+ _asm { mov edi, cim_cmd_ptr } \
+ _asm { add edi, offset } \
+ _asm { mov esi, dataptr } \
+ _asm { add esi, dataoffset } \
+ _asm { mov ecx, dword_count } \
+ _asm { rep movsd } \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_FB_STRING32
+ * Write a series of DWORDS to video memory.
+ *-----------------------------------------------------------------*/
+
+#define WRITE_FB_STRING32(offset, dataptr, dword_count) \
+{ \
+ unsigned long temp = (unsigned long)(dataptr); \
+ _asm { cld } \
+ _asm { mov edi, cim_fb_ptr } \
+ _asm { add edi, offset } \
+ _asm { mov esi, temp } \
+ _asm { mov ecx, dword_count } \
+ _asm { rep movsd } \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_FB_CONSTANT
+ * Write a constant DWORD to multiple video memory addresses
+ *-----------------------------------------------------------------*/
+
+#define WRITE_FB_CONSTANT(offset, value, dword_count) \
+{ \
+ unsigned long outptr = (unsigned long)cim_fb_ptr + offset; \
+ unsigned long dwords = dword_count; \
+ _asm { cld } \
+ _asm { mov edi, outptr } \
+ _asm { mov eax, value } \
+ _asm { mov ecx, dwords } \
+ _asm { rep stosd } \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_HOST_SOURCE_STRING32
+ * Write a series of DWORDs to the GP host source register
+ *-----------------------------------------------------------------*/
+
+#define WRITE_HOST_SOURCE_STRING32(dataptr, dataoffset, dword_count) \
+{ \
+ _asm { cld } \
+ _asm { mov edi, cim_gp_ptr } \
+ _asm { add edi, GP3_HST_SRC_RANGE } \
+ _asm { mov esi, dataptr } \
+ _asm { add esi, dataoffset } \
+ _asm { mov ecx, dword_count } \
+ _asm { rep movsd } \
+}
+
+#elif CIMARRON_OPTIMIZE_FORLOOP
+
+/*-----------------------------------------------------------------
+ * WRITE_COMMAND_STRING32
+ * Write a series of DWORDs to the current command buffer offset
+ *-----------------------------------------------------------------*/
+
+#define WRITE_COMMAND_STRING32(offset, dataptr, dataoffset, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempdata = (unsigned long)dataptr + (dataoffset); \
+ unsigned long byte_off = 0; \
+ for (i = 0; i < dword_count; i++, byte_off += 4) \
+ WRITE_COMMAND32 ((offset) + byte_off, *((unsigned long *)(tempdata + byte_off))); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_FB_STRING32
+ * Write a series of DWORDS to video memory.
+ *-----------------------------------------------------------------*/
+
+#define WRITE_FB_STRING32(offset, dataptr, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempdata = (unsigned long)dataptr; \
+ unsigned long byte_off = 0; \
+ for (i = 0; i < dword_count; i++, byte_off += 4) \
+ WRITE_FB32 ((offset) + byte_off, *((unsigned long *)(tempdata + byte_off))); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_FB_CONSTANT
+ * Write a constant DWORD to multiple video memory addresses
+ *-----------------------------------------------------------------*/
+
+#define WRITE_FB_CONSTANT(offset, value, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempoffset = offset; \
+ for (i = 0; i < dword_count; i++, tempoffset += 4) \
+ WRITE_FB32 (tempoffset, value); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_HOST_SOURCE_STRING32
+ * Write a series of DWORDs to the GP host source register
+ *-----------------------------------------------------------------*/
+
+#define WRITE_HOST_SOURCE_STRING32(dataptr, dataoffset, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempdata = (unsigned long)dataptr + (dataoffset); \
+ unsigned long byte_off = 0; \
+ for (i = 0; i < dword_count; i++, byte_off += 4) \
+ WRITE_GP32 (byte_off + GP3_HST_SRC_RANGE, *((unsigned long *)(tempdata + byte_off))); \
+}
+
+#elif CIMARRON_OPTIMIZE_ABSTRACTED_ASM
+
+#define move_dw(d,s,n) \
+ __asm__ __volatile__( \
+ " rep\n" \
+ " movsl\n" \
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2) \
+ : "0" (n), "1" ((const char *)s), "2" ((char *)d) \
+ : "memory")
+
+/*-----------------------------------------------------------------
+ * WRITE_COMMAND_STRING32
+ * Write a series of DWORDs to the current command buffer offset
+ *-----------------------------------------------------------------*/
+
+#define WRITE_COMMAND_STRING32(offset, dataptr, dataoffset, dword_count) \
+{ \
+ int d0, d1, d2; \
+ move_dw (cim_cmd_ptr+ ((unsigned long)(offset)), \
+ ((unsigned long)(dataptr)+(dataoffset)), \
+ dword_count); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_FB_STRING32
+ * Write a series of DWORDS to video memory.
+ *-----------------------------------------------------------------*/
+
+#define WRITE_FB_STRING32(offset, dataptr, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempdata = (unsigned long)dataptr; \
+ unsigned long byte_off = 0; \
+ for (i = 0; i < dword_count; i++, byte_off += 4) \
+ WRITE_FB32 ((offset) + byte_off, *((unsigned long *)(tempdata + byte_off))); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_FB_CONSTANT
+ * Write a constant DWORD to multiple video memory addresses
+ *-----------------------------------------------------------------*/
+
+#define WRITE_FB_CONSTANT(offset, value, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempoffset = offset; \
+ for (i = 0; i < dword_count; i++, tempoffset += 4) \
+ WRITE_FB32 (tempoffset, value); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_HOST_SOURCE_STRING32
+ * Write a series of DWORDs to the GP host source register
+ *-----------------------------------------------------------------*/
+
+#define WRITE_HOST_SOURCE_STRING32(dataptr, dataoffset, dword_count) \
+{ \
+ unsigned long i; \
+ unsigned long tempdata = (unsigned long)dataptr + (dataoffset); \
+ unsigned long byte_off = 0; \
+ for (i = 0; i < dword_count; i++, byte_off += 4) \
+ WRITE_GP32 (byte_off + GP3_HST_SRC_RANGE, *((unsigned long *)(tempdata + byte_off))); \
+}
+
+#endif
+
+#endif /* #ifdef CIMARRON_INCLUDE_STRING_MACROS */
+
+/*-----------------------------------------------------------------
+ * WRITE_COMMAND_STRING8
+ * Write a series of bytes to the current command buffer offset
+ *-----------------------------------------------------------------*/
+
+#define WRITE_COMMAND_STRING8(offset, dataptr, dataoffset, byte_count) \
+{ \
+ unsigned long i; \
+ unsigned long array = (unsigned long)dataptr + (dataoffset); \
+ for (i = 0; i < byte_count; i++) \
+ WRITE_COMMAND8 ((offset) + i, *((unsigned char *)(array + i))); \
+}
+
+/*-----------------------------------------------------------------
+ * WRITE_HOST_SOURCE_STRING8
+ * Write a series of bytes to the host source register
+ *-----------------------------------------------------------------*/
+
+#define WRITE_HOST_SOURCE_STRING8(dataptr, dataoffset, byte_count) \
+{ \
+ unsigned long temp1 = (unsigned long)dataptr + (dataoffset); \
+ unsigned long temp2 = 0; \
+ unsigned long shift = 0; \
+ unsigned long counter; \
+ if (byte_count) \
+ { \
+ for (counter = 0; counter < byte_count; counter++) \
+ { \
+ temp2 |= ((unsigned long)(*((unsigned char *)(temp1 + counter)))) << shift; \
+ shift += 8; \
+ } \
+ WRITE_GP32 (GP3_HST_SRC, temp2); \
+ } \
+}
+
+/*-----------------------------------------*/
+/* CUSTOM STRING MACROS */
+/*-----------------------------------------*/
+
+#ifndef CIMARRON_EXCLUDE_CUSTOM_MACROS
+
+#define WRITE_CUSTOM_COMMAND_STRING32 WRITE_COMMAND_STRING32
+#define WRITE_CUSTOM_COMMAND_STRING8 WRITE_COMMAND_STRING8
+
+#endif
+
+/*-----------------------------------------*/
+/* IO ACCESS MACROS */
+/*-----------------------------------------*/
+
+#ifdef CIMARRON_INCLUDE_IO_MACROS
+
+#if CIMARRON_IO_DIRECT_ACCESS
+
+/*-------------------------------------------
+ * OUTD
+ * Writes one DWORD to a single I/O address.
+ *-------------------------------------------*/
+
+#define OUTD(port, data) cim_outd(port, data)
+void cim_outd (unsigned short port, unsigned long data)
+{
+ _asm {
+ pushf
+ mov eax, data
+ mov dx, port
+ out dx, eax
+ popf
+ }
+}
+
+/*-------------------------------------------
+ * IND
+ * Reads one DWORD from a single I/O address.
+ *-------------------------------------------*/
+
+#define IND(port) cim_ind(port)
+unsigned long cim_ind (unsigned short port)
+{
+ unsigned long data;
+ _asm {
+ pushf
+ mov dx, port
+ in eax, dx
+ mov data, eax
+ popf
+ }
+ return data;
+}
+
+/*-------------------------------------------
+ * OUTW
+ * Writes one WORD to a single I/O address.
+ *-------------------------------------------*/
+
+#define OUTW(port, data) cim_outw(port, data)
+void cim_outw (unsigned short port, unsigned short data)
+{
+ _asm {
+ pushf
+ mov ax, data
+ mov dx, port
+ out dx, ax
+ popf
+ }
+}
+
+/*-------------------------------------------
+ * INW
+ * Reads one WORD from a single I/O address.
+ *-------------------------------------------*/
+
+#define INW(port) cim_inw(port)
+unsigned short cim_inw (unsigned short port)
+{
+ unsigned short data;
+ _asm {
+ pushf
+ mov dx, port
+ in ax, dx
+ mov data, ax
+ popf
+ }
+ return data;
+}
+
+/*-------------------------------------------
+ * OUTB
+ * Writes one BYTE to a single I/O address.
+ *-------------------------------------------*/
+
+#define OUTB(port, data) cim_outb(port, data)
+void cim_outb (unsigned short port, unsigned char data)
+{
+ _asm {
+ pushf
+ mov al, data
+ mov dx, port
+ out dx, al
+ popf
+ }
+}
+
+/*-------------------------------------------
+ * INB
+ * Reads one BYTE from a single I/O address.
+ *-------------------------------------------*/
+
+#define INB(port) cim_inb(port)
+unsigned char cim_inb (unsigned short port)
+{
+ unsigned char data;
+ _asm {
+ pushf
+ mov dx, port
+ in al, dx
+ mov data, al
+ popf
+ }
+ return data;
+}
+
+#elif CIMARRON_IO_ABSTRACTED_ASM
+
+/*-------------------------------------------
+ * OUTD
+ * Writes one DWORD to a single I/O address.
+ *-------------------------------------------*/
+
+#define OUTD(port, data) cim_outd(port, data)
+void cim_outd (unsigned short port, unsigned long data);
+void cim_outd (unsigned short port, unsigned long data)
+{
+ __asm__ __volatile__ ("outl %0,%w1" : : "a" (data), "Nd" (port));
+}
+
+/*-------------------------------------------
+ * IND
+ * Reads one DWORD from a single I/O address.
+ *-------------------------------------------*/
+
+#define IND(port) cim_ind(port)
+unsigned long cim_ind (unsigned short port);
+unsigned long cim_ind (unsigned short port)
+{
+ unsigned long value;
+ __asm__ __volatile__ ("inl %w1,%0" : "=a" (value) : "Nd" (port) );
+
+ return value;
+}
+
+/*-------------------------------------------
+ * OUTW
+ * Writes one WORD to a single I/O address.
+ *-------------------------------------------*/
+
+#define OUTW(port, data) cim_outw(port, data)
+void cim_outw (unsigned short port, unsigned short data);
+void cim_outw (unsigned short port, unsigned short data)
+{
+ __asm__ volatile ("out %0,%1" : : "a" (data),"d" (port));
+}
+
+/*-------------------------------------------
+ * INW
+ * Reads one WORD from a single I/O address.
+ *-------------------------------------------*/
+
+#define INW(port) cim_inw(port)
+unsigned short cim_inw (unsigned short port);
+unsigned short cim_inw (unsigned short port)
+{
+ unsigned short value;
+ __asm__ volatile ("in %1,%0" : "=a" (value) : "d" (port));
+ return value;
+}
+
+/*-------------------------------------------
+ * INB
+ * Reads one BYTE from a single I/O address.
+ *-------------------------------------------*/
+
+#define INB(port) cim_inb(port)
+unsigned char cim_inb(unsigned short port);
+unsigned char cim_inb(unsigned short port)
+{
+ unsigned char value;
+ __asm__ volatile ("inb %1,%0":"=a" (value):"d"(port));
+
+ return value;
+}
+
+/*-------------------------------------------
+ * OUTB
+ * Writes one BYTE to a single I/O address.
+ *-------------------------------------------*/
+
+#define OUTB(port) cim_outb(port)
+void cim_outb(unsigned short port, unsigned char data);
+void cim_outb(unsigned short port, unsigned char data)
+{
+ __asm__ volatile ("outb %0,%1"::"a" (data), "d"(port));
+}
+
+#endif
+
+#endif /* CIMARRON_INCLUDE_IO_MACROS */
+
+#endif
Index: linux-2.6.11/lib/cimarron/cim/cim_df.c
===================================================================
--- /dev/null
+++ linux-2.6.11/lib/cimarron/cim/cim_df.c
@@ -0,0 +1,2544 @@
+ /*
+ *
+ * Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ *
+ *
+ *
+ *
+ *
+ * Cimarron display filter routines. These routines program the video hardware.
+ *
+ *
+ */
+
+/*---------------------------------------------------------------------------
+ * df_set_crt_enable
+ *
+ * This routine enables or disables CRT output.
+ *---------------------------------------------------------------------------*/
+
+int df_set_crt_enable (int crt_output)
+{
+ unsigned long config, misc;
+
+ config = READ_VID32 (DF_DISPLAY_CONFIG);
+ misc = READ_VID32 (DF_VID_MISC);
+
+ switch (crt_output)
+ {
+ /* DISABLE DISPLAY */
+
+ case DF_CRT_DISABLE:
+
+ config &= ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
+ DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN);
+ misc |= DF_DAC_POWER_DOWN;
+ break;
+
+ /* ENABLE THE DISPLAY */
+
+ case DF_CRT_ENABLE:
+
+ config |= (DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
+ DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN);
+ misc &= ~(DF_DAC_POWER_DOWN | DF_ANALOG_POWER_DOWN);
+ break;
+
+ /* HSYNC:OFF VSYNC:ON */
+
+ case DF_CRT_STANDBY:
+
+ config = (config & ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN | DF_DCFG_DAC_BL_EN)) |
+ DF_DCFG_VSYNC_EN;
+ misc |= DF_DAC_POWER_DOWN;
+ break;
+
+ /* HSYNC:ON VSYNC:OFF */
+
+ case DF_CRT_SUSPEND:
+
+ config = (config & ~(DF_DCFG_DIS_EN | DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN)) |
+ DF_DCFG_HSYNC_EN;
+ misc |= DF_DAC_POWER_DOWN;
+ break;
+
+ default:
+ return CIM_STATUS_INVALIDPARAMS;
+ }
+
+ WRITE_VID32 (DF_DISPLAY_CONFIG, config);
+ WRITE_VID32 (DF_VID_MISC, misc);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_panel_enable
+ *
+ * This routine enables or disables panel output.
+ *---------------------------------------------------------------------------*/
+
+int df_set_panel_enable (int enable)
+{
+ unsigned long pm;
+
+ pm = READ_VID32 (DF_POWER_MANAGEMENT);
+
+ if (enable) pm |= DF_PM_PANEL_ON;
+ else pm &= ~DF_PM_PANEL_ON;
+
+ WRITE_VID32 (DF_POWER_MANAGEMENT, pm);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_configure_video_source
+ *
+ * This routine initializes all aspects of the source buffer for a video overlay.
+ *---------------------------------------------------------------------------*/
+
+int df_configure_video_source (DF_VIDEO_SOURCE_PARAMS *video_source_odd,
+ DF_VIDEO_SOURCE_PARAMS *video_source_even)
+{
+ unsigned long pitch, ctrl, vcfg;
+ unsigned long lock, vg_line, gcfg;
+ unsigned long width, size, scale;
+ unsigned long misc;
+
+ lock = READ_REG32 (DC3_UNLOCK);
+ vg_line = READ_REG32 (DC3_LINE_SIZE);
+ gcfg = READ_REG32 (DC3_GENERAL_CFG);
+ vcfg = READ_VID32 (DF_VIDEO_CONFIG);
+ ctrl = READ_VID32 (DF_VID_ALPHA_CONTROL);
+ scale = READ_VID32 (DF_VIDEO_SCALER);
+
+ /* STORE THE DESIRED SCALING PROCEDURE */
+ /* Cimarron supports two modes when programming the scale and position */
+ /* of the video window. The first mode is designed to implicitly apply */
+ /* the graphics scale to any video operations. The second applys the */
+ /* video unchanged, allowing complete control by the user. To allow */
+ /* visibility between modules, the current mode is stored in a spare */
+ /* bit in the DF miscellaneous register. */
+
+ misc = READ_VID32 (DF_VID_MISC);
+ if (video_source_odd->flags & DF_SOURCEFLAG_IMPLICITSCALING)
+ misc |= DF_USER_IMPLICIT_SCALING;
+ else
+ misc &= DF_USER_IMPLICIT_SCALING;
+ WRITE_VID32 (DF_VID_MISC, misc);
+
+ /* PARAMETER - VIDEO PITCH */
+
+ pitch = (video_source_odd->y_pitch >> 3) | ((video_source_odd->uv_pitch >> 3) << 16);
+
+ /* PARAMETER - VIDEO FORMAT */
+
+ gcfg &= ~DC3_GCFG_YUV_420;
+ vcfg &= ~(DF_VCFG_VID_INP_FORMAT | DF_VCFG_4_2_0_MODE);
+ ctrl &= ~(DF_VIDEO_INPUT_IS_RGB | DF_CSC_VIDEO_YUV_TO_RGB | DF_HD_VIDEO |
+ DF_YUV_CSC_EN);
+
+ /* SELECT PIXEL ORDERING */
+
+ switch (video_source_odd->video_format & 3)
+ {
+ case 0: vcfg |= DF_VCFG_UYVY_FORMAT; break;
+ case 1: vcfg |= DF_VCFG_Y2YU_FORMAT; break;
+ case 2: vcfg |= DF_VCFG_YUYV_FORMAT; break;
+ case 3: vcfg |= DF_VCFG_YVYU_FORMAT; break;
+ }
+
+ /* SELECT SOURCE FORMAT (4:2:2, 4:2:0, RGB) */
+
+ switch (video_source_odd->video_format >> 2)
+ {
+ case 0: ctrl |= DF_CSC_VIDEO_YUV_TO_RGB; break;
+
+ case 1: ctrl |= DF_CSC_VIDEO_YUV_TO_RGB;
+ vcfg |= DF_VCFG_4_2_0_MODE;
+ gcfg |= DC3_GCFG_YUV_420;
+ break;
+
+ case 2: ctrl |= DF_VIDEO_INPUT_IS_RGB; break;
+
+ default: return CIM_STATUS_INVALIDPARAMS;
+ }
+
+ /* ALIGN TO APPROPRIATE OUTPUT COLOR SPACE */
+ /* We have assumed until this point that the output color space is RGB */
+ /* and the input (if YUV) is always SDTV video. */
+
+ if (video_source_odd->flags & DF_SOURCEFLAG_HDTVSOURCE)
+ ctrl |= DF_HD_VIDEO;
+
+ if (ctrl & DF_CSC_GRAPHICS_RGB_TO_YUV)
+ {
+ /* YUV OUTPUT - DISABLE YUV->RGB AND ENABLE YUV->YUV */
+
+ ctrl &= ~DF_CSC_VIDEO_YUV_TO_RGB;
+
+ if ((!(ctrl & DF_HD_VIDEO) && (ctrl & DF_HD_GRAPHICS)) ||
+ ((ctrl & DF_HD_VIDEO) && !(ctrl & DF_HD_GRAPHICS)))
+ {
+ ctrl |= DF_YUV_CSC_EN;
+ }
+ }
+
+ /* PARAMETER - DISPLAY FILTER BUFFER SIZE */
+ /* The line size in the video generator must be 32-byte aligned. */
+ /* However, smaller alignments are managed by setting the */
+ /* appropriate pitch and clipping the video window. */
+
+ vcfg &= ~(DF_VCFG_LINE_SIZE_LOWER_MASK | DF_VCFG_LINE_SIZE_BIT8 |
+ DF_VCFG_LINE_SIZE_BIT9);
+
+ size = ((video_source_odd->width >> 1) + 7) & 0xFFF8;
+
+ vcfg |= (size & 0x00FF) << 8;
+ if (size & 0x0100) vcfg |= DF_VCFG_LINE_SIZE_BIT8;
+ if (size & 0x0200) vcfg |= DF_VCFG_LINE_SIZE_BIT9;
+
+ scale = (scale & ~0x7FF) | video_source_odd->height;
+
+ /* PARAMETER - VIDEO GENERATOR BUFFER SIZE */
+
+ vg_line &= ~DC3_LINE_SIZE_VLS_MASK;
+
+ if (gcfg & DC3_GCFG_YUV_420)
+ width = ((video_source_odd->width >> 1) + 7) & 0xFFF8;
+ else
+ width = ((video_source_odd->width << 1) + 31) & 0xFFE0;
+
+ vg_line |= (width >> 3) << DC3_LINE_SIZE_VB_SHIFT;
+
+ /* WRITE ALL PARAMETERS AT ONCE */
+
+ WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_VID32 (DF_VIDEO_CONFIG, vcfg);
+ WRITE_VID32 (DF_VID_ALPHA_CONTROL, ctrl);
+ WRITE_VID32 (DF_VIDEO_SCALER, scale);
+ WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
+ WRITE_REG32 (DC3_LINE_SIZE, vg_line);
+ WRITE_REG32 (DC3_VID_YUV_PITCH, pitch);
+
+ /* WRITE EVEN OR ODD BUFFER OFFSETS */
+ /* The even buffer is only valid inside an interlaced display. */
+
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ WRITE_REG32 (DC3_VID_EVEN_Y_ST_OFFSET, video_source_even->y_offset);
+ WRITE_REG32 (DC3_VID_EVEN_U_ST_OFFSET, video_source_even->u_offset);
+ WRITE_REG32 (DC3_VID_EVEN_V_ST_OFFSET, video_source_even->v_offset);
+ }
+
+ WRITE_REG32 (DC3_VID_Y_ST_OFFSET, video_source_odd->y_offset);
+ WRITE_REG32 (DC3_VID_U_ST_OFFSET, video_source_odd->u_offset);
+ WRITE_REG32 (DC3_VID_V_ST_OFFSET, video_source_odd->v_offset);
+
+ WRITE_REG32 (DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_offsets
+ *
+ * This routine sets the starting offset for the video buffer(s). The buffers
+ * can also be configured inside df_configure_video_source, but a separate
+ * routine is provided here to allow quick buffer flipping.
+ *---------------------------------------------------------------------------*/
+
+int df_set_video_offsets (int even, unsigned long y_offset,
+ unsigned long u_offset, unsigned long v_offset)
+{
+ unsigned long lock = READ_REG32 (DC3_UNLOCK);
+
+ WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
+
+ if (even)
+ {
+ WRITE_REG32 (DC3_VID_EVEN_Y_ST_OFFSET, y_offset);
+ WRITE_REG32 (DC3_VID_EVEN_U_ST_OFFSET, u_offset);
+ WRITE_REG32 (DC3_VID_EVEN_V_ST_OFFSET, v_offset);
+ }
+ else
+ {
+ WRITE_REG32 (DC3_VID_Y_ST_OFFSET, y_offset);
+ WRITE_REG32 (DC3_VID_U_ST_OFFSET, u_offset);
+ WRITE_REG32 (DC3_VID_V_ST_OFFSET, v_offset);
+ }
+
+ WRITE_REG32 (DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_scale
+ *
+ * This routine programs the horizontal/vertical scale factors for video. To
+ * disable scaling/filtering, this routine should be called with identical source
+ * and destination dimensions.
+ *---------------------------------------------------------------------------*/
+
+int df_set_video_scale (unsigned long src_width, unsigned long src_height,
+ unsigned long dst_width, unsigned long dst_height, unsigned long flags)
+{
+ unsigned long temp, misc;
+ unsigned long scale, gfxscale;
+ unsigned long fbactive, src;
+ unsigned long size, downscale;
+ unsigned long vcfg, gcfg, unlock;
+
+ /* APPLY THE GRAPHICS SCALE */
+ /* When requested by the user, we will adjust the video scale by the */
+ /* current graphics scale factor. This allows video to be programmed */
+ /* in terms of the graphics source resolution. */
+
+ misc = READ_VID32 (DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING)
+ {
+ gfxscale = READ_REG32 (DC3_GFX_SCALE);
+ fbactive = READ_REG32 (DC3_FB_ACTIVE);
+
+ /* REVERSE ENGINEER THE SCALE FACTOR */
+ /* The graphics scale factor is (source / (dst - 1)), so a little */
+ /* math is performed to reverse engineer the correct scale for */
+ /* video. */
+ /* */
+ /* F = (0x4000*S)/(D-1) -> (D/S) = (((0x4000*S)/F)+1)/S */
+
+ scale = gfxscale & 0xFFFF;
+ src = (fbactive >> 16) + 1;
+ if (scale != 0x4000)
+ {
+ dst_width = dst_width * (((0x4000 * src) / scale) + 1);
+ dst_width /= src;
+ }
+
+ scale = gfxscale >> 16;
+ src = (fbactive & 0xFFFF) + 1;
+ if (scale != 0x4000)
+ {
+ dst_height = dst_height * (((0x4000 * src) / scale) + 1);
+ dst_height /= src;
+ }
+ }
+
+ /* CHECK FOR VALID SCALING FACTOR */
+ /* The display filter/video generator can support up to 8:1 */
+ /* horizontal downscale and up to 4:1 vertical downscale. */
+ /* Scale factors above 4:1 horizontal and 2:1 horizontal */
+ /* will have a quality impact. However, at such large scale */
+ /* factors, it might not matter, */
+
+ if (((flags & DF_SCALEFLAG_CHANGEX) && dst_width < (src_width >> 3)) ||
+ ((flags & DF_SCALEFLAG_CHANGEY) && dst_height < (src_height >> 2)))
+ {
+ return CIM_STATUS_INVALIDSCALE;
+ }
+
+ /* ENABLE OR DISABLE ADVANCED SCALING FEATURES */
+ /* Scaling above 2:1 vertical and 4:1 horizontal relies */
+ /* on mechanisms beside the line filter. */
+
+ if (flags & DF_SCALEFLAG_CHANGEX)
+ {
+ scale = READ_VID32 (DF_VIDEO_SCALER);
+ vcfg = READ_VID32 (DF_VIDEO_CONFIG);
+ vcfg &= ~(DF_VCFG_LINE_SIZE_LOWER_MASK | DF_VCFG_LINE_SIZE_BIT8 |
+ DF_VCFG_LINE_SIZE_BIT9);
+
+ if (dst_width < (src_width >> 2))
+ {
+ src_width >>= 1;
+ WRITE_VID32 (DF_VIDEO_SCALER, scale | DF_SCALE_DOUBLE_H_DOWNSCALE);
+ }
+ else
+ {
+ WRITE_VID32 (DF_VIDEO_SCALER, scale & ~DF_SCALE_DOUBLE_H_DOWNSCALE);
+ }
+
+ /* PROGRAM A NEW LINE SIZE */
+ /* The line size must be updated when using the Double Horizontal */
+ /* Downscale (DHD) bit. This is because the amount of VFIFO space */
+ /* consumed is effectively half in this mode. */
+
+ size = ((src_width >> 1) + 7) & 0xFFF8;
+ vcfg |= (size & 0x00FF) << 8;
+ if (size & 0x0100) vcfg |= DF_VCFG_LINE_SIZE_BIT8;
+ if (size & 0x0200) vcfg |= DF_VCFG_LINE_SIZE_BIT9;
+ WRITE_VID32 (DF_VIDEO_CONFIG, vcfg);
+ WRITE_VID32 (DF_VIDEO_XSCALE, ((0x10000 * src_width) / dst_width));
+ }
+ if (flags & DF_SCALEFLAG_CHANGEY)
+ {
+ unlock = READ_REG32 (DC3_UNLOCK);
+ gcfg = READ_REG32 (DC3_GENERAL_CFG) & ~DC3_GCFG_VDSE;
+ WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ if (dst_height < (src_height >> 1))
+ {
+ gcfg |= DC3_GCFG_VDSE;
+ downscale = READ_REG32 (DC3_VID_DS_DELTA) & ~DC3_DS_DELTA_MASK;
+ if (dst_height == (src_height >> 2))
+ downscale |= (0x3FFF << 18);
+ else
+ downscale |= (((src_height >> 1) << 14) / dst_height) << 18;
+
+ WRITE_REG32 (DC3_VID_DS_DELTA, downscale);
+ WRITE_VID32 (DF_VIDEO_YSCALE, 0x20000);
+ }
+ else
+ {
+ WRITE_VID32 (DF_VIDEO_YSCALE, ((0x10000 * src_height) / dst_height));
+ }
+ WRITE_REG32 (DC3_GENERAL_CFG, gcfg);
+ WRITE_REG32 (DC3_UNLOCK, unlock);
+ }
+
+ /* CHECK IF SCALING IS DISABLED */
+ /* If no scaling occurs, we disable the hardware filter. */
+
+ temp = READ_VID32 (DF_VIDEO_CONFIG);
+ if ((READ_VID32 (DF_VIDEO_XSCALE) == 0x10000) &&
+ (READ_VID32 (DF_VIDEO_YSCALE) == 0x10000))
+ {
+ WRITE_VID32 (DF_VIDEO_CONFIG, (temp | DF_VCFG_SC_BYP));
+ }
+ else
+ WRITE_VID32 (DF_VIDEO_CONFIG, (temp & ~DF_VCFG_SC_BYP));
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_position
+ *
+ * This routine programs the position of the video window on the display.
+ * An indent parameter is also passed to this program to prevent artifacts
+ * when the video window is moved beyond the left edge of the screen.
+ *---------------------------------------------------------------------------*/
+
+int df_set_video_position (DF_VIDEO_POSITION *video_window)
+{
+ unsigned long vblankstart_even, vblankend_even, vsyncend_even, vtotal_even, vactive_even;
+ unsigned long hblankstart, hblankend, hsyncend, htotal, hactive;
+ unsigned long vblankstart, vblankend, vsyncend, vtotal, vactive;
+ unsigned long width, height, height_even;
+ unsigned long adjust, border_x, border_y, border_y_even;
+ unsigned long xstart, xend;
+ unsigned long ystart, yend;
+ unsigned long ckey_x, ckey_y;
+ unsigned long x_copy, y_copy;
+ unsigned long width_copy, height_copy;
+ unsigned long vcfg, initread;
+ unsigned long xscale, dst_clip;
+ unsigned long ypos, ypos_even;
+ unsigned long y, gfxscale;
+ unsigned long misc, fbactive;
+ unsigned long scale, src;
+ unsigned long irq_ctl;
+ unsigned long unlock;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vblankend = ((READ_REG32 (DC3_V_BLANK_TIMING) >> 16) & 0xFFF) + 1;
+ hblankend = ((READ_REG32 (DC3_H_BLANK_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vblankstart = (READ_REG32 (DC3_V_BLANK_TIMING) & 0xFFF) + 1;
+ hblankstart = (READ_REG32 (DC3_H_BLANK_TIMING) & 0xFFF) + 1;
+ hactive = (READ_REG32 (DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
+ vactive = (READ_REG32 (DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
+ unlock = READ_REG32 (DC3_UNLOCK);
+
+ /* INCLUDE BORDER IF REQUESTED */
+
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ {
+ border_x = htotal - hblankend;
+ border_y = vtotal - vblankend;
+ hactive = hblankstart + htotal - hblankend;
+ vactive = vblankstart + vtotal - vblankend;
+ }
+ else
+ {
+ border_x = border_y = 0;
+ }
+
+ /* APPLY THE GRAPHICS SCALE */
+ /* Do not alter the input data. */
+
+ width_copy = video_window->width;
+ height_copy = video_window->height;
+ x_copy = video_window->x;
+ y_copy = video_window->y;
+
+ misc = READ_VID32 (DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING)
+ {
+ gfxscale = READ_REG32 (DC3_GFX_SCALE);
+ fbactive = READ_REG32 (DC3_FB_ACTIVE);
+
+ /* REVERSE ENGINEER THE SCALE FACTOR */
+
+ scale = gfxscale & 0xFFFF;
+ src = (fbactive >> 16) + 1;
+ if (scale != 0x4000)
+ {
+ width_copy = width_copy * (((0x4000 * src) / scale) + 1);
+ width_copy /= src;
+ x_copy = x_copy * (((0x4000 * src) / scale) + 1);
+ x_copy /= src;
+ }
+
+ scale = gfxscale >> 16;
+ src = (fbactive & 0xFFFF) + 1;
+ if (scale != 0x4000)
+ {
+ height_copy = height_copy * (((0x4000 * src) / scale) + 1);
+ height_copy /= src;
+ y_copy = y_copy * (((0x4000 * src) / scale) + 1);
+ y_copy /= src;
+ }
+ }
+
+ /* HANDLE INTERLACING */
+ /* When the output is interlaced, we must set the position and height */
+ /* on the fields and not on the composite image. */
+
+ if ((irq_ctl = READ_REG32 (DC3_IRQ_FILT_CTL)) & DC3_IRQFILT_INTL_EN)
+ {
+ vsyncend_even = ((READ_REG32 (DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal_even = ((READ_REG32 (DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vblankend_even = ((READ_REG32 (DC3_V_BLANK_EVEN) >> 16) & 0xFFF) + 1;
+ vactive_even = (READ_REG32 (DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
+ vblankstart_even = (READ_REG32 (DC3_V_BLANK_EVEN) & 0xFFF) + 1;
+
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ {
+ border_y_even = vtotal_even- vblankend_even;
+ vactive_even = vblankstart_even + vtotal_even - vblankend_even;
+ }
+ else
+ border_y_even = 0;
+
+ /* THE ODD FIELD MUST ALWAYS PRECEDE THE EVEN FIELD */
+ /* This implies that we can never start video on an odd y position */
+ /* in the composite image. This is required because the only way to */
+ /* accomplish an odd y start would be to switch the buffer offsets, */
+ /* which could have serious repercussions for genlocked VIP. */
+
+ y = y_copy >> 1;
+
+ /* CALCULATE Y POSITION FOR ODD FIELD */
+ /* Clip the video window to the odd field timings. Note that the */
+ /* height in the odd field may be greater if the video height is */
+ /* odd. */
+
+ height = (height_copy + 1) >> 1;
+ if ((y + height) > vactive)
+ height = vactive - y;
+
+ ystart = y + vtotal_even - vsyncend_even + 1;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ ystart -= border_y_even;
+
+ yend = ystart + height;
+ ypos = (yend << 16) | ystart;
+
+ /* CALCULATE Y POSITION FOR EVEN FIELD */
+
+ height_even = height_copy >> 1;
+ if ((y + height_even) > vactive_even)
+ height_even = vactive_even - y;
+
+ ystart = y + vtotal - vsyncend + 1;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ ystart -= border_y;
+
+ yend = ystart + height_even;
+ ypos_even = (yend << 16) | ystart;
+
+ /* CALCULATE ACTUAL FRAME BUFFER HEIGHT */
+ /* The y position and height are used to determine the actual */
+ /* placement of the color key region. The region will either be */
+ /* the sum of the even and odd fields (for interlaced addressing */
+ /* or flicker filtering) or it will be the union of the two (for */
+ /* line doubling). We must also adjust the region such that the */
+ /* origin (0, 0) is centered on the beginning of graphics data. */
+ /* This is only a problem if video is being displayed over the */
+ /* overscan area. */
+
+ if ((READ_REG32 (DC3_GENLK_CTL) & DC3_GC_FLICKER_FILTER_ENABLE) ||
+ (irq_ctl & DC3_IRQFILT_INTL_ADDR))
+ {
+ y <<= 1;
+ height += height_even;
+ adjust = border_y + border_y_even;
+ }
+ else
+ {
+ adjust = border_y;
+ if (height_even > height)
+ height = height_even;
+ }
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ {
+ if (y > adjust)
+ {
+ y -= adjust;
+ adjust = 0;
+ }
+ else
+ {
+ adjust -= y;
+ if (height > adjust)
+ height -= adjust;
+ else
+ height = 0;
+ }
+ }
+
+ }
+ else
+ {
+ y = y_copy;
+
+ height = height_copy;
+ if ((y + height) > vactive)
+ height = vactive - y;
+
+ ystart = y + vtotal - vsyncend + 1;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ ystart -= border_y;
+
+ yend = ystart + height;
+ ypos = (yend << 16) | ystart;
+ ypos_even = 0;
+ }
+
+ /* HORIZONTAL POSITION */
+ /* The horizontal values are identical for the even and odd field. */
+
+ width = width_copy;
+ xstart = x_copy + htotal - hsyncend - 14;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ xstart -= border_x;
+
+ /* RIGHT CLIPPING */
+
+ if ((x_copy + width) > hactive)
+ width = hactive - x_copy;
+
+ xend = xstart + width;
+
+ /* CALCULATE LEFT CLIPPING PARAMETER */
+ /* The value passed in can be interpreted as destination pixels, in which */
+ /* case the video scale is factored in, or as source pixels, in which case */
+ /* the value is written directly. Also, the display filter's initial read */
+ /* address value is only programmable on 4-pixel increments. However, we */
+ /* can achieve an arbitrary left clip by adjusting the xstart value, as */
+ /* there is a 14-clock delay in which to play. Also, according to the */
+ /* designers, 4:2:0 and 4:2:2 behave identically when setting the initial */
+ /* read address. The addition of scaling further complicates the */
+ /* algorithm. When setting the initial read address, it is in terms of */
+ /* source pixels, while adjusting the xstart value is in destination pixels */
+ /* We may thus not be able to achieve a perfect clipping fit for scaled */
+ /* video. We compensate by including two clipping parameters in our */
+ /* structure. This allows us the user additional control and it allows us */
+ /* to accurately convey to the user the state of clipping on the machine. */
+
+ initread = video_window->left_clip;
+ dst_clip = 0;
+ if (!(video_window->flags & DF_POSFLAG_DIRECTCLIP))
+ {
+ xscale = READ_VID32 (DF_VIDEO_XSCALE) & 0xFFFFF;
+ initread = (initread * xscale) / 0x10000;
+ if (xscale)
+ dst_clip = ((initread & 3) * 0x10000) / xscale;
+ }
+ else
+ dst_clip = video_window->dst_clip;
+
+ /* LIMIT THE CLIP */
+ /* We technically have a 14 pixel window in which to play. However, taking */
+ /* the entire 14 pixels makes the video timing a little hairy... Also note */
+ /* that we cannot do this when performing panel centering, as the video */
+ /* would then exceed the mode size. */
+
+ if (dst_clip > 4)
+ dst_clip = 4;
+ if (READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
+ dst_clip = 0;
+
+ xstart -= dst_clip;
+
+ vcfg = READ_VID32 (DF_VIDEO_CONFIG);
+ vcfg &= ~DF_VCFG_INIT_READ_MASK;
+ vcfg |= (initread >> 2) << 16;
+
+ /* SET COLOR KEY REGION */
+ /* We are assuming that color keying will never be desired outside */
+ /* of the video region. We adjust the color key region for graphics */
+ /* scaling. */
+
+ gfxscale = READ_REG32 (DC3_GFX_SCALE);
+
+ ckey_x = ((x_copy * (gfxscale & 0xFFFF)) / 0x4000) |
+ ((((x_copy + width) * (gfxscale & 0xFFFF)) / 0x4000) << 16);
+ ckey_y = ((y * (gfxscale >> 16)) / 0x4000) |
+ ((((y + height) * (gfxscale >> 16)) / 0x4000) << 16);
+
+ /* WRITE ALL PARAMETERS AT ONCE */
+
+ WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_REG32 (DC3_CLR_KEY_X, ckey_x);
+ WRITE_REG32 (DC3_CLR_KEY_Y, ckey_y);
+ WRITE_VID32 (DF_VIDEO_X_POS, (xend << 16) | xstart);
+ WRITE_VID32 (DF_VIDEO_Y_POS, ypos);
+ WRITE_VID32 (DF_VID_YPOS_EVEN, ypos_even);
+ WRITE_VID32 (DF_VIDEO_CONFIG, vcfg);
+ WRITE_REG32 (DC3_UNLOCK, unlock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_filter_coefficients
+ *
+ * This routine sets the horizontal and vertical filter coefficients for video
+ * scaling. These coefficients are used for upscaling and downscaling video.
+ * If the phase256 parameter is 1, the coefficient arrays are used as single
+ * arrays of 256 phases for both vertical and horizontal scaling. If the
+ * phase256 parameter is clear, the coefficient arrays are used as two 128-phase
+ * arrays. The first 128 entries represent the phases for vertical scaling.
+ * The last 128 entries represent the phases for horizontal scaling.
+ *---------------------------------------------------------------------------*/
+
+int df_set_video_filter_coefficients (long taps[][4], int phase256)
+{
+ unsigned long scale, coeff0, coeff1;
+ unsigned long i;
+ long (*defaults)[2];
+
+ /* SET PHASE COUNT AND CHOOSE COEFFICIENT ARRAY */
+
+ scale = READ_VID32 (DF_VIDEO_SCALER);
+ if (phase256)
+ {
+ WRITE_VID32 (DF_VIDEO_SCALER, (scale & ~DF_SCALE_128_PHASES));
+ defaults = CimarronVideoFilter256;
+ }
+ else
+ {
+ WRITE_VID32 (DF_VIDEO_SCALER, (scale | DF_SCALE_128_PHASES));
+ defaults = CimarronVideoFilter128;
+ }
+
+ /* PROGRAM COEFFICIENTS */
+
+ for (i = 0; i < 256; i++)
+ {
+ if (!taps)
+ {
+ coeff0 = defaults[i][0];
+ coeff1 = defaults[i][1];
+ }
+ else
+ {
+ if (taps[i][1] < 0) coeff0 = -taps[i][1] | 0x8000;
+ else coeff0 = taps[i][1];
+
+ coeff0 <<= 16;
+
+ if (taps[i][0] < 0) coeff0 |= -taps[i][0] | 0x8000;
+ else coeff0 |= taps[i][0];
+
+
+
+ if (taps[i][3] < 0) coeff1 = -taps[i][3] | 0x8000;
+ else coeff1 = taps[i][3];
+
+ coeff1 <<= 16;
+
+ if (taps[i][2] < 0) coeff1 |= -taps[i][2] | 0x8000;
+ else coeff1 |= taps[i][2];
+ }
+
+ WRITE_VID32 ((DF_COEFFICIENT_BASE + (i << 3)), coeff0);
+ WRITE_VID32 ((DF_COEFFICIENT_BASE + (i << 3) + 4), coeff1);
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_enable
+ *
+ * This routine enables or disables the video overlay.
+ *---------------------------------------------------------------------------*/
+
+int df_set_video_enable (int enable, unsigned long flags)
+{
+ unsigned long vcfg, lock, gcfg;
+ unsigned long dcfg, vg_ckey, fifo = 0;
+
+ vcfg = READ_VID32 (DF_VIDEO_CONFIG);
+ lock = READ_REG32 (DC3_UNLOCK);
+ gcfg = READ_REG32 (DC3_GENERAL_CFG);
+
+ /* SET VIDEO FIFO END WATERMARK */
+ /* The video FIFO end watermark is set to 0 when video is disabled */
+ /* to allow low priority transactions in the VG. Otherwise, the */
+ /* priority will be forced high until the VG fills the video FIFO */
+ /* by not fetching video. That could take a while... Note that */
+ /* we set the end priority to be 4 greater than the start. We */
+ /* assume that the start priority has been configured by a modeset. */
+
+ dcfg = READ_REG32 (DC3_DISPLAY_CFG) & ~DC3_DCFG_VFHPEL_MASK;
+ if (enable)
+ {
+ fifo = ((dcfg >> 12) & 0x0000000F) + 4;
+ if (fifo > 0xF)
+ fifo = 0xF;
+ }
+ WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_REG32 (DC3_DISPLAY_CFG, dcfg | (fifo << 16));
+
+ /* ENABLE OR DISABLE VIDEO */
+ /* The mechanism to fetch video data is enabled first and */
+ /* disabled last. */
+
+ if (enable)
+ {
+ WRITE_REG32 (DC3_GENERAL_CFG, (gcfg | DC3_GCFG_VIDE));
+ WRITE_VID32 (DF_VIDEO_CONFIG, (vcfg | DF_VCFG_VID_EN));
+
+ /* DISABLE COLOR KEYING IF REQUESTED BY THE USER */
+
+ if (flags & DF_ENABLEFLAG_NOCOLORKEY)
+ {
+ /* OVERRIDE THE MODE TO COLOR KEYING */
+
+ dcfg = READ_VID32 (DF_DISPLAY_CONFIG);
+ WRITE_VID32 (DF_DISPLAY_CONFIG, (dcfg & ~DF_DCFG_VG_CK));
+
+ /* DISABLE COLOR KEYING IN THE VG */
+
+ vg_ckey = READ_REG32 (DC3_COLOR_KEY);
+ WRITE_REG32 (DC3_COLOR_KEY, (vg_ckey & ~DC3_CLR_KEY_ENABLE));
+ }
+ else if (!(READ_VID32 (DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK))
+ {
+ /* OTHERWISE RE-ENABLE COLOR KEYING */
+
+ vg_ckey = READ_REG32 (DC3_COLOR_KEY);
+ WRITE_REG32 (DC3_COLOR_KEY, (vg_ckey | DC3_CLR_KEY_ENABLE));
+ }
+ }
+ else
+ {
+ WRITE_VID32 (DF_VIDEO_CONFIG, (vcfg & ~DF_VCFG_VID_EN));
+ WRITE_REG32 (DC3_GENERAL_CFG, (gcfg & ~DC3_GCFG_VIDE));
+
+ /* DISABLE COLOR KEY WINDOW WHEN VIDEO IS INACTIVE */
+ /* To mimic legacy functionality, we disble color keying */
+ /* when the video window is not active. We will restore */
+ /* the enable when video is re-enabled if the appropriate */
+ /* bit is set in display config. */
+
+ vg_ckey = READ_REG32 (DC3_COLOR_KEY);
+ WRITE_REG32 (DC3_COLOR_KEY, (vg_ckey & ~DC3_CLR_KEY_ENABLE));
+ }
+ WRITE_REG32 (DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_color_key
+ *
+ * This routine configures the video color/chroma key mechanism.
+ *---------------------------------------------------------------------------*/
+
+int df_set_video_color_key (unsigned long key, unsigned long mask, int graphics)
+{
+ unsigned long lock, vg_ckey, df_dcfg;
+
+ vg_ckey = READ_REG32 (DC3_COLOR_KEY);
+ lock = READ_REG32 (DC3_UNLOCK);
+ df_dcfg = READ_VID32 (DF_DISPLAY_CONFIG);
+
+ WRITE_REG32 (DC3_UNLOCK, DC3_UNLOCK_VALUE);
+
+ if (graphics)
+ {
+ /* COLOR KEY - USE VG HARDWARE */
+ /* Note that color key is never enabled unless a video window */
+ /* is active. This is to match legacy behavior. */
+
+ df_dcfg &= ~DF_DCFG_VG_CK;
+ vg_ckey = (vg_ckey & 0xFF000000) | (key & 0xFFFFFF);
+ if (READ_VID32 (DF_VIDEO_CONFIG) & DF_VCFG_VID_EN)
+ vg_ckey |= DC3_CLR_KEY_ENABLE;
+ else
+ vg_ckey &= ~DC3_CLR_KEY_ENABLE;
+
+ WRITE_VID32 (DF_DISPLAY_CONFIG, df_dcfg);
+ WRITE_REG32 (DC3_COLOR_KEY, vg_ckey);
+ WRITE_REG32 (DC3_COLOR_MASK, (mask & 0xFFFFFF));
+ }
+ else
+ {
+ /* CHROMA KEY - USE DF HARDWARE */
+
+ df_dcfg |= DF_DCFG_VG_CK;
+ vg_ckey &= ~DC3_CLR_KEY_ENABLE;
+
+ WRITE_REG32 (DC3_COLOR_KEY, vg_ckey);
+ WRITE_VID32 (DF_DISPLAY_CONFIG, df_dcfg);
+ WRITE_VID32 (DF_VIDEO_COLOR_KEY, (key & 0xFFFFFF));
+ WRITE_VID32 (DF_VIDEO_COLOR_MASK, (mask & 0xFFFFFF));
+ }
+
+ WRITE_REG32 (DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_palette
+ *
+ * This routine loads the video hardware palette. If a NULL pointer is
+ * specified, the palette is bypassed.
+ *--------------------------------------------------------------------------*/
+
+int df_set_video_palette (unsigned long *palette)
+{
+ unsigned long i, entry;
+ unsigned long misc, dcfg;
+
+ /* LOAD GEODE LX VIDEO PALETTE */
+
+ WRITE_VID32 (DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ {
+ if (palette) entry = palette[i];
+ else entry = i | (i << 8) | (i << 16);
+ WRITE_VID32 (DF_PALETTE_DATA, entry);
+ }
+
+ /* ENABLE THE VIDEO PALETTE */
+ /* Ensure that the video palette has an effect by routing video data */
+ /* through the palette RAM and clearing the 'Bypass Both' bit. */
+
+ dcfg = READ_VID32 (DF_DISPLAY_CONFIG);
+ misc = READ_VID32 (DF_VID_MISC);
+
+ dcfg |= DF_DCFG_GV_PAL_BYP;
+ misc &= ~DF_GAMMA_BYPASS_BOTH;
+
+ WRITE_VID32 (DF_DISPLAY_CONFIG, dcfg);
+ WRITE_VID32 (DF_VID_MISC, misc);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_palette_entry
+ *
+ * This routine loads a single entry of the video hardware palette.
+ *--------------------------------------------------------------------------*/
+
+int df_set_video_palette_entry (unsigned long index, unsigned long palette)
+{
+ unsigned long misc, dcfg;
+
+ if (index > 0xFF)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ /* SET A SINGLE ENTRY */
+
+ WRITE_VID32 (DF_PALETTE_ADDRESS, index);
+ WRITE_VID32 (DF_PALETTE_DATA, palette);
+
+ /* ENABLE THE VIDEO PALETTE */
+ /* Ensure that the video palette has an effect by routing video data */
+ /* through the palette RAM and clearing the 'Bypass Both' bit. */
+
+ dcfg = READ_VID32 (DF_DISPLAY_CONFIG);
+ misc = READ_VID32 (DF_VID_MISC);
+
+ dcfg |= DF_DCFG_GV_PAL_BYP;
+ misc &= ~DF_GAMMA_BYPASS_BOTH;
+
+ WRITE_VID32 (DF_DISPLAY_CONFIG, dcfg);
+ WRITE_VID32 (DF_VID_MISC, misc);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_configure_video_cursor_color_key
+ *
+ * This routine configures the hardware video cursor color key mechanism.
+ *--------------------------------------------------------------------------*/
+
+int df_configure_video_cursor_color_key (DF_VIDEO_CURSOR_PARAMS *cursor_color_key)
+{
+ unsigned long key;
+
+ if (cursor_color_key->select_color2 >= 24)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ key = READ_VID32 (DF_CURSOR_COLOR_KEY) & DF_CURSOR_COLOR_KEY_ENABLE;
+ key = key | (cursor_color_key->key & 0xFFFFFF) | (cursor_color_key->select_color2 << 24);
+
+ WRITE_VID32 (DF_CURSOR_COLOR_KEY, key);
+ WRITE_VID32 (DF_CURSOR_COLOR_MASK, (cursor_color_key->mask & 0xFFFFFF));
+ WRITE_VID32 (DF_CURSOR_COLOR_1, (cursor_color_key->color1 & 0xFFFFFF));
+ WRITE_VID32 (DF_CURSOR_COLOR_2, (cursor_color_key->color2 & 0xFFFFFF));
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_cursor_color_key_enable
+ *
+ * This routine enables or disables the video cursor color key.
+ *--------------------------------------------------------------------------*/
+
+int df_set_video_cursor_color_key_enable (int enable)
+{
+ unsigned long temp = READ_VID32 (DF_CURSOR_COLOR_KEY);
+
+ if (enable) temp |= DF_CURSOR_COLOR_KEY_ENABLE;
+ else temp &= ~DF_CURSOR_COLOR_KEY_ENABLE;
+
+ WRITE_VID32 (DF_CURSOR_COLOR_KEY, temp);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_configure_alpha_window
+ *
+ * This routine configures one of the three hardware alpha regions.
+ *--------------------------------------------------------------------------*/
+
+int df_configure_alpha_window (int window, DF_ALPHA_REGION_PARAMS *alpha_data)
+{
+ unsigned long vsyncend_even, vtotal_even, vactive_even;
+ unsigned long hsyncend, htotal, hactive;
+ unsigned long vsyncend, vtotal, vactive;
+ unsigned long alpha_ctl, pos;
+ unsigned long hadjust, vadjust;
+ unsigned long y, height;
+ unsigned long xstart, xend;
+ unsigned long ystart, yend;
+ unsigned long x_copy, width_copy;
+ unsigned long y_copy, height_copy;
+ unsigned long scale, src, misc;
+ unsigned long gfxscale, fbactive;
+ unsigned long color;
+
+ if (window > 2)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ hactive = (READ_REG32 (DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
+ vactive = (READ_REG32 (DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
+
+ /* APPLY THE GRAPHICS SCALE */
+
+ width_copy = alpha_data->width;
+ height_copy = alpha_data->height;
+ x_copy = alpha_data->x;
+ y_copy = alpha_data->y;
+
+ misc = READ_VID32 (DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING)
+ {
+ gfxscale = READ_REG32 (DC3_GFX_SCALE);
+ fbactive = READ_REG32 (DC3_FB_ACTIVE);
+
+ /* REVERSE ENGINEER THE SCALE FACTOR */
+
+ scale = gfxscale & 0xFFFF;
+ src = (fbactive >> 16) + 1;
+ if (scale != 0x4000)
+ {
+ width_copy = width_copy * (((0x4000 * src) / scale) + 1);
+ width_copy /= src;
+ x_copy = x_copy * (((0x4000 * src) / scale) + 1);
+ x_copy /= src;
+ }
+
+ scale = gfxscale >> 16;
+ src = (fbactive & 0xFFFF) + 1;
+ if (scale != 0x4000)
+ {
+ height_copy = height_copy * (((0x4000 * src) / scale) + 1);
+ height_copy /= src;
+ y_copy = y_copy * (((0x4000 * src) / scale) + 1);
+ y_copy /= src;
+ }
+ }
+
+ /* SET PRIORITY */
+ /* Priority is the only alpha parameter that is not in a register that */
+ /* can be indexed based on the alpha window number. */
+
+ pos = 16 + (window << 1);
+ alpha_ctl = READ_VID32 (DF_VID_ALPHA_CONTROL) & ~(3L << pos);
+ alpha_ctl |= (alpha_data->priority & 3) << pos;
+ WRITE_VID32 (DF_VID_ALPHA_CONTROL, alpha_ctl);
+
+ /* HANDLE INTERLACED MODES */
+
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ vsyncend_even = ((READ_REG32 (DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal_even = ((READ_REG32 (DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vactive_even = (READ_REG32 (DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
+
+ y = y_copy >> 1;
+
+ /* SET Y POSITION FOR ODD FIELD */
+
+ height = (height_copy + 1) >> 1;
+ vadjust = vtotal_even - vsyncend_even + 1;
+
+ ystart = y + vadjust;
+ yend = y + vadjust + height;
+
+ if (yend > (vactive + vadjust))
+ yend = vactive + vadjust;
+
+ WRITE_VID32 ((DF_ALPHA_YPOS_1 + (window << 5)), (ystart | (yend << 16)));
+
+ /* SET Y POSITION FOR EVEN FIELD */
+
+ height = height_copy >> 1;
+ vadjust = vtotal - vsyncend + 1;
+
+ ystart = y + vadjust;
+ yend = y + vadjust + height;
+
+ if (yend > (vactive_even + vadjust))
+ yend = vactive_even + vadjust;
+
+ WRITE_VID32 ((DF_VID_ALPHA_Y_EVEN_1 + (window << 3)), (ystart | (yend << 16)));
+ }
+ else
+ {
+ y = y_copy;
+ height = height_copy;
+ vadjust = vtotal - vsyncend + 1;
+
+ ystart = y + vadjust;
+ yend = y + vadjust + height;
+
+ if (yend > (vactive + vadjust))
+ yend = vactive + vadjust;
+
+ WRITE_VID32 ((DF_ALPHA_YPOS_1 + (window << 5)), (ystart | (yend << 16)));
+ }
+
+ /* SET ALPHA X POSITION */
+ /* The x position is the same for both the odd and even fields. */
+
+ hadjust = htotal - hsyncend - 2;
+
+ xstart = x_copy + hadjust;
+ xend = x_copy + hadjust + width_copy;
+
+ if (xend > (hactive + hadjust))
+ xend = hactive + hadjust;
+
+ WRITE_VID32 ((DF_ALPHA_XPOS_1 + (window << 5)), (xstart | (xend << 16)));
+
+ /* SET COLOR REGISTER */
+
+ color = alpha_data->color & 0xFFFFFF;
+ if (alpha_data->flags & DF_ALPHAFLAG_COLORENABLED)
+ color |= DF_ALPHA_COLOR_ENABLE;
+
+ WRITE_VID32 ((DF_ALPHA_COLOR_1 + (window << 5)), color);
+
+ /* SET ALPHA VALUE, DELTA AND PER PIXEL */
+
+ alpha_ctl = READ_VID32 (DF_ALPHA_CONTROL_1 + (window << 5)) & DF_ACTRL_WIN_ENABLE;
+ alpha_ctl |= (alpha_data->alpha_value & 0xFF) | DF_ACTRL_LOAD_ALPHA |
+ (((unsigned long)alpha_data->delta & 0xFF) << 8);
+ if (alpha_data->flags & DF_ALPHAFLAG_PERPIXELENABLED)
+ alpha_ctl |= DF_ACTRL_PERPIXEL_EN;
+
+ WRITE_VID32 ((DF_ALPHA_CONTROL_1 + (window << 5)), alpha_ctl);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_alpha_window_enable
+ *
+ * This routine enables or disables one of the three hardware alpha regions.
+ *--------------------------------------------------------------------------*/
+
+int df_set_alpha_window_enable (int window, int enable)
+{
+ unsigned long alpha_ctl;
+
+ if (window > 2)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ alpha_ctl = READ_VID32 (DF_ALPHA_CONTROL_1 + (window << 5));
+ if (enable) alpha_ctl |= DF_ACTRL_WIN_ENABLE;
+ else alpha_ctl &= ~DF_ACTRL_WIN_ENABLE;
+ WRITE_VID32 ((DF_ALPHA_CONTROL_1 + (window << 5)), alpha_ctl);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_no_ck_outside_alpha
+ *
+ * This function affects how color/chroma keying is performed inside the video
+ * window.
+ *
+ * If enable is 1, color/chroma key comparison is performed only inside
+ * the enabled alpha windows. Outside the enabled alpha windows, video
+ * is displayed if color keying is enabled, or graphics is displayed if
+ * chroma keying is enabled.
+ * If enable is 0, color/chroma key comparison is performed inside the
+ * entire video window.
+ *--------------------------------------------------------------------------*/
+
+int df_set_no_ck_outside_alpha (int enable)
+{
+ unsigned long value;
+
+ value = READ_VID32 (DF_VID_ALPHA_CONTROL);
+ if (enable) value |= DF_NO_CK_OUTSIDE_ALPHA;
+ else value &= ~DF_NO_CK_OUTSIDE_ALPHA;
+ WRITE_VID32 (DF_VID_ALPHA_CONTROL, value);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_request
+ *
+ * This routine sets the horizontal (pixel) and vertical (line) video request
+ * values.
+ *--------------------------------------------------------------------------*/
+
+int df_set_video_request (unsigned long x, unsigned long y)
+{
+ unsigned long htotal, hsyncend;
+ unsigned long vtotal, vsyncend;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+
+ /* SET DISPLAY FILTER VIDEO REQUEST */
+
+ x += htotal - hsyncend - 2;
+ y += vtotal - vsyncend + 1;
+
+ if (x >= 0x1000 || y >= 0x800)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ WRITE_VID32(DF_VIDEO_REQUEST, (y | (x << 16)));
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_output_color_space
+ *
+ * This routine sets the color space used when combining graphics and video.
+ *--------------------------------------------------------------------------*/
+
+int df_set_output_color_space (int color_space)
+{
+ unsigned long alpha_ctl;
+
+ alpha_ctl = READ_VID32 (DF_VID_ALPHA_CONTROL);
+
+ alpha_ctl &= ~(DF_CSC_GRAPHICS_RGB_TO_YUV | DF_CSC_VIDEO_YUV_TO_RGB |
+ DF_HD_GRAPHICS | DF_YUV_CSC_EN | DF_ALPHA_DRGB);
+
+ /* OUTPUT IS RGB */
+ /* Enable YUV->RGB CSC if necessary and enable alpha output if */
+ /* requested. */
+
+ if (color_space == DF_OUTPUT_RGB || color_space == DF_OUTPUT_ARGB)
+ {
+ if (!(alpha_ctl & DF_VIDEO_INPUT_IS_RGB))
+ alpha_ctl |= DF_CSC_VIDEO_YUV_TO_RGB;
+
+ if (color_space == DF_OUTPUT_ARGB)
+ alpha_ctl |= DF_ALPHA_DRGB;
+ }
+
+ /* OUTPUT IS YUV */
+ /* Enable YUV->YUV CSC if necessary and enable RGB->YUV CSC. */
+
+ else if (color_space == DF_OUTPUT_SDTV || color_space == DF_OUTPUT_HDTV)
+ {
+ alpha_ctl |= DF_CSC_GRAPHICS_RGB_TO_YUV;
+
+ if ( ((alpha_ctl & DF_HD_VIDEO) && color_space == DF_OUTPUT_SDTV) ||
+ (!(alpha_ctl & DF_HD_VIDEO) && color_space == DF_OUTPUT_HDTV))
+ {
+ alpha_ctl |= DF_YUV_CSC_EN;
+ }
+
+ if (color_space == DF_OUTPUT_HDTV)
+ alpha_ctl |= DF_HD_GRAPHICS;
+ }
+ else
+ return CIM_STATUS_INVALIDPARAMS;
+
+ WRITE_VID32 (DF_VID_ALPHA_CONTROL, alpha_ctl);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_output_path
+ *
+ * This routine changes the current output path in the display filter.
+ *--------------------------------------------------------------------------*/
+
+int df_set_output_path (int format)
+{
+ unsigned long panel_tim2, panel_pm;
+ unsigned long output = 0;
+ Q_WORD msr_value;
+
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
+ msr_value.low &= ~(DF_SIMULTANEOUS_CRT_FP | DF_CONFIG_OUTPUT_MASK);
+ panel_tim2 = READ_VID32 (DF_VIDEO_PANEL_TIM2);
+ panel_pm = READ_VID32 (DF_POWER_MANAGEMENT);
+
+ if (format == DF_DISPLAY_CRT)
+ {
+ /* SiBZ #4188 */
+ /* When CRT output is selected, the DF drives the DISP_EN signal */
+ /* with the CRT display enable. As a consequence, systems that */
+ /* wire the DISP_EN signal to the TFT backlight control will not */
+ /* be able to set CRT-only output without leaving the backlight */
+ /* enabled. To workaround this issue, we are setting simultaneous */
+ /* TFT/CRT and disabling the TFT logic. The only caveat to this */
+ /* is that some TFT pins are shared with VIP 601 pins. VIP 601 */
+ /* will thus not work when in this pseudo-CRT mode. To address */
+ /* THAT issue, normal CRT mode sets (in cim_vg.c) will set CRT */
+ /* as the DF output format. This will allow VIP 601 on CRT-only */
+ /* systems without a TFT attached. */
+
+ panel_pm &= ~DF_PM_PANEL_ON;
+ panel_tim2 |= DF_PMTIM2_TFT_PASSHTHROUGH;
+ output = DF_OUTPUT_PANEL | DF_SIMULTANEOUS_CRT_FP;
+ }
+ else if (format == DF_DISPLAY_FP || format == DF_DISPLAY_CRT_FP)
+ {
+ panel_pm |= DF_PM_PANEL_ON;
+ panel_tim2 &= ~DF_PMTIM2_TFT_PASSHTHROUGH;
+
+ if (format == DF_DISPLAY_FP)
+ output = DF_OUTPUT_PANEL;
+ else if (format == DF_DISPLAY_CRT_FP)
+ output = DF_OUTPUT_PANEL | DF_SIMULTANEOUS_CRT_FP;
+ }
+ else
+ {
+ switch (format)
+ {
+ case DF_DISPLAY_VOP: output = DF_OUTPUT_VOP; break;
+ case DF_DISPLAY_DRGB: output = DF_OUTPUT_DRGB; break;
+ case DF_DISPLAY_CRT_DRGB: output = DF_OUTPUT_DRGB | DF_SIMULTANEOUS_CRT_FP; break;
+ default:
+ return CIM_STATUS_INVALIDPARAMS;
+ }
+ }
+ msr_value.low |= output;
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
+ WRITE_VID32 (DF_VIDEO_PANEL_TIM2, panel_tim2);
+ WRITE_VID32 (DF_POWER_MANAGEMENT, panel_pm);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_test_video_flip_status
+ *
+ * This routine tests if a new video offset has been latched.
+ *--------------------------------------------------------------------------*/
+
+unsigned long df_test_video_flip_status (void)
+{
+ return (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VFLIP);
+}
+
+/*---------------------------------------------------------------------------
+ * df_save_state
+ *
+ * This routine saves all persistent DF state information.
+ *---------------------------------------------------------------------------*/
+
+int df_save_state (DF_SAVE_RESTORE *df_state)
+{
+ unsigned long i;
+
+ /* READ ALL DF REGISTERS */
+
+ df_state->vcfg = READ_VID32 (DF_VIDEO_CONFIG);
+ df_state->dcfg = READ_VID32 (DF_DISPLAY_CONFIG);
+ df_state->video_x = READ_VID32 (DF_VIDEO_X_POS);
+ df_state->video_y = READ_VID32 (DF_VIDEO_Y_POS);
+ df_state->video_scaler = READ_VID32 (DF_VIDEO_SCALER);
+ df_state->video_color_key = READ_VID32 (DF_VIDEO_COLOR_KEY);
+ df_state->video_color_mask = READ_VID32 (DF_VIDEO_COLOR_MASK);
+ df_state->sat_limit = READ_VID32 (DF_SATURATION_LIMIT);
+ df_state->vid_misc = READ_VID32 (DF_VID_MISC);
+ df_state->video_yscale = READ_VID32 (DF_VIDEO_YSCALE);
+ df_state->video_xscale = READ_VID32 (DF_VIDEO_XSCALE);
+ df_state->vid_alpha_control = READ_VID32 (DF_VID_ALPHA_CONTROL);
+ df_state->cursor_key = READ_VID32 (DF_CURSOR_COLOR_KEY);
+ df_state->cursor_mask = READ_VID32 (DF_CURSOR_COLOR_MASK);
+ df_state->cursor_color1 = READ_VID32 (DF_CURSOR_COLOR_1);
+ df_state->cursor_color2 = READ_VID32 (DF_CURSOR_COLOR_2);
+ df_state->alpha_xpos1 = READ_VID32 (DF_ALPHA_XPOS_1);
+ df_state->alpha_ypos1 = READ_VID32 (DF_ALPHA_YPOS_1);
+ df_state->alpha_color1 = READ_VID32 (DF_ALPHA_COLOR_1);
+ df_state->alpha_control1 = READ_VID32 (DF_ALPHA_CONTROL_1);
+ df_state->alpha_xpos2 = READ_VID32 (DF_ALPHA_XPOS_2);
+ df_state->alpha_ypos2 = READ_VID32 (DF_ALPHA_YPOS_2);
+ df_state->alpha_color2 = READ_VID32 (DF_ALPHA_COLOR_2);
+ df_state->alpha_control2 = READ_VID32 (DF_ALPHA_CONTROL_2);
+ df_state->alpha_xpos3 = READ_VID32 (DF_ALPHA_XPOS_3);
+ df_state->alpha_ypos3 = READ_VID32 (DF_ALPHA_YPOS_3);
+ df_state->alpha_color3 = READ_VID32 (DF_ALPHA_COLOR_3);
+ df_state->alpha_control3 = READ_VID32 (DF_ALPHA_CONTROL_3);
+ df_state->vid_request = READ_VID32 (DF_VIDEO_REQUEST);
+ df_state->vid_ypos_even = READ_VID32 (DF_VID_YPOS_EVEN);
+ df_state->alpha_ypos_even1 = READ_VID32 (DF_VID_ALPHA_Y_EVEN_1);
+ df_state->alpha_ypos_even2 = READ_VID32 (DF_VID_ALPHA_Y_EVEN_2);
+ df_state->alpha_ypos_even3 = READ_VID32 (DF_VID_ALPHA_Y_EVEN_3);
+ df_state->panel_tim1 = READ_VID32 (DF_VIDEO_PANEL_TIM1);
+ df_state->panel_tim2 = READ_VID32 (DF_VIDEO_PANEL_TIM2);
+ df_state->panel_pm = READ_VID32 (DF_POWER_MANAGEMENT);
+ df_state->panel_dither = READ_VID32 (DF_DITHER_CONTROL);
+
+ /* READ DF PALETTE */
+
+ WRITE_VID32 (DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ df_state->palette[i] = READ_VID32 (DF_PALETTE_DATA);
+
+ /* READ FILTER COEFFICIENTS */
+
+ for (i = 0; i < 512; i++)
+ df_state->coefficients[i] = READ_VID32 (DF_COEFFICIENT_BASE + (i << 2));
+
+ /* READ ALL DF MSRS */
+
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CAP, &(df_state->msr_cap));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &(df_state->msr_config));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_SMI, &(df_state->msr_smi));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_ERROR, &(df_state->msr_error));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_PM, &(df_state->msr_pm));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &(df_state->msr_diag));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &(df_state->msr_df_diag));
+ msr_read64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &(df_state->msr_pad_sel));
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_restore_state
+ *
+ * This routine restores all persistent DF state information.
+ *---------------------------------------------------------------------------*/
+
+int df_restore_state (DF_SAVE_RESTORE *df_state)
+{
+ unsigned long i;
+
+ /* CLEAR VCFG AND DCFG */
+
+ WRITE_VID32 (DF_VIDEO_CONFIG, 0);
+ WRITE_VID32 (DF_DISPLAY_CONFIG, 0);
+
+ /* RESTORE DF MSRS */
+
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CAP, &(df_state->msr_cap));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &(df_state->msr_config));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_SMI, &(df_state->msr_smi));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_ERROR, &(df_state->msr_error));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_PM, &(df_state->msr_pm));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &(df_state->msr_diag));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &(df_state->msr_df_diag));
+ msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL, &(df_state->msr_pad_sel));
+
+ /* RESTORE ALL DF REGISTERS */
+
+ WRITE_VID32 (DF_VIDEO_X_POS, df_state->video_x);
+ WRITE_VID32 (DF_VIDEO_Y_POS, df_state->video_y);
+ WRITE_VID32 (DF_VIDEO_SCALER, df_state->video_scaler);
+ WRITE_VID32 (DF_VIDEO_COLOR_KEY, df_state->video_color_key);
+ WRITE_VID32 (DF_VIDEO_COLOR_MASK, df_state->video_color_mask);
+ WRITE_VID32 (DF_SATURATION_LIMIT, df_state->sat_limit);
+ WRITE_VID32 (DF_VID_MISC, df_state->vid_misc);
+ WRITE_VID32 (DF_VIDEO_YSCALE, df_state->video_yscale);
+ WRITE_VID32 (DF_VIDEO_XSCALE, df_state->video_xscale);
+ WRITE_VID32 (DF_VID_ALPHA_CONTROL, df_state->vid_alpha_control);
+ WRITE_VID32 (DF_CURSOR_COLOR_KEY, df_state->cursor_key);
+ WRITE_VID32 (DF_CURSOR_COLOR_MASK, df_state->cursor_mask);
+ WRITE_VID32 (DF_CURSOR_COLOR_1, df_state->cursor_color1);
+ WRITE_VID32 (DF_CURSOR_COLOR_2, df_state->cursor_color2);
+ WRITE_VID32 (DF_ALPHA_XPOS_1, df_state->alpha_xpos1);
+ WRITE_VID32 (DF_ALPHA_YPOS_1, df_state->alpha_ypos1);
+ WRITE_VID32 (DF_ALPHA_COLOR_1, df_state->alpha_color1);
+ WRITE_VID32 (DF_ALPHA_CONTROL_1, df_state->alpha_control1);
+ WRITE_VID32 (DF_ALPHA_XPOS_2, df_state->alpha_xpos2);
+ WRITE_VID32 (DF_ALPHA_YPOS_2, df_state->alpha_ypos2);
+ WRITE_VID32 (DF_ALPHA_COLOR_2, df_state->alpha_color2);
+ WRITE_VID32 (DF_ALPHA_CONTROL_2, df_state->alpha_control1);
+ WRITE_VID32 (DF_ALPHA_XPOS_3, df_state->alpha_xpos3);
+ WRITE_VID32 (DF_ALPHA_YPOS_3, df_state->alpha_ypos3);
+ WRITE_VID32 (DF_ALPHA_COLOR_3, df_state->alpha_color3);
+ WRITE_VID32 (DF_ALPHA_CONTROL_3, df_state->alpha_control3);
+ WRITE_VID32 (DF_VIDEO_REQUEST, df_state->vid_request);
+ WRITE_VID32 (DF_VID_YPOS_EVEN, df_state->vid_ypos_even);
+ WRITE_VID32 (DF_VID_ALPHA_Y_EVEN_1, df_state->alpha_ypos_even1);
+ WRITE_VID32 (DF_VID_ALPHA_Y_EVEN_2, df_state->alpha_ypos_even2);
+ WRITE_VID32 (DF_VID_ALPHA_Y_EVEN_3, df_state->alpha_ypos_even3);
+ WRITE_VID32 (DF_VIDEO_PANEL_TIM1, df_state->panel_tim1);
+ WRITE_VID32 (DF_VIDEO_PANEL_TIM2, df_state->panel_tim2);
+ WRITE_VID32 (DF_POWER_MANAGEMENT, df_state->panel_pm);
+ WRITE_VID32 (DF_DITHER_CONTROL, df_state->panel_dither);
+
+ /* RESTORE DF PALETTE */
+
+ WRITE_VID32 (DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ WRITE_VID32 (DF_PALETTE_DATA, df_state->palette[i]);
+
+ /* RESTORE FILTER COEFFICIENTS */
+
+ for (i = 0; i < 512; i++)
+ WRITE_VID32 (DF_COEFFICIENT_BASE + (i << 2), df_state->coefficients[i]);
+
+ /* RESTORE DCFG AND VCFG */
+
+ WRITE_VID32 (DF_DISPLAY_CONFIG, df_state->dcfg);
+ WRITE_VID32 (DF_VIDEO_CONFIG, df_state->vcfg);
+
+ return CIM_STATUS_OK;
+}
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * CIMARRON DF READ ROUTINES
+ * These routines are included for use in diagnostics or when debugging. They
+ * can be optionally excluded from a project.
+ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+#if CIMARRON_INCLUDE_DF_READ_ROUTINES
+
+/*---------------------------------------------------------------------------
+ * df_read_composite_crc
+ *
+ * This routine reads the CRC of the combination of graphics/video data. This
+ * CRC checks data immediately before the CRT DACs.
+ *---------------------------------------------------------------------------*/
+
+unsigned long df_read_composite_crc (int crc_source)
+{
+ Q_WORD msr_value;
+ unsigned long crc;
+ unsigned long interlaced;
+ unsigned long line, field;
+ unsigned long timeout = 1000;
+
+ if (!(READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* ENABLE 32-BIT CRCS */
+
+ msr_read64 (MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+ msr_value.low |= DF_DIAG_32BIT_CRC;
+ msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+
+ /* RESET THE CRC */
+
+ WRITE_VID32 (DF_VID_CRC, 0);
+
+ /* WAIT FOR THE RESET TO BE LATCHED */
+
+ while ((READ_VID32 (DF_VID_CRC32) != 0x00000001) && timeout)
+ timeout--;
+
+ /* WAIT FOR THE CORRECT FIELD */
+ /* We use the VG line count and field indicator to determine when */
+ /* to kick off a CRC. */
+
+ if (crc_source & DF_CRC_SOURCE_EVEN) field = 0;
+ else field = DC3_LNCNT_EVEN_FIELD;
+
+ if ((interlaced = (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)))
+ {
+ /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
+ /* Note that we wait for the field to be odd when CRCing the even */
+ /* field and vice versa. This is because the CRC will not begin */
+ /* until the following field. */
+
+ do
+ {
+ line = READ_REG32 (DC3_LINE_CNT_STATUS);
+ } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 10 ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 15);
+ }
+ else
+ {
+ /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
+
+ if (crc_source & DF_CRC_SOURCE_EVEN)
+ return 0xFFFFFFFF;
+ }
+
+ /* ENABLE THE CRC */
+
+ WRITE_VID32 (DF_VID_CRC, 1);
+
+ /* WAIT FOR THE CRC TO BE COMPLETED */
+
+ while (!(READ_VID32 (DF_VID_CRC) & 4))
+ ;
+
+ crc = READ_VID32 (DF_VID_CRC32);
+
+ return crc;
+}
+
+/*---------------------------------------------------------------------------
+ * df_read_composite_window_crc
+ *
+ * This routine reads the CRC of a rectangular subsection of the combination
+ * of graphics/video data.
+ *---------------------------------------------------------------------------*/
+
+unsigned long df_read_composite_window_crc (unsigned long x, unsigned long y,
+ unsigned long width, unsigned long height, int source)
+{
+ Q_WORD msr_value;
+ unsigned long interlaced;
+ unsigned long line, field;
+ unsigned long crc = 0;
+ unsigned long hsyncend, htotal, hsyncstart;
+ unsigned long vsyncend, vtotal, vsyncstart;
+ unsigned long hblankstart, hactive;
+ unsigned long vblankstart, vactive;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ hsyncstart = (READ_REG32 (DC3_H_SYNC_TIMING) & 0xFFF) + 1;
+ hactive = (READ_REG32 (DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
+ hblankstart = (READ_REG32 (DC3_H_BLANK_TIMING) & 0xFFF) + 1;
+ if ((interlaced = (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)) &&
+ !(source & DF_CRC_SOURCE_EVEN))
+ {
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vsyncstart = (READ_REG32 (DC3_V_SYNC_EVEN) & 0xFFF) + 1;
+ vactive = (READ_REG32 (DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
+ vblankstart = (READ_REG32 (DC3_V_BLANK_EVEN) & 0xFFF) + 1;
+ }
+ else
+ {
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncstart = (READ_REG32 (DC3_V_SYNC_TIMING) & 0xFFF) + 1;
+ vactive = (READ_REG32 (DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
+ vblankstart = (READ_REG32 (DC3_V_BLANK_TIMING) & 0xFFF) + 1;
+ }
+
+ /* TIMINGS MUST BE ACTIVE */
+
+ if (!(READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* DISABLE GLCP ACTIONS */
+
+ msr_value.low = 0;
+ msr_value.high = 0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
+
+ /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
+
+ msr_value.low = 5;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
+ msr_value.low = 0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
+ msr_value.low = 3;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
+
+ /* USE H4 FUNCTION A FOR HSYNC AND H4 FUNCTION B FOR NOT HSYNC */
+ /* HSYNC is bit 30 for the DF */
+
+ msr_value.high = 0x00000001;
+ msr_value.low = 0xE0000FF0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
+
+ /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
+ /* VSYNC is bit 54 for VG and bit 29 for DF */
+
+ msr_value.high = 0x00000000;
+ msr_value.low = 0x001D55AA;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
+
+ /* M4 (XSTATE = 00 AND VSYNC HIGH) */
+ /* Goto state 01 */
+ /* Note: VSync = H3A */
+
+ msr_value.high = 0x00000001;
+ msr_value.low = 0x000000A0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 4, &msr_value);
+
+ /* N0 (XSTATE = 01 AND VSYNC LOW) */
+ /* Goto state 02 */
+ /* Note: VSync low = H3B */
+
+ msr_value.high = 0x00040000;
+ msr_value.low = 0x000000C0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL, &msr_value);
+
+ /* M5 (XSTATE = 10 AND VSYNC HIGH) */
+ /* Goto state 11 */
+
+ msr_value.high = 0x00000001;
+ msr_value.low = 0x00000120;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 5, &msr_value);
+
+ /* N1 (XSTATE = 10 and HSYNC LOW) */
+ /* Increment H. Counter */
+ /* Note: HSync = H4 */
+
+ msr_value.high = 0x00080000;
+ msr_value.low = 0x00000120;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 1, &msr_value);
+
+ /* M0 (XSTATE = 10 and H. COUNTER == LIMIT) */
+ /* Clear H. Counter and increment V. Counter */
+
+ msr_value.high = 0x00000000;
+ msr_value.low = 0x00000122;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL, &msr_value);
+
+ /* N4 (XSTATE = 10 && CMP0 <= H. COUNTER <= CMP1 && CMP2 <= V. COUNTER <= CMP3) */
+ /* CRC into REGB */
+
+ msr_value.high = 0x00000000;
+ msr_value.low = 0x10C20120;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 4, &msr_value);
+
+ /* COMPARATOR 0 VALUE */
+ /* Value = xstart + (htotal - hsync_end) - 1 */
+ /* The value will be adjusted for a border if necessary */
+
+ msr_value.low = x + htotal - hsyncend - 1;
+ if (READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
+ msr_value.low -= hblankstart - hactive;
+ msr_value.low--;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0, &msr_value);
+
+ /* COMPARATOR 1 VALUE */
+ /* Value = xstart + (htotal - hsync_end - 1) - 1 + width */
+
+ msr_value.low += width - 1;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 2, &msr_value);
+
+ /* COMPARATOR 2 VALUE */
+ /* Value = ystart + vtotal - vsyncend */
+
+ msr_value.low = (y + vtotal - vsyncend) << 16;
+ if (READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
+ msr_value.low -= (vblankstart - vactive) << 16;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 4, &msr_value);
+
+ /* COMPARATOR 3 VALUE */
+ /* Value = ystart + vtotal - vsyncend + height - 1 */
+
+ msr_value.low += (height - 1) << 16;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 6, &msr_value);
+
+ /* COMPARATOR MASKS */
+ /* Comparators 0 and 1 refer to lower 16 bits of RegB */
+
+ msr_value.low = 0x0000FFFF;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 2, &msr_value);
+
+ /* Comparators 2 and 3 refer to upper 16 bits of RegB */
+
+ msr_value.low = 0xFFFF0000;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 4, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 6, &msr_value);
+
+ /* SET REGB MASK */
+ /* We set the mask such that all only 24 bits of data are CRCed */
+
+ msr_value.low = 0x00FFFFFF;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGBMASK, &msr_value);
+
+ /* SET REGA LIMITS */
+ /* Lower counter uses htotal - sync_time - 1. */
+ /* Upper counter is 0xFFFF to prevent rollover. */
+
+ msr_value.low = 0xFFFF0000 | (htotal - (hsyncend - hsyncstart) - 1);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
+
+ /* ACTIONS */
+
+ /* STATE 00->01 (SET 4M) */
+
+ msr_value.low = 0x000C0000;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 14, &msr_value);
+
+ /* STATE 01->10 (SET 0N) */
+
+ msr_value.low = 0x0000000A;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 15, &msr_value);
+
+ /* STATE 10->11 (SET 5M) */
+
+ msr_value.low = 0x00C00000;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 16, &msr_value);
+
+ /* CLEAR REGA WHEN TRANSITIONING TO STATE 10 */
+ /* Do not clear RegB as the initial value must be 0x00000001 */
+
+ msr_value.low = 0x0000000A;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0, &msr_value);
+
+ /* REGISTER ACTION 1 */
+ /* CRC into RegB if cmp0 <= h.counter <= cmp1 && cmp2 <= v. counter < cmp3 && 7 xstate = 10 8 */
+ /* Increment h.counter if xstate = 10 and HSync is low. */
+
+ msr_value.low = 0x000A00A0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 1, &msr_value);
+
+ /* REGISTER ACTION 2 */
+ /* Increment V. Counter in REGA */
+
+ msr_value.low = 0x0000000C;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 2, &msr_value);
+
+ /* SET REGB TO 0x00000001 */
+
+ msr_value.low = 0x00000001;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
+
+ /* SET XSTATE TO 0 */
+
+ msr_value.low = 0x00000000;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
+
+ /* CLEAR ALL OTHER ACTIONS */
+ /* This prevents side-effects from previous accesses to the GLCP */
+ /* debug logic. */
+
+ msr_value.low = 0x00000000;
+ msr_value.high = 0x00000000;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 3, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 4, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 5, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 6, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 7, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 8, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 9, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 10, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 11, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 12, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 13, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 17, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 18, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 19, &msr_value);
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 20, &msr_value);
+
+ /* WAIT FOR THE CORRECT FIELD */
+ /* We use the VG line count and field indicator to determine when */
+ /* to kick off a CRC. */
+
+ if (source & DF_CRC_SOURCE_EVEN) field = 0;
+ else field = DC3_LNCNT_EVEN_FIELD;
+
+ if (interlaced)
+ {
+ /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
+ /* Note that we wait for the field to be odd when CRCing the even */
+ /* field and vice versa. This is because the CRC will not begin */
+ /* until the following field. */
+
+ do
+ {
+ line = READ_REG32 (DC3_LINE_CNT_STATUS);
+ } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 1 ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 5);
+ }
+ else
+ {
+ /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
+
+ if (source & DF_CRC_SOURCE_EVEN)
+ return 0xFFFFFFFF;
+ }
+
+ /* CONFIGURE DISPLAY FILTER TO LOAD DATA ONTO LOWER 32-BITS */
+
+ msr_value.high = 0;
+ msr_value.low = 0x0000800B;
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &msr_value);
+
+ /* CONFIGURE DIAG CONTROL */
+ /* Set RegA action1 to increment lower 16 bits and clear at limit. (5) */
+ /* Set RegA action2 to increment upper 16 bits. (6) */
+ /* Set RegB action1 to CRC32 (1) */
+ /* Set all comparators to REGA override (0,1 lower mbus, 2,3 upper mbus) */
+ /* Enable all actions */
+
+ msr_value.low = 0x80EA20A0;
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
+
+ /* DELAY TWO FRAMES */
+
+ while (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
+ while (!(READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA));
+ while (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
+ while (!(READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA));
+ while (READ_REG32 (DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA);
+
+ /* VERIFY THAT XSTATE = 11 */
+
+ msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
+ if ((msr_value.low & 3) == 3)
+ {
+ msr_read64 (MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
+
+ crc = msr_value.low;
+ }
+
+ /* DISABLE DF DIAG BUS OUTPUTS */
+
+ msr_value.low = 0x00000000;
+ msr_value.high = 0x00000000;
+ msr_write64 (MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &msr_value);
+
+ /* DISABLE GLCP ACTIONS */
+
+ msr_write64 (MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
+
+ return crc;
+}
+
+/*---------------------------------------------------------------------------
+ * df_read_panel_crc
+ *
+ * This routine reads the CRC for a frame of data after the panel dithering
+ * logic.
+ *---------------------------------------------------------------------------*/
+
+unsigned long df_read_panel_crc (void)
+{
+ Q_WORD msr_value;
+ unsigned long timeout = 1000;
+
+ if (!(READ_REG32 (DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* ENABLE 32-BIT CRCS */
+
+ msr_read64 (MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+ msr_value.low |= DF_DIAG_32BIT_CRC;
+ msr_write64 (MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+
+ /* RESET CRC */
+
+ WRITE_VID32 (DF_PANEL_CRC, 0);
+
+ /* WAIT FOR THE RESET TO BE LATCHED */
+
+ while ((READ_VID32 (DF_PANEL_CRC32) != 0x00000001) && timeout)
+ timeout--;
+
+ WRITE_VID32 (DF_PANEL_CRC, 1);
+
+ /* WAIT FOR THE CRC TO BE COMPLETED */
+
+ while (!(READ_VID32 (DF_PANEL_CRC) & 4))
+ ;
+
+ return READ_VID32 (DF_PANEL_CRC32);
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_enable
+ *
+ * This routine reads the enable status of the video overlay.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_enable (int *enable, unsigned long *flags)
+{
+ *enable = 0;
+ *flags = 0;
+ if (READ_VID32 (DF_VIDEO_CONFIG) & DF_VCFG_VID_EN)
+ {
+ *enable = 1;
+
+ /* CHECK FOR COLOR KEY DISABLED */
+ /* Color keying can be completely disabled when video is enabled to */
+ /* allow unhindered per-pixel alpha blending. As color keying is */
+ /* always disabled when video is disabled, it is only possible to */
+ /* test for this condition when video is enabled. */
+
+ if (!(READ_VID32 (DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK) &&
+ !(READ_REG32 (DC3_COLOR_KEY) & DC3_CLR_KEY_ENABLE))
+ {
+ *flags = DF_ENABLEFLAG_NOCOLORKEY;
+ }
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_source_configuration
+ *
+ * This routine reads the current configuration of the source buffers for the
+ * video overlay.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_source_configuration (DF_VIDEO_SOURCE_PARAMS *video_source_odd,
+ DF_VIDEO_SOURCE_PARAMS *video_source_even)
+{
+ unsigned long format, temp;
+ unsigned long size;
+
+ /* READ VIDEO FORMAT */
+
+ temp = READ_VID32 (DF_VIDEO_CONFIG);
+
+ format = (temp >> 2) & 3;
+ if (temp & DF_VCFG_4_2_0_MODE)
+ format |= 4;
+ else if (READ_VID32 (DF_VID_ALPHA_CONTROL) & DF_VIDEO_INPUT_IS_RGB)
+ format |= 8;
+ video_source_odd->video_format = format;
+
+ /* CHECK IF SOURCE IS HD VIDEO */
+
+ if (READ_VID32 (DF_VID_ALPHA_CONTROL) & DF_HD_VIDEO)
+ video_source_odd->flags = DF_SOURCEFLAG_HDTVSOURCE;
+ else
+ video_source_odd->flags = 0;
+
+ /* READ SCALING ALGORITHM */
+
+ if (READ_VID32 (DF_VID_MISC) & DF_USER_IMPLICIT_SCALING)
+ video_source_odd->flags |= DF_SOURCEFLAG_IMPLICITSCALING;
+
+ /* READ VIDEO PITCH */
+
+ temp = READ_REG32 (DC3_VID_YUV_PITCH);
+ video_source_odd->y_pitch = (temp & 0xFFFF) << 3;
+ video_source_odd->uv_pitch = (temp >> 16) << 3;
+
+ /* READ VIDEO SIZE */
+
+ temp = READ_VID32 (DF_VIDEO_CONFIG);
+ size = (temp >> 8) & 0xFF;
+ if (temp & DF_VCFG_LINE_SIZE_BIT8) size |= 0x100;
+ if (temp & DF_VCFG_LINE_SIZE_BIT9) size |= 0x200;
+
+ video_source_odd->width = size << 1;
+ video_source_odd->height = READ_VID32 (DF_VIDEO_SCALER) & 0x7FF;
+
+ /* READ VIDEO OFFSETS */
+
+ video_source_odd->y_offset = READ_REG32 (DC3_VID_Y_ST_OFFSET) & 0xFFFFFFF;
+ video_source_odd->u_offset = READ_REG32 (DC3_VID_U_ST_OFFSET) & 0xFFFFFFF;
+ video_source_odd->v_offset = READ_REG32 (DC3_VID_V_ST_OFFSET) & 0xFFFFFFF;
+
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ video_source_even->y_offset = READ_REG32 (DC3_VID_EVEN_Y_ST_OFFSET) & 0xFFFFFFF;
+ video_source_even->u_offset = READ_REG32 (DC3_VID_EVEN_U_ST_OFFSET) & 0xFFFFFFF;
+ video_source_even->v_offset = READ_REG32 (DC3_VID_EVEN_V_ST_OFFSET) & 0xFFFFFFF;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_position
+ *
+ * This routine reads the current position of the video overlay.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_position (DF_VIDEO_POSITION *video_window)
+{
+ unsigned long xreg, yreg, dst_clip, clip;
+ unsigned long height;
+ unsigned long xend, yend;
+ unsigned long hsyncend, htotal;
+ unsigned long vsyncend, vtotal;
+ unsigned long hadjust, vadjust;
+ unsigned long misc, gfxscale;
+ unsigned long temp;
+ long xstart, ystart;
+
+ video_window->flags = DF_POSFLAG_DIRECTCLIP;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+
+ /* ODD FIELD START COUNTS FROM THE EVEN FIELD TIMINGS */
+ /* We assume that the even field y position is always programmed */
+ /* to be just after the odd field. */
+
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ }
+ else
+ {
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ }
+
+ hadjust = htotal - hsyncend - 14;
+ vadjust = vtotal - vsyncend + 1;
+
+ xreg = READ_VID32 (DF_VIDEO_X_POS);
+ yreg = READ_VID32 (DF_VIDEO_Y_POS);
+
+ xstart = (xreg & 0xFFF) - hadjust;
+ ystart = (yreg & 0x7FF) - vadjust;
+ xend = ((xreg >> 16) & 0xFFF) - hadjust;
+ yend = ((yreg >> 16) & 0x7FF) - vadjust;
+
+ height = yend - ystart;
+
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ /* Y COORDINATE IS ACTUALLY 2X THE ODD FIELD START */
+
+ ystart <<= 1;
+
+ /* CALCULATE THE EXACT VIDEO HEIGHT */
+ /* The height of the video window is the sum of the */
+ /* odd and even field heights. */
+
+ yreg = READ_VID32 (DF_VID_YPOS_EVEN);
+ height += ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
+ }
+
+ clip = ((READ_VID32 (DF_VIDEO_CONFIG) >> 16) & 0x1FF) << 2;
+
+ /* ADJUST FOR CLIPPING VALUES THAT ARE NOT FOUR-PIXEL ALIGNED */
+
+ dst_clip = 0;
+ if (xstart < 0)
+ {
+ dst_clip += -xstart;
+ xstart = 0;
+ }
+
+ /* REVERSE THE GRAPHICS SCALE */
+
+ misc = READ_VID32 (DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING)
+ {
+ gfxscale = READ_REG32 (DC3_GFX_SCALE);
+
+ if (gfxscale != 0x40004000)
+ {
+ temp = ystart + height;
+ temp = (temp * (gfxscale >> 16)) / 0x4000;
+
+ xstart = (xstart * (gfxscale & 0xFFFF)) / 0x4000;
+ xend = (xend * (gfxscale & 0xFFFF)) / 0x4000;
+ ystart = (ystart * (gfxscale >> 16)) / 0x4000;
+ height = temp - ystart;
+ }
+ }
+
+ video_window->left_clip = clip;
+ video_window->dst_clip = dst_clip;
+ video_window->x = xstart;
+ video_window->y = ystart;
+ video_window->width = xend - xstart;
+ video_window->height = height;
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_scale
+ *
+ * This routine reads the current scale values for video scaling.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_scale (unsigned long *x_scale, unsigned long *y_scale)
+{
+ *x_scale = READ_VID32 (DF_VIDEO_XSCALE) & 0x000FFFFF;
+ *y_scale = READ_VID32 (DF_VIDEO_YSCALE) & 0x000FFFFF;
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_filter_coefficients
+ *
+ * This routine reads the coefficients for the video scaler/filter.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_filter_coefficients (long taps[][4], int *phase256)
+{
+ unsigned long i, temp;
+ long coeff;
+
+ if (READ_VID32 (DF_VIDEO_SCALER) & DF_SCALE_128_PHASES)
+ *phase256 = 0;
+ else
+ *phase256 = 1;
+
+ for (i = 0; i < 256; i++)
+ {
+ temp = READ_VID32 (DF_COEFFICIENT_BASE + (i << 3));
+
+ /* TAP 0 */
+
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000) coeff = -coeff;
+ taps[i][0] = coeff;
+
+ /* TAP 1 */
+
+ temp >>= 16;
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000) coeff = -coeff;
+ taps[i][1] = coeff;
+
+ temp = READ_VID32 (DF_COEFFICIENT_BASE + (i << 3) + 4);
+
+ /* TAP 2 */
+
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000) coeff = -coeff;
+ taps[i][2] = coeff;
+
+ /* TAP 3 */
+
+ temp >>= 16;
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000) coeff = -coeff;
+ taps[i][3] = coeff;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_color_key
+ *
+ * This routine reads the current settings for hardware color/chroma keying.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_color_key (unsigned long *key, unsigned long *mask, int *graphics)
+{
+ unsigned long chroma = READ_VID32 (DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK;
+
+ if (chroma)
+ {
+ /* CHROMA KEY - READ KEY AND MASK FROM DF */
+
+ *graphics = 0;
+ *key = READ_VID32 (DF_VIDEO_COLOR_KEY) & 0xFFFFFF;
+ *mask = READ_VID32 (DF_VIDEO_COLOR_MASK) & 0xFFFFFF;
+ }
+ else
+ {
+ *graphics = 1;
+
+ *key = READ_REG32 (DC3_COLOR_KEY) & 0xFFFFFF;
+ *mask = READ_REG32 (DC3_COLOR_MASK) & 0xFFFFFF;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_palette_entry
+ *
+ * This routine returns a single palette entry.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_palette_entry(unsigned long index, unsigned long *palette)
+{
+ if (index > 0xFF)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ /* READ A SINGLE ENTRY */
+
+ WRITE_VID32 (DF_PALETTE_ADDRESS, index);
+ *palette = READ_VID32 (DF_PALETTE_DATA);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_palette
+ *
+ * This routine returns the entire video palette.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_palette (unsigned long *palette)
+{
+ unsigned long i;
+
+ WRITE_VID32 (DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ palette[i] = READ_VID32 (DF_PALETTE_DATA);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_cursor_color_key
+ *
+ * This routine returns the current configuration for the hardware video cursor
+ * color key.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_cursor_color_key (DF_VIDEO_CURSOR_PARAMS *cursor_color_key)
+{
+ unsigned long key;
+
+ cursor_color_key->flags = 0;
+ cursor_color_key->color1 = READ_VID32 (DF_CURSOR_COLOR_1) & 0xFFFFFF;
+ cursor_color_key->color2 = READ_VID32 (DF_CURSOR_COLOR_2) & 0xFFFFFF;
+ cursor_color_key->mask = READ_VID32 (DF_CURSOR_COLOR_MASK) & 0xFFFFFF;
+
+ key = READ_VID32 (DF_CURSOR_COLOR_KEY);
+ cursor_color_key->key = key & 0xFFFFFF;
+ cursor_color_key->select_color2 = (key >> 24) & 0x1F;
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_cursor_color_key_enable
+ *
+ * This routine returns the current enable status of the hardware video cursor
+ * color key.
+ *---------------------------------------------------------------------------*/
+
+int df_get_video_cursor_color_key_enable (void)
+{
+ if (READ_VID32 (DF_CURSOR_COLOR_KEY) & DF_CURSOR_COLOR_KEY_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_alpha_window_configuration
+ *
+ * This routine reads the current configuration for one of the three hardware
+ * alpha regions.
+ *---------------------------------------------------------------------------*/
+
+int df_get_alpha_window_configuration (int window, DF_ALPHA_REGION_PARAMS *alpha_data)
+{
+ unsigned long pos, color, alpha_ctl;
+ unsigned long hsyncend, htotal;
+ unsigned long vsyncend, vtotal;
+ unsigned long hadjust, vadjust;
+ unsigned long xreg, yreg;
+ unsigned long misc, gfxscale;
+ unsigned long temp;
+ char delta;
+
+ if (window > 2)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ }
+ else
+ {
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ }
+
+ /* GET PRIORITY */
+
+ pos = 16 + (window << 1);
+ alpha_data->priority = (READ_VID32 (DF_VID_ALPHA_CONTROL) >> pos) & 3L;
+
+ /* GET ALPHA WINDOW */
+
+ hadjust = htotal - hsyncend - 2;
+ vadjust = vtotal - vsyncend + 1;
+
+ xreg = READ_VID32 (DF_ALPHA_XPOS_1 + (window << 5));
+ yreg = READ_VID32 (DF_ALPHA_YPOS_1 + (window << 5));
+ alpha_data->width = ((xreg >> 16) & 0xFFF) - (xreg & 0xFFF);
+ alpha_data->height = ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
+ alpha_data->x = (xreg & 0xFFF) - hadjust;
+ alpha_data->y = (yreg & 0x7FF) - vadjust;
+
+ /* REVERSE THE GRAPHICS SCALE */
+
+ misc = READ_VID32 (DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING)
+ {
+ gfxscale = READ_REG32 (DC3_GFX_SCALE);
+ if (gfxscale != 0x40004000)
+ {
+ temp = alpha_data->y + alpha_data->height;
+ temp = (temp * (gfxscale >> 16)) / 0x4000;
+
+ alpha_data->x = (alpha_data->x * (gfxscale & 0xFFFF)) / 0x4000;
+ alpha_data->width = (alpha_data->width * (gfxscale & 0xFFFF)) / 0x4000;
+ alpha_data->y = (alpha_data->y * (gfxscale >> 16)) / 0x4000;
+ alpha_data->height = temp - alpha_data->y;
+ }
+ }
+
+ if (READ_REG32 (DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)
+ {
+ /* Y COORDINATE IS ACTUALLY 2X THE ODD FIELD START */
+
+ alpha_data->y <<= 1;
+
+ /* CALCULATE THE EXACT VIDEO HEIGHT */
+ /* The height of the video window is the sum of the */
+ /* odd and even field heights. */
+
+ yreg = READ_VID32 (DF_VID_ALPHA_Y_EVEN_1 + (window << 3));
+ alpha_data->height += ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
+ }
+
+ /* GET COLOR REGISTER */
+
+ color = READ_VID32 (DF_ALPHA_COLOR_1 + (window << 5));
+ alpha_data->color = color & 0xFFFFFF;
+ if (color & DF_ALPHA_COLOR_ENABLE)
+ alpha_data->flags = DF_ALPHAFLAG_COLORENABLED;
+ else
+ alpha_data->flags = 0;
+
+ /* GET ALPHA VALUE, DELTA AND PER PIXEL */
+
+ alpha_ctl = READ_VID32 (DF_ALPHA_CONTROL_1 + (window << 5));
+ alpha_data->alpha_value = alpha_ctl & 0xFF;
+ if (alpha_ctl & DF_ACTRL_PERPIXEL_EN)
+ alpha_data->flags |= DF_ALPHAFLAG_PERPIXELENABLED;
+
+ delta = (char)((alpha_ctl >> 8) & 0xFF);
+ alpha_data->delta = (long)delta;
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_alpha_window_enable
+ *
+ * This routine reads the current enable status of one of the three hardware
+ * alpha regions.
+ *---------------------------------------------------------------------------*/
+
+int df_get_alpha_window_enable (int window)
+{
+ if (window > 2)
+ return 0;
+
+ if (READ_VID32 (DF_ALPHA_CONTROL_1 + (window << 5)) & DF_ACTRL_WIN_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_request
+ *
+ * This routine reads the horizontal (pixel) and vertical (line) video request
+ * values.
+ *--------------------------------------------------------------------------*/
+
+int df_get_video_request (unsigned long *x, unsigned long *y)
+{
+ unsigned long request;
+ unsigned long hsyncend, htotal;
+ unsigned long vsyncend, vtotal;
+
+ hsyncend = ((READ_REG32 (DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32 (DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32 (DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32 (DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+
+ request = READ_VID32 (DF_VIDEO_REQUEST);
+ *x = ((request >> 16) & 0xFFF) - (htotal - hsyncend - 2);
+ *y = (request & 0x7FF) - (vtotal - vsyncend + 1);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_output_color_space
+ *
+ * This routine sets the color space used when combining graphics and video.
+ *--------------------------------------------------------------------------*/
+
+int df_get_output_color_space (int *color_space)
+{
+ unsigned long alpha_ctl;
+
+ alpha_ctl = READ_VID32 (DF_VID_ALPHA_CONTROL);
+
+ if ((alpha_ctl & DF_CSC_VIDEO_YUV_TO_RGB) ||
+ !(alpha_ctl & DF_CSC_GRAPHICS_RGB_TO_YUV))
+ {
+ if (alpha_ctl & DF_ALPHA_DRGB)
+ *color_space = DF_OUTPUT_ARGB;
+ else
+ *color_space = DF_OUTPUT_RGB;
+ }
+ else
+ {
+ *color_space = DF_OUTPUT_SDTV;
+
+ if (alpha_ctl & DF_HD_GRAPHICS)
+ *color_space = DF_OUTPUT_HDTV;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+#endif
Index: linux-2.6.11/lib/cimarron/cim/cim_filter.c
===================================================================
--- /dev/null
+++ linux-2.6.11/lib/cimarron/cim/cim_filter.c
@@ -0,0 +1,533 @@
+ /*
+ *
+ * Copyright (C) 2005 Advanced Micro Devices, Inc. All Rights Reserved.
+ *
+ *
+ *
+ *
+ *
+ *
+ * Cimarron default video coefficients.
+ *
+ *
+ */
+
+long CimarronVideoFilter256[][2] =
+{
+ { 0x10000000, 0x00000000 }, /* 0, 4096, 0, 0 */
+ { 0x10008008, 0x00000008 }, /* -8, 4096, 8, 0 */
+ { 0x10008010, 0x80010011 }, /* -16, 4096, 17, -1 */
+ { 0x10008019, 0x8001001A }, /* -25, 4096, 26, -1 */
+ { 0x10008021, 0x80020023 }, /* -33, 4096, 35, -2 */
+ { 0x0FFF8029, 0x8003002D }, /* -41, 4095, 45, -3 */
+ { 0x0FFE8031, 0x80030036 }, /* -49, 4094, 54, -3 */
+ { 0x0FFC8038, 0x80040040 }, /* -56, 4092, 64, -4 */
+ { 0x0FFB8040, 0x8005004A }, /* -64, 4091, 74, -5 */
+ { 0x0FF88047, 0x80050054 }, /* -71, 4088, 84, -5 */
+ { 0x0FF6804E, 0x8006005E }, /* -78, 4086, 94, -6 */
+ { 0x0FF48055, 0x80070068 }, /* -85, 4084, 104, -7 */
+ { 0x0FF0805C, 0x80070073 }, /* -92, 4080, 115, -7 */
+ { 0x0FEE8063, 0x8008007D }, /* -99, 4078, 125, -8 */
+ { 0x0FEA8069, 0x80090088 }, /* -105, 4074, 136, -9 */
+ { 0x0FE78070, 0x800A0093 }, /* -112, 4071, 147, -10 */
+ { 0x0FE28076, 0x800A009E }, /* -118, 4066, 158, -10 */
+ { 0x0FDD807C, 0x800B00AA }, /* -124, 4061, 170, -11 */
+ { 0x0FD98082, 0x800C00B5 }, /* -130, 4057, 181, -12 */
+ { 0x0FD48088, 0x800D00C1 }, /* -136, 4052, 193, -13 */
+ { 0x0FCE808E, 0x800D00CD }, /* -142, 4046, 205, -13 */
+ { 0x0FC88093, 0x800E00D9 }, /* -147, 4040, 217, -14 */
+ { 0x0FC38099, 0x800F00E5 }, /* -153, 4035, 229, -15 */
+ { 0x0FBD809E, 0x801000F1 }, /* -158, 4029, 241, -16 */
+ { 0x0FB680A3, 0x801000FD }, /* -163, 4022, 253, -16 */
+ { 0x0FAF80A8, 0x8011010A }, /* -168, 4015, 266, -17 */
+ { 0x0FA880AD, 0x80120117 }, /* -173, 4008, 279, -18 */
+ { 0x0FA180B2, 0x80130124 }, /* -178, 4001, 292, -19 */
+ { 0x0F9980B6, 0x80140131 }, /* -182, 3993, 305, -20 */
+ { 0x0F9280BB, 0x8015013E }, /* -187, 3986, 318, -21 */
+ { 0x0F8880BF, 0x8015014C }, /* -191, 3976, 332, -21 */
+ { 0x0F8080C3, 0x80160159 }, /* -195, 3968, 345, -22 */
+ { 0x0F7880C8, 0x80170167 }, /* -200, 3960, 359, -23 */
+ { 0x0F6E80CB, 0x80180175 }, /* -203, 3950, 373, -24 */
+ { 0x0F6580CF, 0x80190183 }, /* -207, 3941, 387, -25 */
+ { 0x0F5C80D3, 0x801A0191 }, /* -211, 3932, 401, -26 */
+ { 0x0F5280D7, 0x801B01A0 }, /* -215, 3922, 416, -27 */
+ { 0x0F4880DA, 0x801C01AE }, /* -218, 3912, 430, -28 */
+ { 0x0F3D80DD, 0x801D01BD }, /* -221, 3901, 445, -29 */
+ { 0x0F3280E0, 0x801E01CC }, /* -224, 3890, 460, -30 */
+ { 0x0F2880E4, 0x801F01DB }, /* -228, 3880, 475, -31 */
+ { 0x0F1C80E6, 0x802001EA }, /* -230, 3868, 490, -32 */
+ { 0x0F1180E9, 0x802101F9 }, /* -233, 3857, 505, -33 */
+ { 0x0F0480EB, 0x80210208 }, /* -235, 3844, 520, -33 */
+ { 0x0EFA80EF, 0x80230218 }, /* -239, 3834, 536, -35 */
+ { 0x0EEC80F0, 0x80230227 }, /* -240, 3820, 551, -35 */
+ { 0x0EE080F3, 0x80240237 }, /* -243, 3808, 567, -36 */
+ { 0x0ED380F5, 0x80250247 }, /* -245, 3795, 583, -37 */
+ { 0x0EC780F7, 0x80270257 }, /* -247, 3783, 599, -39 */
+ { 0x0EB980F9, 0x80280268 }, /* -249, 3769, 616, -40 */
+ { 0x0EAC80FB, 0x80290278 }, /* -251, 3756, 632, -41 */
+ { 0x0E9E80FD, 0x802A0289 }, /* -253, 3742, 649, -42 */
+ { 0x0E9080FE, 0x802B0299 }, /* -254, 3728, 665, -43 */
+ { 0x0E838100, 0x802D02AA }, /* -256, 3715, 682, -45 */
+ { 0x0E758102, 0x802E02BB }, /* -258, 3701, 699, -46 */
+ { 0x0E668103, 0x802F02CC }, /* -259, 3686, 716, -47 */
+ { 0x0E568104, 0x803002DE }, /* -260, 3670, 734, -48 */
+ { 0x0E498106, 0x803202EF }, /* -262, 3657, 751, -50 */
+ { 0x0E398107, 0x80330301 }, /* -263, 3641, 769, -51 */
+ { 0x0E298108, 0x80340313 }, /* -264, 3625, 787, -52 */
+ { 0x0E1A8109, 0x80360325 }, /* -265, 3610, 805, -54 */
+ { 0x0E0B810A, 0x80370336 }, /* -266, 3595, 822, -55 */
+ { 0x0DFA810A, 0x80380348 }, /* -266, 3578, 840, -56 */
+ { 0x0DEA810B, 0x803A035B }, /* -267, 3562, 859, -58 */
+ { 0x0DDA810C, 0x803B036D }, /* -268, 3546, 877, -59 */
+ { 0x0DCA810C, 0x803D037F }, /* -268, 3530, 895, -61 */
+ { 0x0DB7810B, 0x803E0392 }, /* -267, 3511, 914, -62 */
+ { 0x0DA7810C, 0x804003A5 }, /* -268, 3495, 933, -64 */
+ { 0x0D95810C, 0x804103B8 }, /* -268, 3477, 952, -65 */
+ { 0x0D85810C, 0x804303CA }, /* -268, 3461, 970, -67 */
+ { 0x0D73810C, 0x804403DD }, /* -268, 3443, 989, -68 */
+ { 0x0D61810C, 0x804603F1 }, /* -268, 3425, 1009, -70 */
+ { 0x0D50810C, 0x80480404 }, /* -268, 3408, 1028, -72 */
+ { 0x0D3E810C, 0x80490417 }, /* -268, 3390, 1047, -73 */
+ { 0x0D2C810C, 0x804B042B }, /* -268, 3372, 1067, -75 */
+ { 0x0D1B810C, 0x804D043E }, /* -268, 3355, 1086, -77 */
+ { 0x0D07810B, 0x804E0452 }, /* -267, 3335, 1106, -78 */
+ { 0x0CF5810B, 0x80500466 }, /* -267, 3317, 1126, -80 */
+ { 0x0CE2810A, 0x8052047A }, /* -266, 3298, 1146, -82 */
+ { 0x0CCF810A, 0x8053048E }, /* -266, 3279, 1166, -83 */
+ { 0x0CBC8109, 0x805504A2 }, /* -265, 3260, 1186, -85 */
+ { 0x0CA98108, 0x805704B6 }, /* -264, 3241, 1206, -87 */
+ { 0x0C968108, 0x805904CB }, /* -264, 3222, 1227, -89 */
+ { 0x0C838107, 0x805B04DF }, /* -263, 3203, 1247, -91 */
+ { 0x0C6F8106, 0x805C04F3 }, /* -262, 3183, 1267, -92 */
+ { 0x0C5B8105, 0x805E0508 }, /* -261, 3163, 1288, -94 */
+ { 0x0C478104, 0x8060051D }, /* -260, 3143, 1309, -96 */
+ { 0x0C348103, 0x80620531 }, /* -259, 3124, 1329, -98 */
+ { 0x0C1F8102, 0x80640547 }, /* -258, 3103, 1351, -100 */
+ { 0x0C0C8101, 0x8066055B }, /* -257, 3084, 1371, -102 */
+ { 0x0BF88100, 0x80680570 }, /* -256, 3064, 1392, -104 */
+ { 0x0BE380FE, 0x806A0585 }, /* -254, 3043, 1413, -106 */
+ { 0x0BCF80FD, 0x806C059A }, /* -253, 3023, 1434, -108 */
+ { 0x0BBA80FC, 0x806E05B0 }, /* -252, 3002, 1456, -110 */
+ { 0x0BA480F9, 0x807005C5 }, /* -249, 2980, 1477, -112 */
+ { 0x0B8F80F8, 0x807205DB }, /* -248, 2959, 1499, -114 */
+ { 0x0B7A80F6, 0x807405F0 }, /* -246, 2938, 1520, -116 */
+ { 0x0B6580F5, 0x80760606 }, /* -245, 2917, 1542, -118 */
+ { 0x0B4F80F3, 0x8077061B }, /* -243, 2895, 1563, -119 */
+ { 0x0B3A80F2, 0x80790631 }, /* -242, 2874, 1585, -121 */
+