duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

emmc.fs (3310B) - raw


      1 extends Drive struct[ EMMCDrive
      2   $20000000 const MMIO_BASE
      3   MMIO_BASE $300000 + const EMMC_BASE
      4   EMMC_BASE $04 + const EMMC_BLKSIZECNT
      5   EMMC_BASE $08 + const EMMC_ARG1
      6   EMMC_BASE $0c + const EMMC_CMDTM
      7   EMMC_BASE $10 + const EMMC_RESP0
      8   EMMC_BASE $20 + const EMMC_DATA
      9   EMMC_BASE $24 + const EMMC_STATUS
     10   EMMC_BASE $28 + const EMMC_CONTROL0
     11   EMMC_BASE $2c + const EMMC_CONTROL1
     12   EMMC_BASE $30 + const EMMC_INTERRUPT
     13   EMMC_BASE $34 + const EMMC_IRPT_MASK
     14   $017e8000 const INT_ERROR_MASK
     15   $00000020 const INT_READ_READY
     16   $00000001 const INT_CMD_DONE
     17   $80000000 const ACMD41_COMPLETE
     18   $40000000 const ACMD41_CCS
     19   $01000000 const SRST_HT
     20   $00000002 const CLK_STABLE
     21 
     22   0 value rca \ RCA of current card, stored in higher 16b
     23   0 value ccs
     24 
     25   : err abort" EMMC error" ;
     26   : # not if err then ;
     27   : delay ( n -- ) begin 1- ?dup not until ;
     28   : delayus ( us -- ) 1000 * delay ; \ TODO: use actual timer
     29   : status ( mask -- )
     30     $10000 for
     31       EMMC_STATUS @ over and not if drop break then
     32       EMMC_INTERRUPT @ INT_ERROR_MASK and not #
     33       1 delayus next abort" status timeout" then ;
     34   : cmdwait 1 status ; \ CMD_INHIBIT mask
     35   : datawait 2 status ; \ DAT_INHIBIT mask
     36   : intclr EMMC_INTERRUPT @ EMMC_INTERRUPT ! ;
     37   : intwait ( mask -- )
     38     INT_ERROR_MASK or $10000 for
     39       EMMC_INTERRUPT @ over and if break then 1 delayus next
     40       abort" intwait timeout" then
     41     EMMC_INTERRUPT @ INT_ERROR_MASK and not #
     42     ( mask ) EMMC_INTERRUPT ! ;
     43   : readready INT_READ_READY intwait ;
     44   : cmddone INT_CMD_DONE intwait ;
     45   : cmd ( arg cmdidx -- ) cmdwait intclr swap EMMC_ARG1 ! EMMC_CMDTM ! cmddone ;
     46   : cmdr ( arg cmdidx -- resp ) cmd EMMC_RESP0 @ ;
     47   : acmd ( arg cmdidx -- ) 0 $37020000 cmd ( CMD55 ) 100 delayus cmd ;
     48   : cmd0 0 0 cmd ; \ CMD_GO_IDLE
     49   : cmd2 0 $02010000 cmd ; \ CMD_ALL_SEND_CID
     50   : cmd3 ( -- rca ) 0 $03020000 cmdr ; \ CMD_SEND_REL_ADDR
     51   : cmd7 ( rca -- ) $07030000 cmd ;
     52   : cmd8 ( arg -- resp ) $08020000 cmd 1000 delayus EMMC_RESP0 @ ;
     53   : cmd17 ( lba -- ) $11220010 cmd ;
     54   : acmd41 ( arg -- resp ) $29020000 acmd 1000 delayus EMMC_RESP0 @ ;
     55   : clk! ( div -- )
     56     cmdwait datawait 8 lshift $000e0005 or EMMC_CONTROL1 ! 10000 for
     57       10 delayus
     58       EMMC_CONTROL1 @ CLK_STABLE and if break then next
     59       abort" clk failed" then ;
     60   : sec@ ( sec dst self -- ) drop
     61     datawait $00010200 EMMC_BLKSIZECNT !
     62     swap ccs not if $200 * then cmd17 readready
     63     $200 >> >> for EMMC_DATA @ swap !+ next drop ;
     64   : sec! err ;
     65   \ We assume the EMMC base clock to be 100 MHz. During identification, we need
     66   \ 400 kHz, which means a 250 divider. Then, later, we go to a "normal" frequency
     67   \ of 25 MHz, which means a 4 divider.
     68   : :init ( self -- )
     69     drop SRST_HT EMMC_CONTROL1 ! \ reset
     70     100 for 1 delayus EMMC_CONTROL1 @ SRST_HT and not if break then next err then
     71     250 clk! \ 400 kHz
     72     INT_READ_READY INT_CMD_DONE or INT_ERROR_MASK or EMMC_IRPT_MASK !
     73     cmd0 $1aa cmd8 $fff and $1aa <> if abort" CMD8 error" then 10 for
     74       $50ff8000 acmd41 ACMD41_COMPLETE and if break then 400 delayus next
     75       abort" CMD41 timeout" then
     76     EMMC_RESP0 @ ACMD41_CCS and bool to ccs
     77     cmd2 cmd3 $ffff0000 and to rca
     78     4 clk! \ 25 MHz
     79     rca cmd7 ;
     80   : :new $200 -1 Drive :new ,[ :[methods] ], move, ;
     81 ]struct
     82 
     83 EMMCDrive :new structbind EMMCDrive emmc