217 lines
8.4 KiB
C
217 lines
8.4 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_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 "fdebug.h"
|
||
#include "fgeneric_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__)
|
||
|
||
/************************** 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);
|
||
|
||
FUSB_DEBUG(" mmio base: 0x%x", mmio->base);
|
||
FUSB_DEBUG(" oper base: 0x%x", mmio->oper_base);
|
||
FUSB_DEBUG(" doorbell base: 0x%x", mmio->doorbell_base);
|
||
FUSB_DEBUG(" runtime base: 0x%x", mmio->runtime_base);
|
||
FUSB_DEBUG(" port base: 0x%x", mmio->port_base);
|
||
|
||
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;
|
||
u32 tick = 0U;
|
||
|
||
do
|
||
{
|
||
if ((FXhciReadOper32(mmio, offset) & mask) == exp_val)
|
||
{
|
||
ret = FUSB_SUCCESS;
|
||
break;
|
||
}
|
||
fsleep_millisec(10);
|
||
}
|
||
while (tick++ < timeout_tick);
|
||
|
||
if (FUSB_SUCCESS != ret)
|
||
{
|
||
FUSB_ERROR("wait status 0x%x timeout, current 0x%x, tick: %ld", exp_val, mask, tick);
|
||
}
|
||
|
||
return ret;
|
||
} |