|
|
|
/*
|
|
|
|
* 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_hw.c
|
|
|
|
* Date: 2022-02-11 13:33:12
|
|
|
|
* LastEditTime: 2022-02-18 09:13:30
|
|
|
|
* Description: This files is for implementation of XHCI register functions
|
|
|
|
*
|
|
|
|
* Modify History:
|
|
|
|
* Ver Who Date Changes
|
|
|
|
* ----- ------ -------- --------------------------------------
|
|
|
|
* 1.0 Zhugengyu 2022/2/7 init commit
|
|
|
|
*/
|
|
|
|
|
|
|
|
/***************************** Include Files *********************************/
|
|
|
|
#include "ft_debug.h"
|
|
|
|
#include "generic_timer.h"
|
|
|
|
#include "fsleep.h"
|
|
|
|
|
|
|
|
#include "fxhci_private.h"
|
|
|
|
|
|
|
|
|
|
|
|
/************************** Constant Definitions *****************************/
|
|
|
|
|
|
|
|
/**************************** Type Definitions *******************************/
|
|
|
|
|
|
|
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|
|
|
#define FUSB_DEBUG_TAG "FXHCI_HW"
|
|
|
|
#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__)
|
|
|
|
|
|
|
|
static inline tick_t FXhciGetTick(void)
|
|
|
|
{
|
|
|
|
return GenericTimerRead();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline tick_t FXhciStartTick(void)
|
|
|
|
{
|
|
|
|
GenericTimerStart();
|
|
|
|
return FXhciGetTick();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void FXhciStopTick(void)
|
|
|
|
{
|
|
|
|
GenericTimerStop();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline boolean FXhciTimeout(tick_t start_tick, tick_t timeout_tick)
|
|
|
|
{
|
|
|
|
return (FXhciGetTick() - start_tick) > timeout_tick;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************** Function Prototypes ******************************/
|
|
|
|
|
|
|
|
/************************** Variable Definitions *****************************/
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
FError FXhciSetupMMIO(FXhciMMIO *mmio, uintptr base_addr)
|
|
|
|
{
|
|
|
|
FASSERT(mmio);
|
|
|
|
u32 reg_val;
|
|
|
|
|
|
|
|
mmio->base = base_addr;
|
|
|
|
|
|
|
|
/* add to register base to find the beginning of the Operational Register Space */
|
|
|
|
mmio->oper_base = mmio->base + FtIn8(mmio->base + FXHCI_REG_CAP_CAPLENGTH);
|
|
|
|
mmio->doorbell_base = mmio->base + FXHCI_REG_CAP_DBOFF_GET(FtIn32(mmio->base + FXHCI_REG_CAP_DBOFF));
|
|
|
|
mmio->runtime_base = mmio->base + FXHCI_REG_CAP_RTSOFF_GET(FtIn32(mmio->base + FXHCI_REG_CAP_RTSOFF));
|
|
|
|
mmio->port_base = mmio->oper_base + FXHCI_REG_OP_PORTS_BASE;
|
|
|
|
|
|
|
|
/* cache static information of CAP_HCSPARAMS */
|
|
|
|
mmio->hcx_params[0] = FtIn32(mmio->base + FXHCI_REG_CAP_HCSPARAMS1);
|
|
|
|
mmio->hcx_params[1] = FtIn32(mmio->base + FXHCI_REG_CAP_HCSPARAMS2);
|
|
|
|
mmio->hcx_params[2] = FtIn32(mmio->base + FXHCI_REG_CAP_HCSPARAMS3);
|
|
|
|
mmio->hcx_params[3] = FtIn32(mmio->base + FXHCI_REG_CAP_HCCPARAMS);
|
|
|
|
|
|
|
|
reg_val = mmio->hcx_params[3];
|
|
|
|
mmio->xecp_base = mmio->base + (FXHCI_REG_CAP_HCCPARAMS_XECP_GET(reg_val) << 2);
|
|
|
|
return FUSB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FXhciParseExtCap(FXhciMMIO *mmio, const uintptr offset, const u32 cap_id)
|
|
|
|
{
|
|
|
|
FASSERT(mmio);
|
|
|
|
FASSERT(mmio->base != 0);
|
|
|
|
u32 reg_val;
|
|
|
|
u32 major_ver, minor_ver;
|
|
|
|
u32 psic; /* Protocol Speed ID (PSI) */
|
|
|
|
|
|
|
|
switch (cap_id)
|
|
|
|
{
|
|
|
|
case FXHCI_EXT_CAP_ID_USB_LEGACY_SUPPORT:
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, offset + FXHCI_REG_EXT_CAP_USBLEGSUP_OFFSET);
|
|
|
|
FUSB_INFO(" BIOS owned %d OS owned %d",
|
|
|
|
FXHCI_USBLEGSUP_BIOS_OWNED_SEMAPHORE & reg_val,
|
|
|
|
FXHCI_USBLEGSUP_OS_OWNED_SEMAPHORE & reg_val);
|
|
|
|
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, offset + FXHCI_REG_EXT_CAP_USBLEGCTLSTS_OFFSET);
|
|
|
|
FUSB_INFO(" SMI ctrl/status 0x%x", reg_val);
|
|
|
|
break;
|
|
|
|
case FXHCI_EXT_CAP_ID_SUPPORT_PROTOCOL:
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, offset + FXHCI_REG_EXT_CAP_USBSPCFDEF_OFFSET);
|
|
|
|
FUSB_INFO(" Name: %c%c%c%c",
|
|
|
|
*((char*)®_val), *((char*)®_val + 1),
|
|
|
|
*((char*)®_val + 2), *((char*)®_val + 3));
|
|
|
|
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, offset + FXHCI_REG_EXT_CAP_USBSPCF_OFFSET);
|
|
|
|
major_ver = FXHCI_USBSPCF_MAJOR_REVERSION_GET(reg_val);
|
|
|
|
minor_ver = FXHCI_USBSPCF_MINOR_REVERSION_GET(reg_val);
|
|
|
|
FUSB_INFO(" Version: %d.%d", major_ver, minor_ver);
|
|
|
|
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, offset + FXHCI_REG_EXT_CAP_USBSPCFDEF2_OFFSET);
|
|
|
|
FUSB_INFO(" Compatible ports: [%d-%d]",
|
|
|
|
FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(reg_val),
|
|
|
|
FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(reg_val) + FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_CNT_GET(reg_val) - 1);
|
|
|
|
|
|
|
|
if (FXHCI_MAJOR_REVERSION_USB2 == major_ver)
|
|
|
|
{
|
|
|
|
mmio->usb2_ports.port_beg = FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(reg_val);
|
|
|
|
mmio->usb2_ports.port_end = FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(reg_val) + FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_CNT_GET(reg_val) - 1;
|
|
|
|
|
|
|
|
FUSB_INFO(" High-speed only: %d, Integrated hub: %d, Hardware LMP: %d",
|
|
|
|
FXHCI_USBSPCFDEF2_USB2_HIGH_SPEED_ONLY & reg_val,
|
|
|
|
FXHCI_USBSPCFDEF2_USB2_INTERGRATED_HUB & reg_val,
|
|
|
|
FXHCI_USBSPCFDEF2_USB2_HW_LMP_CAP & reg_val);
|
|
|
|
}
|
|
|
|
else if (FXHCI_MAJOR_REVERSION_USB3 == major_ver)
|
|
|
|
{
|
|
|
|
mmio->usb3_ports.port_beg = FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(reg_val);
|
|
|
|
mmio->usb3_ports.port_end = FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(reg_val) + FXHCI_USBSPCFDEF2_COMPATIBLE_PORT_CNT_GET(reg_val) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
psic = FXHCI_USBSPCFDEF2_PROTOCOL_SPEED_ID_CNT_GET(reg_val);
|
|
|
|
FUSB_INFO(" PSIC: 0x%x", psic);
|
|
|
|
|
|
|
|
if (0 != psic)
|
|
|
|
{
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, offset + FXHCI_REG_PROTOCOL_SPEED_ID_OFFSET(psic));
|
|
|
|
|
|
|
|
FUSB_INFO(" Protocol speed-id: %d^%d",
|
|
|
|
FXHCI_PROTOCOL_SPEED_ID_VALUE_GET(reg_val),
|
|
|
|
FXHCI_PROTOCOL_SPEED_ID_EXPONENT_GET(reg_val));
|
|
|
|
FUSB_INFO(" PSI type: %d, PSI full-duplex: %d, Mantissa: 0x%x",
|
|
|
|
FXHCI_PROTOCOL_SPEED_ID_PSI_TYPE_GET(reg_val),
|
|
|
|
(FXHCI_PROTOCOL_SPEED_ID_PSI_FULL_DUPLEX & reg_val == FXHCI_PROTOCOL_SPEED_ID_PSI_FULL_DUPLEX),
|
|
|
|
FXHCI_PROTOCOL_SPEED_ID_MANTISSA_GET(reg_val));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (FXHCI_MAJOR_REVERSION_USB3 == major_ver)
|
|
|
|
FUSB_INFO("For USB3, only the default SuperSpeed bit rate is supported !!!");
|
|
|
|
else if (FXHCI_MAJOR_REVERSION_USB2 == major_ver)
|
|
|
|
FUSB_INFO("For USB2, default Full-speed, Low-speed and High-speed bit rate supported !!!");
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case FXHCI_EXT_CAP_ID_USB_DEBUG_CAPABILITY:
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
FUSB_WARN("Unhandled extend capabilities %d", cap_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FXhciListExtCap(FXhciMMIO *mmio)
|
|
|
|
{
|
|
|
|
FASSERT(mmio);
|
|
|
|
FASSERT(mmio->base != 0);
|
|
|
|
|
|
|
|
uintptr next_ext_cap_offset = 0;
|
|
|
|
uintptr ext_cap_offset = 0;
|
|
|
|
u32 cap_id = 0;
|
|
|
|
u32 reg_val;
|
|
|
|
|
|
|
|
FUSB_INFO("Extended capabilities");
|
|
|
|
do
|
|
|
|
{
|
|
|
|
reg_val = FXhciReadExtCap32(mmio, ext_cap_offset);
|
|
|
|
next_ext_cap_offset = (FXHCI_REG_EXT_CAP_NEXT_CAP_PTR_GET(reg_val) << 2);
|
|
|
|
cap_id = FXHCI_REG_EXT_CAP_CAP_ID_GET(reg_val);
|
|
|
|
FXhciParseExtCap(mmio, ext_cap_offset, cap_id);
|
|
|
|
|
|
|
|
FUSB_INFO("==== Capability ID: %d, Next Capability Pointer: 0x%x",
|
|
|
|
cap_id, next_ext_cap_offset);
|
|
|
|
ext_cap_offset += next_ext_cap_offset;
|
|
|
|
} while (0 != next_ext_cap_offset);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FError FXhciWaitOper32(FXhciMMIO *mmio, u32 offset, u32 mask, u32 exp_val, u32 timeout_tick)
|
|
|
|
{
|
|
|
|
FASSERT(mmio);
|
|
|
|
FASSERT(mmio->base != 0);
|
|
|
|
FError ret = FUSB_ERR_WAIT_TIMEOUT;
|
|
|
|
tick_t start_tick = FXhciStartTick();
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if ((FXhciReadOper32(mmio, offset) & mask) == exp_val)
|
|
|
|
{
|
|
|
|
ret = FUSB_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fsleep_microsec(10);
|
|
|
|
} while (!FXhciTimeout(start_tick, timeout_tick));
|
|
|
|
|
|
|
|
if (FUSB_SUCCESS != ret)
|
|
|
|
{
|
|
|
|
FUSB_ERROR("wait status 0x%x timeout, current 0x%x, tick: %ld %ld", exp_val, mask, FXhciGetTick(), start_tick);
|
|
|
|
}
|
|
|
|
|
|
|
|
FXhciStopTick();
|
|
|
|
return ret;
|
|
|
|
}
|