/*
 * Copyright (c) 2009, 2012, ETH Zurich. All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
 */

/*
 * ehci.dev
 *
 * DESCRIPTION: Enhanced Host Controller Interface description
 *
 * Numbers in comments refer to the Intel Enhanced Host Controller
 * Interface Specification for Universal Serial Bus, March 12, 2002,
 * Revision: 1.0 
 */

device ehci msbfirst (addr cap, addr op) "EHCI USB Controller" {

    /* 
     * Section 2.2 
     * Host controller capabilty registers 
     */
    
    // 2.2.1 
    // The correct value for 'op' is actually 'cap' plus this number. 
    register caplength ro addr(cap, 0x00) "Capability Registers Length" 
    type(uint8);

    // 2.2.2
    register hciversion ro addr(cap, 0x02) "Host Controller Interface Version Number" 
    type(uint16);

    // 2.2.3
    register hcsparams ro addr(cap, 0x04) "Structural parameters" {
    _        8;
    dpn      4  "Debug port number";
    _        3;
    p_indicator  1      "Port indicator";
    n_cc     4  "Number of campanion controller";
    n_pcc    4      "Number of ports per companion controller";
    prr      1      "Port routing rules";
    _        2;
    ppc      1      "Port power control";
    n_ports  4      "Num. physical downstream ports on this controller";
   }; 
    
    // 2.2.4
    register hccparams ro addr(cap, 0x08) "Capability parameters" {
    _        16;
    eecp     8     "EHCI extended capabilities pointer"; 
    ist      4     "Isochronous scheduling threshold";
    _        1;
    aspc     1     "Asynchronous sechedule park capability";
    pflf     1     "Programmable frame list flag";
    bit64ac    1     "Extended 64 bit addressing capability";
    };
    
    // section 2.2.5 Companion port route descriptor 
    register hcspportroute ro addr(cap, 0x0C) "Companion port route descr." {
    attr    60  "Port array";
    _   4;
    };

    /* 
     * Section 2.3
     * Host controller operational registers
     */
 
    constants itc_val "Interrupt threshold control" {
    itc_val_rsvd  = 0x00  "Reserved";
    uframe_1      = 0x01  "1 Micro frame";
    uframes_2     = 0x02  "2 Micro frames";
    uframes_4     = 0x04  "4 Micro frames";
    uframes_8     = 0x08  "8 Micro frames (default, equates to 1 ms)";
    uframes_16    = 0x10  "16 Micro frames (2 ms)";
    uframes_32    = 0x20  "32 Micro frames (4 ms)";
    uframes_64    = 0x40  "64 Micro frames (8 ms)";
    };
    
    constants frame_val "Frame list size" {
    elem_1024    = 0b00   "1024 Elements (4096 bytes, default)";
    elem_512     = 0b01   "512 Elements (2048 bytes)";
    elem_256     = 0b10   "256 Elements (1024 bytes)";
    frame_rsvd   = 0b11   "Reserved";
    };
    
    // 2.3.1
    register usbcmd rw addr(op, 0x00) "USB command" {
    _       8    mbz;
    itc     8    type(itc_val) "Interrupt threshold control";
    _       4    mbz;
    aspme   1    rw     "Asynchronous schedule park mode enable";
    _       1    mbz;
    aspmc   2    rw     "Asynchronous schedule park mode count";
    lhcr    1    rw     "Light host controller reset";
    iaad    1    rw     "Interrupt on async advance doorbell";
    ase     1    rw     "Asynchronous schedule enable";
    pse     1    rw     "Periodic schedule enable";
    fls     2    type(frame_val)  "Frame list size";
    hcr     1    rw     "Host controller reset";
    rs      1    rw     "Run stop for scheduling";
    };

    // 2.3.2
    register usbsts rw addr(op, 0x04) "USB status" {
    _        16   mbz;
    ass      1    ro   "Asynchronous schedule status";
    pss      1    ro   "Periodic schedule status";
    rec      1    ro   "Reclamation";
    hch      1    ro   "Host controller halted see Run/Stop";   
    _        6    mbz;
    iaa      1    rwc  "Interrupt on Async advance";
    hse      1    rwc  "Host system error";
    flr      1    rwc  "Frame list rollover";
    pcd      1    rwc  "Port change detect";
    usbei    1    rwc  "USB error interrupt";
    usbi     1    rwc  "USB interrupt";
    };

    // 2.3.3
    register usbintr rw addr(op, 0x08) "USB interrupt enable" {
    _       26 mbz;
    iaae   1  "Interrupt on async advance enable";
    hsee   1  "Host system error enable";
    flre   1  "Frame list rollover enable";
    pcie   1  "Port change interrupt enable";
    usbeie 1  "USB error interrupt enable";
    usbie  1  "USB interrupt enable";
    };

    // 2.3.4
    register frindex rw addr(op, 0x0C) "Frame index" {
    _    18  mbz;
    fi   14     "Frame index";
    };

    // 2.3.5 
    // NOTE: Only enabled if 64 bit address capability is enabled 
    register ctrldssegment rw addr(op, 0x10) "Control data structure segment" {
    data 32 rw "MSB [63:32] bits of EHCI data strctures";
    };

    // 2.3.6 
    register periodiclistbase rw addr(op, 0x14) "Periodic frame list base addr" {
    addr   20   rw    "Base address (must be 4k aligned)";
    _      12   mbz; 
    };
    
    // 2.3.7
    register asynclistaddr rw addr(op, 0x18) "Current async. list addr." {
    lpl    27   rw   "Link pointer low";
    _      5    mbz;
    };
    
    // 2.3.8 
    register configflag rw addr(op, 0x40) "Configure flag" {
    _     31   mbz;
    cf    1    rw   "Configure flag";
    };
    
    // 2.3.9
    constants test_mode_val "Test modes" {
    disabled  =  0b0000   "Test mode not enabled";
    test_j_st =  0b0001   "Test J_STATE";
    test_k_st =  0b0010   "Test K_STATE";
    se0_nak   =  0b0011   "Test SE0_NAK";
    test_pack =  0b0100   "Test packet";
    force_ena =  0b0101   "Force enable";
    };
    
    constants indi_val "Port indicator values" {
    off                = 0b00  "Port indicators are off";
    amber              = 0b01  "Amber";
    green              = 0b10  "Green";
    indi_val_undef     = 0b11  "Undefined";
    };     
    
    constants lstatus_val "USB line status" {
    se0           =  0b00   "Not low speed device, perform EHCI reset";
    j_state       =  0b10   "Not low speed device, perform EHCI reset";
    k_state       =  0b01   "Low speed device, release ownership of port";
    lstatus_undef =  0b11   "Not low speed device, perform EHCI reset"; 
    };

    regarray portsc rw addr(op, 0x44)[16] "Port status and control" {
    _            9 mbz;
    wkoc_e       1      "Wake on over-current enable";
    wkdscnnt_e   1      "Wake on disconnect enable";
    wkcnnt_e     1      "Wake on connect enable";
    ptc          4 type(test_mode_val) "Port test control";
    pic          2 type(indi_val)      "Port indicator control";
    po           1      "Port owner";
    pp           1      "Port power";
    ls           2 type(lstatus_val)   "Line status value";
    _            1 mbz;
    pr           1      "Port reset";
    sus          1      "Port suspend";
    fpr          1      "Force port resume";
    occ          1 rwc  "Over current change";
    oca          1 ro   "Over current active";
    pec          1 rwc  "Port enable/disbale change";
    ped          1      "Port enabled/disabled";
    csc          1 rwc  "Connect status change";
    ccs          1 ro   "Current connect status";
    };
/*
    //
    // In-memory data structures
    //

    // 3.1
    constants lptype width(2) "Link pointer type" {
    lp_itd  = 0b00  "Isochronous transfer descriptor";
    lp_qh   = 0b01  "Queue head";
    lp_sitd = 0b10  "Split transaction isochronous trans. desc.";
    lp_fstn = 0b11  "Frame span traversal node";
    };

    datatype lp msbfirst(32) "Link pointer" {
    p   27      "Frame list link pointer";
    _   2 mbz;
    typ 2 type(lptype) "Pointer type";
    t   1       "Pointer value invalid";
    };

    // 3.3
    datatype itd msbfirst(32) "Isochronous transfer descriptor" {
    next    32 type(lp) "Next descriptor";
    sc0 32 type(itsc)   "Transaction 0 Status/control";
    sc1 32 type(itsc)   "Transaction 1 Status/control";
    sc2 32 type(itsc)   "Transaction 2 Status/control";
    sc3 32 type(itsc)   "Transaction 3 Status/control";
    sc4 32 type(itsc)   "Transaction 4 Status/control";
    sc5 32 type(itsc)   "Transaction 5 Status/control";
    sc6 32 type(itsc)   "Transaction 6 Status/control";
    sc7 32 type(itsc)   "Transaction 7 Status/control";
    bp0 32 type(itbp0)  "Buffer pointer 0";
    bp1 32 type(itbp1)  "Buffer pointer 1";
    bp2     32 type(itbp2)  "Buffer pointer 2";
    bp3 32 type(itbp3)  "Buffer pointer 3";
    bp4 32 type(itbp3)  "Buffer pointer 4";
    bp5 32 type(itbp3)  "Buffer pointer 5";
    bp6 32 type(itbp3)  "Buffer pointer 6";
    };

    // 3.3.2
    datatype itsc msbfirst(32) "Isochronous transaction status/control" {
    // Status
    active  1       "Active";
    dbe 1       "Data buffer error";
    bd  1       "Babble detected";
    xacterr 1       "Transaction error";
    // Control
    length  12      "Transaction length";
    ioc 1       "Interrupt on complete";
    pg  3       "Page select (0-6)";
    offset  12      "Offset from state of buffer";
    };

    // 3.3.3
    datatype itbp0 msbfirst(32) "iTD buffer pointer page 0" {
    p   20      "Buffer pointer (4k aligned)";
    epn 4       "Endpoint number";
    _   1 mbz;
    da  7       "Device address";
    };
    datatype itdp1 msbfirst(32) "iTD buffer pointer page 1" {
    p   20      "Buffer pointer (4k aligned)";
    dir 1       "In (1) or out (0) PID";
    mps 11      "Maximum packet size";
    };
    datatype itdp2 msbfirst(32) "iTD buffer pointer page 2" {
    p   20      "Buffer pointer (4k aligned)";
    _   10 mbz;
    multi   2       "Num. transactions/micro-frame + 1 (0=rsvd)";
    };
    datatype itdp3 msbfirst(32) "iTD buffer pointer page 3" {
    p   20      "Buffer pointer (4k aligned)";
    _   12 mbz;
    };

    // 3.4
    datatype sitd msbfirst(32) "Split isochronous transfer descriptor" {
    next    32 type(lp) "Next descriptor";
    cap 32 type(sitcap) "Endpoint capabilities/characteristics";
    msc 32 type(sitmsc) "Micro-frame schedule control";
    tsc 32 type(sittsc) "Transfer status and control";
    bpl0    32 type(sitbpl0) "Buffer page pointer 0";
    bpl1    32 type(sitbpl1) "Buffer page pointer 1";
    bp  32 type(sitblp) "Back link";
    };

    // 3.4.2
    datatype sitcap msbfirst(32) "siTD endpoint capabilities/characteristics" {
    dir 1       "In (1) or out (0) PID";
    port    7       "Port number";
    _   1 mbz;
    hub 7       "Hub address";
    _   4 mbz;
    epn 4       "Endpoint number";
    _   1 mbz;
    da  7       "Device address";
    };
    datatype sitmsc msbfirst(32) "siTD micro-frame schedule control" {
    _   16 mbz;
    scm 8       "Split completion mask";
    ssm 8       "Split start mask";
    };

    // 3.4.3 
    datatype sittsc msbfirst(32) "siTD transfer status and control" {
    ioc 1       "Interrupt on complete";
    p   1       "Page select";
    _   4 mbz;
    total   10      "Total bytes to transfer";
    cpm 8       "Microframe complete-split progress mask";
    active  1       "Status active";
    err 1       "ERR response rcvd from transaction translator";
    dbe 1       "Data buffer error";
    babble  1       "Babble detected";
    xacterr 1       "Transaction error";
    mmf 1       "Missed micro-frame";
    sts 1       "Split transaction state";
    _   1 mbz;
    };

    // 3.4.4 
    constants xpos width(2) "Transaction position" {
    tp_all  = 0b00      "Entire payload";
    tp_begin = 0b01     "First data payload";
    tp_mid  = 0b10      "Middle payload";
    tp_end = 0b11       "Final payload";
    };
    datatype sitbpl0 msbfirst(32) "siTD buffer page pointer list page 0" {
    p   20      "Buffer pointer (4k aligned)";
    offset  12      "Current offset";
    };
    datatype sitbpl1 msbfirst(32) "siTD buffer page pointer list page 1" {
    p   20      "Buffer pointer (4k aligned)";
    _   7 mbz;
    tp  2 type(xpos)    "Transaction position";
    tc  3       "Transaction count";
    };

    // 3.4.5
    datatype sitblp msbfirst(32) "siTD back link pointer" {
    bp  27      "Back pointer";
    _   4 mbz;
    t   1       "Terminate (0 -> bp is valid)";
    };

    // 3.5
    datatype qtd msbfirst(32) "Queue element transfer descriptor" {
    next    32 type(lp) "Next element";
    altnext 32 type(lp) "Alternate next pointer";
    token   32 type(qttok)  "Token";
    bp0 32 type(qtbp0)  "Buffer pointer 0";
    bp1 32 type(qtbp1)  "Buffer pointer 1";
    bp2 32 type(qtbp1)  "Buffer pointer 2";
    bp3 32 type(qtbp1)  "Buffer pointer 3";
    bp4 32 type(qtbp1)  "Buffer pointer 4";
    };

    // 3.5.3
    constants pid "PID token encoding" {
    pid_out     = 0b00  "Generates OUT token (E1H)";
    pid_in      = 0b01  "Generates IN token (69H)";
    pid_setup   = 0b10  "Generates SETUP token (2DH)";
    pid_rsvd    = 0b11  "Reserved";
    };
    
    datatype qttok msbfirst(32) "qTD Token" {
    toggle  1       "Data toggle";
    tbt 15      "Total bytes to transfer";
    ioc 1       "Interrupt on complete";
    cp  3       "Current page";
    cerr    2       "Error counter";
    pidc    2 type(pid) "PID code token";
    active  1       "Status active";
    halted  1       "Serious error at endpoint";
    dbe 1       "Data buffer error";
    babble  1       "Babble detected";
    xacterr 1       "Transaction error";
    mmf 1       "Missed micro-frame";
    sts 1       "Split transaction state";
    ping    1       "Ping state";
    };

    // 3.5.4
    datatype qtbp0 msbfirst(32) "Queue element buffer pointer page 0" {
    p   20      "Buffer pointer (4k aligned)";
    offset  12      "Current offset";
    };
    datatype qtbp1 msbfirst(32) "Queue element buffer pointer page 1" {
    p   20      "Buffer pointer (4k aligned)";
    _   12 mbz;
    };

    // 3.6
    datatype qh msbfirst(32) "Queue head" {
    hlp 32 type(lp) "Horizontal link pointer";
    cap1    32 type(qhcap1) "Endpoint capabilities/characteristics 1";
    cap2    32 type(qhcap2) "Endpoint capabilities/characteristics 2";
    current 32 type(lp) "Current element";
    next    32 type(lp) "Next element";
    altnext 32 type(qhlp)   "Alternate next pointer";
    token   32 type(qttok)  "Token";
    bp0 32 type(qtbp0)  "Buffer pointer 0";
    bp1 32 type(qhbp1)  "Buffer pointer 1";
    bp2 32 type(qhbp2)  "Buffer pointer 2";
    bp3 32 type(qtbp1)  "Buffer pointer 3";
    bp4 32 type(qtbp1)  "Buffer pointer 4";
    };  

    // 3.6.2 
    constants speed width(2) "Endpoint speed" {
    fullspeed   = 0b00 "Full-speed (12Mbs)";
    lowspeed    = 0b01 "Low-speed (1.5Mbs)";
    highspeed   = 0b10 "High-speed (480 Mb/s)";
    };

    datatype qhcap1 msbfirst(32) "Endpoint capabilities: queue head word 1"{
    rl  4       "NAK count reload";
    c   1       "Control endpoint flag";
    mpl 11      "Maximum packet length";
    h   1       "Head of reclamation list flag";
    dtc 1       "Data toggle control";
    eps 2 type(speed)   "Endpoint speed";
    epn 4       "Endpoint number";
    i   1       "Inactivate on next transaction";
    da  7       "Device address";
    };

    datatype qhcap2 msbfirst(32) "Endpoint capabilities: queue head word 2"{
    mult    2       "High-bandwidth pipe multiplier";
    port    7       "Port number";
    hub 7       "Hub address";
    scm 8       "Split completion mask";
    ism 8       "Interrupt schedule mask";
    };

    // 3.6.3 
    datatype qhlpa msbfirst(32) "Alternate queue head link pointer" {
    p   27      "Frame list link pointer";
    nakcnt  4       "NACK counter";
    t   1       "Pointer value invalid";
    };

    datatype qhbp1 msbfirst(32) "Queue head buffer pointer page 1" {
    p   20      "Buffer pointer (4k aligned)";
    _   4 mbz;
    cpm 8       "Split-transaction complete-split progress";
    };

    datatype qhbp2 msbfirst(32) "Queue head buffer pointer page 2" {
    p   20      "Buffer pointer (4k aligned)";
    sb  7       "S-bytes";
    ft  5       "Split-transaction frame tag";
    };

    // 3.7
    datatype fstm msbfirst(32) "Periodic Frame Span Traversal Node" {
    normal  32 type(lp) "Normal path link pointer"; 
    back    32 type(lp) "Back path link pointer";
    };*/
};

