Author: wmb Date: Mon Aug 20 23:53:06 2012 New Revision: 3206 URL: http://tracker.coreboot.org/trac/openfirmware/changeset/3206
Log: SDHCI - handle host controllers that spuriously set the transfer interrupt bit during cmd13.
Modified: dev/mmc/sdhci/sdhci.fth
Modified: dev/mmc/sdhci/sdhci.fth ============================================================================== --- dev/mmc/sdhci/sdhci.fth Mon Aug 20 12:37:59 2012 (r3205) +++ dev/mmc/sdhci/sdhci.fth Mon Aug 20 23:53:06 2012 (r3206) @@ -92,10 +92,16 @@ \ hardware has a bug that blocks the card detection status bits \ unless the interrupt enables are on. 0 instance value intstat-count +: xfer-int-on ( -- ) h# 34 cw@ 2 or h# 34 cw! ; +: xfer-int-off ( -- ) h# 34 cw@ 2 invert and h# 34 cw! ; + : intstat-on ( -- ) intstat-count 0= if - h# 00cb h# 34 cw! \ normal interrupt status en reg - \ Enable: Remove, Insert, DMA Interrupt, Transfer Complete, CMD Complete + \ Enable: Remove, Insert, DMA Interrupt, CMD Complete + \ Transfer complete is handled separately because some host controllers + \ (e.g. Marvell MMP3) set it spuriously during commands that shouldn't set it. + h# 00c9 h# 34 cw! \ normal interrupt status en reg + \ Disable: Card Interrupt, Read Ready, Write Ready, Block Gap h# f1ff h# 36 cw! \ error interrupt status en reg then @@ -218,6 +224,7 @@ true " dma-map-in" $call-parent ( padr ) \ Prepare DMA buffer dup to dma-padr ( padr ) \ Remember for later 0 cl! \ Set address + xfer-int-on ;
: dma-setup ( #blocks adr -- ) @@ -374,6 +381,10 @@
: cmd ( arg cmd mode -- ) debug? if ." CMD: " over 4 u.r space then + + \ R1B-class commands have an implied data transfer phase + over h# ff and h# 1b = if xfer-int-on then + over add-cmd wait-ready h# c cw! ( arg cmd ) \ Mode @@ -451,6 +462,7 @@ : mmc-switch ( arg -- ) \ CMD6 for MMC - no data h# 061b 0 cmd response h# 80 and if ." MMC SWITCH_ERROR" cr then 2 wait \ This command appears to have a transfer-complete + xfer-int-off ;
: deselect-card ( -- ) 0 h# 0700 0 cmd ; \ CMD7 - with null RCA @@ -461,6 +473,7 @@ \ commands, so we must clear that bit if it is set. d# 16 ms \ Give the operation time to complete isr@ isr! + xfer-int-off ;
: send-if-cond ( -- ) h# 1aa h# 081a 0 cmd ( response h# 1aa <> if ." Error" then ) ; \ CMD8 R7 (SD) @@ -1063,12 +1076,9 @@ then ;
-: wait-dat ( -- ) d# 10 ms begin 2 ms present-state@ 4 and 0= until ; - \ Wait for completion : r/w-blocks-end ( in? -- error? ) drop - wait-dat wait-dma-done intstat-on wait-write-done intstat-off ; @@ -1080,11 +1090,18 @@
: r/w-blocks-start ( addr block# #blocks in? fresh? -- error? ) wait-dma-done ( addr block# #blocks fresh? in? ) + + \ wait-write-done used to be after dma-setup in an attempt to overlap + \ work with waiting time, but that doesn't work now that dma-setup + \ enables transfer interrupts, which can happen spuriously during + \ wait-write-done on some host controllers. + wait-write-done if 3drop 2drop true exit then ( addr block# #blocks fresh? in? ) + 2 pick 0= if 3drop 2drop false exit then \ Prevents hangs intstat-on ( addr block# #blocks fresh? in? ) 2 pick >r >r >r ( addr block# #blocks r: #blocks fresh? in? ) rot dma-setup ( block# r: #blocks fresh? in? ) - wait-write-done if drop r> r> r> 3drop true exit then ( block# ) + address-shift lshift r> if ( block# r: #blocks fresh? ) r> drop ( block# r: #blocks ) r> issue-read ( ) @@ -1097,8 +1114,6 @@ false ( error? ) ; : fresh-write-blocks-start ( addr block# #blocks -- error? ) - intstat-on - wait-dat false true r/w-blocks-start ;
openfirmware@openfirmware.info