commit 754d92b947842fbde4df0cf23827f3a72bc8c581
parent d9ad228c80f1133d8ee94d3592b6e841c9542986
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Mon, 19 Jun 2023 16:17:08 -0400
rpi: can read block from EMMC on real hardware!
When I run "emmc$ 0 here block@ here @ .x" on a rpi1 with a SanDisk Ultra HC-I,
I reliably get proper initialization and the number I get corresponds to the
beginning of the first sector of the card. Hell yeah!
Diffstat:
2 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/fs/drv/rpi/emmc.fs b/fs/drv/rpi/emmc.fs
@@ -12,40 +12,48 @@ EMMC_BASE $30 + const EMMC_INTERRUPT
EMMC_BASE $34 + const EMMC_IRPT_MASK
$017e8000 const INT_ERROR_MASK
$00000020 const INT_READ_READY
+$00000001 const INT_CMD_DONE
$80000000 const ACMD41_COMPLETE
$01000000 const SRST_HT
$00000002 const CLK_STABLE
-0 value rca \ RCA of current card
+0 value rca \ RCA of current card, stored in higher 16b
: err abort" EMMC error" ;
: # not if err then ;
: delay ( n -- ) begin 1- ?dup not until ;
: delayus ( us -- ) 1000 * delay ; \ TODO: use actual timer
-: status ( mask -- f ) \ f=1 if things are ok
+: status ( mask -- )
$10000 for
- EMMC_STATUS @ over and not if drop 1 break then
+ EMMC_STATUS @ over and not if drop break then
EMMC_INTERRUPT @ INT_ERROR_MASK and not #
- 1 delayus next drop 0 then ( f ) ;
-: cmdwait 1 status # ; \ CMD_INHIBIT mask
-: datawait 2 status # ; \ DAT_INHIBIT mask
+ 1 delayus next abort" status timeout" then ;
+: cmdwait 1 status ; \ CMD_INHIBIT mask
+: datawait 2 status ; \ DAT_INHIBIT mask
: intclr EMMC_INTERRUPT @ EMMC_INTERRUPT ! ;
: intwait ( mask -- )
INT_ERROR_MASK or $10000 for
- EMMC_INTERRUPT @ over and if break then 1 delayus next err then
+ EMMC_INTERRUPT @ over and if break then 1 delayus next
+ abort" intwait timeout" then
EMMC_INTERRUPT @ INT_ERROR_MASK and not #
( mask ) EMMC_INTERRUPT ! ;
: readready INT_READ_READY intwait ;
-: cmd ( arg cmdidx -- ) cmdwait intclr swap EMMC_ARG1 ! EMMC_CMDTM ! cmdwait ;
-: cmdr cmd EMMC_RESP0 @ ;
-: acmd ( arg cmdidx -- ) 0 $37000000 cmd ( CMD55 ) 100 delayus cmd ;
+: cmddone INT_CMD_DONE intwait ;
+: cmd ( arg cmdidx -- ) cmdwait intclr swap EMMC_ARG1 ! EMMC_CMDTM ! cmddone ;
+: cmdr ( arg cmdidx -- resp ) cmd EMMC_RESP0 @ ;
+: acmd ( arg cmdidx -- ) 0 $37020000 cmd ( CMD55 ) 100 delayus cmd ;
: cmd0 0 0 cmd ; \ CMD_GO_IDLE
: cmd2 0 $02010000 cmd ; \ CMD_ALL_SEND_CID
-: cmd3 ( -- rca ) 0 $03010000 cmdr ; \ CMD_SEND_REL_ADDR
+: cmd3 ( -- rca ) 0 $03020000 cmdr ; \ CMD_SEND_REL_ADDR
: cmd7 ( rca -- ) $07030000 cmd ;
-: cmd8 ( arg -- resp ) $08020000 cmd 2000 delayus EMMC_RESP0 @ ;
+: cmd8 ( arg -- resp ) $08020000 cmd 1000 delayus EMMC_RESP0 @ ;
: cmd17 ( lba -- ) $11220010 cmd ;
: acmd41 ( arg -- resp ) $29020000 acmd 1000 delayus EMMC_RESP0 @ ;
+: clk! ( div -- )
+ cmdwait datawait 8 lshift $000e0005 or EMMC_CONTROL1 ! 10000 for
+ 10 delayus
+ EMMC_CONTROL1 @ CLK_STABLE and if break then next
+ abort" clk failed" then ;
: block@ ( lba dst -- )
datawait $00010200 EMMC_BLKSIZECNT !
swap $200 * cmd17 readready \ TODO: check CCS flag to know if we do "$200 *"
@@ -56,12 +64,11 @@ $00000002 const CLK_STABLE
: emmc$
SRST_HT EMMC_CONTROL1 ! \ reset
100 for 1 delayus EMMC_CONTROL1 @ SRST_HT and not if break then next err then
- $000efa05 EMMC_CONTROL1 ! \ enable clock, 400khz
- 10000 for
- 10 delayus
- EMMC_CONTROL1 @ CLK_STABLE and if break then next err then
- INT_READ_READY INT_ERROR_MASK or EMMC_IRPT_MASK ! \ enable INTs we use
- cmd0 $1aa cmd8 $fff and $1aa = # 0 acmd41 drop 6 for
- 400 delay $40ff8000 acmd41 ACMD41_COMPLETE and if break then next err then
- cmd2 \ no idea why it's needed
- cmd3 dup to rca cmd7 ;
+ 250 clk! \ 400 kHz
+ INT_READ_READY INT_CMD_DONE or INT_ERROR_MASK or EMMC_IRPT_MASK !
+ cmd0 $1aa cmd8 $fff and $1aa <> if abort" CMD8 error" then 10 for
+ $50ff8000 acmd41 ACMD41_COMPLETE and if break then 400 delayus next
+ abort" CMD41 timeout" then
+ cmd2 cmd3 dup $ffff0000 and to rca
+ 4 clk! \ 25 MHz
+ rca cmd7 ;
diff --git a/fs/xcomp/arm/rpi/build.fs b/fs/xcomp/arm/rpi/build.fs
@@ -15,11 +15,11 @@ org value kernel
kernel kernellen V1 IO :write
S" /xcomp/bootlo.fs" V1 spitfile
S" /drv/rpi/uart.fs" V1 spitfile
- S" /drv/rpi/emmc.fs" V1 spitfile
S" /xcomp/arm/rpi/glue.fs" V1 spitfile
S" /lib/struct.fs" V1 spitfile
S" /sys/io.fs" V1 spitfile
S" /lib/fmt.fs" V1 spitfile
+ S" /drv/rpi/emmc.fs" V1 spitfile
S" /sys/rdln.fs" V1 spitfile
S" /xcomp/arm/rpi/init.fs" V1 spitfile
r> IO :flush ;