Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / dev / usb2 / hcd / ohci / edtd.fth
\ ========== Copyright Header Begin ==========================================
\
\ Hypervisor Software File: edtd.fth
\
\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
\
\ - Do no alter or remove copyright notices
\
\ - Redistribution and use of this software in source and binary forms, with
\ or without modification, are permitted provided that the following
\ conditions are met:
\
\ - Redistribution of source code must retain the above copyright notice,
\ this list of conditions and the following disclaimer.
\
\ - Redistribution 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.
\
\ Neither the name of Sun Microsystems, Inc. or the names of contributors
\ may be used to endorse or promote products derived from this software
\ without specific prior written permission.
\
\ This software is provided "AS IS," without a warranty of any kind.
\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
\
\ You acknowledge that this software is not designed, licensed or
\ intended for use in the design, construction, operation or maintenance of
\ any nuclear facility.
\
\ ========== Copyright Header End ============================================
id: @(#)edtd.fth 1.1 07/01/24
purpose: Data structures and manuipulation routines for OHCI USB Controller
\ See license at end of file
hex
headers
\ XXX Isochronous is not supported in the current version of the OHCI driver
\ ---------------------------------------------------------------------------
\ Data structures for this implementation of the OHCI USB Driver include:
\ - hcca 256 bytes defined by OCHI Spec for USB HC
\ - ed-control pointer to the control ED list
\ - ed-bulk pointer to the bulk ED list
\ - intr internal array of interrupts (to complement the hcca)
\ ---------------------------------------------------------------------------
\ ---------------------------------------------------------------------------
\ HcHCCA as defined by the OHCI Spec; 256-byte aligned
\ ---------------------------------------------------------------------------
0 value intr \ Software interrupt buffer
0 value hcca \ Virtual address of HcHCCA
0 value hcca-unaligned \ Unaligned virtual address of HcHCCA
0 value hcca-phys \ Physical address of HcHCCA
\ HCCA
d# 32 constant #intr
struct ( hcca )
#intr 4 * field >hcca-intr \ Physical addresses of interrupt EDs
2 field >hcca-frame
2 field >hcca-pad
4 field >hcca-done \ Physical addresses of done EDs
d# 120 field >hcca-reserved
constant /hcca
: hcca! ( padr idx -- ) 4 * hcca + le-l! ;
: init-hcca ( -- )
\ Allocate hcca
/hcca aligned256-alloc
dup to hcca \ Aligned address
swap to hcca-unaligned \ Unaligned address
/hcca true dma-map-in to hcca-phys \ Physical address
\ Initialize hcca
hcca /hcca erase
hcca hcca-phys /hcca dma-sync
;
\ ---------------------------------------------------------------------------
\ Internal interrupt list per >hcca-intr entry
\
\ XXX I can see how this can be expanded to >intr-head32ms, >intr-tail32ms,
\ XXX and so on, to support the various poll intervals. See comment on
\ XXX interrupt scheduling below.
\ ---------------------------------------------------------------------------
struct \ An entry of intr
4 field >intr-head \ Virtual address of interrupt head
4 field >intr-tail \ Virtual address of interrupt tail
4 field >iso-head \ Virtual address of isochronous head
4 field >iso-tail \ Virtual address of isochronous tail
dup constant /intr-entry
#intr * constant /intr
: init-intr ( -- )
/intr alloc-mem dup to intr \ Allocate intr
/intr erase \ Initialize intr
;
: 'intr ( idx -- adr ) /intr-entry * intr + ;
: intr-head@ ( idx -- adr ) 'intr >intr-head l@ ;
: intr-head! ( adr idx -- ) 'intr >intr-head l! ;
: intr-tail@ ( idx -- adr ) 'intr >intr-tail l@ ;
: intr-tail! ( adr idx -- ) 'intr >intr-tail l! ;
: iso-head@ ( idx -- adr ) 'intr >iso-head l@ ;
: iso-head! ( adr idx -- ) 'intr >iso-head l! ;
: iso-tail@ ( idx -- adr ) 'intr >iso-tail l@ ;
: iso-tail! ( adr idx -- ) 'intr >iso-tail l! ;
\ ---------------------------------------------------------------------------
\ Endpoint descriptor (ED) as defined by the OHCI Spec; 16-byte aligned
\ ---------------------------------------------------------------------------
\ XXX If we add ed-control-tail & ed-bulk-tail, then insert-* does not have
\ XXX to disable the function, we need to skip tail until insert is done.
0 value ed-control \ Virtual address of head of control ED list
0 value ed-bulk \ Virtual address of head of bulk ED list
struct \ Beginning of ED
4 field >hced-control \ ED control info
4 field >hced-tdtail \ Physical address of TD tail
4 field >hced-tdhead \ Physical address of TD head
4 field >hced-next \ Physical address of next ED
dup constant /hced
\ Driver specific fields
4 field >ed-phys \ Physical address of HC ED
4 field >ed-next \ Pointer to the next endpoint
4 field >ed-prev \ Pointer to the previous endpoint
4 field >ed-unaligned \ Unaligned virtual address of the ED
4 field >ed-size \ Size of EDs+TDs
d# 32 round-up \ Multiple of 32 bytes
\ 32 bytes because there are cases where
\ EDs and TDs are allocated together
dup constant /ed \ Size of each ed
#intr * constant /eds \ Size of all eds allocated at a time
\ >hced-control constants
0000 constant ED_DIR_TD
0800 constant ED_DIR_OUT
1000 constant ED_DIR_IN
1800 constant ED_DIR_MASK
0000 constant ED_SPEED_FULL
2000 constant ED_SPEED_LO
2000 constant ED_SPEED_MASK
0000 constant ED_SKIP_OFF
4000 constant ED_SKIP_ON
4000 constant ED_SKIP_MASK
0000 constant ED_FORMAT_G
8000 constant ED_FORMAT_I
8000 constant ED_FORMAT_MASK
0000 constant ED_TOGGLE_DATA0
0002 constant ED_TOGGLE_DATA1
0002 constant ED_TOGGLE_MASK
0001 constant ED_HALTED
: ed-data>di-data ( n -- n' ) ED_TOGGLE_MASK and if 1 else 0 then ;
: di-data>ed-data ( n -- n' ) if ED_TOGGLE_DATA1 else ED_TOGGLE_DATA0 then ;
: (set-skip) ( ed skip-bit -- )
>r
dup >hced-control dup le-l@
ED_SKIP_MASK invert and r> or
swap le-l!
dup >ed-phys l@ /hced dma-sync
;
: ed-set-skip ( ed -- ) ED_SKIP_ON (set-skip) ;
: ed-unset-skip ( ed -- ) ED_SKIP_OFF (set-skip) ;
\ ---------------------------------------------------------------------------
\ Transfer Descriptor (TD) as defined by the OHCI Spec:
\ general TDs are 16-byte aligned; isochronous TDs are 32-byte aligned.
\ ---------------------------------------------------------------------------
struct \ Beginning of General TD fields
4 field >hctd-control \ TD control info
4 field >hctd-cbp \ Physical address of current buffer pointer
4 field >hctd-next \ physical address of next TD
4 field >hctd-be \ physical address of buffer end
dup constant /gtd
\ Isochronous TD fields
2 field >hctd-offset0 \ Offset 0 / PSW 0
2 field >hctd-offset1 \ Offset 1 / PSW 1
2 field >hctd-offset2 \ Offset 2 / PSW 2
2 field >hctd-offset3 \ Offset 3 / PSW 3
2 field >hctd-offset4 \ Offset 4 / PSW 4
2 field >hctd-offset5 \ Offset 5 / PSW 5
2 field >hctd-offset6 \ Offset 6 / PSW 6
2 field >hctd-offset7 \ Offset 7 / PSW 7
dup constant /itd
\ Driver specific fields
4 field >td-phys \ Physical address of HC TD
4 field >td-next \ Virtual address of next TD
4 field >td-cbp \ Virtual address of current buffer pointer
4 field >td-pcbp \ Physical address of current buffer pointer
4 field >td-/cbp-all \ Buffer length (size of the entire buffer)
\ For bulk and intr TDs
d# 32 round-up \ Multiple of 32 bytes
constant /td
\ >hctd-control constants
0004.0000 constant TD_ROUND_ON
0000.0000 constant TD_ROUND_ERR
0004.0000 constant TD_ROUND_MASK
0000.0000 constant TD_DIR_SETUP
0008.0000 constant TD_DIR_OUT
0010.0000 constant TD_DIR_IN
0018.0000 constant TD_DIR_MASK
00c0.0000 constant TD_INTR_MIN
00e0.0000 constant TD_INTR_OFF
00e0.0000 constant TD_INTR_MASK
0000.0000 constant TD_TOGGLE_USE_ED
0200.0000 constant TD_TOGGLE_USE_LSB0
0300.0000 constant TD_TOGGLE_USE_LSB1
0100.0000 constant TD_TOGGLE_MASK
0c00.0000 constant TD_ERR_CNT_MASK
0000.0000 constant TD_CC_NOERROR
1000.0000 constant TD_CC_CRC
2000.0000 constant TD_CC_BITSTUFFING
3000.0000 constant TD_CC_DATATOGGLEMISMATCH
4000.0000 constant TD_CC_STALL
5000.0000 constant TD_CC_DEVICENOTRESPONDING
6000.0000 constant TD_CC_PIDCHECKFAILURE
7000.0000 constant TD_CC_UNEXPECTEDPID
8000.0000 constant TD_CC_DATAOVERRUN
9000.0000 constant TD_CC_DATAUNDERRUN
c000.0000 constant TD_CC_BUFFEROVERRUN
d000.0000 constant TD_CC_BUFFERUNDERRUN
f000.0000 constant TD_CC_NOTACCESSED
f000.0000 constant TD_CC_MASK
: td-data>di-data ( n -- n' ) TD_TOGGLE_MASK and if 1 else 0 then ;
: di-data>td-data ( n -- n' ) if TD_TOGGLE_USE_LSB1 else TD_TOGGLE_USE_LSB0 then ;
\ ---------------------------------------------------------------------------
: init-struct ( -- )
init-struct
0 to ed-control 0 to ed-bulk
init-hcca
init-intr
;
\ ---------------------------------------------------------------------------
\ ED and TDs for bulk, control and interrupt operations.
\ ED and its list of TDs are allocated as needed.
\ ---------------------------------------------------------------------------
: init-ed ( ed.u,v,p len -- )
2 pick >ed-size l! ( ed.u,v,p )
over >ed-phys l! ( ed,u,v )
>ed-unaligned l! ( )
;
: link-tds ( td.v td.p #tds -- )
1- 0 ?do ( td.v td.p )
2dup swap >td-phys l! ( td.v td.p )
/td + tuck over >hctd-next le-l! ( td.p' td.v )
dup /td + tuck swap ( td.p td.v' td.v' td.v )
>td-next l! ( td.p td.v )
swap ( td.v td.p )
loop
swap >td-phys l! ( )
;
: link-edtd ( td.p #tds ed -- )
>r ( td.p #tds ) ( R: ed )
1- /td * over + ( td.p ptail ) ( R: ed )
r@ >hced-tdtail le-l! ( td.p ) ( R: ed )
r> >hced-tdhead le-l! ( )
;
: link-edtds ( td.v td.p #tds ed -- )
>r 2dup r> link-edtd ( td.v td.p #tds ) \ Link ED to TD
link-tds ( ) \ Link TDs
;
: alloc-edtds ( #tds -- ed td )
dup >r /td * /ed + dup >r ( len ) ( R: #tds len )
aligned32-alloc-map-in ( ed.u,v,p ) ( R: #tds len )
over r@ erase ( ed.u,v,p ) ( R: #tds len )
3dup r> init-ed ( ed.u,v,p ) ( R: #tds )
rot drop ( ed.v,p ) ( R: #tds )
over /ed + dup -rot ( ed td ed.p td.v ) ( R: #tds )
swap /ed + ( ed td td.v td.p ) ( R: #tds )
r> 4 pick link-edtds ( ed td )
;
: free-edtds ( ed -- )
>r ( R: ed )
r@ >ed-unaligned l@ ( ed.u ) ( R: ed )
r@ dup >ed-phys l@ ( ed.u,v,p ) ( R: ed )
r> >ed-size l@ ( ed.u,v,p size )
aligned32-free-map-out ( )
;
: sync-edtds ( ed -- )
dup >ed-phys l@ ( ed.v,p )
over >ed-size l@ ( ed.v,p len )
dma-sync ( )
;
: map-out-cbp ( td -- )
dup >td-cbp l@ over >td-pcbp l@ rot >td-/cbp-all l@ hcd-map-out
;
\ ---------------------------------------------------------------------------
\ Control scheduling
\ ---------------------------------------------------------------------------
: fixup-ed-next-prev ( ed -- ed )
dup >ed-prev l@ ?dup if over >ed-next l@ swap >ed-next l! then
dup >ed-next l@ ?dup if over >ed-prev l@ swap >ed-prev l! then
;
: insert-ed ( new-ed old-ed -- )
?dup 0= if drop exit then \ No old-ed, done
2dup >ed-prev l! \ old-ed's prev is new-ed
2dup swap >ed-next l! \ new-ed's next is old-ed
>ed-phys l@ swap >hced-next le-l! \ new-ed's hced-next is old-ed's phys
;
: insert-control-ed ( ed -- )
dup ed-control insert-ed
to ed-control
;
: remove-control-ed ( ed -- )
fixup-ed-next-prev ( ed )
dup ed-control = if >ed-next l@ to ed-control else drop then
;
\ ---------------------------------------------------------------------------
\ Bulk scheduling
\ ---------------------------------------------------------------------------
: insert-bulk-ed ( ed -- )
dup ed-bulk insert-ed
to ed-bulk
;
: remove-bulk-ed ( ed -- )
fixup-ed-next-prev ( ed )
dup ed-bulk = if >ed-next l@ to ed-bulk else drop then
;
\ ---------------------------------------------------------------------------
\ Interrupt scheduling
\ Schedule interrupt at the rate min(interval,2**x).
\
\ XXX Need to determines which scheduling queue for that rate has the smallest
\ committed bandwidth.
\
\ XXX To really implement the various poll intervals, the simplistic way is
\ XXX to have 32 dummy EDs for 1ms interval; 16 dummy EDs for 2ms interval;
\ XXX 8 dummy EDs for 4ms interval; 4 dummy EDs for 8ms interval;
\ XXX 2 dummy EDs for 16ms interval; and, 1 dummy ED for 32ms interval.
\ XXX Then you link to the end of the lists of EDs for each interval. Ughhh!
\
\ XXX For now, just implement fixed poll interval.
\
\ XXX On further thought, since we're polling the intr pipeline from the
\ XXX device driver, the driver driver can poll the intr at the interval
\ XXX specified. And thus, the need to fully implement poll intervals at
\ XXX the HCD level is redundant.
\ ---------------------------------------------------------------------------
4 constant intr-interval
: (insert-intr-ed) ( ed idx -- )
dup >r ( ed idx ) ( R: idx )
intr-tail@ ?dup 0= if ( ed ) ( R: idx )
dup r@ intr-head! ( ed ) ( R: idx )
dup >ed-phys l@ r@ hcca! ( ed ) ( R: idx )
else ( ed ted ) ( R: idx )
2dup >ed-next l! ( ed ted ) ( R: idx )
over >ed-phys l@ over >hced-next le-l! ( ed ted ) ( R: idx )
over >ed-prev l! ( ed ) ( R: idx )
then
r@ iso-head@ over >ed-next l! ( ed ) ( R: idx )
r> intr-tail! ( )
;
: insert-intr-ed ( ed interval -- )
drop
#intr 0 do dup i (insert-intr-ed) intr-interval +loop drop
;
: (remove-intr-ed) ( ed idx -- )
>r ( ed ) ( R: idx )
fixup-ed-next-prev ( ed ) ( R: idx )
r@ intr-head@ over = if ( ed ) ( R: idx )
dup >ed-next l@ dup r@ intr-head! ( ed ped ) ( R: idx )
dup if >ed-phys l@ then r@ hcca!
( ed ) ( R: idx )
then
r@ intr-tail@ over = if ( ed ) ( R: idx )
dup >ed-prev l@ r@ intr-tail! ( ed ) ( R: idx )
then
r> 2drop
;
: remove-intr-ed ( ed -- )
#intr 0 do dup i (remove-intr-ed) intr-interval +loop drop
;
\ ---------------------------------------------------------------------------
\ Wait for an ED to be done and process any errors.
\
\ When done? returns no error found yet, the caller should should if errors
\ were found in the TDs.
\ ---------------------------------------------------------------------------
defer process-hc-status
0 value timeout
: .td-error ( cc -- )
case
TD_CC_CRC of " CRC" USB_ERR_CRC endof
TD_CC_BITSTUFFING of " Bit Stuffing" USB_ERR_BITSTUFFING endof
TD_CC_DATATOGGLEMISMATCH of " Data Toggle Mismatch" USB_ERR_DATATOGGLEMISMATCH endof
TD_CC_STALL of " Stall" USB_ERR_STALL endof
TD_CC_DEVICENOTRESPONDING of " Device Not Responding" USB_ERR_DEVICENOTRESPONDING endof
TD_CC_PIDCHECKFAILURE of " PID Check Failure" USB_ERR_PIDCHECKFAILURE endof
TD_CC_UNEXPECTEDPID of " Unexpected PID" USB_ERR_UNEXPECTEDPIC endof
TD_CC_DATAOVERRUN of " Data Overrun" USB_ERR_DATAOVERRUN endof
TD_CC_DATAUNDERRUN of " Data Underrun" USB_ERR_DATAUNDERRUN endof
TD_CC_BUFFEROVERRUN of " Buffer Overrun" USB_ERR_BUFFEROVERRUN endof
TD_CC_BUFFERUNDERRUN of " Buffer Underrun" USB_ERR_BUFFERUNDERRUN endof
TD_CC_NOTACCESSED of " Not Accessed" USB_ERR_NOTACCESSED endof
( default ) " Unknown Error" rot USB_ERR_UNKNOWN swap
endcase
set-usb-error
;
: error? ( td -- usberr )
begin
dup >td-next l@ if \ Process a real TD
dup >hctd-control le-l@ TD_CC_MASK and ?dup if
.td-error drop 0 \ Error found in TD
else
>td-next l@ \ TD's ok, examine the next TD
then
else \ Don't need to process last dummy TD
drop 0
then
?dup 0= until
usb-error
;
: ed-done? ( ed -- done? )
dup >hced-tdhead le-l@ dup ED_HALTED and ( ed head halted? )
swap h# ffff.fff0 and ( ed halted? head )
rot >hced-tdtail le-l@ h# ffff.fff0 and = ( halted? head=tail? )
or ( done? )
;
: done? ( ed -- error? )
begin
process-hc-status
dup sync-edtds
dup ed-done? ?dup 0= if
1 ms
timeout 1- dup to timeout 0=
then
until
ed-done? 0= if " Timeout" USB_ERR_TIMEOUT set-usb-error then
usb-error
;
: get-actual ( td -- actual )
dup >hctd-cbp le-l@ ?dup if
swap >td-pcbp l@ -
else
dup >hctd-be le-l@ swap >td-pcbp l@ - 1+
then
;
headers
\ LICENSE_BEGIN
\ Copyright (c) 2006 FirmWorks
\
\ Permission is hereby granted, free of charge, to any person obtaining
\ a copy of this software and associated documentation files (the
\ "Software"), to deal in the Software without restriction, including
\ without limitation the rights to use, copy, modify, merge, publish,
\ distribute, sublicense, and/or sell copies of the Software, and to
\ permit persons to whom the Software is furnished to do so, subject to
\ the following conditions:
\
\ The above copyright notice and this permission notice shall be
\ included in all copies or substantial portions of the Software.
\
\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\
\ LICENSE_END