text: // Copyright 2017 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "dwc3.h"
  #include "dwc3-regs.h"
  
  #include <fbl/auto_lock.h>
  
  #include <stdio.h>
  #include <unistd.h>
  
  void dwc3_cmd_start_new_config(dwc3_t* dwc, unsigned ep_num, unsigned rsrc_id) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    DEPCMDPAR0::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR1::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num)
        .FromValue(0)
        .set_CMDTYP(DEPCMD::DEPSTARTCFG)
        .set_COMMANDPARAM(rsrc_id)
        .set_CMDACT(1)
        .WriteTo(mmio);
  }
  
  void dwc3_cmd_ep_set_config(dwc3_t* dwc, unsigned ep_num, unsigned ep_type,
                              unsigned max_packet_size, unsigned interval, bool modify) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    // fifo number is zero for OUT endpoints and EP0_IN
    uint32_t fifo_num = (EP_OUT(ep_num) || ep_num == EP0_IN ? 0 : ep_num >> 1);
    uint32_t action =
        (modify ? DEPCFG_DEPCMDPAR0::ACTION_MODIFY : DEPCFG_DEPCMDPAR0::ACTION_INITIALIZE);
  
    DEPCFG_DEPCMDPAR0::Get(ep_num)
        .FromValue(0)
        .set_FIFO_NUM(fifo_num)
        .set_MAX_PACKET_SIZE(max_packet_size)
        .set_EP_TYPE(ep_type)
        .set_ACTION(action)
        .WriteTo(mmio);
    DEPCFG_DEPCMDPAR1::Get(ep_num)
        .FromValue(0)
        .set_EP_NUMBER(ep_num)
        .set_INTERVAL(interval)
        .set_XFER_NOT_READY_EN(1)
        .set_XFER_COMPLETE_EN(1)
        .set_INTR_NUM(0)
        .WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num).FromValue(0).set_CMDTYP(DEPCMD::DEPCFG).set_CMDACT(1).WriteTo(mmio);
  }
  
  void dwc3_cmd_ep_transfer_config(dwc3_t* dwc, unsigned ep_num) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    DEPCMDPAR0::Get(ep_num).FromValue(0).set_PARAMETER(1).WriteTo(mmio);
    DEPCMDPAR1::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num).FromValue(0).set_CMDTYP(DEPCMD::DEPXFERCFG).set_CMDACT(1).WriteTo(mmio);
  }
  
  void dwc3_cmd_ep_start_transfer(dwc3_t* dwc, unsigned ep_num, zx_paddr_t trb_phys) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    DEPCMDPAR0::Get(ep_num)
        .FromValue(0)
        .set_PARAMETER(static_cast<uint32_t>(trb_phys >> 32))
        .WriteTo(mmio);
    DEPCMDPAR1::Get(ep_num).FromValue(0).set_PARAMETER(static_cast<uint32_t>(trb_phys)).WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num)
        .FromValue(0)
        .set_CMDTYP(DEPCMD::DEPSTRTXFER)
        .set_CMDACT(1)
        .set_CMDIOC(1)
        .WriteTo(mmio);
  
    while (DEPCMD::Get(ep_num).ReadFrom(mmio).CMDACT()) {
      usleep(1000);
    }
  }
  
  void dwc3_cmd_ep_end_transfer(dwc3_t* dwc, unsigned ep_num) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    unsigned rsrc_id = dwc->eps[ep_num].rsrc_id;
  
    DEPCMDPAR0::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR1::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num)
        .FromValue(0)
        .set_CMDTYP(DEPCMD::DEPENDXFER)
        .set_COMMANDPARAM(rsrc_id)
        .set_CMDACT(1)
        .set_CMDIOC(1)
        .set_HIPRI_FORCERM(1)
        .WriteTo(mmio);
  
    while (DEPCMD::Get(ep_num).ReadFrom(mmio).CMDACT()) {
      usleep(1000);
    }
  }
  
  void dwc3_cmd_ep_set_stall(dwc3_t* dwc, unsigned ep_num) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    DEPCMDPAR0::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR1::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num)
        .FromValue(0)
        .set_CMDTYP(DEPCMD::DEPSSTALL)
        .set_CMDACT(1)
        .set_CMDIOC(1)
        .WriteTo(mmio);
  
    while (DEPCMD::Get(ep_num).ReadFrom(mmio).CMDACT()) {
      usleep(1000);
    }
  }
  
  void dwc3_cmd_ep_clear_stall(dwc3_t* dwc, unsigned ep_num) {
    auto* mmio = dwc3_mmio(dwc);
  
    fbl::AutoLock lock(&dwc->lock);
  
    DEPCMDPAR0::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR1::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMDPAR2::Get(ep_num).FromValue(0).WriteTo(mmio);
    DEPCMD::Get(ep_num)
        .FromValue(0)
        .set_CMDTYP(DEPCMD::DEPCSTALL)
        .set_CMDACT(1)
        .set_CMDIOC(1)
        .WriteTo(mmio);
  
    while (DEPCMD::Get(ep_num).ReadFrom(mmio).CMDACT()) {
      usleep(1000);
    }
  }
  