SD/MMC driver for OpenRD Board

Tobias Quintern Tobias.Quintern at brunel.de
Tue May 10 12:55:43 UTC 2011


Hello,

I've integrated Rafal Czubaks SDIO driver
(http://people.freebsd.org/~raj/misc/mv_sdio.c) into the FreeBSD HEAD
(r221725).

The patch has been verified to function with the OpenRD Ultimate board. To
ensure data-consistency the options noclusterr and noclusterw have to be
given to mount.

This is the current status:

- Booting from SD works
- DMA transfers work fine
- PIO transfers not tested

This patch only adds SDIO support to the kernel. The current Ethernet-Issues
(http://www.freebsd.org/cgi/query-pr.cgi?pr=156814) have to be patched
separately. The openrd-cl.dts from this patch is preferable over the patch
from Arnaud, because it includes the configuration for several SD specific
GPIO pins.

I attached 3 different kernel-configs for the sake of completeness. The
OPENRD-CL-SDBOOT and OPENRD-CL-SATABOOT work just fine.
 
The OPENRD-CL config tries to boot via BOOTP/NFS, which seems to be broken
momentarily. I have an older SVN checkout (r219450) where the board is able
to boot from NFS. That kernel is patched quite similar to
http://www.freebsd.org/cgi/query-pr.cgi?pr=156814.
A bootlog of the failed boot is attached.	

Regards
Tobias 
-------------- next part --------------
## Starting application at 0x00900000 ...
 dtbp = 0xc0be3f10
KDB: debugger backends: ddb
KDB: current backend: ddb
Copyright (c) 1992-2011 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
        The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 9.0-CURRENT #5 r221725M: Tue May 10 11:51:35 UTC 2011
    root at vbcspc15.bcs.brunel.local:/usr/obj/arm.arm/build/arm/head_r221525/sys/O
PENRD-CL arm
module mvs already present!
CPU: Feroceon 88FR131 rev 1 (Marvell core)
  DC enabled IC enabled WB enabled EABT branch prediction enabled
  16KB/32B 4-way Instruction cache
  16KB/32B 4-way write-back-locking-C Data cache
real memory  = 536870912 (512 MB)
avail memory = 520105984 (496 MB)
SOC: Marvell 88F6281 rev A1, TClock 200MHz
simplebus0: <Flattened device tree simple bus> on fdtbus0
ic0: <Marvell Integrated Interrupt Controller> mem 0xf1020200-0xf102023b on simp
lebus0
timer0: <Marvell CPU Timer> mem 0xf1020300-0xf102032f irq 1 on simplebus0
Event timer "CPUTimer0" frequency 200000000 Hz quality 1000
Timecounter "CPUTimer1" frequency 200000000 Hz quality 1000
gpio0: <Marvell Integrated GPIO Controller> mem 0xf1010100-0xf101011f irq 35,36,
37,38,39,40,41 on simplebus0
rtc0: <Marvell Integrated RTC> mem 0xf1010300-0xf1010307 on simplebus0
twsi0: <Marvell Integrated I2C Bus Controller> mem 0xf1011000-0xf101101f irq 43
on simplebus0
iicbus0: <Philips I2C bus> on twsi0
iic0: <I2C generic I/O> on iicbus0
mge0: <Marvell Gigabit Ethernet controller> mem 0xf1072000-0xf1073fff irq 12,13,
14,11,46 on simplebus0
mge0: Ethernet address: f0:ad:4e:00:61:96
miibus0: <MII bus> on mge0
e1000phy0: <Marvell 88E1149 Gigabit PHY> PHY 0 on miibus0
e1000phy0:  none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 100
0baseT-master, 1000baseT-FDX, 1000baseT-FDX-master, auto
mge1: <Marvell Gigabit Ethernet controller> mem 0xf1076000-0xf1077fff irq 16,17,
18,15,47 on simplebus0
mge1: Ethernet address: f0:ad:4e:00:61:97
miibus1: <MII bus> on mge1
e1000phy1: <Marvell 88E1149 Gigabit PHY> PHY 1 on miibus1
e1000phy1:  none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 100
0baseT-master, 1000baseT-FDX, 1000baseT-FDX-master, auto
uart0: <16550 or compatible> mem 0xf1012000-0xf101201f irq 33 on simplebus0
uart0: console (1066,n,8,1)
ehci0: <Marvell Integrated USB 2.0 controller> mem 0xf1050000-0xf1050fff irq 48,
19 on simplebus0
usbus0: EHCI version 1.0
usbus0: set host controller mode
usbus0: <Marvell Integrated USB 2.0 controller> on ehci0
mvs0: <Marvell 88F6281 SATA controller> mem 0xf1080000-0xf1085fff irq 21 on simp
lebus0
mvs0: Gen-IIe, 2 3Gbps ports, Port Multiplier supported with FBS
mvsch0: <Marvell SATA channel> at channel 0 on mvs0
mvsch1: <Marvell SATA channel> at channel 1 on mvs0
sdio0: <Marvell Integrated SDIO Host Controller> mem 0xf1090000-0xf1090133 irq 2
8 on simplebus0
mmc0: <MMC/SD bus> on sdio0
pcib0: <Marvell Integrated PCI/PCI-E Controller> mem 0xf1040000-0xf1041fff irq 4
4 on fdtbus0
pcib0: PCI IO/Memory space exhausted
device_attach: pcib0 attach returned 12
Timecounters tick every 10.000 msec
usbus0: 480Mbps High Speed USB v2.0
ugen0.1: <Marvell> at usbus0
uhub0: <Marvell EHCI root HUB, class 9/0, rev 2.00/1.00, addr 1> on usbus0
ada0 at mvsch0 bus 0 scbus0 target 0 lun 0
ada0: <WDC WD600BEVS-00RST0 04.01G04> ATA-7 SATA 1.x device
ada0: 150.000MB/s transfers (SATA 1.x, UDMA6, PIO 8192bytes)
ada0: Command Queueing enabled
ada0: 57231MB (117210240 512 byte sectors: 16H 63S/T 16383C)
mmcsd0: 3849MB <SDHC Memory Card> at mmc0 50MHz/4bit
bootpc_init: wired to interface 'mge0'
Sending DHCP Discover packet from interface mge0 (f0:ad:4e:00:61:96)
Received DHCP Offer packet on mge0 from 172.16.102.155 (accepted) (no root path)
uhub0: 1 port with 1 removable, self powered
mge0: link state changed to UP
ugen0.2: <vendor 0x05e3> at usbus0
uhub1: <vendor 0x05e3 USB2.0 Hub, class 9/0, rev 2.00/77.32, addr 2> on usbus0
uhub1: 4 ports with 4 removable, self powered
ugen0.3: <vendor 0x05e3> at usbus0
uhub2: <vendor 0x05e3 USB2.0 Hub, class 9/0, rev 2.00/77.32, addr 3> on usbus0
Sending DHCP Request packet from interface mge0 (f0:ad:4e:00:61:96)
Received DHCP Ack packet on mge0 from 172.16.102.155 (accepted) (got root path)
uhub2: 4 ports with 4 removable, self powered
mge0 at 172.16.102.152 server 172.16.102.155
subnet mask 255.255.255.0 router 172.16.102.3 rootfs 172.16.102.78:/bcstoqu/open
rd5_rootfs/ hostname open-rd5
Adjusted interface mge0
Trying to mount root from nfs: []...
Mounting from nfs: failed with error 2: unknown file system.

Loader variables:

Manual root filesystem specification:
  <fstype>:<device> [options]
      Mount <device> using filesystem <fstype>
      and with the specified (optional) option list.

    eg. ufs:/dev/da0s1a
        zfs:tank
        cd9660:/dev/acd0 ro
          (which is equivalent to: mount -t cd9660 -o ro /dev/acd0 /)

  ?               List valid disk boot devices
  .               Yield 1 second (for background tasks)
  <empty line>    Abort manual input

mountroot>
-------------- next part --------------
Ôò¡          ÿÿ     'ÉMÂ v   v    
V~Ò×ð­N a– E  h   @U{¬f˜¬fNÿ o TÉVÿÿÿ        †                                          †¥          'ÉMà F   F   ð­N a– 
V~Ò× E  8  @ @®¬fN¬f˜ oÿ $%=ÿÿÿ                     ¡'ÉMDÄ ‚   ‚    
V~Ò×ð­N a– E  t   @Un¬f˜¬fNÿ¡ `«ûÿÿÿ        †¥                                           /bcstoqu/openrd5_rootfs/'ÉMÐÄ  v   v   ð­N a– 
V~Ò× E  h  @ @~¬fN¬f˜¡ÿ T%mÿÿÿ                             ý    €L ù<¤â           ós ót óu'ÉM
Æ  v   v    
V~Ò×ð­N a– E  h   @Uy¬f˜¬fNÿ o TÉVÿÿÿ        †                                          †£          'ÉM”Ê  F   F   ð­N a– 
V~Ò× E  8  @ @®¬fN¬f˜ oÿ $%=ÿÿÿ                     
-------------- next part --------------
diff -prN --exclude=.svn head_r221725/sys/arm/conf/OPENRD-CL head_r221525/sys/arm/conf/OPENRD-CL
*** head_r221725/sys/arm/conf/OPENRD-CL	Thu Jan  1 00:00:00 1970
--- head_r221525/sys/arm/conf/OPENRD-CL	Tue May 10 08:25:28 2011
***************
*** 0 ****
--- 1,94 ----
+ #
+ # Custom kernel for OpenRD Client/Ultimate devices.
+ #
+ # $FreeBSD$
+ #
+ 
+ ident		OPENRD-CL
+ include		"../mv/kirkwood/std.db88f6xxx"
+ 
+ options 	SOC_MV_KIRKWOOD
+ makeoptions	MODULES_OVERRIDE=""
+ 
+ makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+ makeoptions	WERROR="-Werror"
+ 
+ options 	SCHED_4BSD		#4BSD scheduler
+ options 	INET			#InterNETworking
+ options 	INET6			#IPv6 communications protocols
+ options 	FFS			#Berkeley Fast Filesystem
+ options 	NFSCLIENT		#Network Filesystem Client
+ options 	NFSLOCKD		#Network Lock Manager
+ options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+ options 	BOOTP
+ options 	BOOTP_NFSROOT
+ options 	BOOTP_NFSV3
+ options 	BOOTP_WIRED_TO=mge0
+ 
+ # Root fs on USB device
+ #options 	ROOTDEVNAME=\"ufs:/dev/da0a\"
+ 
+ options 	SYSVSHM			#SYSV-style shared memory
+ options 	SYSVMSG			#SYSV-style message queues
+ options 	SYSVSEM			#SYSV-style semaphores
+ options 	_KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+ options 	MUTEX_NOINLINE
+ options 	RWLOCK_NOINLINE
+ options 	NO_FFS_SNAPSHOT
+ options 	NO_SWAPPING
+ 
+ # Debugging
+ options 	ALT_BREAK_TO_DEBUGGER
+ options 	DDB
+ options 	KDB
+ 
+ # Pseudo devices
+ device		loop
+ device		md
+ device		pty
+ device		random
+ 
+ # PCI Express
+ device		pci
+ 
+ # Serial ports
+ device		uart
+ 
+ # Networking
+ device		ether
+ device		mge			# Marvell Gigabit Ethernet controller
+ device		mii
+ device		e1000phy
+ device		bpf
+ 
+ # USB
+ options 	USB_DEBUG		# enable debug msgs
+ device		usb
+ device		ehci
+ device		umass
+ 
+ # SATA
+ device		mvs
+ 
+ # CAM
+ device		scbus
+ device		da
+ device		cd
+ device		pass
+ 
+ # I2C (TWSI)
+ device		iic
+ device		iicbus
+ 
+ # Enable Flattened Device Tree support
+ options 	FDT
+ options		FDT_DTB_STATIC
+ makeoptions	FDT_DTS_FILE=openrd-cl.dts
+ 
+ 
+ # MMC/SD
+ device          mv_sdio
+ device          mmc
+ device          mmcsd
+ 
+ 
diff -prN --exclude=.svn head_r221725/sys/arm/conf/OPENRD-CL-SATABOOT head_r221525/sys/arm/conf/OPENRD-CL-SATABOOT
*** head_r221725/sys/arm/conf/OPENRD-CL-SATABOOT	Thu Jan  1 00:00:00 1970
--- head_r221525/sys/arm/conf/OPENRD-CL-SATABOOT	Tue May 10 08:25:27 2011
***************
*** 0 ****
--- 1,97 ----
+ #
+ # Custom kernel for OpenRD Client/Ultimate devices.
+ #
+ # $FreeBSD$
+ #
+ 
+ ident		OPENRD-CL
+ include		"../mv/kirkwood/std.db88f6xxx"
+ 
+ options 	SOC_MV_KIRKWOOD
+ makeoptions	MODULES_OVERRIDE=""
+ 
+ makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+ makeoptions	WERROR="-Wall"
+ 
+ options 	SCHED_4BSD		#4BSD scheduler
+ options 	INET			#InterNETworking
+ options 	INET6			#IPv6 communications protocols
+ #options         MFS                     # Memory Filesystem
+ options 	FFS			#Berkeley Fast Filesystem
+ options 	NFSCLIENT		#Network Filesystem Client
+ options 	NFSLOCKD		#Network Lock Manager
+ #options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+ #options 	BOOTP
+ #options 	BOOTP_NFSROOT
+ #options 	BOOTP_NFSV3
+ #options 	BOOTP_WIRED_TO=mge0
+ 
+ # Root fs on USB device
+ #options 	ROOTDEVNAME=\"ufs:/dev/da0a\"
+ options         ROOTDEVNAME=\"ufs:/dev/ada0s2a\"
+ options 	SYSVSHM			#SYSV-style shared memory
+ options 	SYSVMSG			#SYSV-style message queues
+ options 	SYSVSEM			#SYSV-style semaphores
+ options 	_KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+ options 	MUTEX_NOINLINE
+ options 	RWLOCK_NOINLINE
+ options 	NO_FFS_SNAPSHOT
+ options 	NO_SWAPPING
+ options		HZ=2000
+ 
+ # Debugging
+ #options 	ALT_BREAK_TO_DEBUGGER
+ #options 	DDB
+ #options 	KDB
+ 
+ # Pseudo devices
+ device		loop
+ device		md
+ device		pty
+ device		random
+ 
+ # PCI Express
+ device		pci
+ 
+ # Serial ports
+ device		uart
+ 
+ # Networking
+ device		ether
+ device		mge			# Marvell Gigabit Ethernet controller
+ device		mii
+ device		e1000phy
+ device		bpf
+ 
+ # USB
+ options 	USB_DEBUG		# enable debug msgs
+ device		usb
+ device		ehci
+ device		umass
+ 
+ # SATA
+ device		mvs
+ #device ata
+ #device atadisk # ATA disk drives
+ #options ATA_STATIC_ID # Static device numbering
+ options         EXT2FS
+ 
+ # CAM
+ device		scbus
+ device		da
+ device		cd
+ device		pass
+ 
+ # I2C (TWSI)
+ device		iic
+ device		iicbus
+ 
+ # Enable Flattened Device Tree support
+ options 	FDT
+ options		FDT_DTB_STATIC
+ makeoptions	FDT_DTS_FILE=openrd-cl.dts
+ 
+ # MMC/SD
+ device          mv_sdio
+ device          mmc
+ device          mmcsd
\ No newline at end of file
diff -prN --exclude=.svn head_r221725/sys/arm/conf/OPENRD-CL-SDBOOT head_r221525/sys/arm/conf/OPENRD-CL-SDBOOT
*** head_r221725/sys/arm/conf/OPENRD-CL-SDBOOT	Thu Jan  1 00:00:00 1970
--- head_r221525/sys/arm/conf/OPENRD-CL-SDBOOT	Tue May 10 08:25:27 2011
***************
*** 0 ****
--- 1,96 ----
+ #
+ # Custom kernel for OpenRD Client/Ultimate devices.
+ #
+ # $FreeBSD$
+ #
+ 
+ ident		OPENRD-CL
+ include		"../mv/kirkwood/std.db88f6xxx"
+ 
+ options 	SOC_MV_KIRKWOOD
+ makeoptions	MODULES_OVERRIDE=""
+ 
+ makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+ makeoptions	WERROR="-Wall"
+ 
+ options 	SCHED_4BSD		#4BSD scheduler
+ options 	INET			#InterNETworking
+ options 	INET6			#IPv6 communications protocols
+ #options         MFS                     # Memory Filesystem
+ options 	FFS			#Berkeley Fast Filesystem
+ options 	NFSCLIENT		#Network Filesystem Client
+ options 	NFSLOCKD		#Network Lock Manager
+ #options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+ #options 	BOOTP
+ #options 	BOOTP_NFSROOT
+ #options 	BOOTP_NFSV3
+ #options 	BOOTP_WIRED_TO=mge0
+ 
+ # Root fs on USB device
+ options         ROOTDEVNAME=\"ufs:/dev/mmcsd0a\"
+ options 	SYSVSHM			#SYSV-style shared memory
+ options 	SYSVMSG			#SYSV-style message queues
+ options 	SYSVSEM			#SYSV-style semaphores
+ options 	_KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+ options 	MUTEX_NOINLINE
+ options 	RWLOCK_NOINLINE
+ options 	NO_FFS_SNAPSHOT
+ options 	NO_SWAPPING
+ options		HZ=2000
+ 
+ # Debugging
+ #options 	ALT_BREAK_TO_DEBUGGER
+ #options 	DDB
+ #options 	KDB
+ 
+ # Pseudo devices
+ device		loop
+ device		md
+ device		pty
+ device		random
+ 
+ # PCI Express
+ device		pci
+ 
+ # Serial ports
+ device		uart
+ 
+ # Networking
+ device		ether
+ device		mge			# Marvell Gigabit Ethernet controller
+ device		mii
+ device		e1000phy
+ device		bpf
+ 
+ # USB
+ options 	USB_DEBUG		# enable debug msgs
+ device		usb
+ device		ehci
+ device		umass
+ 
+ # SATA
+ device		mvs
+ #device ata
+ #device atadisk # ATA disk drives
+ #options ATA_STATIC_ID # Static device numbering
+ options         EXT2FS
+ 
+ # CAM
+ device		scbus
+ device		da
+ device		cd
+ device		pass
+ 
+ # I2C (TWSI)
+ device		iic
+ device		iicbus
+ 
+ # Enable Flattened Device Tree support
+ options 	FDT
+ options		FDT_DTB_STATIC
+ makeoptions	FDT_DTS_FILE=openrd-cl.dts
+ 
+ # MMC/SD
+ device          mv_sdio
+ device          mmc
+ device          mmcsd
diff -prN --exclude=.svn head_r221725/sys/arm/mv/files.mv head_r221525/sys/arm/mv/files.mv
*** head_r221725/sys/arm/mv/files.mv	Tue May 10 10:11:30 2011
--- head_r221525/sys/arm/mv/files.mv	Tue May 10 08:24:17 2011
*************** arm/mv/mv_pci.c			optional	pci
*** 27,32 ****
--- 27,33 ----
  arm/mv/mv_sata.c		optional	ata | atamvsata
  arm/mv/timer.c			standard
  arm/mv/twsi.c			optional	iicbus
+ arm/mv/mv_sdio.c                optional        mv_sdio
  
  dev/mge/if_mge.c		optional	mge
  dev/mvs/mvs_soc.c		optional	mvs
diff -prN --exclude=.svn head_r221725/sys/arm/mv/gpio.c head_r221525/sys/arm/mv/gpio.c
*** head_r221725/sys/arm/mv/gpio.c	Tue May 10 10:11:30 2011
--- head_r221525/sys/arm/mv/gpio.c	Tue May 10 11:50:01 2011
***************
*** 29,35 ****
   */
  
  #include <sys/cdefs.h>
! __FBSDID("$FreeBSD: head/sys/arm/mv/gpio.c 219684 2011-03-16 00:42:15Z marcel $");
  
  #include <sys/param.h>
  #include <sys/systm.h>
--- 29,35 ----
   */
  
  #include <sys/cdefs.h>
! __FBSDID("$FreeBSD$");
  
  #include <sys/param.h>
  #include <sys/systm.h>
*************** mv_gpio_attach(device_t dev)
*** 145,151 ****
  
  	mv_gpio_softc = sc;
  
! 	/* Get chip id and revision */
  	soc_id(&dev_id, &rev_id);
  
  	if (dev_id == MV_DEV_88F5182 ||
--- 145,151 ----
  
  	mv_gpio_softc = sc;
  
!   /* Get chip id and revision */
  	soc_id(&dev_id, &rev_id);
  
  	if (dev_id == MV_DEV_88F5182 ||
*************** static int
*** 207,213 ****
  mv_gpio_intr(void *arg)
  {
  	uint32_t int_cause, gpio_val;
! 	uint32_t int_cause_hi, gpio_val_hi = 0;
  	int i;
  
  	int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE);
--- 207,214 ----
  mv_gpio_intr(void *arg)
  {
  	uint32_t int_cause, gpio_val;
! 	uint32_t int_cause_hi = 0;
!   uint32_t gpio_val_hi = 0;
  	int i;
  
  	int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE);
*************** mv_gpio_intr(void *arg)
*** 240,245 ****
--- 241,287 ----
  	return (FILTER_HANDLED);
  }
  
+ 
+ static int32_t mv_gpio_get_gpio_irq( const uint32_t u32_gpio )
+ {
+   int32_t s32_ret_val = 0;
+   
+   if( 7 >= u32_gpio )
+   {
+     s32_ret_val = MV_INT_GPIO7_0;
+   }
+   else if( 15 >= u32_gpio )
+   {
+     s32_ret_val = MV_INT_GPIO15_8;
+   }
+   else if( 23 >= u32_gpio )
+   {
+     s32_ret_val = MV_INT_GPIO23_16;
+   }
+   else if( 31 >= u32_gpio )
+   {
+     s32_ret_val = MV_INT_GPIO31_24;
+   }
+   else if( ( 32 + 7 ) >= u32_gpio )
+   {
+     s32_ret_val = MV_INT_GPIOHI7_0;
+   }
+   else if( ( 32 + 15 ) >= u32_gpio )
+   {
+     s32_ret_val =  MV_INT_GPIOHI15_8;
+   }
+   else if( ( 32 + 23 ) >= u32_gpio )
+   {
+     s32_ret_val = MV_INT_GPIOHI23_16;
+   }
+   else
+   {
+     s32_ret_val = -1;
+   }
+   
+   return s32_ret_val;
+ }
+ 
  /*
   * GPIO interrupt handling
   */
*************** mv_gpio_setup_intrhandler(const char *na
*** 253,268 ****
  	struct	intr_event *event;
  	int	error;
  
  	if (pin < 0 || pin >= mv_gpio_softc->pin_num)
  		return (ENXIO);
  	event = gpio_events[pin];
  	if (event == NULL) {
! 		error = intr_event_create(&event, (void *)pin, 0, pin,
! 		    (void (*)(void *))mv_gpio_intr_mask,
! 		    (void (*)(void *))mv_gpio_intr_unmask,
! 		    (void (*)(void *))mv_gpio_int_ack,
! 		    NULL,
! 		    "gpio%d:", pin);
  		if (error != 0)
  			return (error);
  		gpio_events[pin] = event;
--- 295,321 ----
  	struct	intr_event *event;
  	int	error;
  
+   int32_t s32_irq = mv_gpio_get_gpio_irq( pin );
+   
+   if( 0 > s32_irq )
+   {
+     printf("Could not find corresponding IRQ for pin %i\n",
+            pin );
+     return( ENXIO );
+   }
+ 
  	if (pin < 0 || pin >= mv_gpio_softc->pin_num)
  		return (ENXIO);
  	event = gpio_events[pin];
  	if (event == NULL) {
!     
! 		error = intr_event_create(&event, (void *)pin, 0,
!                               s32_irq ,
!                               (void (*)(void *))mv_gpio_intr_mask,
!                               (void (*)(void *))mv_gpio_intr_unmask,
!                               (void (*)(void *))mv_gpio_int_ack,
!                               NULL,
!                               "gpio%d:", pin);
  		if (error != 0)
  			return (error);
  		gpio_events[pin] = event;
*************** mv_gpio_intr_unmask(int pin)
*** 294,302 ****
--- 347,359 ----
  		return;
  
  	if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE)
+   {
  		mv_gpio_edge(pin, 1);
+   }
  	else
+   {
  		mv_gpio_level(pin, 1);
+   }
  }
  
  static void
*************** mv_gpio_intr_handler(int pin)
*** 306,314 ****
  
  	event = gpio_events[pin];
  	if (event == NULL || TAILQ_EMPTY(&event->ie_handlers))
  		return;
! 
  	intr_event_handle(event, NULL);
  }
  
  static int
--- 363,377 ----
  
  	event = gpio_events[pin];
  	if (event == NULL || TAILQ_EMPTY(&event->ie_handlers))
+   {
+     printf("mv_gpio_intr_handler(): No handler for Pin %i\n",
+            pin);
+     mv_gpio_int_ack(pin);
  		return;
!   }
  	intr_event_handle(event, NULL);
+ 
+   mv_gpio_int_ack(pin);
  }
  
  static int
diff -prN --exclude=.svn head_r221725/sys/arm/mv/mv_sdio.c head_r221525/sys/arm/mv/mv_sdio.c
*** head_r221725/sys/arm/mv/mv_sdio.c	Thu Jan  1 00:00:00 1970
--- head_r221525/sys/arm/mv/mv_sdio.c	Tue May 10 08:24:17 2011
***************
*** 0 ****
--- 1,1806 ----
+ /*-
+  * Copyright (c) 2009 Semihalf, Rafal Czubak
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  */
+ 
+ /*
+  * Driver for Marvell Integrated SDIO Host Controller.
+  * Works stable in DMA mode. PIO mode has problems with large data transfers
+  * (timeouts).
+  */
+ 
+ #include <sys/cdefs.h>
+ 
+ #include <sys/param.h>
+ #include <sys/bus.h>
+ #include <sys/kernel.h>
+ #include <sys/lock.h>
+ #include <sys/module.h>
+ #include <sys/mutex.h>
+ #include <sys/rman.h>
+ #include <sys/sysctl.h>
+ #include <sys/systm.h>
+ #include <sys/taskqueue.h>
+ 
+ #include <arm/mv/mvreg.h>
+ #include <arm/mv/mvvar.h>
+ 
+ #include <machine/bus.h>
+ #include <machine/intr.h>
+ 
+ #include <dev/mmc/bridge.h>
+ #include <dev/mmc/mmcreg.h>
+ #include <dev/mmc/mmcvar.h>
+ #include <dev/mmc/mmcbrvar.h>
+ 
+ #include <dev/ofw/ofw_bus.h>
+ #include <dev/ofw/ofw_bus_subr.h>
+ 
+ #include "mmcbr_if.h"
+ 
+ #include "mv_sdio.h"
+ 
+ /* Minimum DMA segment size. */
+ #define MV_SDIO_DMA_SEGMENT_SIZE	4096
+ 
+ /* Transferred block size. */
+ #define MV_SDIO_BLOCK_SIZE  512
+ 
+ /* Maximum number of blocks the controller can handle. */
+ #define MV_SDIO_BLOCKS_MAX		65535
+ 
+ /* Halfword bit masks used for command response extraction. */
+ #define MV_SDIO_RSP48_BM2	0x0002	/* Lower 2 bits. */
+ #define MV_SDIO_RSP48_BM6	0x003f	/* Lower 6 bits. */
+ #define MV_SDIO_RSP48_BM16	0xffff	/* 16 bits */
+ 
+ /* SDIO aggregated command interrupts */
+ #define MV_SDIO_IRQS_CMD (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_UNEXPECTED_RSP)
+ #define MV_SDIO_EIRQS_CMD (MV_SDIO_EIRQ_CMD_TMO | MV_SDIO_EIRQ_CMD_CRC7 | \
+     MV_SDIO_EIRQ_CMD_ENDBIT | MV_SDIO_EIRQ_CMD_INDEX | \
+     MV_SDIO_EIRQ_CMD_STARTBIT | MV_SDIO_EIRQ_RSP_TBIT)
+ 
+ /* SDIO aggregated data interrupts */
+ #define MV_SDIO_IRQS_DATA (MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_TX_EMPTY | \
+     MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_AUTOCMD12)
+ #define MV_SDIO_EIRQS_DATA (MV_SDIO_EIRQ_DATA_TMO | \
+     MV_SDIO_EIRQ_DATA_CRC16 | MV_SDIO_EIRQ_DATA_ENDBIT | \
+     MV_SDIO_EIRQ_AUTOCMD12 | MV_SDIO_EIRQ_XFER_SIZE | \
+     MV_SDIO_EIRQ_CRC_ENDBIT | MV_SDIO_EIRQ_CRC_STARTBIT | \
+     MV_SDIO_EIRQ_CRC_STAT)
+ 
+ /*
+  * Timing configuration.
+  */
+ 
+ /* SDIO controller base clock frequency. */
+ #define MV_SDIO_F_BASE			100000000		/* 200 MHz */
+ 
+ /* Maximum SD clock frequency. */
+ #define MV_SDIO_F_MAX			(MV_SDIO_F_BASE / 2)	/* 50 MHz */
+ 
+ /* Maximum timeout value. */
+ #define MV_SDIO_TMO_MAX			0xf
+ 
+ /* Reset delay in microseconds. */
+ #define MV_SDIO_RESET_DELAY		10000	/* 10 ms */
+ 
+ /* Empty FIFO polling delay. */
+ #define MV_SDIO_FIFO_EMPTY_DELAY	1000	/* 1 ms */
+ 
+ /* Delays between operations on multiple blocks. */
+ #define MV_SDIO_RD_DELAY		50 /*50*/	/* Read access time. */
+ #define MV_SDIO_WR_DELAY		10 /*10*/	/* Write access time. */
+ 
+ /* Maximum clock divider value. */
+ #define MV_SDIO_CLK_DIV_MAX		0x7ff
+ 
+ /*
+  * Platform-dependent pins 
+  */
+ /* Card-Detect Pin */
+ #define MV_SDIO_CARD_DETECT_PIN 29
+ 
+ /* Pin that connects the SD-Card-Port Pins to the processor */
+ #define MV_SDIO_OPENRD_MUX_PIN 34
+ 
+ struct mv_sdio_softc {
+ 	device_t		sc_dev;
+ 	device_t		sc_child;
+ 
+ 	bus_space_handle_t	sc_bsh;
+ 	bus_space_tag_t		sc_bst;
+ 
+ 	int			sc_use_dma;
+ 	bus_dma_tag_t		sc_dmatag;
+ 	bus_dmamap_t		sc_dmamap;
+ 	uint8_t			*sc_dmamem;
+ 	bus_addr_t		sc_physaddr;
+ 	int			sc_mapped;
+ 	size_t			sc_dma_size;
+ 
+ 	struct resource		*sc_mem_res;
+ 	int			sc_mem_rid;
+ 
+ 	struct resource		*sc_irq_res;
+ 	int			sc_irq_rid;
+ 	void			*sc_ihl;
+ 
+ 	struct resource		*sc_cd_irq_res;
+ 	int			sc_cd_irq_rid;
+ 	void			*sc_cd_ihl;
+ 
+ 	uint32_t		sc_irq_mask;
+ 	uint32_t		sc_eirq_mask;
+ 
+ 	struct task		sc_card_task;
+ 	struct callout		sc_card_callout;
+ 
+ 	struct mtx		sc_mtx;
+ 
+ 	int			sc_bus_busy;
+ 	int			sc_card_present;
+ 	struct mmc_host		sc_host;
+ 	struct mmc_request	*sc_req;
+ 	struct mmc_command	*sc_curcmd;
+ 
+ 	uint32_t		sc_data_offset;
+ };
+ 
+ /* Read/write data from/to registers.*/
+ static uint32_t MV_SDIO_RD4(struct mv_sdio_softc *, bus_size_t);
+ static void MV_SDIO_WR4(struct mv_sdio_softc *, bus_size_t, uint32_t);
+ 
+ static int mv_sdio_probe(device_t);
+ static int mv_sdio_attach(device_t);
+ 
+ static int mv_sdio_read_ivar(device_t, device_t, int, uintptr_t *);
+ static int mv_sdio_write_ivar(device_t, device_t, int, uintptr_t);
+ 
+ static int mv_sdio_update_ios(device_t, device_t);
+ static int mv_sdio_request(device_t, device_t, struct mmc_request *);
+ static int mv_sdio_get_ro(device_t, device_t);
+ static int mv_sdio_acquire_host(device_t, device_t);
+ static int mv_sdio_release_host(device_t, device_t);
+ 
+ /* Finalizes active MMC request. */
+ static void mv_sdio_finalize_request(struct mv_sdio_softc *);
+ 
+ /* Initializes controller's registers. */
+ static void mv_sdio_init(device_t);
+ 
+ /* Initializes host structure. */
+ static void mv_sdio_init_host(struct mv_sdio_softc *);
+ 
+ /* Used to add and handle sysctls. */
+ static void mv_sdio_add_sysctls(struct mv_sdio_softc *);
+ static int mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS);
+ 
+ /* DMA initialization and cleanup functions. */
+ static int mv_sdio_dma_init(struct mv_sdio_softc *);
+ static void mv_sdio_dma_finish(struct mv_sdio_softc *);
+ 
+ /* DMA map load callback. */
+ static void mv_sdio_getaddr(void *, bus_dma_segment_t *, int, int);
+ 
+ /* Prepare command/data before transaction. */
+ static int mv_sdio_start_command(struct mv_sdio_softc *, struct
+     mmc_command *);
+ static int mv_sdio_start_data(struct mv_sdio_softc *, struct mmc_data *);
+ 
+ /* Finish command after transaction. */
+ static void mv_sdio_finish_command(struct mv_sdio_softc *);
+ 
+ /* Response handling. */
+ static void mv_sdio_handle_136bit_resp(struct mv_sdio_softc *);
+ static void mv_sdio_handle_48bit_resp(struct mv_sdio_softc *,
+     struct mmc_command *);
+ 
+ /* Interrupt handler and interrupt helper functions. */
+ static void mv_sdio_intr(void *);
+ static void mv_sdio_cmd_intr(struct mv_sdio_softc *, uint32_t, uint32_t);
+ static void mv_sdio_data_intr(struct mv_sdio_softc *, uint32_t, uint32_t);
+ static void mv_sdio_cd_intr(void *);
+ static void mv_sdio_disable_intr(struct mv_sdio_softc *);
+ 
+ /* Used after card detect interrupt has been handled. */
+ static void mv_sdio_card_delay(void *);
+ static void mv_sdio_card_task(void *, int);
+ 
+ /* Read/write data from FIFO in PIO mode. */
+ static uint32_t mv_sdio_read_fifo(struct mv_sdio_softc *);
+ static void mv_sdio_write_fifo(struct mv_sdio_softc *, uint32_t);
+ 
+ /*
+  * PIO mode handling.
+  *
+  * Inspired by sdhci(4) driver routines.
+  */
+ static void mv_sdio_transfer_pio(struct mv_sdio_softc *);
+ static void mv_sdio_read_block_pio(struct mv_sdio_softc *);
+ static void mv_sdio_write_block_pio(struct mv_sdio_softc *);
+ 
+ 
+ static device_method_t mv_sdio_methods[] = {
+ 	/* device_if */
+ 	DEVMETHOD(device_probe, mv_sdio_probe),
+ 	DEVMETHOD(device_attach, mv_sdio_attach),
+ 
+ 	/* Bus interface */
+ 	DEVMETHOD(bus_read_ivar, mv_sdio_read_ivar),
+ 	DEVMETHOD(bus_write_ivar, mv_sdio_write_ivar),
+ 
+ 	/* mmcbr_if */
+ 	DEVMETHOD(mmcbr_update_ios, mv_sdio_update_ios),
+ 	DEVMETHOD(mmcbr_request, mv_sdio_request),
+ 	DEVMETHOD(mmcbr_get_ro, mv_sdio_get_ro),
+ 	DEVMETHOD(mmcbr_acquire_host, mv_sdio_acquire_host),
+ 	DEVMETHOD(mmcbr_release_host, mv_sdio_release_host),
+ 
+ 	{0, 0},
+ };
+ 
+ static driver_t mv_sdio_driver = {
+ 	"sdio",
+ 	mv_sdio_methods,
+ 	sizeof(struct mv_sdio_softc),
+ };
+ static devclass_t mv_sdio_devclass;
+ 
+ DRIVER_MODULE( sdio, simplebus, mv_sdio_driver, mv_sdio_devclass, 0, 0);
+ 
+ 
+ static __inline uint32_t
+ MV_SDIO_RD4(struct mv_sdio_softc *sc, bus_size_t off)
+ {
+ 
+ 	return (bus_read_4(sc->sc_mem_res, off));
+ }
+ 
+ static __inline void
+ MV_SDIO_WR4(struct mv_sdio_softc *sc, bus_size_t off, uint32_t val)
+ {
+ 
+ 	bus_write_4(sc->sc_mem_res, off, val);
+ }
+ 
+ static int platform_sdio_slot_signal( int signal )
+ {
+ #ifdef MV_SDIO_OPENRD_MUX_PIN 
+   uint32_t gpio_read = 0;
+ #endif /* MV_SDIO_OPENRD_MUX_PIN  */
+   
+   switch( signal )
+   {
+     case MV_SDIO_SIG_CD:
+     {
+ #ifndef MV_SDIO_OPENRD_MUX_PIN 
+       return -1;
+ #else
+       gpio_read = mv_gpio_in(MV_SDIO_CARD_DETECT_PIN);
+             
+       if( 0 == gpio_read )
+       {
+         return 0;
+       }
+       else
+       {
+         return 1;
+       }
+ #endif /* MV_SDIO_OPENRD_MUX_PIN  */
+       break;
+     }
+     case MV_SDIO_SIG_WP:
+       return 0;
+       break;
+     default:
+       return -1;
+       break;
+   }
+   
+   return 0;
+ }
+ 
+ static int
+ mv_sdio_probe(device_t dev)
+ {
+ 	uint32_t device, revision;
+   
+   /*device_printf(dev,"SDIO probe!\n");*/
+   
+   if (!ofw_bus_is_compatible(dev, "mrvl,sdio"))
+ 		return (ENXIO);
+ 
+ 
+ 	soc_id(&device, &revision);
+ 
+ 	switch (device) {
+ 	case MV_DEV_88F6281:
+ 		break;
+ 	default:
+     printf("ENXIO!\n");
+ 		return (ENXIO);
+ 	}
+ 
+ 	device_set_desc(dev, "Marvell Integrated SDIO Host Controller");
+ 
+ 	return (BUS_PROBE_SPECIFIC);
+ }
+ 
+ static int
+ mv_sdio_attach(device_t dev)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	int task_initialized = 0;
+ 
+ 	sc = device_get_softc(dev);
+ 	sc->sc_dev = dev;
+ 
+ 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+ 
+ 	/* Allocate memory and interrupt resources. */
+ 	sc->sc_mem_rid = 0;
+ 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ 	    &sc->sc_mem_rid, RF_ACTIVE);
+ 
+ 	if (sc->sc_mem_res == NULL) {
+ 		device_printf(dev, "Could not allocate memory!\n");
+ 		goto fail;
+ 	}
+ 
+ 	sc->sc_irq_rid = 0;
+ 	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ 	    &sc->sc_irq_rid, RF_ACTIVE);
+ 
+ 	if (sc->sc_irq_res == NULL) {
+ 		device_printf(dev, "Could not allocate IRQ!\n");
+ 		goto fail;
+ 	}
+ 
+ 	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
+ 	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
+ 
+   
+ 	/* Initialize host controller's registers. */
+ 	mv_sdio_init(dev);
+ 
+ 	/* Try to setup DMA. */
+ 	sc->sc_mapped = 0;	/* No DMA buffer is mapped. */
+ 	sc->sc_use_dma = 1;	/* DMA mode is preferred to PIO mode. */
+ 
+ 	if (mv_sdio_dma_init(sc) < 0) {
+ 		device_printf(dev, "Falling back to PIO mode.\n");
+ 		sc->sc_use_dma = 0;
+ 	}
+ 
+ 	/* Add sysctls. */
+ 	mv_sdio_add_sysctls(sc);
+ 
+ #ifdef MV_SDIO_OPENRD_MUX_PIN
+   
+   /* Set Pin 34 to 1, to forward SD-Card Pins to processor */
+   mv_gpio_out( MV_SDIO_OPENRD_MUX_PIN, /* uint32_t pin*/
+                1, /* uint8_t val,*/
+                1 /*uint8_t enable*/);
+ 
+ #endif /* MV_SDIO_OPENRD_MUX_PIN */
+ 
+ 	if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) {
+ 
+ #ifdef MV_SDIO_OPENRD_MUX_PIN 
+     
+     /* Register IRQ-handler for pin in GPIO-framework */
+     if( 0 != mv_gpio_setup_intrhandler( "Card detect IRQ",            /* name */
+                                         NULL,                         /*driver_filter_t *filt*/
+                                         mv_sdio_cd_intr,              /*void (*hand)(void *)*/
+                                         sc,                           /*void *arg*/
+                                         MV_SDIO_CARD_DETECT_PIN,      /*int pin*/
+                                         INTR_TYPE_MISC | INTR_MPSAFE, /*int flags*/ 
+                                         &sc->sc_cd_ihl                /*void **cookiep*/) )
+     {
+       device_printf(dev, "mv_gpio_setup_intrhandler failed!\n");
+ 			goto fail;
+     }
+     
+     /* Activate IRQ for Pin 29 */
+     mv_gpio_intr_unmask(MV_SDIO_CARD_DETECT_PIN);
+ 
+ #endif /* MV_SDIO_OPENRD_MUX_PIN */
+ 
+ 
+ 		/* Check if card is present in the slot. */
+ 		if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) == 1)
+ 			sc->sc_card_present = 1;
+ 	}
+ 
+ 	TASK_INIT(&sc->sc_card_task, 0, mv_sdio_card_task, sc);
+ 	callout_init(&sc->sc_card_callout, 1);
+ 	task_initialized = 1;
+ 
+ 	/* Setup interrupt. */
+ 	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC |
+ 	    INTR_MPSAFE, NULL, mv_sdio_intr, sc, &sc->sc_ihl) != 0) {
+ 		device_printf(dev, "Could not setup interrupt!\n");
+ 		goto fail;
+ 	}
+ 
+ 	/* Host can be acquired. */
+ 	sc->sc_bus_busy = 0;
+ 
+ 	/*
+ 	 * Attach MMC bus only if the card is in the slot or card detect is
+ 	 * not supported on the platform.
+ 	 */
+ 	if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) == -1) ||
+ 	    sc->sc_card_present) {
+ 		sc->sc_child = device_add_child(dev, "mmc", -1);
+ 
+ 		if (sc->sc_child == NULL) {
+ 			device_printf(dev, "Could not add MMC bus!\n");
+ 			goto fail;
+ 		}
+ 
+ 		/* Initialize host structure for MMC bus. */
+ 		mv_sdio_init_host(sc);
+ 
+ 		device_set_ivars(sc->sc_child, &sc->sc_host);
+ 	}
+ 
+ 	return (bus_generic_attach(dev));
+ 
+ fail:
+ 	mv_sdio_dma_finish(sc);
+ 	if (task_initialized) {
+ 		callout_drain(&sc->sc_card_callout);
+ 		taskqueue_drain(taskqueue_swi, &sc->sc_card_task);
+ 	}
+ 	if (sc->sc_ihl != NULL)
+ 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_ihl);
+ 	if (sc->sc_cd_ihl != NULL)
+ 		bus_teardown_intr(dev, sc->sc_cd_irq_res, sc->sc_cd_ihl);
+ 	if (sc->sc_irq_res != NULL)
+ 		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid,
+ 		    sc->sc_irq_res);
+ 	if (sc->sc_cd_irq_res != NULL)
+ 		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_cd_irq_rid,
+ 		    sc->sc_cd_irq_res);
+ 	if (sc->sc_mem_res != NULL)
+ 		bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid,
+ 		    sc->sc_mem_res);
+ 	mtx_destroy(&sc->sc_mtx);
+ 	return (ENXIO);
+ }
+ 
+ static int
+ mv_sdio_update_ios(device_t brdev, device_t reqdev)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	struct mmc_host *host;
+ 	struct mmc_ios *ios;
+ 	uint32_t xfer, clk_div, host_cr;
+ 
+ 	sc = device_get_softc(brdev);
+ 	host = device_get_ivars(reqdev);
+ 	ios = &host->ios;
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 
+ 	if (ios->power_mode == power_off)
+ 		/* Re-initialize the controller. */
+ 		mv_sdio_init(brdev);
+ 
+ 	xfer = MV_SDIO_RD4(sc, MV_SDIO_XFER);
+ 
+ 	if (ios->clock == 0) {
+ 		/* Disable clock. */
+ 		xfer |= MV_SDIO_XFER_STOP_CLK;
+ 		MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer);
+ 
+ 		/* Set maximum clock divider. */
+ 		MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX);
+ 	} else {
+ 		/*
+ 		 * Calculate and set clock divider.
+ 		 * Clock rate value is:
+ 		 *     clock = MV_SDIO_F_BASE / (clk_div + 1)
+ 		 * Thus we calculate the divider value as:
+ 		 *     clk_div = (MV_SDIO_F_BASE / clock) - 1
+ 		 */
+ 		clk_div = (MV_SDIO_F_BASE / ios->clock) - 1;
+ 		if (clk_div > MV_SDIO_CLK_DIV_MAX)
+ 			clk_div = MV_SDIO_CLK_DIV_MAX;
+ 		MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, clk_div);
+     
+ 		/* Enable clock. */
+ 		xfer &= ~MV_SDIO_XFER_STOP_CLK;
+ 		MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer);
+ 	}
+ 
+ 	host_cr = MV_SDIO_RD4(sc, MV_SDIO_HOST_CR);
+ 
+ 	/* Set card type. */
+ 	if (host->mode == mode_mmc)
+ 		host_cr |= MV_SDIO_HOST_CR_MMC;		/* MMC card. */
+ 	else
+ 		host_cr &= ~MV_SDIO_HOST_CR_MMC;	/* SD card. */
+ 
+ 	/* Set bus width. */
+ 	if (ios->bus_width == bus_width_4)
+ 		host_cr |= MV_SDIO_HOST_CR_4BIT;	/* 4-bit bus width */
+ 	else
+ 		host_cr &= ~MV_SDIO_HOST_CR_4BIT;	/* 1-bit bus width */
+ 
+ 	/* Set high/normal speed mode. */
+ #if 0 /* Some cards have problems with the highspeed-mode 
+        * Not selecting High-Speed mode enables all cards to work
+        */
+   
+ 	if ((ios->timing == bus_timing_hs ) && ( 1 == 0 ) )
+ 		host_cr |= MV_SDIO_HOST_CR_HIGHSPEED;
+ 	else
+ #endif
+ 		host_cr &= ~MV_SDIO_HOST_CR_HIGHSPEED;
+ 
+ 	MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr);
+ 
+ 	mtx_unlock(&sc->sc_mtx);
+ 
+ 	return (0);
+ }
+ 
+ static int
+ mv_sdio_request(device_t brdev, device_t reqdev, struct mmc_request *req)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	int rv;
+ 
+ 	sc = device_get_softc(brdev);
+ 	rv = EBUSY;
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 
+ 	if (sc->sc_req != NULL) {
+ 		mtx_unlock(&sc->sc_mtx);
+ 		return (rv);
+ 	}
+ 
+ 	sc->sc_req = req;
+ /*
+   device_printf(sc->sc_dev, "cmd %d (hw state 0x%04x)\n",
+           req->cmd->opcode , MV_SDIO_RD4( sc, MV_SDIO_HOST_SR ) );
+ */
+ 	rv = mv_sdio_start_command(sc, req->cmd);
+ 
+ 	mtx_unlock(&sc->sc_mtx);
+ 
+ 	return (rv);
+ }
+ 
+ static int
+ mv_sdio_get_ro(device_t brdev, device_t reqdev)
+ {
+ 	int rv;
+ 
+ 	/* Check if card is read only. */
+ 	rv = platform_sdio_slot_signal(MV_SDIO_SIG_WP);
+ 
+ 	/*
+ 	 * Assume that card is not write protected, when platform doesn't
+ 	 * support WP signal.
+ 	 */
+ 	if (rv < 0)
+ 		rv = 0;
+ 
+ 	return (rv);
+ }
+ 
+ static int
+ mv_sdio_acquire_host(device_t brdev, device_t reqdev)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	int rv;
+ 
+ 	sc = device_get_softc(brdev);
+ 	rv = 0;
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 	while (sc->sc_bus_busy)
+ 		rv = mtx_sleep(sc, &sc->sc_mtx, PZERO, "sdioah", 0);
+ 	sc->sc_bus_busy++;
+ 	mtx_unlock(&sc->sc_mtx);
+ 
+ 	return (rv);
+ }
+ 
+ static int
+ mv_sdio_release_host(device_t brdev, device_t reqdev)
+ {
+ 	struct mv_sdio_softc *sc;
+ 
+ 	sc = device_get_softc(brdev);
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 	sc->sc_bus_busy--;
+ 	wakeup(sc);
+ 	mtx_unlock(&sc->sc_mtx);
+ 
+ 	return (0);
+ }
+ 
+ static void
+ mv_sdio_finalize_request(struct mv_sdio_softc *sc)
+ {
+ 	struct mmc_request *req;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	req = sc->sc_req;
+ 
+ 	if (req) {
+ 		/* Finalize active request. */
+     /*device_printf(sc->sc_dev, "Finalize request %i\n",req->cmd->opcode);*/
+ 		sc->sc_req = NULL;
+ 		sc->sc_curcmd = NULL;
+ 		req->done(req);
+     
+     
+ 	} else
+ 		device_printf(sc->sc_dev, "No active request to finalize!\n");
+ }
+ 
+ static void
+ mv_sdio_init(device_t dev)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	uint32_t host_cr;
+ 
+ 	sc = device_get_softc(dev);
+ 
+ 	/* Disable interrupts. */
+ 	sc->sc_irq_mask = 0;
+ 	sc->sc_eirq_mask = 0;
+ 	MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask);
+ 
+ 	/* Clear interrupt status registers. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, MV_SDIO_IRQ_ALL);
+ 	MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, MV_SDIO_EIRQ_ALL);
+ 
+ 	/* Enable interrupt status registers. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR_EN, MV_SDIO_IRQ_ALL);
+ 	MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR_EN, MV_SDIO_EIRQ_ALL);
+ 
+ 	/* Initialize Host Control Register. */
+ 	host_cr = (MV_SDIO_HOST_CR_PUSHPULL | MV_SDIO_HOST_CR_BE |
+              MV_SDIO_HOST_CR_TMOVAL(MV_SDIO_TMO_MAX) | MV_SDIO_HOST_CR_TMO);
+ 
+ 	MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr);
+ 
+ 	/* Stop clock and reset Transfer Mode Register. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_XFER, MV_SDIO_XFER_STOP_CLK);
+ 
+ 	/* Set maximum clock divider value. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX);
+ 
+ 	/* Reset status, state machine and FIFOs synchronously. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_SW_RESET, MV_SDIO_SW_RESET_ALL);
+ 	    DELAY(MV_SDIO_RESET_DELAY);
+ }
+ 
+ static void
+ mv_sdio_init_host(struct mv_sdio_softc *sc)
+ {
+ 	struct mmc_host *host;
+ 
+ 	host = &sc->sc_host;
+ 
+ 	/* Clear host structure. */
+ 	bzero(host, sizeof(struct mmc_host));
+ 
+ 	/* Calculate minimum and maximum operating frequencies. */
+ 	host->f_min = MV_SDIO_F_BASE / (MV_SDIO_CLK_DIV_MAX + 1);
+ 	host->f_max = MV_SDIO_F_MAX;
+   
+ 	/* Set operation conditions (voltage). */
+ 	host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
+ 
+ 	/* Set additional host controller capabilities. */
+ 	host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED;
+ }
+ 
+ static void
+ mv_sdio_add_sysctls(struct mv_sdio_softc *sc)
+ {
+ 	struct sysctl_ctx_list *ctx;
+ 	struct sysctl_oid_list *children;
+ 	struct sysctl_oid *tree;
+ 
+ 	ctx = device_get_sysctl_ctx(sc->sc_dev);
+ 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev));
+ 	tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "params",
+ 	    CTLFLAG_RD, 0, "Driver parameters");
+ 	children = SYSCTL_CHILDREN(tree);
+ 
+ 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "use_dma",
+ 	    CTLTYPE_UINT | CTLFLAG_RW, sc, 0, mv_sdio_sysctl_use_dma,
+ 	    "I", "Use DMA for data transfers (0-1)");
+ }
+ 
+ /*
+  * This sysctl allows switching between DMA and PIO modes for data transfers:
+  *
+  * dev.mv_sdio.<unit>.params.use_dma
+  *
+  * Values:
+  *
+  * - 1 sets DMA mode
+  * - 0 sets PIO mode
+  *
+  * Driver uses DMA mode by default.
+  */
+ static int
+ mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	uint32_t use_dma;
+ 	int error;
+ 
+ 	sc = (struct mv_sdio_softc *)arg1;
+ 
+ 	use_dma = sc->sc_use_dma;
+ 
+ 	error = sysctl_handle_int(oidp, &use_dma, 0, req);
+ 	if (error != 0 || req->newptr == NULL)
+ 		return (error);
+ 
+ 	if (use_dma > 1)
+ 		return (EINVAL);
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 
+ 	/* Check if requested mode is already being used. */
+ 	if (sc->sc_use_dma == use_dma) {
+ 		mtx_unlock(&sc->sc_mtx);
+ 		return (EPERM);
+ 	}
+ 
+ 	if (!(sc->sc_mapped)) {
+ 		device_printf(sc->sc_dev, "DMA not initialized!\n");
+ 		mtx_unlock(&sc->sc_mtx);
+ 		return (ENOMEM);
+ 	}
+ 
+ 	/* Set new mode. */
+ 	sc->sc_use_dma = use_dma;
+ 
+ 	mtx_unlock(&sc->sc_mtx);
+ 
+ 	return (0);
+ }
+ 
+ static void
+ mv_sdio_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+ {
+ 
+ 	if (error != 0)
+ 		return;
+ 
+ 	/* Get first segment's physical address. */
+ 	*(bus_addr_t *)arg = segs->ds_addr;
+ }
+ 
+ static int
+ mv_sdio_dma_init(struct mv_sdio_softc *sc)
+ {
+ 	device_t dev;
+ 	bus_size_t dmabuf_size;
+ 
+ 	dev = sc->sc_dev;
+ 	dmabuf_size = MAXPHYS;
+ 
+ 	/* Create DMA tag. */
+ 	if (bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
+ 	    MV_SDIO_DMA_SEGMENT_SIZE, 0,	/* alignment, boundary */
+ 	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
+ 	    BUS_SPACE_MAXADDR,			/* highaddr */
+ 	    NULL, NULL,				/* filtfunc, filtfuncarg */
+ 	    MAXPHYS, 1,				/* maxsize, nsegments */
+ 	    MAXPHYS, BUS_DMA_ALLOCNOW,		/* maxsegsz, flags */
+ 	    NULL, NULL,				/* lockfunc, lockfuncarg */
+ 	    &sc->sc_dmatag) != 0) {
+ 		device_printf(dev, "Could not create DMA tag!\n");
+ 		return (-1);
+ 	}
+ 
+ 	/* Allocate DMA memory. */
+ 	if (bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_dmamem,
+ 	    BUS_DMA_NOWAIT, &sc->sc_dmamap) != 0) {
+ 		device_printf(dev, "Could not allocate DMA memory!\n");
+ 		mv_sdio_dma_finish(sc);
+ 		return (-1);
+ 	}
+ 
+ 	/* Find the biggest available DMA buffer size. */
+ 	while (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap,
+ 	    (void *)sc->sc_dmamem, dmabuf_size, mv_sdio_getaddr,
+ 	    &sc->sc_physaddr, 0) != 0) {
+ 		dmabuf_size >>= 1;
+ 		if (dmabuf_size < MV_SDIO_BLOCK_SIZE) {
+ 			device_printf(dev, "Could not load DMA map!\n");
+ 			mv_sdio_dma_finish(sc);
+ 			return (-1);
+ 		}
+ 	}
+ 
+ 	sc->sc_mapped++;
+ 	sc->sc_dma_size = dmabuf_size;
+ 
+ 	return (0);
+ }
+ 
+ static void
+ mv_sdio_dma_finish(struct mv_sdio_softc *sc)
+ {
+ 
+ 	/* Free DMA resources. */
+ 	if (sc->sc_mapped) {
+ 		bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+ 		sc->sc_mapped--;
+ 	}
+ 	if (sc->sc_dmamem != NULL)
+ 		bus_dmamem_free(sc->sc_dmatag, sc->sc_dmamem, sc->sc_dmamap);
+ 	if (sc->sc_dmamap != NULL)
+ 		bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dmamap);
+ 	if (sc->sc_dmatag != NULL)
+ 		bus_dma_tag_destroy(sc->sc_dmatag);
+ }
+ 
+ static int
+ mv_sdio_start_command(struct mv_sdio_softc *sc, struct mmc_command *cmd)
+ {
+ 	struct mmc_request *req;
+ 	uint32_t cmdreg;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	req = sc->sc_req;
+ 
+ 	sc->sc_curcmd = cmd;
+ 
+ 	cmd->error = MMC_ERR_NONE;
+ 
+ 	/* Check if card is in the slot. */
+ 	if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) &&
+ 	    (sc->sc_card_present == 0)) {
+ 		cmd->error = MMC_ERR_FAILED;
+ 		mv_sdio_finalize_request(sc);
+ 		return (-1);
+ 	}
+ 
+ 	/* Check if clock is enabled. */
+ 	if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_STOP_CLK) {
+ 		cmd->error = MMC_ERR_FAILED;
+ 		mv_sdio_finalize_request(sc);
+ 		return (-1);
+ 	}
+ 
+ 	/* Write command argument. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGL, cmd->arg & 0xffff);
+ 	MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGH, cmd->arg >> 16);
+ 
+ 	/* Determine response type. */
+ 	if (cmd->flags & MMC_RSP_136)
+ 		cmdreg = MV_SDIO_CMD_RSP_136;
+ 	else if (cmd->flags & MMC_RSP_BUSY)
+ 		cmdreg = MV_SDIO_CMD_RSP_48_BUSY;
+ 	else if (cmd->flags & MMC_RSP_PRESENT)
+ 		cmdreg = MV_SDIO_CMD_RSP_48;
+ 	else {
+ 		/* No response. */
+ 		cmdreg = MV_SDIO_CMD_RSP_NONE;
+ 		/* Enable host to detect unexpected response. */
+ 		cmdreg |= MV_SDIO_CMD_UNEXPECTED_RSP;
+ 		sc->sc_irq_mask |= MV_SDIO_CMD_UNEXPECTED_RSP;
+ 	}
+ 
+ 	/* Check command checksum if needed. */
+ 	if (cmd->flags & MMC_RSP_CRC)
+ 		cmdreg |= MV_SDIO_CMD_CRC7;
+ 	/* Check command opcode if needed. */
+ 	if (cmd->flags & MMC_RSP_OPCODE)
+ 		cmdreg |= MV_SDIO_CMD_INDEX_CHECK;
+ 
+ 	/* Set commannd opcode. */
+ 	cmdreg |= MV_SDIO_CMD_INDEX(cmd->opcode);
+ 
+ 	/* Setup interrupts. */
+ 	sc->sc_irq_mask = MV_SDIO_IRQ_CMD;
+ 	sc->sc_eirq_mask = MV_SDIO_EIRQ_ALL;
+ 
+ 	/* Prepare data transfer. */
+ 	if (cmd->data) {
+ 		cmdreg |= (MV_SDIO_CMD_DATA_PRESENT | MV_SDIO_CMD_DATA_CRC16);
+ 		if (mv_sdio_start_data(sc, cmd->data) < 0) {
+ 			cmd->error = MMC_ERR_FAILED;
+       printf("mv_sdio_start_data() failed!\n");
+ 			mv_sdio_finalize_request(sc);
+ 			return (-1);
+ 		}
+ 	}
+ 
+ 	/* Write command register. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_CMD, cmdreg);
+ 
+ 	/* Clear interrupt status. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, ~MV_SDIO_IRQ_CARD_EVENT /*MV_SDIO_IRQ_ALL*/);
+ 	MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, 0xffff /*MV_SDIO_EIRQ_ALL*/);
+ 
+ 	/* Update interrupt/error interrupt enable registers. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask);
+ 
+ 	/* Do not complete request, interrupt handler will do this. */
+ 	return (0);
+ }
+ 
+ static void
+ mv_sdio_finish_command(struct mv_sdio_softc *sc)
+ {
+ 	struct mmc_command *cmd;
+ 	struct mmc_data *data;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	cmd = sc->sc_curcmd;
+ 	data = cmd->data;
+ 
+ 	/* Get response. */
+ 	if (cmd->flags & MMC_RSP_PRESENT) {
+ 		if(cmd->flags & MMC_RSP_136)
+ 			/* 136-bit response. */
+ 			mv_sdio_handle_136bit_resp(sc);
+ 		else
+ 			/* 48-bit response. */
+ 			mv_sdio_handle_48bit_resp(sc, NULL);
+ 	}
+ 
+ 	if (data) {
+ 		/*
+ 		 * Disable command complete interrupt. It has already been
+ 		 * handled.
+ 		 */
+ 		sc->sc_irq_mask &= ~MV_SDIO_IRQ_CMD;
+ 
+ 		/* Enable XFER interrupt. */
+ 		sc->sc_irq_mask |= MV_SDIO_IRQ_XFER;
+ 
+ 		/* Check which data interrupts we need to activate. */
+ 		if (sc->sc_use_dma)
+ 			/* DMA transaction. */
+ 			sc->sc_irq_mask |= MV_SDIO_IRQ_DMA;
+ 		else if (data->flags & MMC_DATA_READ)
+ 			/* Read transaction in PIO mode. */
+ 			sc->sc_irq_mask |= MV_SDIO_IRQ_RX_FULL;
+ 		else
+ 			/* Write transaction in PIO mode. */
+ 			sc->sc_irq_mask |= MV_SDIO_IRQ_TX_EMPTY;
+ 
+ 		/* Check if Auto-CMD12 interrupt will be needed. */
+ 		if (sc->sc_req->stop)
+ 			sc->sc_irq_mask |= MV_SDIO_IRQ_AUTOCMD12;
+ 
+ 		/* Update interrupt enable register. */
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	} else {
+ 		/* We're done. Disable interrupts and finalize request. */
+ 		mv_sdio_disable_intr(sc);
+ 		mv_sdio_finalize_request(sc);
+ 	}
+ }
+ 
+ static int
+ mv_sdio_start_data(struct mv_sdio_softc *sc, struct mmc_data *data)
+ {
+ 	struct mmc_command *stop;
+ 	uint32_t autocmd12reg, xfer, host_sr;
+ 	size_t blk_size, blk_count;
+ 	int retries;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	/*
+ 	 * No transfer can be started when FIFO_EMPTY bit in MV_SDIO_HOST_SR
+ 	 * is not set. This bit is sometimes not set instantly after XFER
+ 	 * interrupt has been asserted.
+ 	 */
+ 	host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR);
+ 
+ 	retries = 10;
+ 	while (!(host_sr & MV_SDIO_HOST_SR_FIFO_EMPTY)) {
+ 		if (retries == 0)
+ 			return (-1);
+ 		retries--;
+ 		DELAY(MV_SDIO_FIFO_EMPTY_DELAY);
+ 		host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR);
+ 	}
+ 
+ 	/* Clear data offset. */
+ 	sc->sc_data_offset = 0;
+ 
+ 	/*
+ 	 * Set block size. It can be less than or equal to MV_SDIO_BLOCK_SIZE
+ 	 * bytes.
+ 	 */
+ 	blk_size = (data->len < MV_SDIO_BLOCK_SIZE) ? data->len :
+ 	    MV_SDIO_BLOCK_SIZE;
+ 	MV_SDIO_WR4(sc, MV_SDIO_BLK_SIZE, blk_size);
+ 
+ 	/* Set block count. */
+ 	blk_count = (data->len + MV_SDIO_BLOCK_SIZE - 1) / MV_SDIO_BLOCK_SIZE;
+ 	MV_SDIO_WR4(sc, MV_SDIO_BLK_COUNT, blk_count);
+ 
+ 	/* We want to initiate transfer by software. */
+ 	xfer = MV_SDIO_XFER_SW_WR_EN;
+ 
+ 	if (sc->sc_use_dma) {
+ 		/* Synchronize before DMA transfer. */
+ 		if (data->flags & MMC_DATA_READ)
+ 			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap,
+ 			    BUS_DMASYNC_PREREAD);
+ 		else {
+ 			memcpy(sc->sc_dmamem, data->data, data->len);
+ 			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap,
+ 			    BUS_DMASYNC_PREWRITE);
+ 		}
+ 
+ 		/* Write DMA buffer address register. */
+ 		MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRL, sc->sc_physaddr & 0xffff);
+ 		MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRH, sc->sc_physaddr >> 16);
+ 	} else
+ 		/* Set PIO transfer mode. */
+ 		xfer |= MV_SDIO_XFER_PIO;
+ 
+ 	/*
+ 	 * Prepare Auto-CMD12. This command is automatically sent to the card
+ 	 * by the host controller to stop multiple-block data transaction.
+ 	 */
+ 	if (sc->sc_req->stop) {
+ 		stop = sc->sc_req->stop;
+ 
+ 		/* Set Auto-CMD12 argument. */
+ 		MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGL, stop->arg & 0xffff);
+ 		MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGH, stop->arg >> 16);
+ 
+ 		/* Set Auto-CMD12 opcode. */
+ 		autocmd12reg = MV_SDIO_AUTOCMD12_INDEX(stop->opcode);
+ 
+ 		/* Check busy signal if needed. */
+ 		if (stop->flags & MMC_RSP_BUSY)
+ 			autocmd12reg |= MV_SDIO_AUTOCMD12_BUSY_CHECK;
+ 		/* Check Auto-CMD12 index. */
+ 		if (stop->flags & MMC_RSP_OPCODE)
+ 			autocmd12reg |= MV_SDIO_AUTOCMD12_INDEX_CHECK;
+ 
+ 		MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12, autocmd12reg);
+ 
+ 		xfer |= MV_SDIO_XFER_AUTOCMD12;
+ 	}
+ 
+ 	/* Change data direction. */
+ 	if (data->flags & MMC_DATA_READ)
+ 		xfer |= MV_SDIO_XFER_TO_HOST;
+ 
+ 	/* Write transfer mode register. */
+ 	MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer);
+ 
+ 	return (0);
+ }
+ 
+ static void
+ mv_sdio_handle_136bit_resp(struct mv_sdio_softc *sc)
+ {
+ 	struct mmc_command *cmd;
+ 	uint32_t resp[8];
+ 	uint32_t base, extra;
+ 	int i, j, off;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	cmd = sc->sc_curcmd;
+ 
+ 	/* Collect raw response from the controller. */
+ 	for (i = 0; i < 8; i++)
+ 		resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i));
+ 
+ 	/* Response passed to MMC bus is shifted by one byte. */
+ 	extra = 0;
+ 	for (i = 0, j = 7; i < 4; i++, j -= 2) {
+ 		off = (i ? 0 : 2);
+ 		base = resp[j] | (resp[j - 1] << (16 - off));
+ 		cmd->resp[3 - i] = (base << (6 + off)) + extra;
+ 		extra = base >> (26 - off);
+ 	}
+ }
+ 
+ static void
+ mv_sdio_handle_48bit_resp(struct mv_sdio_softc *sc, struct mmc_command *stop)
+ {
+ 	struct mmc_command *cmd;
+ 	uint32_t resp[3], word;
+ 	uint8_t *rp;
+ 	int i;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	if (stop == NULL)
+ 		cmd = sc->sc_curcmd;
+ 	else
+ 		cmd = stop;
+ 
+ 	/* Collect raw response from the controller. */
+ 	for (i = 0; i < 3; i++) {
+ 		if (stop == NULL)
+ 			resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i));
+ 		else
+ 			resp[i] = MV_SDIO_RD4(sc, MV_SDIO_AUTOCMD12_RSP(i));
+ 	}
+ 
+ 	/* Clear MMC bus response buffer. */
+ 	bzero(&cmd->resp[0], 4 * sizeof(uint32_t));
+ 
+ 	/*
+ 	 * Fill MMC bus response buffer.
+ 	 */
+ 
+ 	rp = (uint8_t *)&cmd->resp[0];
+ 
+ 	/* Response bits [45:14] */
+ 	word = (resp[1] & MV_SDIO_RSP48_BM16) |
+ 	    ((resp[0] & MV_SDIO_RSP48_BM16) << 16);
+ 
+ 	/* Response bits [15:14] and [13:8] */
+ 	*rp++ = (resp[2] & MV_SDIO_RSP48_BM6) |
+ 	    ((word & MV_SDIO_RSP48_BM2) << 6);
+ 
+ 	/* Response bits [15:14] are already included. */
+ 	word >>= 2;
+ 
+ 	/* Response bits [45:16] */
+ 	memcpy(rp, &word, sizeof(uint32_t));
+ }
+ 
+ static void
+ mv_sdio_intr(void *arg)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	uint32_t irq_stat, eirq_stat;
+ 
+   sc = (struct mv_sdio_softc *)arg;
+ #if 0
+ 	device_printf(sc->sc_dev,"intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n",
+                 MV_SDIO_RD4( sc, MV_SDIO_IRQ_SR ) ,  
+                 MV_SDIO_RD4( sc, MV_SDIO_IRQ_EN ),
+                 MV_SDIO_RD4( sc, MV_SDIO_HOST_SR ));
+ #endif
+   
+   
+ 	mtx_lock(&sc->sc_mtx);
+ 
+   
+ 
+ 	irq_stat = MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & sc->sc_irq_mask;
+ 	eirq_stat = MV_SDIO_RD4(sc, MV_SDIO_EIRQ_SR) & sc->sc_eirq_mask;
+ 
+ 	/*
+ 	 * In case of error interrupt, interrupt cause will be identified by
+ 	 * checking bits in error interrupt status register.
+ 	 */
+ 	irq_stat &= ~MV_SDIO_IRQ_ERR;
+ 
+ 	/* Handle command interrupts. */
+ 	if ((irq_stat & MV_SDIO_IRQS_CMD) ||
+ 	    (eirq_stat & MV_SDIO_EIRQS_CMD)) {
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat);
+ 		MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat);
+ 		mv_sdio_cmd_intr(sc, irq_stat, eirq_stat);
+ 		irq_stat &= ~MV_SDIO_IRQS_CMD;
+ 		eirq_stat &= ~MV_SDIO_EIRQS_CMD;
+ 	}
+ 
+ 	/* Handle data interrupts. */
+ 	if ((irq_stat & MV_SDIO_IRQS_DATA) ||
+ 	    (eirq_stat & MV_SDIO_EIRQS_DATA)) {
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat);
+ 		MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat);
+ 		mv_sdio_data_intr(sc, irq_stat, eirq_stat);
+ 		irq_stat &= ~MV_SDIO_IRQS_DATA;
+ 		eirq_stat &= ~MV_SDIO_EIRQS_DATA;
+ 	}
+ 
+ 	/* Handle unexpected interrupts. */
+ 	if (irq_stat) {
+ 		device_printf(sc->sc_dev, "Unexpected interrupt(s)! "
+ 		    "IRQ SR = 0x%08x\n", irq_stat);
+ 		/* Clear interrupt status. */
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat);
+ 	}
+ 	if (eirq_stat) {
+ 		device_printf(sc->sc_dev, "Unexpected error interrupt(s)! "
+ 		    "EIRQ SR = 0x%08x\n", eirq_stat);
+ 		/* Clear error interrupt status. */
+ 		MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat);
+ 	}
+ 
+ 	mtx_unlock(&sc->sc_mtx);
+ }
+ 
+ static void
+ mv_sdio_cmd_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq)
+ {
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	if (!sc->sc_curcmd) {
+ 		device_printf(sc->sc_dev, "Got command interrupt, but there "
+ 		    "is no active command!\n");
+ 		return;
+ 	}
+ 
+ 	/* Handle unexpected response error. */
+ 	if (irq & MV_SDIO_IRQ_UNEXPECTED_RSP) {
+ 		sc->sc_curcmd->error = MMC_ERR_FAILED;
+ 		device_printf(sc->sc_dev, "Unexpected response!\n");
+ 	}
+ 
+ 	/* Handle errors. */
+ 	if (eirq & MV_SDIO_EIRQ_CMD_TMO) {
+ 		sc->sc_curcmd->error = MMC_ERR_TIMEOUT;
+ 		device_printf(sc->sc_dev, "Error - command %d timeout!\n",
+ 		    sc->sc_curcmd->opcode);
+ 	} else if (eirq & MV_SDIO_EIRQ_CMD_CRC7) {
+ 		sc->sc_curcmd->error = MMC_ERR_BADCRC;
+ 		device_printf(sc->sc_dev, "Error - bad command %d "
+ 		    "checksum!\n", sc->sc_curcmd->opcode);
+ 	} else if (eirq) {
+ 		sc->sc_curcmd->error = MMC_ERR_FAILED;
+ 		device_printf(sc->sc_dev, "Command %d error!\n",
+ 		    sc->sc_curcmd->opcode);
+ 	}
+ 
+ 	if (sc->sc_curcmd->error != MMC_ERR_NONE) {
+ 		/* Error. Disable interrupts and finalize request. */
+ 		mv_sdio_disable_intr(sc);
+ 		mv_sdio_finalize_request(sc);
+ 		return;
+ 	}
+ 
+ 	if (irq & MV_SDIO_IRQ_CMD)
+ 		mv_sdio_finish_command(sc);
+ }
+ 
+ static void
+ mv_sdio_data_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq)
+ {
+ 	struct mmc_command *stop;
+ 
+ 	mtx_assert(&sc->sc_mtx, MA_OWNED);
+ 
+ 	if (!sc->sc_curcmd) {
+ 		device_printf(sc->sc_dev, "Got data interrupt, but there is "
+ 		    "no active command.\n");
+ 		return;
+ 	}
+ 	if ((!sc->sc_curcmd->data) && ((sc->sc_curcmd->flags &
+ 	    MMC_RSP_BUSY) == 0)) {
+ 		device_printf(sc->sc_dev, "Got data interrupt, but there is "
+ 		    "no active data transaction.n\n");
+ 		sc->sc_curcmd->error = MMC_ERR_FAILED;
+ 		return;
+ 	}
+ 
+ 	/* Handle errors. */
+ 	if(eirq & MV_SDIO_EIRQ_DATA_TMO) {
+ 		sc->sc_curcmd->error = MMC_ERR_TIMEOUT;
+ 		device_printf(sc->sc_dev, "Data %s timeout!\n",
+ 		    (sc->sc_curcmd->data->flags & MMC_DATA_READ) ? "read" :
+ 		    "write");
+ 	} else if (eirq & (MV_SDIO_EIRQ_DATA_CRC16 |
+ 	    MV_SDIO_EIRQ_DATA_ENDBIT)) {
+ 		sc->sc_curcmd->error = MMC_ERR_BADCRC;
+ 		device_printf(sc->sc_dev, "Bad data checksum!\n");
+ 	} else if (eirq) {
+ 		sc->sc_curcmd->error = MMC_ERR_FAILED;
+ 		device_printf(sc->sc_dev, "Data error!: 0x%04X \n",
+       eirq);
+ 
+     if( 0 != ( eirq & MV_SDIO_EIRQ_CRC_STAT ) )
+     {
+       device_printf(sc->sc_dev, "MV_SDIO_EIRQ_CRC_STAT\n");
+     }
+ 	}
+ 
+ 	/* Handle Auto-CMD12 error. */
+ 	if (eirq & MV_SDIO_EIRQ_AUTOCMD12) {
+ 		sc->sc_req->stop->error = MMC_ERR_FAILED;
+ 		sc->sc_curcmd->error = MMC_ERR_FAILED;
+ 		device_printf(sc->sc_dev, "Auto-CMD12 error!\n");
+ 	}
+ 
+ 	if (sc->sc_curcmd->error != MMC_ERR_NONE) {
+ 		/* Error. Disable interrupts and finalize request. */
+ 		mv_sdio_disable_intr(sc);
+ 		mv_sdio_finalize_request(sc);
+ 		return;
+ 	}
+ 
+ 	/* Handle PIO interrupt. */
+ 	if (irq & (MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_RX_FULL))
+ 		mv_sdio_transfer_pio(sc);
+ 
+ 	/* Handle DMA interrupt. */
+ 	if (irq & (MV_SDIO_IRQ_DMA)) {
+ 		/* Synchronize DMA buffer. */
+ 		if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_TO_HOST) {
+ 			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap,
+ 			    BUS_DMASYNC_POSTWRITE);
+ 			memcpy(sc->sc_curcmd->data->data, sc->sc_dmamem,
+ 			    sc->sc_curcmd->data->len);
+ 		} else
+ 			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap,
+ 			    BUS_DMASYNC_POSTREAD);
+ 
+ 		/* Disable DMA interrupt. */
+ 		sc->sc_irq_mask &= ~MV_SDIO_IRQ_DMA;
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	}
+ 
+ 	/* Handle Auto-CMD12 interrupt. */
+ 	if (irq & (MV_SDIO_IRQ_AUTOCMD12)) {
+ 		stop = sc->sc_req->stop;
+ 		/* Get 48-bit response. */
+ 		mv_sdio_handle_48bit_resp(sc, stop);
+ 
+ 		/* Disable Auto-CMD12 interrupt. */
+ 		sc->sc_irq_mask &= ~MV_SDIO_IRQ_AUTOCMD12;
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	}
+ 
+ 	/* Transfer finished. Disable interrupts and finalize request. */
+ 	if (irq & (MV_SDIO_IRQ_XFER)) {
+ 		mv_sdio_disable_intr(sc);
+ 		mv_sdio_finalize_request(sc);
+ 	}
+ }
+ 
+ static void
+ mv_sdio_cd_intr(void *arg)
+ {
+ 	struct mv_sdio_softc *sc;
+ 
+ 	sc = (struct mv_sdio_softc *)arg;
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 
+ 	if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) == 0) {
+     
+     device_printf(sc->sc_dev, "Card removed\n");
+ 		
+     callout_stop(&sc->sc_card_callout);
+ 
+ 		sc->sc_card_present = 0;
+ 
+ 		taskqueue_enqueue(taskqueue_swi, &sc->sc_card_task);
+ 
+ 		
+ 	} else {
+     
+     device_printf(sc->sc_dev, "Card inserted\n");
+     
+     
+     if( 1 == sc->sc_card_present )
+     {
+       /* Card has been removed previously 
+        * Remove the child-device, before it is added again
+        */
+       if( NULL != sc->sc_child )
+       {
+         device_printf(sc->sc_dev, "Previous removal has not been detected properly\n");
+         if (device_delete_child(sc->sc_dev, sc->sc_child) != 0) {
+           device_printf(sc->sc_dev, "Could not delete MMC "
+                         "bus!\n");
+         }
+         sc->sc_child = NULL;
+       }
+     }
+     else
+     {
+       sc->sc_card_present = 1;
+     }
+ 		callout_reset(&sc->sc_card_callout, hz / 2,
+                   mv_sdio_card_delay, sc);
+ 
+ 		
+ 	}
+ 
+ 	mtx_unlock(&sc->sc_mtx);
+ }
+ 
+ static void
+ mv_sdio_disable_intr(struct mv_sdio_softc *sc)
+ {
+ 
+ 	/* Disable interrupts that were enabled. */
+ 	sc->sc_irq_mask &= ~(sc->sc_irq_mask);
+ 	sc->sc_eirq_mask &= ~(sc->sc_eirq_mask);
+ 	MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask);
+ }
+ 
+ #if 1
+ static void
+ mv_sdio_card_delay(void *arg)
+ {
+ 	struct mv_sdio_softc *sc;
+ 
+ 	sc = (struct mv_sdio_softc *)arg;
+ 
+ 	taskqueue_enqueue(taskqueue_swi, &sc->sc_card_task);
+ }
+ #endif
+ 
+ static void
+ mv_sdio_card_task(void *arg, int pending)
+ {
+ 	struct mv_sdio_softc *sc;
+   
+   int device_probe_and_attach_ret_val = 0;
+ 
+ 	sc = (struct mv_sdio_softc *)arg;
+ 
+ 	mtx_lock(&sc->sc_mtx);
+ 
+ #if 0
+   device_printf(sc->sc_dev, "mv_sdio_card_task\n");
+ #endif
+ 
+ 	if (sc->sc_card_present) {
+ 		if (sc->sc_child) {
+ 			mtx_unlock(&sc->sc_mtx);
+ 			return;
+ 		}
+ 
+ 		/* Initialize host controller's registers. */
+ 		mv_sdio_init(sc->sc_dev);
+ 
+ 		sc->sc_child = device_add_child(sc->sc_dev, "mmc", -1);
+ 		if (sc->sc_child == NULL) {
+ 			device_printf(sc->sc_dev, "Could not add MMC bus!\n");
+ 			mtx_unlock(&sc->sc_mtx);
+ 			return;
+ 		}
+             
+ 		/* Initialize host structure for MMC bus. */
+ 		mv_sdio_init_host(sc);
+ 
+ 		device_set_ivars(sc->sc_child, &sc->sc_host);
+ 
+ 		mtx_unlock(&sc->sc_mtx);
+ 
+     // device_probe_and_attach_ret_val = bus_generic_attach( sc->sc_dev );
+     
+     device_probe_and_attach_ret_val = device_probe_and_attach(sc->sc_child);
+ 
+     //device_probe_and_attach_ret_val = device_probe_child( sc->sc_dev, sc->sc_child ); //device_t dev, device_t child)
+         
+     if( 0 != device_probe_and_attach_ret_val ) {
+ 			device_printf(sc->sc_dev, "MMC bus failed on probe "
+                     "and attach! %i\n",device_probe_and_attach_ret_val);
+ 			device_delete_child(sc->sc_dev, sc->sc_child);
+ 			sc->sc_child = NULL;
+ 		}
+ 	} else {
+ 		if (sc->sc_child == NULL) {
+ 			mtx_unlock(&sc->sc_mtx);
+ 			return;
+ 		}
+ 
+ 		mtx_unlock(&sc->sc_mtx);
+ 		if (device_delete_child(sc->sc_dev, sc->sc_child) != 0) {
+ 			device_printf(sc->sc_dev, "Could not delete MMC "
+ 			    "bus!\n");
+ 		}
+ 		sc->sc_child = NULL;
+ 	}
+ }
+ 
+ static uint32_t
+ mv_sdio_read_fifo(struct mv_sdio_softc *sc)
+ {
+ 	uint32_t data;
+   device_printf(sc->sc_dev, "This is not tested, yet MV_SDIO_FIFO not ensured\n ");
+   
+  	while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL));
+ 	data = MV_SDIO_RD4(sc, MV_SDIO_FIFO);
+ 	while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL));
+ 	data |= (MV_SDIO_RD4(sc, MV_SDIO_FIFO) << 16);
+ 	return data;
+ }
+ 
+ static void
+ mv_sdio_write_fifo(struct mv_sdio_softc *sc, uint32_t val)
+ {
+ 	while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY));
+ 	MV_SDIO_WR4(sc, MV_SDIO_FIFO, val & 0xffff);
+ 	while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY));
+ 	MV_SDIO_WR4(sc, MV_SDIO_FIFO, val >> 16);
+ }
+ 
+ static void
+ mv_sdio_transfer_pio(struct mv_sdio_softc *sc)
+ {
+ 	struct mmc_command *cmd;
+   
+   device_printf(sc->sc_dev, "mv_sdio_transfer_pio()\n");
+ 
+ 	cmd = sc->sc_curcmd;
+ 
+ 	if (cmd->data->flags & MMC_DATA_READ) {
+ 		while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) &
+ 		    MV_SDIO_IRQ_RX_FULL) {
+ 			mv_sdio_read_block_pio(sc);
+ 			/*
+ 			 * Assert delay after each block transfer to meet read
+ 			 * access timing constraint.
+ 			 */
+ 			DELAY(MV_SDIO_RD_DELAY);
+ 			if (sc->sc_data_offset >= cmd->data->len)
+ 				break;
+ 		}
+ 		/* All blocks read in PIO mode. Disable interrupt. */
+ 		sc->sc_irq_mask &= ~MV_SDIO_IRQ_RX_FULL;
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	} else {
+ 		while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) &
+ 		    MV_SDIO_IRQ_TX_EMPTY) {
+ 			mv_sdio_write_block_pio(sc);
+ 			/* Wait while card is programming the memory. */
+ 			while ((MV_SDIO_RD4(sc, MV_SDIO_HOST_SR) &
+               MV_SDIO_HOST_SR_CARD_BUSY));
+ 			/*
+ 			 * Assert delay after each block transfer to meet
+ 			 * write access timing constraint.
+ 			 */
+ 			DELAY(MV_SDIO_WR_DELAY);
+ 
+ 			if (sc->sc_data_offset >= cmd->data->len)
+ 				break;
+ 		}
+ 		/* All blocks written in PIO mode. Disable interrupt. */
+ 		sc->sc_irq_mask &= ~MV_SDIO_IRQ_TX_EMPTY;
+ 		MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask);
+ 	}
+ }
+ 
+ static void
+ mv_sdio_read_block_pio(struct mv_sdio_softc *sc)
+ {
+ 	uint32_t data;
+ 	char *buffer;
+ 	size_t left;
+ 
+ 	buffer = sc->sc_curcmd->data->data;
+ 	buffer += sc->sc_data_offset;
+ 	/* Transfer one block at a time. */
+ 	left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len -
+ 	    sc->sc_data_offset);
+ 	sc->sc_data_offset += left;
+ 
+ 	/* Handle unaligned and aligned buffer cases. */
+ 	if ((intptr_t)buffer & 3) {
+ 		while (left > 3) {
+ 			data = mv_sdio_read_fifo(sc);
+ 			buffer[0] = data;
+ 			buffer[1] = (data >> 8);
+ 			buffer[2] = (data >> 16);
+ 			buffer[3] = (data >> 24);
+ 			buffer += 4;
+ 			left -= 4;
+ 		}
+ 	} else {
+ 		while (left > 3) {
+ 			data = mv_sdio_read_fifo(sc);
+ 			*((uint32_t *)buffer) = data;
+ 			buffer += 4;
+ 			left -= 4;
+ 		}
+ 	}
+ 	/* Handle uneven size case. */
+ 	if (left > 0) {
+ 		data = mv_sdio_read_fifo(sc);
+ 		while (left > 0) {
+ 			*(buffer++) = data;
+ 			data >>= 8;
+ 			left--;
+ 		}
+ 	}
+ }
+ 
+ static void
+ mv_sdio_write_block_pio(struct mv_sdio_softc *sc)
+ {
+ 	uint32_t data = 0;
+ 	char *buffer;
+ 	size_t left;
+ 
+ 	buffer = sc->sc_curcmd->data->data;
+ 	buffer += sc->sc_data_offset;
+ 	/* Transfer one block at a time. */
+ 	left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len -
+ 	    sc->sc_data_offset);
+ 	sc->sc_data_offset += left;
+ 
+ 	/* Handle unaligned and aligned buffer cases. */
+ 	if ((intptr_t)buffer & 3) {
+ 		while (left > 3) {
+ 			data = buffer[0] +
+ 			    (buffer[1] << 8) +
+ 			    (buffer[2] << 16) +
+ 			    (buffer[3] << 24);
+ 			left -= 4;
+ 			buffer += 4;
+ 			mv_sdio_write_fifo(sc, data);
+ 		}
+ 	} else {
+ 		while (left > 3) {
+ 			data = *((uint32_t *)buffer);
+ 			left -= 4;
+ 			buffer += 4;
+ 			mv_sdio_write_fifo(sc, data);
+ 		}
+ 	}
+ 	/* Handle uneven size case. */
+ 	if (left > 0) {
+ 		data = 0;
+ 		while (left > 0) {
+ 			data <<= 8;
+ 			data += *(buffer++);
+ 			left--;
+ 		}
+ 		mv_sdio_write_fifo(sc, data);
+ 	}
+ }
+ 
+ static int
+ mv_sdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+ {
+ 	struct mv_sdio_softc *sc;
+ 	struct mmc_host *host;
+ 
+ 	sc = device_get_softc(dev);
+ 	host = device_get_ivars(child);
+ 
+ 	switch (index) {
+ 	case MMCBR_IVAR_BUS_MODE:
+ 		*(int *)result = host->ios.bus_mode;
+ 		break;
+ 	case MMCBR_IVAR_BUS_WIDTH:
+ 		*(int *)result = host->ios.bus_width;
+ 		break;
+ 	case MMCBR_IVAR_CHIP_SELECT:
+ 		*(int *)result = host->ios.chip_select;
+ 		break;
+ 	case MMCBR_IVAR_CLOCK:
+ 		*(int *)result = host->ios.clock;
+ 		break;
+ 	case MMCBR_IVAR_F_MIN:
+ 		*(int *)result = host->f_min;
+ 		break;
+ 	case MMCBR_IVAR_F_MAX:
+ 		*(int *)result = host->f_max;
+ 		break;
+ 	case MMCBR_IVAR_HOST_OCR:
+ 		*(int *)result = host->host_ocr;
+ 		break;
+ 	case MMCBR_IVAR_MODE:
+ 		*(int *)result = host->mode;
+ 		break;
+ 	case MMCBR_IVAR_OCR:
+ 		*(int *)result = host->ocr;
+ 		break;
+ 	case MMCBR_IVAR_POWER_MODE:
+ 		*(int *)result = host->ios.power_mode;
+ 		break;
+ 	case MMCBR_IVAR_VDD:
+ 		*(int *)result = host->ios.vdd;
+ 		break;
+ 	case MMCBR_IVAR_CAPS:
+ 		*(int *)result = host->caps;
+ 		break;
+ 	case MMCBR_IVAR_TIMING:
+ 		*(int *)result = host->ios.timing;
+ 		break;
+ 	case MMCBR_IVAR_MAX_DATA:
+ 		mtx_lock(&sc->sc_mtx);
+ 		/* Return maximum number of blocks the driver can handle. */
+ 		if (sc->sc_use_dma)
+ 			*(int *)result = (sc->sc_dma_size /
+ 			    MV_SDIO_BLOCK_SIZE);
+ 		else
+ 			*(int *)result = MV_SDIO_BLOCKS_MAX;
+ 		mtx_unlock(&sc->sc_mtx);
+ 		break;
+ 	default:
+ 		return (EINVAL);
+ 	}
+ 
+ 	return (0);
+ }
+ 
+ static int
+ mv_sdio_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
+ {
+ 	struct mmc_host *host;
+ 
+ 	host = device_get_ivars(child);
+ 
+ 	switch (index) {
+ 	case MMCBR_IVAR_BUS_MODE:
+ 		host->ios.bus_mode = value;
+ 		break;
+ 	case MMCBR_IVAR_BUS_WIDTH:
+ 		host->ios.bus_width = value;
+ 		break;
+ 	case MMCBR_IVAR_CHIP_SELECT:
+ 		host->ios.chip_select = value;
+ 		break;
+ 	case MMCBR_IVAR_CLOCK:
+ 		host->ios.clock = value;
+ 		break;
+ 	case MMCBR_IVAR_MODE:
+ 		host->mode = value;
+ 		break;
+ 	case MMCBR_IVAR_OCR:
+ 		host->ocr = value;
+ 		break;
+ 	case MMCBR_IVAR_POWER_MODE:
+ 		host->ios.power_mode = value;
+ 		break;
+ 	case MMCBR_IVAR_VDD:
+ 		host->ios.vdd = value;
+ 		break;
+ 	case MMCBR_IVAR_TIMING:
+ 		host->ios.timing = value;
+ 		break;
+ 	case MMCBR_IVAR_CAPS:
+ 	case MMCBR_IVAR_HOST_OCR:
+ 	case MMCBR_IVAR_F_MIN:
+ 	case MMCBR_IVAR_F_MAX:
+ 	case MMCBR_IVAR_MAX_DATA:
+ 	default:
+ 		/* Instance variable not writable. */
+ 		return (EINVAL);
+ 	}
+ 
+ 	return (0);
+ }
diff -prN --exclude=.svn head_r221725/sys/arm/mv/mv_sdio.h head_r221525/sys/arm/mv/mv_sdio.h
*** head_r221725/sys/arm/mv/mv_sdio.h	Thu Jan  1 00:00:00 1970
--- head_r221525/sys/arm/mv/mv_sdio.h	Tue May 10 08:24:17 2011
***************
*** 0 ****
--- 1,172 ----
+ /*
+  *  Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
+  */
+ 
+ #ifndef _MVSDMMC_INCLUDE
+ #define _MVSDMMC_INCLUDE
+ 
+ 
+ #define MVSDMMC_DMA_SIZE			65536
+ 
+ 
+ 
+ /*
+  * The base MMC clock rate
+  */
+ 
+ #define MVSDMMC_CLOCKRATE_MIN			100000
+ #define MVSDMMC_CLOCKRATE_MAX			50000000
+ 
+ #define MVSDMMC_BASE_FAST_CLOCK			200000000
+ 
+ 
+ /*
+  * SDIO register
+  */
+ 
+ #define MV_SDIO_DMA_ADDRL       0x000 
+ #define MV_SDIO_DMA_ADDRH       0x004
+ #define MV_SDIO_BLK_SIZE				0x008
+ #define MV_SDIO_BLK_COUNT				0x00c
+ #define MV_SDIO_CMD             0x01c
+ #define MV_SDIO_CMD_ARGL        0x010
+ #define MV_SDIO_CMD_ARGH        0x014
+ #define MV_SDIO_XFER    				0x018
+ #define MV_SDIO_HOST_SR         0x048
+ #define MV_SDIO_HOST_CR         0x050
+ #define MV_SDIO_SW_RESET        0x05c
+ #define MV_SDIO_IRQ_SR		      0x060
+ #define MV_SDIO_EIRQ_SR         0x064
+ #define MV_SDIO_IRQ_SR_EN       0x068
+ #define MV_SDIO_EIRQ_SR_EN      0x06c
+ #define MV_SDIO_IRQ_EN          0x070
+ #define MV_SDIO_EIRQ_EN         0x074
+ #define MV_SDIO_AUTOCMD12_ARGL	0x084
+ #define MV_SDIO_AUTOCMD12_ARGH	0x088
+ #define MV_SDIO_AUTOCMD12			  0x08c
+ #define MV_SDIO_CLK_DIV				  0x128
+ #define MV_SDIO_FIFO     0xa2100 /* FIXME!!! */
+ 
+ #define MV_SDIO_RSP(i)			  (0x020 + ((i)<<2))
+ #define MV_SDIO_AUTOCMD12_RSP(i)	(0x090 + ((i)<<2))
+ 
+ /*
+  * SDIO Status-Register
+  */
+ #define MV_SDIO_HOST_SR_CARD_BUSY (1<<1)
+ #define MV_SDIO_HOST_SR_FIFO_EMPTY (1<<13)
+ 
+ 
+ 
+ /*
+  * SDIO_CMD
+  */
+ #define MV_SDIO_CMD_RSP_NONE			(0 << 0)
+ #define MV_SDIO_CMD_RSP_136			(1 << 0)
+ #define MV_SDIO_CMD_RSP_48				(2 << 0)
+ #define MV_SDIO_CMD_RSP_48_BUSY			(3 << 0)
+ #define MV_SDIO_CMD_DATA_CRC16 (1<<2)
+ #define MV_SDIO_CMD_CRC7 (1<<3)
+ #define MV_SDIO_CMD_INDEX_CHECK (1<<4)
+ #define MV_SDIO_CMD_DATA_PRESENT (1<<5)
+ #define MV_SDIO_CMD_UNEXPECTED_RSP (1<<7)
+ #define MV_SDIO_CMD_INDEX(x) ( (x) << 8 )
+ 
+ 
+ /*
+  * SDIO_XFER_MODE
+  */
+ #define MV_SDIO_XFER_STOP_CLK			(1 << 5)
+ #define MV_SDIO_XFER_TO_HOST			(1 << 4)
+ #define MV_SDIO_XFER_PIO          (1 << 3)
+ #define MV_SDIO_XFER_AUTOCMD12		(1 << 2)
+ #define MV_SDIO_XFER_SW_WR_EN     (1 << 1)
+ 
+ /*
+  * SDIO_HOST_CTRL
+  */
+ #define MV_SDIO_HOST_CR_PUSHPULL  (1 <<  0)
+ #define MV_SDIO_HOST_CR_MMC       (3 <<  1)
+ #define MV_SDIO_HOST_CR_BE        (1 <<  3)
+ #define MV_SDIO_HOST_CR_4BIT      (1 <<  9)
+ #define MV_SDIO_HOST_CR_HIGHSPEED (1 << 10)
+ 
+ #define MV_SDIO_HOST_CR_TMOVAL(x) ((x) << 11)
+ #define MV_SDIO_HOST_CR_TMO       ( 1 << 15 ) 
+ 
+ /*
+  * NORmal status bits
+  */
+ 
+ 
+ #define MV_SDIO_IRQ_ERR            (1<<15)
+ #define MV_SDIO_IRQ_UNEXPECTED_RSP (1<<14)
+ #define MV_SDIO_IRQ_AUTOCMD12      (1<<13)
+ #define MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN (1<<12)
+ #define MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL (1<<11)
+ #define MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED (1<<10)
+ #define MV_SDIO_IRQ_READ_WAIT (1<<9)
+ #define MV_SDIO_IRQ_CARD_EVENT (1<<8)
+ #define MV_SDIO_IRQ_RX_FULL (1<<5)
+ #define MV_SDIO_IRQ_TX_EMPTY (1<<4)
+ #define MV_SDIO_IRQ_DMA (1<<3)
+ #define MV_SDIO_IRQ_BLOCK_GAP (1<<2)
+ #define MV_SDIO_IRQ_XFER (1<<1)
+ #define MV_SDIO_IRQ_CMD (1<<0)
+ 
+ #define MV_SDIO_IRQ_ALL (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_BLOCK_GAP | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_CARD_EVENT | MV_SDIO_IRQ_READ_WAIT | MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED | MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL | MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN | MV_SDIO_IRQ_AUTOCMD12 | MV_SDIO_IRQ_UNEXPECTED_RSP | MV_SDIO_IRQ_ERR )
+ 
+ //#define MV_SDIO_IRQ_SR 
+ 
+ 
+ /*
+  * ERR status bits
+  */
+ #define MV_SDIO_EIRQ_CRC_STAT     (1<<14)
+ #define MV_SDIO_EIRQ_CRC_STARTBIT (1<<13)
+ #define MV_SDIO_EIRQ_CRC_ENDBIT   (1<<12)
+ #define MV_SDIO_EIRQ_RSP_TBIT     (1<<11)
+ #define MV_SDIO_EIRQ_XFER_SIZE    (1<<10)
+ #define MV_SDIO_EIRQ_CMD_STARTBIT (1<<9)
+ #define MV_SDIO_EIRQ_AUTOCMD12    (1<<8)
+ #define MV_SDIO_EIRQ_DATA_ENDBIT  (1<<6)
+ #define MV_SDIO_EIRQ_DATA_CRC16   (1<<5)
+ #define MV_SDIO_EIRQ_DATA_TMO     (1<<4)
+ #define MV_SDIO_EIRQ_CMD_INDEX    (1<<3)
+ #define MV_SDIO_EIRQ_CMD_ENDBIT   (1<<2)
+ #define MV_SDIO_EIRQ_CMD_CRC7     (1<<1)
+ #define MV_SDIO_EIRQ_CMD_TMO      (1<<0)
+ 
+ #define MV_SDIO_EIRQ_ALL (MV_SDIO_EIRQ_CMD_TMO | \
+                           MV_SDIO_EIRQ_CMD_CRC7 | \
+                           MV_SDIO_EIRQ_CMD_ENDBIT | \
+                           MV_SDIO_EIRQ_CMD_INDEX | \
+                           MV_SDIO_EIRQ_DATA_TMO | \
+                           MV_SDIO_EIRQ_DATA_CRC16 | \
+                           MV_SDIO_EIRQ_DATA_ENDBIT | \
+                           MV_SDIO_EIRQ_AUTOCMD12 | \
+                           MV_SDIO_EIRQ_CMD_STARTBIT |\
+                           MV_SDIO_EIRQ_XFER_SIZE |\
+                           MV_SDIO_EIRQ_RSP_TBIT |\
+                           MV_SDIO_EIRQ_CRC_ENDBIT |\
+                           MV_SDIO_EIRQ_CRC_STARTBIT |\
+                           MV_SDIO_EIRQ_CRC_STAT)
+ 
+ /* AUTOCMD12 register values */
+ #define MV_SDIO_AUTOCMD12_BUSY_CHECK (1<<0)
+ #define MV_SDIO_AUTOCMD12_INDEX_CHECK (1<<1)
+ #define MV_SDIO_AUTOCMD12_INDEX(x) (x<<8)
+ 
+ /* Software reset register */
+ #define MV_SDIO_SW_RESET_ALL (1<<8)
+ 
+ /* */
+ #define MV_SDIO_SIG_CD 1
+ #define MV_SDIO_SIG_WP 2
+ 
+ #endif /* _MVSDMMC_INCLUDE */
diff -prN --exclude=.svn head_r221725/sys/boot/fdt/dts/openrd-cl.dts head_r221525/sys/boot/fdt/dts/openrd-cl.dts
*** head_r221725/sys/boot/fdt/dts/openrd-cl.dts	Thu Jan  1 00:00:00 1970
--- head_r221525/sys/boot/fdt/dts/openrd-cl.dts	Tue May 10 08:24:54 2011
***************
*** 0 ****
--- 1,399 ----
+ /*
+  * Copyright (c) 2009-2010 The FreeBSD Foundation
+  * All rights reserved.
+  *
+  * This software was developed by Semihalf under sponsorship from
+  * the FreeBSD Foundation.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  * OpenRD-Client/Ultimate Device Tree Source.
+  *
+  * $FreeBSD$
+  */
+ 
+ /dts-v1/;
+ 
+ / {
+ 	model = "mrvl,OpenRD-CL";
+ 	compatible = "OpenRD-CL";
+ 	#address-cells = <1>;
+ 	#size-cells = <1>;
+ 
+ 	aliases {
+ 		ethernet0 = &enet0;
+ 		ethernet1 = &enet1;
+ 		mpp = &MPP;
+ 		pci0 = &pci0;
+ 		serial0 = &serial0;
+ 		/*serial1 = &serial1;*/
+ 		soc = &SOC;
+ 		sram = &SRAM;
+ 	};
+ 
+ 	cpus {
+ 		#address-cells = <1>;
+ 		#size-cells = <0>;
+ 
+ 		cpu at 0 {
+ 			device_type = "cpu";
+ 			compatible = "ARM,88FR131";
+ 			reg = <0x0>;
+ 			d-cache-line-size = <32>;	// 32 bytes
+ 			i-cache-line-size = <32>;	// 32 bytes
+ 			d-cache-size = <0x4000>;	// L1, 16K
+ 			i-cache-size = <0x4000>;	// L1, 16K
+ 			timebase-frequency = <0>;
+ 			bus-frequency = <0>;
+ 			clock-frequency = <0>;
+ 		};
+ 	};
+ 
+ 	memory {
+ 		device_type = "memory";
+ 		reg = <0x0 0x20000000>;		// 512M at 0x0
+ 	};
+ 
+ 	localbus at f1000000 {
+ 		#address-cells = <2>;
+ 		#size-cells = <1>;
+ 		compatible = "mrvl,lbc";
+ 
+ 		/* This reflects CPU decode windows setup. */
+ 		ranges = <0x0 0x0f 0xf9300000 0x00100000
+ 			  0x1 0x1e 0xfa000000 0x00100000
+ 			  0x2 0x1d 0xfa100000 0x02000000
+ 			  0x3 0x1b 0xfc100000 0x00000400>;
+ 
+ 		nor at 0,0 {
+ 			#address-cells = <1>;
+ 			#size-cells = <1>;
+ 			compatible = "cfi-flash";
+ 			reg = <0x0 0x0 0x00100000>;
+ 			bank-width = <2>;
+ 			device-width = <1>;
+ 		};
+ 
+ 		led at 1,0 {
+ 			#address-cells = <1>;
+ 			#size-cells = <1>;
+ 			compatible = "led";
+ 			reg = <0x1 0x0 0x00100000>;
+ 		};
+ 
+ 		nor at 2,0 {
+ 			#address-cells = <1>;
+ 			#size-cells = <1>;
+ 			compatible = "cfi-flash";
+ 			reg = <0x2 0x0 0x02000000>;
+ 			bank-width = <2>;
+ 			device-width = <1>;
+ 		};
+ 
+ 		nand at 3,0 {
+ 			#address-cells = <1>;
+ 			#size-cells = <1>;
+ 			reg = <0x3 0x0 0x00100000>;
+ 			bank-width = <2>;
+ 			device-width = <1>;
+ 		};
+ 	};
+ 
+ 	SOC: soc88f6281 at f1000000 {
+ 		#address-cells = <1>;
+ 		#size-cells = <1>;
+ 		compatible = "simple-bus";
+ 		ranges = <0x0 0xf1000000 0x00100000>;
+ 		bus-frequency = <0>;
+ 
+ 		PIC: pic at 20200 {
+ 			interrupt-controller;
+ 			#address-cells = <0>;
+ 			#interrupt-cells = <1>;
+ 			reg = <0x20200 0x3c>;
+ 			compatible = "mrvl,pic";
+ 		};
+ 
+ 		timer at 20300 {
+ 			compatible = "mrvl,timer";
+ 			reg = <0x20300 0x30>;
+ 			interrupts = <1>;
+ 			interrupt-parent = <&PIC>;
+ 			mrvl,has-wdt;
+ 		};
+ 
+ 		MPP: mpp at 10000 {
+ 			#pin-cells = <2>;
+ 			compatible = "mrvl,mpp";
+ 			reg = <0x10000 0x34>;
+ 			pin-count = <50>;
+ 			pin-map = <
+ 				0  1		/* MPP[0]:  NF_IO[2] */
+ 				1  1		/* MPP[1]:  NF_IO[3] */
+ 				2  1		/* MPP[2]:  NF_IO[4] */
+ 				3  1		/* MPP[3]:  NF_IO[5] */
+ 				4  1		/* MPP[4]:  NF_IO[6] */
+ 				5  1		/* MPP[5]:  NF_IO[7] */
+ 				6  1		/* MPP[6]:  SYSRST_OUTn */
+ 				7  0		/* MPP[7]:  GPO[7] */
+ 				8  1		/* MPP[8]:  TW_SDA */
+ 				9  1		/* MPP[9]:  TW_SCK */
+ 				10 3		/* MPP[10]: UA0_TXD */
+ 				11 3		/* MPP[11]: UA0_RXD */
+ 				12 1		/* MPP[12]: SD_CLK */
+ 				13 1		/* MPP[13]: SD_CMD */
+ 				14 1		/* MPP[14]: SD_D[0] */
+ 				15 1		/* MPP[15]: SD_D[1] */
+ 				16 1		/* MPP[16]: SD_D[2] */
+ 				17 1		/* MPP[17]: SD_D[3] */
+ 				18 1		/* MPP[18]: NF_IO[0] */
+ 				19 1		/* MPP[19]: NF_IO[1] */
+ 				20 3		/* MPP[20]: GE1[0] */
+ 				21 3		/* MPP[21]: GE1[1] */
+ 				22 3		/* MPP[22]: GE1[2] */
+ 				23 3		/* MPP[23]: GE1[3] */
+ 				24 3		/* MPP[24]: GE1[4] */
+ 				25 3		/* MPP[25]: GE1[5] */
+ 				26 3		/* MPP[26]: GE1[6] */
+ 				27 3		/* MPP[27]: GE1[7] */
+ 				28 0		/* MPP[28]: GPIO[28] */
+ 				29 0		/* MPP[29]: GPIO[29] */
+ 				30 3		/* MPP[30]: GE1[10] */
+ 				31 3		/* MPP[31]: GE1[11] */
+ 				32 3		/* MPP[32]: GE1[12] */
+ 				33 3		/* MPP[33]: GE1[13] */
+ 				34 0		/* MPP[34]: GPIO[34] */
+ 				35 2		/* MPP[35]: TDM_CH0_TX_QL */
+ 				36 2		/* MPP[36]: TDM_SPI_CS1 */
+ 				37 2		/* MPP[37]: TDM_CH2_TX_QL */
+ 				38 2		/* MPP[38]: TDM_CH2_RX_QL */
+ 				39 4		/* MPP[39]: AU_I2SBCLK */
+ 				40 4		/* MPP[40]: AU_I2SDO */
+ 				41 4		/* MPP[41]: AU_I2SLRCLK */
+ 				42 4		/* MPP[42]: AU_I2SMCLK */
+ 				43 4		/* MPP[43]: AU_I2SDI */
+ 				44 4		/* MPP[44]: AU_EXTCLK */
+ 				45 2		/* MPP[45]: TDM_PCLK */
+ 				46 2		/* MPP[46]: TDM_FS */
+ 				47 2		/* MPP[47]: TDM_DRX */
+ 				48 2		/* MPP[48]: TDM_DTX */
+ 				49 2>;		/* MPP[49]: TDM_CH0_TX_QL */
+ 		};
+ 
+ 		GPIO: gpio at 10100 {
+ 			#gpio-cells = <3>;
+ 			compatible = "mrvl,gpio";
+ 			reg = <0x10100 0x20>;
+ 			gpio-controller = <1>;
+ 			pin-count = <50>;
+ 			interrupts = <35 36 37 38 39 40 41>;
+ 			interrupt-parent = <&PIC>;
+ 			
+ 			
+ 
+ 
+ 		};
+ 
+ 		rtc at 10300 {
+ 			compatible = "mrvl,rtc";
+ 			reg = <0x10300 0x08>;
+ 		};
+ 
+ 		twsi at 11000 {
+ 			#address-cells = <1>;
+ 			#size-cells = <0>;
+ 			compatible = "mrvl,twsi";
+ 			reg = <0x11000 0x20>;
+ 			interrupts = <43>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ 
+ 		mdio0: mdio at 72000 {
+ 			   device_type = "mdio";
+ 			   compatible = "mrvl,mdio";
+ 			   reg = <72000 20>;
+ 			   #address-cells = <1>;
+ 			   #size-cells = <0>;
+ 
+ 			   phy0: ethernet-phy at 0 {
+ 				reg = <0>;
+ 				device_type = "ethernet-phy";
+ 			   };
+ 			   
+ 		
+ 		};
+ 		
+ 		mdio1: mdio at 76000 {
+ 			   device_type = "mdio";
+ 			   compatible = "mrvl,mdio";
+ 			   reg = <76000 20>;
+ 			   #address-cells = <1>;
+ 			   #size-cells = <0>;
+ 			   
+ 			   phy1: ethernet-phy at 0 {
+ 				reg = <1>;
+ 				device_type = "ethernet-phy";
+ 			   };
+ 			   
+ 		
+ 		};
+ 
+ 		enet0: ethernet at 72000 {
+ 			#address-cells = <1>;
+ 			#size-cells = <1>;
+ 			model = "V2";
+ 			compatible = "mrvl,ge";
+ 			reg = <0x72000 0x2000>;
+ 			ranges = <0x0 0x72000 0x2000>;
+ 			local-mac-address = [ 00 00 00 00 00 00 ];
+ 			interrupts = <12 13 14 11 46>;
+ 			interrupt-parent = <&PIC>;
+ 			phy-handle = <&phy0>;
+ 
+ 		};
+ 
+ 		enet1: ethernet at 76000 {
+ 			#address-cells = <1>;
+ 			#size-cells = <1>;
+ 			model = "V2";
+ 			compatible = "mrvl,ge";
+ 			reg = <0x76000 0x2000>;
+ 			ranges = <0x0 0x76000 0x2000>;
+ 			local-mac-address = [ 00 00 00 00 00 00 ];
+ 			interrupts = <16 17 18 15 47>;
+ 			interrupt-parent = <&PIC>;
+ 			phy-handle = <&phy1>;
+ /*
+ 			mdio at 1 {
+ 				#address-cells = <1>;
+ 				#size-cells = <0>;
+ 				compatible = "mrvl,mdio";
+ 			};
+ */
+ 		};
+ 
+ 		serial0: serial at 12000 {
+ 			compatible = "ns16550";
+ 			reg = <0x12000 0x20>;
+ 			reg-shift = <2>;
+ 			clock-frequency = <0>;
+ 			interrupts = <33>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ /*
+ 		serial1: serial at 12100 {
+ 			compatible = "ns16550";
+ 			reg = <0x12100 0x20>;
+ 			reg-shift = <2>;
+ 			clock-frequency = <0>;
+ 			interrupts = <34>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ */
+ 		
+ 		
+ 		crypto at 30000 {
+ 			compatible = "mrvl,cesa";
+ 			reg = <0x30000 0x10000>;
+ 			interrupts = <22>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ 
+ 		usb at 50000 {
+ 			compatible = "mrvl,usb-ehci", "usb-ehci";
+ 			reg = <0x50000 0x1000>;
+ 			interrupts = <48 19>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ 
+ 		xor at 60000 {
+ 			compatible = "mrvl,xor";
+ 			reg = <0x60000 0x1000>;
+ 			interrupts = <5 6 7 8>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ 
+ 		sata at 80000 {
+ 			compatible = "mrvl,sata";
+ 			reg = <0x80000 0x6000>;
+ 			interrupts = <21>;
+ 			interrupt-parent = <&PIC>;
+ 		};
+ 		sdio at 90000 {
+ 			compatible = "mrvl,sdio";
+ 			reg = <0x90000 0x134>;
+ 			interrupts = <28>;
+ 			interrupt-parent = <&PIC>;
+ 			
+ 			gpios = <&GPIO 29 1 0x00030000   /* GPIO[29]:  IN_POL_LOW, IRQ (edge) */
+ 			         &GPIO 34 2 0x00000000>; /* GPIO[34]:  OUT */	
+ 			
+ 		};
+ 	};
+ 
+ 	SRAM: sram at fd000000 {
+ 		compatible = "mrvl,cesa-sram";
+ 		reg = <0xfd000000 0x00100000>;
+ 	};
+ 
+ 	chosen {
+ 		stdin  = "serial0";
+ 		stdout = "serial0";
+ 	};
+ 
+ 
+ 	pci0: pcie at f1040000 {
+ 		compatible = "mrvl,pcie";
+ 		device_type = "pci";
+ 		#interrupt-cells = <1>;
+ 		#size-cells = <2>;
+ 		#address-cells = <3>;
+ 		reg = <0xf1040000 0x2000>;
+ 		bus-range = <0 255>;
+ 		ranges = <0x02000000 0x0 0xf4000000 0xf4000000 0x0 0x04000000
+ 			  0x01000000 0x0 0x00000000 0xf1100000 0x0 0x00100000>;
+ 		clock-frequency = <33333333>;
+ 		interrupt-parent = <&PIC>;
+ 		interrupts = <44>;
+ 		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ 		interrupt-map = <
+ 			/* IDSEL 0x1 */
+ 			0x0800 0x0 0x0 0x1 &PIC 0x9
+ 			0x0800 0x0 0x0 0x2 &PIC 0x9
+ 			0x0800 0x0 0x0 0x3 &PIC 0x9
+ 			0x0800 0x0 0x0 0x4 &PIC 0x9
+ 			>;
+ 		pcie at 0 {
+ 			reg = <0x0 0x0 0x0 0x0 0x0>;
+ 			#size-cells = <2>;
+ 			#address-cells = <3>;
+ 			device_type = "pci";
+ 			ranges = <0x02000000 0x0 0xf4000000
+ 				  0x02000000 0x0 0xf4000000
+ 				  0x0 0x04040000
+ 
+ 				  0x01000000 0x0 0x0
+ 				  0x01000000 0x0 0x0
+ 				  0x0 0x00100000>;
+ 		};
+ 	};
+ };
diff -prN --exclude=.svn head_r221725/sys/dev/mge/if_mge.c head_r221525/sys/dev/mge/if_mge.c
*** head_r221725/sys/dev/mge/if_mge.c	Tue May 10 10:19:23 2011
--- head_r221525/sys/dev/mge/if_mge.c	Fri May  6 09:35:05 2011
***************
*** 34,40 ****
  #endif
  
  #include <sys/cdefs.h>
! __FBSDID("$FreeBSD: head/sys/dev/mge/if_mge.c 213893 2010-10-15 14:52:11Z marius $");
  
  #include <sys/param.h>
  #include <sys/systm.h>
--- 34,40 ----
  #endif
  
  #include <sys/cdefs.h>
! __FBSDID("$FreeBSD$");
  
  #include <sys/param.h>
  #include <sys/systm.h>
diff -prN --exclude=.svn head_r221725/sys/dev/mmc/mmc.c head_r221525/sys/dev/mmc/mmc.c
*** head_r221725/sys/dev/mmc/mmc.c	Tue May 10 10:17:04 2011
--- head_r221525/sys/dev/mmc/mmc.c	Fri May  6 09:04:27 2011
*************** static devclass_t mmc_devclass;
*** 1539,1542 ****
--- 1539,1543 ----
  
  
  DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL);
+ DRIVER_MODULE(mmc, sdio, mmc_driver, mmc_devclass, NULL, NULL);
  DRIVER_MODULE(mmc, sdhci, mmc_driver, mmc_devclass, NULL, NULL);


More information about the freebsd-arm mailing list