rt-thread/bsp/phytium/libraries/standalone/drivers/usb/fxhci/fxhci_roothub.c

194 lines
6.5 KiB
C
Raw Normal View History

/*
* 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_roothub.c
* Date: 2022-02-11 13:33:12
* LastEditTime: 2022-02-18 09:17:02
* Description:  This files is for implementation of XHCI roothub function
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 Zhugengyu 2022/2/7 init commit
*/
#include "fdebug.h"
#include "fusb.h"
#include "fusb_generic_hub.h"
#include "fxhci_private.h"
#define FUSB_DEBUG_TAG "FXHCI_ROOTHUB"
#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 int FXhciRootHubStatusChanged(FUsbDev *const dev)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 reg_val = FXhciReadOper32(&xhci->mmio, FXHCI_REG_OP_USBSTS);
const int changed = !!(FXHCI_REG_OP_USBSTS_PCD & reg_val);
/* clear port change bit */
if (changed)
{
reg_val &= FXHCI_REG_OP_USBSTS_PRSRV_MASK;
reg_val |= FXHCI_REG_OP_USBSTS_PCD;
FXhciWriteOper32(&xhci->mmio, FXHCI_REG_OP_USBSTS, reg_val);
}
return changed;
}
static int FXhciRootHubPortStatusChanged(FUsbDev *const dev, const int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
const int changed = !!(portsc & (FXHCI_REG_OP_PORTS_PORTSC_CSC | FXHCI_REG_OP_PORTS_PORTSC_PRC));
/* always clear all the status change bits */
portsc &= FXHCI_REG_OP_PORTS_PORTSC_RW_MASK;
portsc |= 0x00fe0000;
FXhciWritePort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC, portsc);
return changed;
}
static int FXhciRootHubPortConnected(FUsbDev *const dev, const int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
return portsc & FXHCI_REG_OP_PORTS_PORTSC_CCS;
}
static int FXhciRootHubPortInReset(FUsbDev *const dev, const int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
return !!(portsc & FXHCI_REG_OP_PORTS_PORTSC_PR);
}
static int FXhciRootHubPortEnabled(FUsbDev *const dev, const int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
return !!(portsc & FXHCI_REG_OP_PORTS_PORTSC_PED);
}
static FUsbSpeed FXhciRootHubPortSpeed(FUsbDev *const dev, const int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
if (portsc & FXHCI_REG_OP_PORTS_PORTSC_PED)
{
return FXHCI_REG_OP_PORTS_PORTSC_PORT_SPEED_GET(portsc) - 1;
}
else
{
return FUSB_UNKNOWN_SPEED;
}
}
static int FXhciRootHubResetPort(FUsbDev *const dev, const int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
/* Trigger port reset. */
portsc &= FXHCI_REG_OP_PORTS_PORTSC_RW_MASK;
portsc |= FXHCI_REG_OP_PORTS_PORTSC_PR;
FXhciWritePort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC, portsc);
/* Wait for port_in_reset == 0, up to 150 * 1000us = 150ms */
if (FUsbGenericHubWaitForPort(dev, port, 0, FXhciRootHubPortInReset,
150, 1000) == 0)
{
FUSB_INFO("xhci_rh: Reset timed out at port %d ", port);
}
else
{
portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
portsc &= FXHCI_REG_OP_PORTS_PORTSC_RW_MASK;
portsc |= FXHCI_REG_OP_PORTS_PORTSC_PRC | FXHCI_REG_OP_PORTS_PORTSC_WRC;
FXhciWritePort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC, portsc);
}
return 0;
}
static int FXhciRootHubEnablePort(FUsbDev *const dev, int port)
{
FXhci *const xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
u32 portsc = FXhciReadPort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC);
/*
* Before sending commands to a port, the Port Power in
* PORTSC register should be enabled.
*/
portsc &= FXHCI_REG_OP_PORTS_PORTSC_RW_MASK;
portsc |= FXHCI_REG_OP_PORTS_PORTSC_PP;
FXhciWritePort32(&xhci->mmio, port - 1, FXHCI_REG_OP_PORTS_PORTSC, portsc);
return 0;
}
static const FUsbGenericHubOps FXHCI_ROOTHUB_OPS =
{
.hub_status_changed = FXhciRootHubStatusChanged,
.port_status_changed = FXhciRootHubPortStatusChanged,
.port_connected = FXhciRootHubPortConnected,
.port_in_reset = FXhciRootHubPortInReset,
.port_enabled = FXhciRootHubPortEnabled,
.port_speed = FXhciRootHubPortSpeed,
.enable_port = FXhciRootHubEnablePort,
.disable_port = NULL,
.start_port_reset = NULL,
.reset_port = FXhciRootHubResetPort,
};
/**
* @name: FXhciRootHubInit
* @msg: Roothub
* @return {*}
* @param {FUsbDev} *dev, Roothub实例
*/
void FXhciRootHubInit(FUsbDev *dev)
{
u32 reg_val;
FXhci *xhci = FXHCI_INST_GET(dev->controller);
FASSERT(xhci);
/* we can set them here because a root hub _really_ shouldn't
appear elsewhere */
dev->address = 0;
dev->hub = FUSB_NO_HUB;
dev->port = FUSB_NO_PORT;
reg_val = FXhciReadCap32(&xhci->mmio, FXHCI_REG_CAP_HCSPARAMS1);
const int num_ports = FXHCI_REG_CAP_HCSPARAMS1_MAX_PORTS_GET(reg_val); /* TODO: maybe we need to read extended caps */
FUsbGenericHubInit(dev, num_ports, &FXHCI_ROOTHUB_OPS);
FUSB_INFO("xHCI: root hub init done ");
}