244 lines
7.5 KiB
C
244 lines
7.5 KiB
C
|
/*
|
|||
|
* Copyright : (C) 2022 Phytium Information Technology, Inc.
|
|||
|
* All Rights Reserved.
|
|||
|
*
|
|||
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
|||
|
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
|||
|
* either version 1.0 of the License, or (at your option) any later version.
|
|||
|
*
|
|||
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
|||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|||
|
* See the Phytium Public License for more details.
|
|||
|
*
|
|||
|
*
|
|||
|
* FilePath: fxhci_cmd.c
|
|||
|
* Date: 2022-02-11 13:33:12
|
|||
|
* LastEditTime: 2022-02-18 09:11:23
|
|||
|
* Description: This files is for implementation of XHCI command
|
|||
|
*
|
|||
|
* Modify History:
|
|||
|
* Ver Who Date Changes
|
|||
|
* ----- ------ -------- --------------------------------------
|
|||
|
* 1.0 Zhugengyu 2022/2/7 init commit
|
|||
|
*/
|
|||
|
|
|||
|
#include "fdebug.h"
|
|||
|
#include "fxhci_private.h"
|
|||
|
|
|||
|
#define FUSB_DEBUG_TAG "FXHCI_CMD"
|
|||
|
#define FUSB_ERROR(format, ...) FT_DEBUG_PRINT_E(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
|
|||
|
#define FUSB_WARN(format, ...) FT_DEBUG_PRINT_W(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
|
|||
|
#define FUSB_INFO(format, ...) FT_DEBUG_PRINT_I(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
|
|||
|
#define FUSB_DEBUG(format, ...) FT_DEBUG_PRINT_D(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
|
|||
|
|
|||
|
FXhciTrb *FXhciNextCmdTrb(FXhci *const xhci)
|
|||
|
{
|
|||
|
FXhciClearTrb(xhci->cr.cur, xhci->cr.pcs);
|
|||
|
return xhci->cr.cur;
|
|||
|
}
|
|||
|
|
|||
|
void FXhciPostCmd(FXhci *const xhci)
|
|||
|
{
|
|||
|
FUSB_INFO("Command %d (@%p) ", FXHCI_TRB_GET(TT, xhci->cr.cur), xhci->cr.cur);
|
|||
|
|
|||
|
FXHCI_TRB_SET(C, xhci->cr.cur, xhci->cr.pcs); /* Cycle Bit */
|
|||
|
++xhci->cr.cur;
|
|||
|
|
|||
|
/* pass command trb to hardware */
|
|||
|
WMB();
|
|||
|
|
|||
|
/* Ring the doorbell */
|
|||
|
FXhciWriteDb32(&xhci->mmio, FXHCI_REG_DB_HOST_CONTROLLER, FXHCI_REG_DB_TARGET_HC_COMMAND);
|
|||
|
|
|||
|
while (FXHCI_TRB_GET(TT, xhci->cr.cur) == FXHCI_TRB_LINK)
|
|||
|
{
|
|||
|
FUSB_DEBUG("Handling LINK pointer (@%p) ", xhci->cr.cur);
|
|||
|
const int tc = FXHCI_TRB_GET(TC, xhci->cr.cur); /* Completion Code */
|
|||
|
FXHCI_TRB_SET(C, xhci->cr.cur, xhci->cr.pcs); /* Cycle Bit */
|
|||
|
xhci->cr.cur = (void *)(uintptr)(xhci->cr.cur->ptr_low);
|
|||
|
if (tc)
|
|||
|
xhci->cr.pcs ^= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static FXhciTransCode FXhciWaitForCmd(FXhci *const xhci,
|
|||
|
const FXhciTrb *const cmd_trb,
|
|||
|
const int clear_event)
|
|||
|
{
|
|||
|
FXhciTransCode cc;
|
|||
|
u64 reg_val64;
|
|||
|
|
|||
|
cc = FXhciWaitForCmdDone(xhci, cmd_trb, clear_event);
|
|||
|
if (cc != FXHCI_CC_TIMEOUT)
|
|||
|
return cc;
|
|||
|
|
|||
|
/* Abort command on timeout */
|
|||
|
FUSB_ERROR("Aborting command (@%p), CRCR: 0x%x ", cmd_trb, FXhciReadOper64(&xhci->mmio, FXHCI_REG_OP_CRCR));
|
|||
|
|
|||
|
/*
|
|||
|
* Ref. xHCI Specification Revision 1.2, May 2019.
|
|||
|
* Section 5.4.5, Table 5-24.
|
|||
|
*
|
|||
|
* Abort the command and stop the ring.
|
|||
|
*/
|
|||
|
reg_val64 = FXhciReadOper64(&xhci->mmio, FXHCI_REG_OP_CRCR);
|
|||
|
reg_val64 |= FXHCI_REG_OP_CRCR_CA;
|
|||
|
FXhciWriteOper64(&xhci->mmio, FXHCI_REG_OP_CRCR, reg_val64);
|
|||
|
|
|||
|
cc = FXhciWaitForCmdAborted(xhci, cmd_trb);
|
|||
|
|
|||
|
if ((FXhciReadOper64(&xhci->mmio, FXHCI_REG_OP_CRCR) & FXHCI_REG_OP_CRCR_CRR))
|
|||
|
FUSB_ERROR("xhci_wait_for_command: Command ring still running");
|
|||
|
|
|||
|
return cc;
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdNop(FXhci *const xhci)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_NOOP); /* TRB Type */
|
|||
|
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
/* wait for result in event ring */
|
|||
|
FXhciTransCode cc = FXhciWaitForCmdDone(xhci, cmd, 1);
|
|||
|
|
|||
|
FUSB_INFO("Command ring is %srunning: cc: %d",
|
|||
|
(FXhciReadOper64(&xhci->mmio, FXHCI_REG_OP_CRCR) & FXHCI_REG_OP_CRCR_CRR) ? "" : "not ", /* check if cmd ring is running */
|
|||
|
cc);
|
|||
|
|
|||
|
if (cc != FXHCI_CC_SUCCESS)
|
|||
|
FUSB_ERROR("noop command failed. ");
|
|||
|
|
|||
|
return cc;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* xhci_cmd_* return >= 0: xhci completion code (cc)
|
|||
|
* < 0: driver error code
|
|||
|
*/
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdEnableSlot(FXhci *const xhci, int *const slot_id)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_ENABLE_SLOT); /* TRB Type */
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
FXhciTransCode cc = FXhciWaitForCmd(xhci, cmd, 0);
|
|||
|
if (cc >= 0)
|
|||
|
{
|
|||
|
if (cc == FXHCI_CC_SUCCESS)
|
|||
|
{
|
|||
|
*slot_id = FXHCI_TRB_GET(ID, xhci->er.cur);
|
|||
|
if (*slot_id > xhci->max_slots_en)
|
|||
|
cc = FXHCI_CC_CONTROLLER_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
FXhciAdvanceEvtRing(xhci);
|
|||
|
FXhciHandleEvts(xhci);
|
|||
|
}
|
|||
|
|
|||
|
return cc;
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdDisableSlot(FXhci *const xhci, const int slot_id)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_DISABLE_SLOT); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdAddressDevice(FXhci *const xhci,
|
|||
|
const int slot_id,
|
|||
|
FXhciInputCtx *const ic)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_ADDRESS_DEV); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
cmd->ptr_low = (uintptr)(ic->raw);
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdConfigureEp(FXhci *const xhci,
|
|||
|
const int slot_id,
|
|||
|
const int config_id,
|
|||
|
FXhciInputCtx *const ic)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_CONFIGURE_EP); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
cmd->ptr_low = (uintptr)(ic->raw);
|
|||
|
|
|||
|
if (config_id == 0)
|
|||
|
FXHCI_TRB_SET(DC, cmd, 1); /* Deconfigure */
|
|||
|
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdEvaluateCtx(FXhci *const xhci,
|
|||
|
const int slot_id,
|
|||
|
FXhciInputCtx *const ic)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_EVAL_CTX); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
|
|||
|
cmd->ptr_low = (uintptr)(ic->raw);
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdResetEp(FXhci *const xhci, const int slot_id, const int ep)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_RESET_EP); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
FXHCI_TRB_SET(EP, cmd, ep); /* Endpoint ID */
|
|||
|
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdStopEp(FXhci *const xhci, const int slot_id, const int ep)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_STOP_EP); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
FXHCI_TRB_SET(EP, cmd, ep); /* Endpoint ID */
|
|||
|
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|
|||
|
|
|||
|
FXhciTransCode FXhciCmdSetTrDq(FXhci *const xhci, const int slot_id, const int ep,
|
|||
|
FXhciTrb *const dq_trb, const int dcs)
|
|||
|
{
|
|||
|
FXhciTrb *const cmd = FXhciNextCmdTrb(xhci);
|
|||
|
|
|||
|
FXHCI_TRB_SET(TT, cmd, FXHCI_TRB_CMD_SET_TR_DQ); /* TRB Type */
|
|||
|
FXHCI_TRB_SET(ID, cmd, slot_id); /* Slot ID */
|
|||
|
FXHCI_TRB_SET(EP, cmd, ep); /* Endpoint ID */
|
|||
|
|
|||
|
cmd->ptr_low = (uintptr)(dq_trb) | dcs;
|
|||
|
|
|||
|
FXhciPostCmd(xhci);
|
|||
|
|
|||
|
return FXhciWaitForCmd(xhci, cmd, 1);
|
|||
|
}
|