parent
2f5f498969
commit
a75b692557
@ -0,0 +1,445 @@ |
||||
#include "mtk-phy.h" |
||||
|
||||
#ifdef CONFIG_PROJECT_7621 |
||||
#include "mtk-phy-7621.h" |
||||
|
||||
//not used on SoC
|
||||
PHY_INT32 phy_init(struct u3phy_info *info){
|
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
//not used on SoC
|
||||
PHY_INT32 phy_change_pipe_phase(struct u3phy_info *info, PHY_INT32 phy_drv, PHY_INT32 pipe_phase){ |
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
//--------------------------------------------------------
|
||||
// Function : fgEyeScanHelper_CheckPtInRegion()
|
||||
// Description : Check if the test point is in a rectangle region.
|
||||
// If it is in the rectangle, also check if this point
|
||||
// is on the multiple of deltaX and deltaY.
|
||||
// Parameter : strucScanRegion * prEye - the region
|
||||
// BYTE bX
|
||||
// BYTE bY
|
||||
// Return : BYTE - TRUE : This point needs to be tested
|
||||
// FALSE: This point will be omitted
|
||||
// Note : First check within the rectangle.
|
||||
// Secondly, use modulous to check if the point will be tested.
|
||||
//--------------------------------------------------------
|
||||
static PHY_INT8 fgEyeScanHelper_CheckPtInRegion(struct strucScanRegion * prEye, PHY_INT8 bX, PHY_INT8 bY) |
||||
{ |
||||
PHY_INT8 fgValid = true; |
||||
|
||||
|
||||
/// Be careful, the axis origin is on the TOP-LEFT corner.
|
||||
/// Therefore the top-left point has the minimum X and Y
|
||||
/// Botton-right point is the maximum X and Y
|
||||
if ( (prEye->bX_tl <= bX) && (bX <= prEye->bX_br) |
||||
&& (prEye->bY_tl <= bY) && (bY <= prEye->bX_br)) |
||||
{ |
||||
// With the region, now check whether or not the input test point is
|
||||
// on the multiples of X and Y
|
||||
// Do not have to worry about negative value, because we have already
|
||||
// check the input bX, and bY is within the region.
|
||||
if ( ((bX - prEye->bX_tl) % (prEye->bDeltaX)) |
||||
|| ((bY - prEye->bY_tl) % (prEye->bDeltaY)) ) |
||||
{ |
||||
// if the division will have remainder, that means
|
||||
// the input test point is on the multiples of X and Y
|
||||
fgValid = false; |
||||
} |
||||
else |
||||
{ |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
|
||||
fgValid = false; |
||||
} |
||||
return fgValid; |
||||
} |
||||
|
||||
//--------------------------------------------------------
|
||||
// Function : EyeScanHelper_RunTest()
|
||||
// Description : Enable the test, and wait til it is completed
|
||||
// Parameter : None
|
||||
// Return : None
|
||||
// Note : None
|
||||
//--------------------------------------------------------
|
||||
static void EyeScanHelper_RunTest(struct u3phy_info *info) |
||||
{ |
||||
DRV_UDELAY(100); |
||||
// Disable the test
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_CNT_EN_OFST, RG_SSUSB_EQ_EYE_CNT_EN, 0); //RG_SSUSB_RX_EYE_CNT_EN = 0
|
||||
DRV_UDELAY(100); |
||||
// Run the test
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_CNT_EN_OFST, RG_SSUSB_EQ_EYE_CNT_EN, 1); //RG_SSUSB_RX_EYE_CNT_EN = 1
|
||||
DRV_UDELAY(100); |
||||
// Wait til it's done
|
||||
//RGS_SSUSB_RX_EYE_CNT_RDY
|
||||
while(!U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->phya_rx_mon5) |
||||
, RGS_SSUSB_EQ_EYE_CNT_RDY_OFST, RGS_SSUSB_EQ_EYE_CNT_RDY)); |
||||
} |
||||
|
||||
//--------------------------------------------------------
|
||||
// Function : fgEyeScanHelper_CalNextPoint()
|
||||
// Description : Calcualte the test point for the measurement
|
||||
// Parameter : None
|
||||
// Return : BOOL - TRUE : the next point is within the
|
||||
// boundaryof HW limit
|
||||
// FALSE: the next point is out of the HW limit
|
||||
// Note : The next point is obtained by calculating
|
||||
// from the bottom left of the region rectangle
|
||||
// and then scanning up until it reaches the upper
|
||||
// limit. At this time, the x will increment, and
|
||||
// start scanning downwards until the y hits the
|
||||
// zero.
|
||||
//--------------------------------------------------------
|
||||
static PHY_INT8 fgEyeScanHelper_CalNextPoint(void) |
||||
{ |
||||
if ( ((_bYcurr == MAX_Y) && (_eScanDir == SCAN_DN)) |
||||
|| ((_bYcurr == MIN_Y) && (_eScanDir == SCAN_UP)) |
||||
) |
||||
{ |
||||
/// Reaches the limit of Y axis
|
||||
/// Increment X
|
||||
_bXcurr++; |
||||
_fgXChged = true; |
||||
_eScanDir = (_eScanDir == SCAN_UP) ? SCAN_DN : SCAN_UP; |
||||
|
||||
if (_bXcurr > MAX_X) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
_bYcurr = (_eScanDir == SCAN_DN) ? _bYcurr + 1 : _bYcurr - 1; |
||||
_fgXChged = false; |
||||
} |
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
PHY_INT32 eyescan_init(struct u3phy_info *info){ |
||||
//initial PHY setting
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phya_regs->rega) |
||||
, RG_SSUSB_CDR_EPEN_OFST, RG_SSUSB_CDR_EPEN, 1);
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->phyd_mix3) |
||||
, RG_SSUSB_FORCE_CDR_PI_PWD_OFST, RG_SSUSB_FORCE_CDR_PI_PWD, 1); |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_PI_CAL_EN_SEL_OFST, RG_SSUSB_RX_PI_CAL_EN_SEL, 1); //RG_SSUSB_RX_PI_CAL_MANUAL_SEL = 1
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_PI_CAL_EN_OFST, RG_SSUSB_RX_PI_CAL_EN, 1); //RG_SSUSB_RX_PI_CAL_MANUAL_EN = 1
|
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
PHY_INT32 phy_eyescan(struct u3phy_info *info, PHY_INT32 x_t1, PHY_INT32 y_t1, PHY_INT32 x_br, PHY_INT32 y_br, PHY_INT32 delta_x, PHY_INT32 delta_y |
||||
, PHY_INT32 eye_cnt, PHY_INT32 num_cnt, PHY_INT32 PI_cal_en, PHY_INT32 num_ignore_cnt){ |
||||
PHY_INT32 cOfst = 0; |
||||
PHY_UINT8 bIdxX = 0; |
||||
PHY_UINT8 bIdxY = 0; |
||||
//PHY_INT8 bCnt = 0;
|
||||
PHY_UINT8 bIdxCycCnt = 0; |
||||
PHY_INT8 fgValid; |
||||
PHY_INT8 cX; |
||||
PHY_INT8 cY; |
||||
PHY_UINT8 bExtendCnt; |
||||
PHY_INT8 isContinue; |
||||
//PHY_INT8 isBreak;
|
||||
PHY_UINT32 wErr0 = 0, wErr1 = 0; |
||||
//PHY_UINT32 temp;
|
||||
|
||||
PHY_UINT32 pwErrCnt0[CYCLE_COUNT_MAX][ERRCNT_MAX][ERRCNT_MAX]; |
||||
PHY_UINT32 pwErrCnt1[CYCLE_COUNT_MAX][ERRCNT_MAX][ERRCNT_MAX]; |
||||
|
||||
_rEye1.bX_tl = x_t1; |
||||
_rEye1.bY_tl = y_t1; |
||||
_rEye1.bX_br = x_br; |
||||
_rEye1.bY_br = y_br; |
||||
_rEye1.bDeltaX = delta_x; |
||||
_rEye1.bDeltaY = delta_y; |
||||
|
||||
_rEye2.bX_tl = x_t1; |
||||
_rEye2.bY_tl = y_t1; |
||||
_rEye2.bX_br = x_br; |
||||
_rEye2.bY_br = y_br; |
||||
_rEye2.bDeltaX = delta_x; |
||||
_rEye2.bDeltaY = delta_y; |
||||
|
||||
_rTestCycle.wEyeCnt = eye_cnt; |
||||
_rTestCycle.bNumOfEyeCnt = num_cnt; |
||||
_rTestCycle.bNumOfIgnoreCnt = num_ignore_cnt; |
||||
_rTestCycle.bPICalEn = PI_cal_en;
|
||||
|
||||
_bXcurr = 0; |
||||
_bYcurr = 0; |
||||
_eScanDir = SCAN_DN; |
||||
_fgXChged = false; |
||||
|
||||
printk("x_t1: %x, y_t1: %x, x_br: %x, y_br: %x, delta_x: %x, delta_y: %x, \
|
||||
eye_cnt: %x, num_cnt: %x, PI_cal_en: %x, num_ignore_cnt: %x\n", \
|
||||
x_t1, y_t1, x_br, y_br, delta_x, delta_y, eye_cnt, num_cnt, PI_cal_en, num_ignore_cnt);
|
||||
|
||||
//force SIGDET to OFF
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_SIGDET_EN_SEL_OFST, RG_SSUSB_RX_SIGDET_EN_SEL, 1); //RG_SSUSB_RX_SIGDET_SEL = 1
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_SIGDET_EN_OFST, RG_SSUSB_RX_SIGDET_EN, 0); //RG_SSUSB_RX_SIGDET_EN = 0
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye1) |
||||
, RG_SSUSB_EQ_SIGDET_OFST, RG_SSUSB_EQ_SIGDET, 0); //RG_SSUSB_RX_SIGDET = 0
|
||||
|
||||
// RX_TRI_DET_EN to Disable
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq3) |
||||
, RG_SSUSB_EQ_TRI_DET_EN_OFST, RG_SSUSB_EQ_TRI_DET_EN, 0); //RG_SSUSB_RX_TRI_DET_EN = 0
|
||||
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_MON_EN_OFST, RG_SSUSB_EQ_EYE_MON_EN, 1); //RG_SSUSB_EYE_MON_EN = 1
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_XOFFSET_OFST, RG_SSUSB_EQ_EYE_XOFFSET, 0); //RG_SSUSB_RX_EYE_XOFFSET = 0
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE0_Y_OFST, RG_SSUSB_EQ_EYE0_Y, 0); //RG_SSUSB_RX_EYE0_Y = 0
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE1_Y_OFST, RG_SSUSB_EQ_EYE1_Y, 0); //RG_SSUSB_RX_EYE1_Y = 0
|
||||
|
||||
|
||||
if (PI_cal_en){ |
||||
// PI Calibration
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_PI_CAL_EN_SEL_OFST, RG_SSUSB_RX_PI_CAL_EN_SEL, 1); //RG_SSUSB_RX_PI_CAL_MANUAL_SEL = 1
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_PI_CAL_EN_OFST, RG_SSUSB_RX_PI_CAL_EN, 0); //RG_SSUSB_RX_PI_CAL_MANUAL_EN = 0
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_PI_CAL_EN_OFST, RG_SSUSB_RX_PI_CAL_EN, 1); //RG_SSUSB_RX_PI_CAL_MANUAL_EN = 1
|
||||
|
||||
DRV_UDELAY(20); |
||||
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_bank2_regs->b2_phyd_misc0) |
||||
, RG_SSUSB_RX_PI_CAL_EN_OFST, RG_SSUSB_RX_PI_CAL_EN, 0); //RG_SSUSB_RX_PI_CAL_MANUAL_EN = 0
|
||||
_bPIResult = U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->phya_rx_mon5) |
||||
, RGS_SSUSB_EQ_PILPO_OFST, RGS_SSUSB_EQ_PILPO); //read RGS_SSUSB_RX_PILPO
|
||||
|
||||
printk(KERN_ERR "PI result: %d\n", _bPIResult); |
||||
} |
||||
// Read Initial DAC
|
||||
// Set CYCLE
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye3) |
||||
,RG_SSUSB_EQ_EYE_CNT_OFST, RG_SSUSB_EQ_EYE_CNT, eye_cnt); //RG_SSUSB_RX_EYE_CNT
|
||||
|
||||
// Eye Monitor Feature
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye1) |
||||
, RG_SSUSB_EQ_EYE_MASK_OFST, RG_SSUSB_EQ_EYE_MASK, 0x3ff); //RG_SSUSB_RX_EYE_MASK = 0x3ff
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_MON_EN_OFST, RG_SSUSB_EQ_EYE_MON_EN, 1); //RG_SSUSB_EYE_MON_EN = 1
|
||||
|
||||
// Move X,Y to the top-left corner
|
||||
for (cOfst = 0; cOfst >= -64; cOfst--) |
||||
{ |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
,RG_SSUSB_EQ_EYE_XOFFSET_OFST, RG_SSUSB_EQ_EYE_XOFFSET, cOfst); //RG_SSUSB_RX_EYE_XOFFSET
|
||||
} |
||||
for (cOfst = 0; cOfst < 64; cOfst++) |
||||
{ |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE0_Y_OFST, RG_SSUSB_EQ_EYE0_Y, cOfst); //RG_SSUSB_RX_EYE0_Y
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE1_Y_OFST, RG_SSUSB_EQ_EYE1_Y, cOfst); //RG_SSUSB_RX_EYE1_Y
|
||||
} |
||||
//ClearErrorResult
|
||||
for(bIdxCycCnt = 0; bIdxCycCnt < CYCLE_COUNT_MAX; bIdxCycCnt++){ |
||||
for(bIdxX = 0; bIdxX < ERRCNT_MAX; bIdxX++) |
||||
{ |
||||
for(bIdxY = 0; bIdxY < ERRCNT_MAX; bIdxY++){ |
||||
pwErrCnt0[bIdxCycCnt][bIdxX][bIdxY] = 0; |
||||
pwErrCnt1[bIdxCycCnt][bIdxX][bIdxY] = 0; |
||||
} |
||||
} |
||||
} |
||||
isContinue = true; |
||||
while(isContinue){ |
||||
//printk(KERN_ERR "_bXcurr: %d, _bYcurr: %d\n", _bXcurr, _bYcurr);
|
||||
// The point is within the boundary, then let's check if it is within
|
||||
// the testing region.
|
||||
// The point is only test-able if one of the eye region
|
||||
// includes this point.
|
||||
fgValid = fgEyeScanHelper_CheckPtInRegion(&_rEye1, _bXcurr, _bYcurr) |
||||
|| fgEyeScanHelper_CheckPtInRegion(&_rEye2, _bXcurr, _bYcurr); |
||||
// Translate bX and bY to 2's complement from where the origin was on the
|
||||
// top left corner.
|
||||
// 0x40 and 0x3F needs a bit of thinking!!!! >"<
|
||||
cX = (_bXcurr ^ 0x40); |
||||
cY = (_bYcurr ^ 0x3F); |
||||
|
||||
// Set X if necessary
|
||||
if (_fgXChged == true) |
||||
{ |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_XOFFSET_OFST, RG_SSUSB_EQ_EYE_XOFFSET, cX); //RG_SSUSB_RX_EYE_XOFFSET
|
||||
} |
||||
// Set Y
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE0_Y_OFST, RG_SSUSB_EQ_EYE0_Y, cY); //RG_SSUSB_RX_EYE0_Y
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE1_Y_OFST, RG_SSUSB_EQ_EYE1_Y, cY); //RG_SSUSB_RX_EYE1_Y
|
||||
|
||||
/// Test this point!
|
||||
if (fgValid){ |
||||
for (bExtendCnt = 0; bExtendCnt < num_ignore_cnt; bExtendCnt++) |
||||
{ |
||||
//run test
|
||||
EyeScanHelper_RunTest(info); |
||||
} |
||||
for (bExtendCnt = 0; bExtendCnt < num_cnt; bExtendCnt++) |
||||
{ |
||||
EyeScanHelper_RunTest(info); |
||||
wErr0 = U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->phya_rx_mon3) |
||||
, RGS_SSUSB_EQ_EYE_MONITOR_ERRCNT_0_OFST, RGS_SSUSB_EQ_EYE_MONITOR_ERRCNT_0); |
||||
wErr1 = U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->phya_rx_mon4) |
||||
, RGS_SSUSB_EQ_EYE_MONITOR_ERRCNT_1_OFST, RGS_SSUSB_EQ_EYE_MONITOR_ERRCNT_1); |
||||
|
||||
pwErrCnt0[bExtendCnt][_bXcurr][_bYcurr] = wErr0; |
||||
pwErrCnt1[bExtendCnt][_bXcurr][_bYcurr] = wErr1; |
||||
|
||||
//EyeScanHelper_GetResult(&_rRes.pwErrCnt0[bCnt], &_rRes.pwErrCnt1[bCnt]);
|
||||
// printk(KERN_ERR "cnt[%d] cur_x,y [0x%x][0x%x], cX,cY [0x%x][0x%x], ErrCnt[%d][%d]\n"
|
||||
// , bExtendCnt, _bXcurr, _bYcurr, cX, cY, pwErrCnt0[bExtendCnt][_bXcurr][_bYcurr], pwErrCnt1[bExtendCnt][_bXcurr][_bYcurr]);
|
||||
} |
||||
//printk(KERN_ERR "cur_x,y [0x%x][0x%x], cX,cY [0x%x][0x%x], ErrCnt[%d][%d]\n", _bXcurr, _bYcurr, cX, cY, pwErrCnt0[0][_bXcurr][_bYcurr], pwErrCnt1[0][_bXcurr][_bYcurr]);
|
||||
} |
||||
else{ |
||||
|
||||
} |
||||
if (fgEyeScanHelper_CalNextPoint() == false){ |
||||
#if 0 |
||||
printk(KERN_ERR "Xcurr [0x%x] Ycurr [0x%x]\n", _bXcurr, _bYcurr); |
||||
printk(KERN_ERR "XcurrREG [0x%x] YcurrREG [0x%x]\n", cX, cY); |
||||
#endif |
||||
printk(KERN_ERR "end of eye scan\n"); |
||||
isContinue = false; |
||||
} |
||||
} |
||||
printk(KERN_ERR "CurX [0x%x] CurY [0x%x]\n" |
||||
, U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0), RG_SSUSB_EQ_EYE_XOFFSET_OFST, RG_SSUSB_EQ_EYE_XOFFSET) |
||||
, U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0), RG_SSUSB_EQ_EYE0_Y_OFST, RG_SSUSB_EQ_EYE0_Y)); |
||||
|
||||
// Move X,Y to the top-left corner
|
||||
for (cOfst = 63; cOfst >= 0; cOfst--) |
||||
{ |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE_XOFFSET_OFST, RG_SSUSB_EQ_EYE_XOFFSET, cOfst); //RG_SSUSB_RX_EYE_XOFFSET
|
||||
} |
||||
for (cOfst = 63; cOfst >= 0; cOfst--) |
||||
{ |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE0_Y_OFST, RG_SSUSB_EQ_EYE0_Y, cOfst); |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0) |
||||
, RG_SSUSB_EQ_EYE1_Y_OFST, RG_SSUSB_EQ_EYE1_Y, cOfst); |
||||
|
||||
} |
||||
printk(KERN_ERR "CurX [0x%x] CurY [0x%x]\n" |
||||
, U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0), RG_SSUSB_EQ_EYE_XOFFSET_OFST, RG_SSUSB_EQ_EYE_XOFFSET) |
||||
, U3PhyReadField32(((PHY_UINT32)&info->u3phyd_regs->eq_eye0), RG_SSUSB_EQ_EYE0_Y_OFST, RG_SSUSB_EQ_EYE0_Y)); |
||||
|
||||
printk(KERN_ERR "PI result: %d\n", _bPIResult); |
||||
printk(KERN_ERR "pwErrCnt0 addr: 0x%x\n", (PHY_UINT32)pwErrCnt0); |
||||
printk(KERN_ERR "pwErrCnt1 addr: 0x%x\n", (PHY_UINT32)pwErrCnt1); |
||||
|
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
//not used on SoC
|
||||
PHY_INT32 u2_save_cur_en(struct u3phy_info *info){ |
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
//not used on SoC
|
||||
PHY_INT32 u2_save_cur_re(struct u3phy_info *info){ |
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
PHY_INT32 u2_slew_rate_calibration(struct u3phy_info *info){ |
||||
PHY_INT32 i=0; |
||||
//PHY_INT32 j=0;
|
||||
//PHY_INT8 u1SrCalVal = 0;
|
||||
//PHY_INT8 u1Reg_addr_HSTX_SRCAL_EN;
|
||||
PHY_INT32 fgRet = 0;
|
||||
PHY_INT32 u4FmOut = 0;
|
||||
PHY_INT32 u4Tmp = 0; |
||||
//PHY_INT32 temp;
|
||||
|
||||
// => RG_USB20_HSTX_SRCAL_EN = 1
|
||||
// enable HS TX SR calibration
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u2phy_regs->u2phyacr0) |
||||
, RG_USB20_HSTX_SRCAL_EN_OFST, RG_USB20_HSTX_SRCAL_EN, 0x1); |
||||
DRV_MSLEEP(1); |
||||
|
||||
// => RG_FRCK_EN = 1
|
||||
// Enable free run clock
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->sifslv_fm_regs->fmmonr1) |
||||
, RG_FRCK_EN_OFST, RG_FRCK_EN, 1); |
||||
|
||||
// MT6290 HS signal quality patch
|
||||
// => RG_CYCLECNT = 400
|
||||
// Setting cyclecnt =400
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->sifslv_fm_regs->fmcr0) |
||||
, RG_CYCLECNT_OFST, RG_CYCLECNT, 0x400); |
||||
|
||||
// => RG_FREQDET_EN = 1
|
||||
// Enable frequency meter
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->sifslv_fm_regs->fmcr0) |
||||
, RG_FREQDET_EN_OFST, RG_FREQDET_EN, 0x1); |
||||
|
||||
// wait for FM detection done, set 10ms timeout
|
||||
for(i=0; i<10; i++){ |
||||
// => u4FmOut = USB_FM_OUT
|
||||
// read FM_OUT
|
||||
u4FmOut = U3PhyReadReg32(((PHY_UINT32)&info->sifslv_fm_regs->fmmonr0)); |
||||
printk("FM_OUT value: u4FmOut = %d(0x%08X)\n", u4FmOut, u4FmOut); |
||||
|
||||
// check if FM detection done
|
||||
if (u4FmOut != 0) |
||||
{ |
||||
fgRet = 0; |
||||
printk("FM detection done! loop = %d\n", i); |
||||
|
||||
break; |
||||
} |
||||
|
||||
fgRet = 1; |
||||
DRV_MSLEEP(1); |
||||
} |
||||
// => RG_FREQDET_EN = 0
|
||||
// disable frequency meter
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->sifslv_fm_regs->fmcr0) |
||||
, RG_FREQDET_EN_OFST, RG_FREQDET_EN, 0); |
||||
|
||||
// => RG_FRCK_EN = 0
|
||||
// disable free run clock
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->sifslv_fm_regs->fmmonr1) |
||||
, RG_FRCK_EN_OFST, RG_FRCK_EN, 0); |
||||
|
||||
// => RG_USB20_HSTX_SRCAL_EN = 0
|
||||
// disable HS TX SR calibration
|
||||
U3PhyWriteField32(((PHY_UINT32)&info->u2phy_regs->u2phyacr0) |
||||
, RG_USB20_HSTX_SRCAL_EN_OFST, RG_USB20_HSTX_SRCAL_EN, 0); |
||||
DRV_MSLEEP(1); |
||||
|
||||
if(u4FmOut == 0){ |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u2phy_regs->u2phyacr0) |
||||
, RG_USB20_HSTX_SRCTRL_OFST, RG_USB20_HSTX_SRCTRL, 0x4); |
||||
|
||||
fgRet = 1; |
||||
} |
||||
else{ |
||||
// set reg = (1024/FM_OUT) * 25 * 0.028 (round to the nearest digits)
|
||||
u4Tmp = (((1024 * 25 * U2_SR_COEF_7621) / u4FmOut) + 500) / 1000; |
||||
printk("SR calibration value u1SrCalVal = %d\n", (PHY_UINT8)u4Tmp); |
||||
U3PhyWriteField32(((PHY_UINT32)&info->u2phy_regs->u2phyacr0) |
||||
, RG_USB20_HSTX_SRCTRL_OFST, RG_USB20_HSTX_SRCTRL, u4Tmp); |
||||
} |
||||
return fgRet; |
||||
} |
||||
|
||||
#endif |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,58 @@ |
||||
#include "mtk-phy.h" |
||||
#ifdef CONFIG_U3D_HAL_SUPPORT |
||||
#include "mu3d_hal_osal.h" |
||||
#endif |
||||
|
||||
#ifdef CONFIG_U3_PHY_AHB_SUPPORT |
||||
#include <linux/gfp.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/slab.h> |
||||
|
||||
#ifndef CONFIG_U3D_HAL_SUPPORT |
||||
#define os_writel(addr,data) {\ |
||||
(*((volatile PHY_UINT32*)(addr)) = data);\
|
||||
} |
||||
#define os_readl(addr) *((volatile PHY_UINT32*)(addr)) |
||||
#define os_writelmsk(addr, data, msk) \ |
||||
{ os_writel(addr, ((os_readl(addr) & ~(msk)) | ((data) & (msk)))); \
|
||||
} |
||||
#define os_setmsk(addr, msk) \ |
||||
{ os_writel(addr, os_readl(addr) | msk); \
|
||||
} |
||||
#define os_clrmsk(addr, msk) \ |
||||
{ os_writel(addr, os_readl(addr) &~ msk); \
|
||||
} |
||||
/*msk the data first, then umsk with the umsk.*/ |
||||
#define os_writelmskumsk(addr, data, msk, umsk) \ |
||||
{\
|
||||
os_writel(addr, ((os_readl(addr) & ~(msk)) | ((data) & (msk))) & (umsk));\
|
||||
} |
||||
|
||||
#endif |
||||
|
||||
PHY_INT32 U3PhyWriteReg32(PHY_UINT32 addr, PHY_UINT32 data) |
||||
{ |
||||
os_writel(addr, data); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
PHY_INT32 U3PhyReadReg32(PHY_UINT32 addr) |
||||
{ |
||||
return os_readl(addr); |
||||
} |
||||
|
||||
PHY_INT32 U3PhyWriteReg8(PHY_UINT32 addr, PHY_UINT8 data) |
||||
{ |
||||
os_writelmsk(addr&0xfffffffc, data<<((addr%4)*8), 0xff<<((addr%4)*8)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
PHY_INT8 U3PhyReadReg8(PHY_UINT32 addr) |
||||
{ |
||||
return ((os_readl(addr)>>((addr%4)*8))&0xff); |
||||
} |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,102 @@ |
||||
#include <linux/gfp.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/slab.h> |
||||
#define U3_PHY_LIB |
||||
#include "mtk-phy.h" |
||||
#ifdef CONFIG_PROJECT_7621 |
||||
#include "mtk-phy-7621.h" |
||||
#endif |
||||
#ifdef CONFIG_PROJECT_PHY |
||||
static struct u3phy_operator project_operators = { |
||||
.init = phy_init, |
||||
.change_pipe_phase = phy_change_pipe_phase, |
||||
.eyescan_init = eyescan_init, |
||||
.eyescan = phy_eyescan, |
||||
.u2_slew_rate_calibration = u2_slew_rate_calibration, |
||||
}; |
||||
#endif |
||||
|
||||
|
||||
PHY_INT32 u3phy_init(){ |
||||
#ifndef CONFIG_PROJECT_PHY |
||||
PHY_INT32 u3phy_version; |
||||
#endif |
||||
|
||||
if(u3phy != NULL){ |
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
u3phy = kmalloc(sizeof(struct u3phy_info), GFP_NOIO); |
||||
#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM) |
||||
u3phy_p1 = kmalloc(sizeof(struct u3phy_info), GFP_NOIO); |
||||
#endif |
||||
#ifdef CONFIG_U3_PHY_GPIO_SUPPORT |
||||
u3phy->phyd_version_addr = 0x2000e4; |
||||
#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM) |
||||
u3phy_p1->phyd_version_addr = 0x2000e4; |
||||
#endif |
||||
#else |
||||
u3phy->phyd_version_addr = U3_PHYD_B2_BASE + 0xe4; |
||||
#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM) |
||||
u3phy_p1->phyd_version_addr = U3_PHYD_B2_BASE_P1 + 0xe4; |
||||
#endif |
||||
#endif |
||||
|
||||
#ifdef CONFIG_PROJECT_PHY |
||||
|
||||
u3phy->u2phy_regs = (struct u2phy_reg *)U2_PHY_BASE; |
||||
u3phy->u3phyd_regs = (struct u3phyd_reg *)U3_PHYD_BASE; |
||||
u3phy->u3phyd_bank2_regs = (struct u3phyd_bank2_reg *)U3_PHYD_B2_BASE; |
||||
u3phy->u3phya_regs = (struct u3phya_reg *)U3_PHYA_BASE; |
||||
u3phy->u3phya_da_regs = (struct u3phya_da_reg *)U3_PHYA_DA_BASE; |
||||
u3phy->sifslv_chip_regs = (struct sifslv_chip_reg *)SIFSLV_CHIP_BASE;
|
||||
u3phy->sifslv_fm_regs = (struct sifslv_fm_feg *)SIFSLV_FM_FEG_BASE;
|
||||
u3phy_ops = &project_operators; |
||||
|
||||
#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM) |
||||
u3phy_p1->u2phy_regs = (struct u2phy_reg *)U2_PHY_BASE_P1; |
||||
u3phy_p1->u3phyd_regs = (struct u3phyd_reg *)U3_PHYD_BASE_P1; |
||||
u3phy_p1->u3phyd_bank2_regs = (struct u3phyd_bank2_reg *)U3_PHYD_B2_BASE_P1; |
||||
u3phy_p1->u3phya_regs = (struct u3phya_reg *)U3_PHYA_BASE_P1; |
||||
u3phy_p1->u3phya_da_regs = (struct u3phya_da_reg *)U3_PHYA_DA_BASE_P1; |
||||
u3phy_p1->sifslv_chip_regs = (struct sifslv_chip_reg *)SIFSLV_CHIP_BASE; |
||||
u3phy_p1->sifslv_fm_regs = (struct sifslv_fm_feg *)SIFSLV_FM_FEG_BASE; |
||||
#endif |
||||
#endif |
||||
|
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
PHY_INT32 U3PhyWriteField8(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask, PHY_INT32 value){ |
||||
PHY_INT8 cur_value; |
||||
PHY_INT8 new_value; |
||||
|
||||
cur_value = U3PhyReadReg8(addr); |
||||
new_value = (cur_value & (~mask)) | (value << offset); |
||||
//udelay(i2cdelayus);
|
||||
U3PhyWriteReg8(addr, new_value); |
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
PHY_INT32 U3PhyWriteField32(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask, PHY_INT32 value){ |
||||
PHY_INT32 cur_value; |
||||
PHY_INT32 new_value; |
||||
|
||||
cur_value = U3PhyReadReg32(addr); |
||||
new_value = (cur_value & (~mask)) | ((value << offset) & mask); |
||||
U3PhyWriteReg32(addr, new_value); |
||||
//DRV_MDELAY(100);
|
||||
|
||||
return PHY_TRUE; |
||||
} |
||||
|
||||
PHY_INT32 U3PhyReadField8(PHY_INT32 addr,PHY_INT32 offset,PHY_INT32 mask){ |
||||
|
||||
return ((U3PhyReadReg8(addr) & mask) >> offset); |
||||
} |
||||
|
||||
PHY_INT32 U3PhyReadField32(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask){ |
||||
|
||||
return ((U3PhyReadReg32(addr) & mask) >> offset); |
||||
} |
||||
|
@ -0,0 +1,179 @@ |
||||
#ifndef __MTK_PHY_NEW_H |
||||
#define __MTK_PHY_NEW_H |
||||
|
||||
//#define CONFIG_U3D_HAL_SUPPORT
|
||||
|
||||
/* include system library */ |
||||
#include <linux/gfp.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/slab.h> |
||||
#include <linux/delay.h> |
||||
|
||||
/* Choose PHY R/W implementation */ |
||||
//#define CONFIG_U3_PHY_GPIO_SUPPORT //SW I2C implemented by GPIO
|
||||
#define CONFIG_U3_PHY_AHB_SUPPORT //AHB, only on SoC
|
||||
|
||||
/* Choose PHY version */ |
||||
//Select your project by defining one of the followings
|
||||
#define CONFIG_PROJECT_7621 //7621
|
||||
#define CONFIG_PROJECT_PHY |
||||
|
||||
/* BASE ADDRESS DEFINE, should define this on ASIC */ |
||||
#define PHY_BASE 0xBE1D0000 |
||||
#define SIFSLV_FM_FEG_BASE (PHY_BASE+0x100) |
||||
#define SIFSLV_CHIP_BASE (PHY_BASE+0x700) |
||||
#define U2_PHY_BASE (PHY_BASE+0x800) |
||||
#define U3_PHYD_BASE (PHY_BASE+0x900) |
||||
#define U3_PHYD_B2_BASE (PHY_BASE+0xa00) |
||||
#define U3_PHYA_BASE (PHY_BASE+0xb00) |
||||
#define U3_PHYA_DA_BASE (PHY_BASE+0xc00) |
||||
|
||||
#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM) |
||||
#define SIFSLV_FM_FEG_BASE_P1 (PHY_BASE+0x100) |
||||
#define SIFSLV_CHIP_BASE_P1 (PHY_BASE+0x700) |
||||
#define U2_PHY_BASE_P1 (PHY_BASE+0x1000) |
||||
#define U3_PHYD_BASE_P1 (PHY_BASE+0x1100) |
||||
#define U3_PHYD_B2_BASE_P1 (PHY_BASE+0x1200) |
||||
#define U3_PHYA_BASE_P1 (PHY_BASE+0x1300) |
||||
#define U3_PHYA_DA_BASE_P1 (PHY_BASE+0x1400) |
||||
#endif |
||||
|
||||
/*
|
||||
|
||||
0x00000100 MODULE ssusb_sifslv_fmreg ssusb_sifslv_fmreg |
||||
0x00000700 MODULE ssusb_sifslv_ippc ssusb_sifslv_ippc |
||||
0x00000800 MODULE ssusb_sifslv_u2phy_com ssusb_sifslv_u2_phy_com_T28 |
||||
0x00000900 MODULE ssusb_sifslv_u3phyd ssusb_sifslv_u3phyd_T28 |
||||
0x00000a00 MODULE ssusb_sifslv_u3phyd_bank2 ssusb_sifslv_u3phyd_bank2_T28 |
||||
0x00000b00 MODULE ssusb_sifslv_u3phya ssusb_sifslv_u3phya_T28 |
||||
0x00000c00 MODULE ssusb_sifslv_u3phya_da ssusb_sifslv_u3phya_da_T28 |
||||
*/ |
||||
|
||||
|
||||
/* TYPE DEFINE */ |
||||
typedef unsigned int PHY_UINT32; |
||||
typedef int PHY_INT32; |
||||
typedef unsigned short PHY_UINT16; |
||||
typedef short PHY_INT16; |
||||
typedef unsigned char PHY_UINT8; |
||||
typedef char PHY_INT8; |
||||
|
||||
typedef PHY_UINT32 __bitwise PHY_LE32; |
||||
|
||||
/* CONSTANT DEFINE */ |
||||
#define PHY_FALSE 0 |
||||
#define PHY_TRUE 1 |
||||
|
||||
/* MACRO DEFINE */ |
||||
#define DRV_WriteReg32(addr,data) ((*(volatile PHY_UINT32 *)(addr)) = (unsigned long)(data)) |
||||
#define DRV_Reg32(addr) (*(volatile PHY_UINT32 *)(addr)) |
||||
|
||||
#define DRV_MDELAY mdelay |
||||
#define DRV_MSLEEP msleep |
||||
#define DRV_UDELAY udelay |
||||
#define DRV_USLEEP usleep |
||||
|
||||
/* PHY FUNCTION DEFINE, implemented in platform files, ex. ahb, gpio */ |
||||
PHY_INT32 U3PhyWriteReg32(PHY_UINT32 addr, PHY_UINT32 data); |
||||
PHY_INT32 U3PhyReadReg32(PHY_UINT32 addr); |
||||
PHY_INT32 U3PhyWriteReg8(PHY_UINT32 addr, PHY_UINT8 data); |
||||
PHY_INT8 U3PhyReadReg8(PHY_UINT32 addr); |
||||
|
||||
/* PHY GENERAL USAGE FUNC, implemented in mtk-phy.c */ |
||||
PHY_INT32 U3PhyWriteField8(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask, PHY_INT32 value); |
||||
PHY_INT32 U3PhyWriteField32(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask, PHY_INT32 value); |
||||
PHY_INT32 U3PhyReadField8(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask); |
||||
PHY_INT32 U3PhyReadField32(PHY_INT32 addr, PHY_INT32 offset, PHY_INT32 mask); |
||||
|
||||
struct u3phy_info { |
||||
PHY_INT32 phy_version; |
||||
PHY_INT32 phyd_version_addr; |
||||
|
||||
#ifdef CONFIG_PROJECT_PHY |
||||
struct u2phy_reg *u2phy_regs; |
||||
struct u3phya_reg *u3phya_regs; |
||||
struct u3phya_da_reg *u3phya_da_regs; |
||||
struct u3phyd_reg *u3phyd_regs; |
||||
struct u3phyd_bank2_reg *u3phyd_bank2_regs; |
||||
struct sifslv_chip_reg *sifslv_chip_regs;
|
||||
struct sifslv_fm_feg *sifslv_fm_regs;
|
||||
#endif |
||||
}; |
||||
|
||||
struct u3phy_operator { |
||||
PHY_INT32 (*init) (struct u3phy_info *info); |
||||
PHY_INT32 (*change_pipe_phase) (struct u3phy_info *info, PHY_INT32 phy_drv, PHY_INT32 pipe_phase); |
||||
PHY_INT32 (*eyescan_init) (struct u3phy_info *info); |
||||
PHY_INT32 (*eyescan) (struct u3phy_info *info, PHY_INT32 x_t1, PHY_INT32 y_t1, PHY_INT32 x_br, PHY_INT32 y_br, PHY_INT32 delta_x, PHY_INT32 delta_y, PHY_INT32 eye_cnt, PHY_INT32 num_cnt, PHY_INT32 PI_cal_en, PHY_INT32 num_ignore_cnt); |
||||
PHY_INT32 (*u2_save_current_entry) (struct u3phy_info *info); |
||||
PHY_INT32 (*u2_save_current_recovery) (struct u3phy_info *info); |
||||
PHY_INT32 (*u2_slew_rate_calibration) (struct u3phy_info *info); |
||||
}; |
||||
|
||||
#ifdef U3_PHY_LIB |
||||
#define AUTOEXT |
||||
#else |
||||
#define AUTOEXT extern |
||||
#endif |
||||
|
||||
AUTOEXT struct u3phy_info *u3phy; |
||||
AUTOEXT struct u3phy_info *u3phy_p1; |
||||
AUTOEXT struct u3phy_operator *u3phy_ops; |
||||
|
||||
/*********eye scan required*********/ |
||||
|
||||
#define LO_BYTE(x) ((PHY_UINT8)((x) & 0xFF)) |
||||
#define HI_BYTE(x) ((PHY_UINT8)(((x) & 0xFF00) >> 8)) |
||||
|
||||
typedef enum |
||||
{ |
||||
SCAN_UP, |
||||
SCAN_DN |
||||
} enumScanDir; |
||||
|
||||
struct strucScanRegion |
||||
{ |
||||
PHY_INT8 bX_tl; |
||||
PHY_INT8 bY_tl; |
||||
PHY_INT8 bX_br; |
||||
PHY_INT8 bY_br; |
||||
PHY_INT8 bDeltaX; |
||||
PHY_INT8 bDeltaY; |
||||
}; |
||||
|
||||
struct strucTestCycle |
||||
{ |
||||
PHY_UINT16 wEyeCnt; |
||||
PHY_INT8 bNumOfEyeCnt; |
||||
PHY_INT8 bPICalEn; |
||||
PHY_INT8 bNumOfIgnoreCnt; |
||||
}; |
||||
|
||||
#define ERRCNT_MAX 128 |
||||
#define CYCLE_COUNT_MAX 15 |
||||
|
||||
/// the map resolution is 128 x 128 pts
|
||||
#define MAX_X 127 |
||||
#define MAX_Y 127 |
||||
#define MIN_X 0 |
||||
#define MIN_Y 0 |
||||
|
||||
PHY_INT32 u3phy_init(void); |
||||
|
||||
AUTOEXT struct strucScanRegion _rEye1; |
||||
AUTOEXT struct strucScanRegion _rEye2; |
||||
AUTOEXT struct strucTestCycle _rTestCycle; |
||||
AUTOEXT PHY_UINT8 _bXcurr; |
||||
AUTOEXT PHY_UINT8 _bYcurr; |
||||
AUTOEXT enumScanDir _eScanDir; |
||||
AUTOEXT PHY_INT8 _fgXChged; |
||||
AUTOEXT PHY_INT8 _bPIResult; |
||||
/* use local variable instead to save memory use */ |
||||
#if 0 |
||||
AUTOEXT PHY_UINT32 pwErrCnt0[CYCLE_COUNT_MAX][ERRCNT_MAX][ERRCNT_MAX]; |
||||
AUTOEXT PHY_UINT32 pwErrCnt1[CYCLE_COUNT_MAX][ERRCNT_MAX][ERRCNT_MAX]; |
||||
#endif |
||||
|
||||
/***********************************/ |
||||
#endif |
||||
|
@ -0,0 +1,115 @@ |
||||
#include "xhci-mtk.h" |
||||
#include "xhci-mtk-power.h" |
||||
#include "xhci.h" |
||||
#include <linux/kernel.h> /* printk() */ |
||||
#include <linux/slab.h> |
||||
#include <linux/delay.h> |
||||
|
||||
static int g_num_u3_port; |
||||
static int g_num_u2_port; |
||||
|
||||
|
||||
void enableXhciAllPortPower(struct xhci_hcd *xhci){ |
||||
int i; |
||||
u32 port_id, temp; |
||||
u32 __iomem *addr; |
||||
|
||||
g_num_u3_port = SSUSB_U3_PORT_NUM(readl(SSUSB_IP_CAP)); |
||||
g_num_u2_port = SSUSB_U2_PORT_NUM(readl(SSUSB_IP_CAP)); |
||||
|
||||
for(i=1; i<=g_num_u3_port; i++){ |
||||
port_id=i; |
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(port_id-1 & 0xff); |
||||
temp = xhci_readl(xhci, addr); |
||||
temp = xhci_port_state_to_neutral(temp); |
||||
temp |= PORT_POWER; |
||||
xhci_writel(xhci, temp, addr); |
||||
} |
||||
for(i=1; i<=g_num_u2_port; i++){ |
||||
port_id=i+g_num_u3_port; |
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(port_id-1 & 0xff); |
||||
temp = xhci_readl(xhci, addr); |
||||
temp = xhci_port_state_to_neutral(temp); |
||||
temp |= PORT_POWER; |
||||
xhci_writel(xhci, temp, addr); |
||||
} |
||||
} |
||||
|
||||
void enableAllClockPower(){ |
||||
|
||||
int i; |
||||
u32 temp; |
||||
|
||||
g_num_u3_port = SSUSB_U3_PORT_NUM(readl(SSUSB_IP_CAP)); |
||||
g_num_u2_port = SSUSB_U2_PORT_NUM(readl(SSUSB_IP_CAP)); |
||||
|
||||
//2. Enable xHC
|
||||
writel(readl(SSUSB_IP_PW_CTRL) | (SSUSB_IP_SW_RST), SSUSB_IP_PW_CTRL); |
||||
writel(readl(SSUSB_IP_PW_CTRL) & (~SSUSB_IP_SW_RST), SSUSB_IP_PW_CTRL); |
||||
writel(readl(SSUSB_IP_PW_CTRL_1) & (~SSUSB_IP_PDN), SSUSB_IP_PW_CTRL_1); |
||||
|
||||
//1. Enable target ports
|
||||
for(i=0; i<g_num_u3_port; i++){ |
||||
temp = readl(SSUSB_U3_CTRL(i)); |
||||
temp = temp & (~SSUSB_U3_PORT_PDN) & (~SSUSB_U3_PORT_DIS); |
||||
writel(temp, SSUSB_U3_CTRL(i)); |
||||
} |
||||
for(i=0; i<g_num_u2_port; i++){ |
||||
temp = readl(SSUSB_U2_CTRL(i)); |
||||
temp = temp & (~SSUSB_U2_PORT_PDN) & (~SSUSB_U2_PORT_DIS); |
||||
writel(temp, SSUSB_U2_CTRL(i)); |
||||
} |
||||
msleep(100); |
||||
} |
||||
|
||||
|
||||
//(X)disable clock/power of a port
|
||||
//(X)if all ports are disabled, disable IP ctrl power
|
||||
//disable all ports and IP clock/power, this is just mention HW that the power/clock of port
|
||||
//and IP could be disable if suspended.
|
||||
//If doesn't not disable all ports at first, the IP clock/power will never be disabled
|
||||
//(some U2 and U3 ports are binded to the same connection, that is, they will never enter suspend at the same time
|
||||
//port_index: port number
|
||||
//port_rev: 0x2 - USB2.0, 0x3 - USB3.0 (SuperSpeed)
|
||||
void disablePortClockPower(void){ |
||||
int i; |
||||
u32 temp; |
||||
|
||||
g_num_u3_port = SSUSB_U3_PORT_NUM(readl(SSUSB_IP_CAP)); |
||||
g_num_u2_port = SSUSB_U2_PORT_NUM(readl(SSUSB_IP_CAP)); |
||||
|
||||
for(i=0; i<g_num_u3_port; i++){ |
||||
temp = readl(SSUSB_U3_CTRL(i)); |
||||
temp = temp | (SSUSB_U3_PORT_PDN); |
||||
writel(temp, SSUSB_U3_CTRL(i)); |
||||
} |
||||
for(i=0; i<g_num_u2_port; i++){ |
||||
temp = readl(SSUSB_U2_CTRL(i)); |
||||
temp = temp | (SSUSB_U2_PORT_PDN); |
||||
writel(temp, SSUSB_U2_CTRL(i)); |
||||
} |
||||
writel(readl(SSUSB_IP_PW_CTRL_1) | (SSUSB_IP_PDN), SSUSB_IP_PW_CTRL_1); |
||||
} |
||||
|
||||
//if IP ctrl power is disabled, enable it
|
||||
//enable clock/power of a port
|
||||
//port_index: port number
|
||||
//port_rev: 0x2 - USB2.0, 0x3 - USB3.0 (SuperSpeed)
|
||||
void enablePortClockPower(int port_index, int port_rev){ |
||||
int i; |
||||
u32 temp; |
||||
|
||||
writel(readl(SSUSB_IP_PW_CTRL_1) & (~SSUSB_IP_PDN), SSUSB_IP_PW_CTRL_1); |
||||
|
||||
if(port_rev == 0x3){ |
||||
temp = readl(SSUSB_U3_CTRL(port_index)); |
||||
temp = temp & (~SSUSB_U3_PORT_PDN); |
||||
writel(temp, SSUSB_U3_CTRL(port_index)); |
||||
} |
||||
else if(port_rev == 0x2){ |
||||
temp = readl(SSUSB_U2_CTRL(port_index)); |
||||
temp = temp & (~SSUSB_U2_PORT_PDN); |
||||
writel(temp, SSUSB_U2_CTRL(port_index)); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,13 @@ |
||||
#ifndef _XHCI_MTK_POWER_H |
||||
#define _XHCI_MTK_POWER_H |
||||
|
||||
#include <linux/usb.h> |
||||
#include "xhci.h" |
||||
#include "xhci-mtk.h" |
||||
|
||||
void enableXhciAllPortPower(struct xhci_hcd *xhci); |
||||
void enableAllClockPower(void); |
||||
void disablePortClockPower(void); |
||||
void enablePortClockPower(int port_index, int port_rev); |
||||
|
||||
#endif |
@ -0,0 +1,608 @@ |
||||
#include "xhci-mtk-scheduler.h" |
||||
#include <linux/kernel.h> /* printk() */ |
||||
|
||||
static struct sch_ep **ss_out_eps[MAX_EP_NUM]; |
||||
static struct sch_ep **ss_in_eps[MAX_EP_NUM]; |
||||
static struct sch_ep **hs_eps[MAX_EP_NUM]; //including tt isoc
|
||||
static struct sch_ep **tt_intr_eps[MAX_EP_NUM]; |
||||
|
||||
|
||||
int mtk_xhci_scheduler_init(void){ |
||||
int i; |
||||
|
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
ss_out_eps[i] = NULL; |
||||
} |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
ss_in_eps[i] = NULL; |
||||
} |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
hs_eps[i] = NULL; |
||||
} |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
tt_intr_eps[i] = NULL; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int add_sch_ep(int dev_speed, int is_in, int isTT, int ep_type, int maxp, int interval, int burst |
||||
, int mult, int offset, int repeat, int pkts, int cs_count, int burst_mode |
||||
, int bw_cost, mtk_u32 *ep, struct sch_ep *tmp_ep){ |
||||
|
||||
struct sch_ep **ep_array; |
||||
int i; |
||||
|
||||
if(is_in && dev_speed == USB_SPEED_SUPER ){ |
||||
ep_array = (struct sch_ep **)ss_in_eps; |
||||
} |
||||
else if(dev_speed == USB_SPEED_SUPER){ |
||||
ep_array = (struct sch_ep **)ss_out_eps; |
||||
} |
||||
else if(dev_speed == USB_SPEED_HIGH || (isTT && ep_type == USB_EP_ISOC)){ |
||||
ep_array = (struct sch_ep **)hs_eps; |
||||
} |
||||
else{ |
||||
ep_array = (struct sch_ep **)tt_intr_eps; |
||||
} |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
if(ep_array[i] == NULL){ |
||||
tmp_ep->dev_speed = dev_speed; |
||||
tmp_ep->isTT = isTT; |
||||
tmp_ep->is_in = is_in; |
||||
tmp_ep->ep_type = ep_type; |
||||
tmp_ep->maxp = maxp; |
||||
tmp_ep->interval = interval; |
||||
tmp_ep->burst = burst; |
||||
tmp_ep->mult = mult; |
||||
tmp_ep->offset = offset; |
||||
tmp_ep->repeat = repeat; |
||||
tmp_ep->pkts = pkts; |
||||
tmp_ep->cs_count = cs_count; |
||||
tmp_ep->burst_mode = burst_mode; |
||||
tmp_ep->bw_cost = bw_cost; |
||||
tmp_ep->ep = ep; |
||||
ep_array[i] = tmp_ep; |
||||
return SCH_SUCCESS; |
||||
} |
||||
} |
||||
return SCH_FAIL; |
||||
} |
||||
|
||||
int count_ss_bw(int is_in, int ep_type, int maxp, int interval, int burst, int mult, int offset, int repeat |
||||
, int td_size){ |
||||
int i, j, k; |
||||
int bw_required[3]; |
||||
int final_bw_required; |
||||
int bw_required_per_repeat; |
||||
int tmp_bw_required; |
||||
struct sch_ep *cur_sch_ep; |
||||
struct sch_ep **ep_array; |
||||
int cur_offset; |
||||
int cur_ep_offset; |
||||
int tmp_offset; |
||||
int tmp_interval; |
||||
int ep_offset; |
||||
int ep_interval; |
||||
int ep_repeat; |
||||
int ep_mult; |
||||
|
||||
if(is_in){ |
||||
ep_array = (struct sch_ep **)ss_in_eps; |
||||
} |
||||
else{ |
||||
ep_array = (struct sch_ep **)ss_out_eps; |
||||
} |
||||
|
||||
bw_required[0] = 0; |
||||
bw_required[1] = 0; |
||||
bw_required[2] = 0; |
||||
|
||||
if(repeat == 0){ |
||||
final_bw_required = 0; |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
cur_sch_ep = ep_array[i]; |
||||
if(cur_sch_ep == NULL){ |
||||
continue; |
||||
} |
||||
ep_interval = cur_sch_ep->interval; |
||||
ep_offset = cur_sch_ep->offset; |
||||
if(cur_sch_ep->repeat == 0){ |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = ep_offset + ep_interval - offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = offset + interval - ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
if(tmp_offset % tmp_interval == 0){ |
||||
final_bw_required += cur_sch_ep->bw_cost; |
||||
} |
||||
} |
||||
else{ |
||||
ep_repeat = cur_sch_ep->repeat; |
||||
ep_mult = cur_sch_ep->mult; |
||||
for(k=0; k<=ep_mult; k++){ |
||||
cur_ep_offset = ep_offset+(k*ep_mult); |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = cur_ep_offset + ep_interval - offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = offset + interval - cur_ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
if(tmp_offset % tmp_interval == 0){ |
||||
final_bw_required += cur_sch_ep->bw_cost; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
final_bw_required += td_size; |
||||
} |
||||
else{ |
||||
bw_required_per_repeat = maxp * (burst+1); |
||||
for(j=0; j<=mult; j++){ |
||||
tmp_bw_required = 0; |
||||
cur_offset = offset+(j*repeat); |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
cur_sch_ep = ep_array[i]; |
||||
if(cur_sch_ep == NULL){ |
||||
continue; |
||||
} |
||||
ep_interval = cur_sch_ep->interval; |
||||
ep_offset = cur_sch_ep->offset; |
||||
if(cur_sch_ep->repeat == 0){ |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = ep_offset + ep_interval - cur_offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = cur_offset + interval - ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
if(tmp_offset % tmp_interval == 0){ |
||||
tmp_bw_required += cur_sch_ep->bw_cost; |
||||
} |
||||
} |
||||
else{ |
||||
ep_repeat = cur_sch_ep->repeat; |
||||
ep_mult = cur_sch_ep->mult; |
||||
for(k=0; k<=ep_mult; k++){ |
||||
cur_ep_offset = ep_offset+(k*ep_repeat); |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = cur_ep_offset + ep_interval - cur_offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = cur_offset + interval - cur_ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
if(tmp_offset % tmp_interval == 0){ |
||||
tmp_bw_required += cur_sch_ep->bw_cost; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
bw_required[j] = tmp_bw_required; |
||||
} |
||||
final_bw_required = SS_BW_BOUND; |
||||
for(j=0; j<=mult; j++){ |
||||
if(bw_required[j] < final_bw_required){ |
||||
final_bw_required = bw_required[j]; |
||||
} |
||||
} |
||||
final_bw_required += bw_required_per_repeat; |
||||
} |
||||
return final_bw_required; |
||||
} |
||||
|
||||
int count_hs_bw(int ep_type, int maxp, int interval, int offset, int td_size){ |
||||
int i; |
||||
int bw_required; |
||||
struct sch_ep *cur_sch_ep; |
||||
int tmp_offset; |
||||
int tmp_interval; |
||||
int ep_offset; |
||||
int ep_interval; |
||||
int cur_tt_isoc_interval; //for isoc tt check
|
||||
|
||||
bw_required = 0; |
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
|
||||
cur_sch_ep = (struct sch_ep *)hs_eps[i]; |
||||
if(cur_sch_ep == NULL){ |
||||
continue; |
||||
} |
||||
ep_offset = cur_sch_ep->offset; |
||||
ep_interval = cur_sch_ep->interval; |
||||
|
||||
if(cur_sch_ep->isTT && cur_sch_ep->ep_type == USB_EP_ISOC){ |
||||
cur_tt_isoc_interval = ep_interval<<3; |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = ep_offset + cur_tt_isoc_interval - offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = offset + interval - ep_offset; |
||||
tmp_interval = cur_tt_isoc_interval; |
||||
} |
||||
if(cur_sch_ep->is_in){ |
||||
if((tmp_offset%tmp_interval >=2) && (tmp_offset%tmp_interval <= cur_sch_ep->cs_count)){ |
||||
bw_required += 188; |
||||
} |
||||
} |
||||
else{ |
||||
if(tmp_offset%tmp_interval <= cur_sch_ep->cs_count){ |
||||
bw_required += 188; |
||||
} |
||||
} |
||||
} |
||||
else{ |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = ep_offset + ep_interval - offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = offset + interval - ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
if(tmp_offset%tmp_interval == 0){ |
||||
bw_required += cur_sch_ep->bw_cost; |
||||
} |
||||
} |
||||
} |
||||
bw_required += td_size; |
||||
return bw_required; |
||||
} |
||||
|
||||
int count_tt_isoc_bw(int is_in, int maxp, int interval, int offset, int td_size){ |
||||
char is_cs; |
||||
int mframe_idx, frame_idx, s_frame, s_mframe, cur_mframe; |
||||
int bw_required, max_bw; |
||||
int ss_cs_count; |
||||
int cs_mframe; |
||||
int max_frame; |
||||
int i,j; |
||||
struct sch_ep *cur_sch_ep; |
||||
int ep_offset; |
||||
int ep_interval; |
||||
int ep_cs_count; |
||||
int tt_isoc_interval; //for isoc tt check
|
||||
int cur_tt_isoc_interval; //for isoc tt check
|
||||
int tmp_offset; |
||||
int tmp_interval; |
||||
|
||||
is_cs = 0; |
||||
|
||||
tt_isoc_interval = interval<<3; //frame to mframe
|
||||
if(is_in){ |
||||
is_cs = 1; |
||||
} |
||||
s_frame = offset/8; |
||||
s_mframe = offset%8; |
||||
ss_cs_count = (maxp + (188 - 1))/188; |
||||
if(is_cs){ |
||||
cs_mframe = offset%8 + 2 + ss_cs_count; |
||||
if (cs_mframe <= 6) |
||||
ss_cs_count += 2; |
||||
else if (cs_mframe == 7) |
||||
ss_cs_count++; |
||||
else if (cs_mframe > 8) |
||||
return -1; |
||||
} |
||||
max_bw = 0; |
||||
if(is_in){ |
||||
i=2; |
||||
} |
||||
for(cur_mframe = offset+i; i<ss_cs_count; cur_mframe++, i++){ |
||||
bw_required = 0; |
||||
for(j=0; j<MAX_EP_NUM; j++){ |
||||
cur_sch_ep = (struct sch_ep *)hs_eps[j]; |
||||
if(cur_sch_ep == NULL){ |
||||
continue; |
||||
} |
||||
ep_offset = cur_sch_ep->offset; |
||||
ep_interval = cur_sch_ep->interval; |
||||
if(cur_sch_ep->isTT && cur_sch_ep->ep_type == USB_EP_ISOC){ |
||||
//isoc tt
|
||||
//check if mframe offset overlap
|
||||
//if overlap, add 188 to the bw
|
||||
cur_tt_isoc_interval = ep_interval<<3; |
||||
if(cur_tt_isoc_interval >= tt_isoc_interval){ |
||||
tmp_offset = (ep_offset+cur_tt_isoc_interval) - cur_mframe; |
||||
tmp_interval = tt_isoc_interval; |
||||
} |
||||
else{ |
||||
tmp_offset = (cur_mframe+tt_isoc_interval) - ep_offset; |
||||
tmp_interval = cur_tt_isoc_interval; |
||||
} |
||||
if(cur_sch_ep->is_in){ |
||||
if((tmp_offset%tmp_interval >=2) && (tmp_offset%tmp_interval <= cur_sch_ep->cs_count)){ |
||||
bw_required += 188; |
||||
} |
||||
} |
||||
else{ |
||||
if(tmp_offset%tmp_interval <= cur_sch_ep->cs_count){ |
||||
bw_required += 188; |
||||
} |
||||
} |
||||
|
||||
} |
||||
else if(cur_sch_ep->ep_type == USB_EP_INT || cur_sch_ep->ep_type == USB_EP_ISOC){ |
||||
//check if mframe
|
||||
if(ep_interval >= tt_isoc_interval){ |
||||
tmp_offset = (ep_offset+ep_interval) - cur_mframe; |
||||
tmp_interval = tt_isoc_interval; |
||||
} |
||||
else{ |
||||
tmp_offset = (cur_mframe+tt_isoc_interval) - ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
if(tmp_offset%tmp_interval == 0){ |
||||
bw_required += cur_sch_ep->bw_cost; |
||||
} |
||||
} |
||||
} |
||||
bw_required += 188; |
||||
if(bw_required > max_bw){ |
||||
max_bw = bw_required; |
||||
} |
||||
} |
||||
return max_bw; |
||||
} |
||||
|
||||
int count_tt_intr_bw(int interval, int frame_offset){ |
||||
//check all eps in tt_intr_eps
|
||||
int ret; |
||||
int i,j; |
||||
int ep_offset; |
||||
int ep_interval; |
||||
int tmp_offset; |
||||
int tmp_interval; |
||||
ret = SCH_SUCCESS; |
||||
struct sch_ep *cur_sch_ep; |
||||
|
||||
for(i=0; i<MAX_EP_NUM; i++){ |
||||
cur_sch_ep = (struct sch_ep *)tt_intr_eps[i]; |
||||
if(cur_sch_ep == NULL){ |
||||
continue; |
||||
} |
||||
ep_offset = cur_sch_ep->offset; |
||||
ep_interval = cur_sch_ep->interval; |
||||
if(ep_interval >= interval){ |
||||
tmp_offset = ep_offset + ep_interval - frame_offset; |
||||
tmp_interval = interval; |
||||
} |
||||
else{ |
||||
tmp_offset = frame_offset + interval - ep_offset; |
||||
tmp_interval = ep_interval; |
||||
} |
||||
|
||||
if(tmp_offset%tmp_interval==0){ |
||||
return SCH_FAIL; |
||||
} |
||||
} |
||||
return SCH_SUCCESS; |
||||
} |
||||
|
||||
struct sch_ep * mtk_xhci_scheduler_remove_ep(int dev_speed, int is_in, int isTT, int ep_type, mtk_u32 *ep){ |
||||
int i; |
||||
struct sch_ep **ep_array; |
||||
struct sch_ep *cur_ep; |
||||
|
||||
if (is_in && dev_speed == USB_SPEED_SUPER) { |
||||
ep_array = (struct sch_ep **)ss_in_eps; |
||||
} |
||||
else if (dev_speed == USB_SPEED_SUPER) { |
||||
ep_array = (struct sch_ep **)ss_out_eps; |
||||
} |
||||
else if (dev_speed == USB_SPEED_HIGH || (isTT && ep_type == USB_EP_ISOC)) { |
||||
ep_array = (struct sch_ep **)hs_eps; |
||||
} |
||||
else { |
||||
ep_array = (struct sch_ep **)tt_intr_eps; |
||||
} |
||||
for (i = 0; i < MAX_EP_NUM; i++) { |
||||
cur_ep = (struct sch_ep *)ep_array[i]; |
||||
if(cur_ep != NULL && cur_ep->ep == ep){ |
||||
ep_array[i] = NULL; |
||||
return cur_ep; |
||||
} |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
int mtk_xhci_scheduler_add_ep(int dev_speed, int is_in, int isTT, int ep_type, int maxp, int interval, int burst |
||||
, int mult, mtk_u32 *ep, mtk_u32 *ep_ctx, struct sch_ep *sch_ep){ |
||||
mtk_u32 bPkts = 0; |
||||
mtk_u32 bCsCount = 0; |
||||
mtk_u32 bBm = 1; |
||||
mtk_u32 bOffset = 0; |
||||
mtk_u32 bRepeat = 0; |
||||
int ret; |
||||
struct mtk_xhci_ep_ctx *temp_ep_ctx; |
||||
int td_size; |
||||
int mframe_idx, frame_idx; |
||||
int bw_cost; |
||||
int cur_bw, best_bw, best_bw_idx,repeat, max_repeat, best_bw_repeat; |
||||
int cur_offset, cs_mframe; |
||||
int break_out; |
||||
int frame_interval; |
||||
|
||||
printk(KERN_ERR "add_ep parameters, dev_speed %d, is_in %d, isTT %d, ep_type %d, maxp %d, interval %d, burst %d, mult %d, ep 0x%x, ep_ctx 0x%x, sch_ep 0x%x\n", dev_speed, is_in, isTT, ep_type, maxp |
||||
, interval, burst, mult, ep, ep_ctx, sch_ep); |
||||
if(isTT && ep_type == USB_EP_INT && ((dev_speed == USB_SPEED_LOW) || (dev_speed == USB_SPEED_FULL))){ |
||||
frame_interval = interval >> 3; |
||||
for(frame_idx=0; frame_idx<frame_interval; frame_idx++){ |
||||
printk(KERN_ERR "check tt_intr_bw interval %d, frame_idx %d\n", frame_interval, frame_idx); |
||||
if(count_tt_intr_bw(frame_interval, frame_idx) == SCH_SUCCESS){ |
||||
printk(KERN_ERR "check OK............\n"); |
||||
bOffset = frame_idx<<3; |
||||
bPkts = 1; |
||||
bCsCount = 3; |
||||
bw_cost = maxp; |
||||
bRepeat = 0; |
||||
if(add_sch_ep(dev_speed, is_in, isTT, ep_type, maxp, frame_interval, burst, mult |
||||
, bOffset, bRepeat, bPkts, bCsCount, bBm, maxp, ep, sch_ep) == SCH_FAIL){ |
||||
return SCH_FAIL; |
||||
} |
||||
ret = SCH_SUCCESS; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
else if(isTT && ep_type == USB_EP_ISOC){ |
||||
best_bw = HS_BW_BOUND; |
||||
best_bw_idx = -1; |
||||
cur_bw = 0; |
||||
td_size = maxp; |
||||
break_out = 0; |
||||
frame_interval = interval>>3; |
||||
for(frame_idx=0; frame_idx<frame_interval && !break_out; frame_idx++){ |
||||
for(mframe_idx=0; mframe_idx<8; mframe_idx++){ |
||||
cur_offset = (frame_idx*8) + mframe_idx; |
||||
cur_bw = count_tt_isoc_bw(is_in, maxp, frame_interval, cur_offset, td_size); |
||||
if(cur_bw > 0 && cur_bw < best_bw){ |
||||
best_bw_idx = cur_offset; |
||||
best_bw = cur_bw; |
||||
if(cur_bw == td_size || cur_bw < (HS_BW_BOUND>>1)){ |
||||
break_out = 1; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if(best_bw_idx == -1){ |
||||
return SCH_FAIL; |
||||
} |
||||
else{ |
||||
bOffset = best_bw_idx; |
||||
bPkts = 1; |
||||
bCsCount = (maxp + (188 - 1)) / 188; |
||||
if(is_in){ |
||||
cs_mframe = bOffset%8 + 2 + bCsCount; |
||||
if (cs_mframe <= 6) |
||||
bCsCount += 2; |
||||
else if (cs_mframe == 7) |
||||
bCsCount++; |
||||
} |
||||
bw_cost = 188; |
||||
bRepeat = 0; |
||||
if(add_sch_ep( dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult |
||||
, bOffset, bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL){ |
||||
return SCH_FAIL; |
||||
} |
||||
ret = SCH_SUCCESS; |
||||
} |
||||
} |
||||
else if((dev_speed == USB_SPEED_FULL || dev_speed == USB_SPEED_LOW) && ep_type == USB_EP_INT){ |
||||
bPkts = 1; |
||||
ret = SCH_SUCCESS; |
||||
} |
||||
else if(dev_speed == USB_SPEED_FULL && ep_type == USB_EP_ISOC){ |
||||
bPkts = 1; |
||||
ret = SCH_SUCCESS; |
||||
} |
||||
else if(dev_speed == USB_SPEED_HIGH && (ep_type == USB_EP_INT || ep_type == USB_EP_ISOC)){ |
||||
best_bw = HS_BW_BOUND; |
||||
best_bw_idx = -1; |
||||
cur_bw = 0; |
||||
td_size = maxp*(burst+1); |
||||
for(cur_offset = 0; cur_offset<interval; cur_offset++){ |
||||
cur_bw = count_hs_bw(ep_type, maxp, interval, cur_offset, td_size); |
||||
if(cur_bw > 0 && cur_bw < best_bw){ |
||||
best_bw_idx = cur_offset; |
||||
best_bw = cur_bw; |
||||
if(cur_bw == td_size || cur_bw < (HS_BW_BOUND>>1)){ |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if(best_bw_idx == -1){ |
||||
return SCH_FAIL; |
||||
} |
||||
else{ |
||||
bOffset = best_bw_idx; |
||||
bPkts = burst + 1; |
||||
bCsCount = 0; |
||||
bw_cost = td_size; |
||||
bRepeat = 0; |
||||
if(add_sch_ep(dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult |
||||
, bOffset, bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL){ |
||||
return SCH_FAIL; |
||||
} |
||||
ret = SCH_SUCCESS; |
||||
} |
||||
} |
||||
else if(dev_speed == USB_SPEED_SUPER && (ep_type == USB_EP_INT || ep_type == USB_EP_ISOC)){ |
||||
best_bw = SS_BW_BOUND; |
||||
best_bw_idx = -1; |
||||
cur_bw = 0; |
||||
td_size = maxp * (mult+1) * (burst+1); |
||||
if(mult == 0){ |
||||
max_repeat = 0; |
||||
} |
||||
else{ |
||||
max_repeat = (interval-1)/(mult+1); |
||||
} |
||||
break_out = 0; |
||||
for(frame_idx = 0; (frame_idx < interval) && !break_out; frame_idx++){ |
||||
for(repeat = max_repeat; repeat >= 0; repeat--){ |
||||
cur_bw = count_ss_bw(is_in, ep_type, maxp, interval, burst, mult, frame_idx |
||||
, repeat, td_size); |
||||
printk(KERN_ERR "count_ss_bw, frame_idx %d, repeat %d, td_size %d, result bw %d\n" |
||||
, frame_idx, repeat, td_size, cur_bw); |
||||
if(cur_bw > 0 && cur_bw < best_bw){ |
||||
best_bw_idx = frame_idx; |
||||
best_bw_repeat = repeat; |
||||
best_bw = cur_bw; |
||||
if(cur_bw <= td_size || cur_bw < (HS_BW_BOUND>>1)){ |
||||
break_out = 1; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
printk(KERN_ERR "final best idx %d, best repeat %d\n", best_bw_idx, best_bw_repeat); |
||||
if(best_bw_idx == -1){ |
||||
return SCH_FAIL; |
||||
} |
||||
else{ |
||||
bOffset = best_bw_idx; |
||||
bCsCount = 0; |
||||
bRepeat = best_bw_repeat; |
||||
if(bRepeat == 0){ |
||||
bw_cost = (burst+1)*(mult+1)*maxp; |
||||
bPkts = (burst+1)*(mult+1); |
||||
} |
||||
else{ |
||||
bw_cost = (burst+1)*maxp; |
||||
bPkts = (burst+1); |
||||
} |
||||
if(add_sch_ep(dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult |
||||
, bOffset, bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL){ |
||||
return SCH_FAIL; |
||||
} |
||||
ret = SCH_SUCCESS; |
||||
} |
||||
} |
||||
else{ |
||||
bPkts = 1; |
||||
ret = SCH_SUCCESS; |
||||
} |
||||
if(ret == SCH_SUCCESS){ |
||||
temp_ep_ctx = (struct mtk_xhci_ep_ctx *)ep_ctx; |
||||
temp_ep_ctx->reserved[0] |= (BPKTS(bPkts) | BCSCOUNT(bCsCount) | BBM(bBm)); |
||||
temp_ep_ctx->reserved[1] |= (BOFFSET(bOffset) | BREPEAT(bRepeat)); |
||||
|
||||
printk(KERN_DEBUG "[DBG] BPKTS: %x, BCSCOUNT: %x, BBM: %x\n", bPkts, bCsCount, bBm); |
||||
printk(KERN_DEBUG "[DBG] BOFFSET: %x, BREPEAT: %x\n", bOffset, bRepeat); |
||||
return SCH_SUCCESS; |
||||
} |
||||
else{ |
||||
return SCH_FAIL; |
||||
} |
||||
} |
@ -0,0 +1,77 @@ |
||||
#ifndef _XHCI_MTK_SCHEDULER_H |
||||
#define _XHCI_MTK_SCHEDULER_H |
||||
|
||||
#define MTK_SCH_NEW 1 |
||||
|
||||
#define SCH_SUCCESS 1 |
||||
#define SCH_FAIL 0 |
||||
|
||||
#define MAX_EP_NUM 64 |
||||
#define SS_BW_BOUND 51000 |
||||
#define HS_BW_BOUND 6144 |
||||
|
||||
#define USB_EP_CONTROL 0 |
||||
#define USB_EP_ISOC 1 |
||||
#define USB_EP_BULK 2 |
||||
#define USB_EP_INT 3 |
||||
|
||||
#define USB_SPEED_LOW 1 |
||||
#define USB_SPEED_FULL 2 |
||||
#define USB_SPEED_HIGH 3 |
||||
#define USB_SPEED_SUPER 5 |
||||
|
||||
/* mtk scheduler bitmasks */ |
||||
#define BPKTS(p) ((p) & 0x3f) |
||||
#define BCSCOUNT(p) (((p) & 0x7) << 8) |
||||
#define BBM(p) ((p) << 11) |
||||
#define BOFFSET(p) ((p) & 0x3fff) |
||||
#define BREPEAT(p) (((p) & 0x7fff) << 16) |
||||
|
||||
|
||||
#if 1 |
||||
typedef unsigned int mtk_u32; |
||||
typedef unsigned long long mtk_u64; |
||||
#endif |
||||
|
||||
#define NULL ((void *)0) |
||||
|
||||
struct mtk_xhci_ep_ctx { |
||||
mtk_u32 ep_info; |
||||
mtk_u32 ep_info2; |
||||
mtk_u64 deq; |
||||
mtk_u32 tx_info; |
||||
/* offset 0x14 - 0x1f reserved for HC internal use */ |
||||
mtk_u32 reserved[3]; |
||||
}; |
||||
|
||||
|
||||
struct sch_ep |
||||
{ |
||||
//device info
|
||||
int dev_speed; |
||||
int isTT; |
||||
//ep info
|
||||
int is_in; |
||||
int ep_type; |
||||
int maxp; |
||||
int interval; |
||||
int burst; |
||||
int mult; |
||||
//scheduling info
|
||||
int offset; |
||||
int repeat; |
||||
int pkts; |
||||
int cs_count; |
||||
int burst_mode; |
||||
//other
|
||||
int bw_cost; //bandwidth cost in each repeat; including overhead
|
||||
mtk_u32 *ep; //address of usb_endpoint pointer
|
||||
}; |
||||
|
||||
int mtk_xhci_scheduler_init(void); |
||||
int mtk_xhci_scheduler_add_ep(int dev_speed, int is_in, int isTT, int ep_type, int maxp, int interval, int burst |
||||
, int mult, mtk_u32 *ep, mtk_u32 *ep_ctx, struct sch_ep *sch_ep); |
||||
struct sch_ep * mtk_xhci_scheduler_remove_ep(int dev_speed, int is_in, int isTT, int ep_type, mtk_u32 *ep); |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,265 @@ |
||||
#include "xhci-mtk.h" |
||||
#include "xhci-mtk-power.h" |
||||
#include "xhci.h" |
||||
#include "mtk-phy.h" |
||||
#ifdef CONFIG_C60802_SUPPORT |
||||
#include "mtk-phy-c60802.h" |
||||
#endif |
||||
#include "xhci-mtk-scheduler.h" |
||||
#include <linux/kernel.h> /* printk() */ |
||||
#include <linux/slab.h> |
||||
#include <linux/delay.h> |
||||
#include <asm/uaccess.h> |
||||
#include <linux/dma-mapping.h> |
||||
#include <linux/platform_device.h> |
||||
|
||||
void setInitialReg(void ) |
||||
{ |
||||
__u32 __iomem *addr; |
||||
u32 temp; |
||||
|
||||
/* set SSUSB DMA burst size to 128B */ |
||||
addr = SSUSB_U3_XHCI_BASE + SSUSB_HDMA_CFG; |
||||
temp = SSUSB_HDMA_CFG_MT7621_VALUE; |
||||
writel(temp, addr); |
||||
|
||||
/* extend U3 LTSSM Polling.LFPS timeout value */ |
||||
addr = SSUSB_U3_XHCI_BASE + U3_LTSSM_TIMING_PARAMETER3; |
||||
temp = U3_LTSSM_TIMING_PARAMETER3_VALUE; |
||||
writel(temp, addr); |
||||
|
||||
/* EOF */ |
||||
addr = SSUSB_U3_XHCI_BASE + SYNC_HS_EOF; |
||||
temp = SYNC_HS_EOF_VALUE; |
||||
writel(temp, addr); |
||||
|
||||
#if defined (CONFIG_PERIODIC_ENP) |
||||
/* HSCH_CFG1: SCH2_FIFO_DEPTH */ |
||||
addr = SSUSB_U3_XHCI_BASE + HSCH_CFG1; |
||||
temp = readl(addr); |
||||
temp &= ~(0x3 << SCH2_FIFO_DEPTH_OFFSET); |
||||
writel(temp, addr); |
||||
#endif |
||||
|
||||
/* Doorbell handling */ |
||||
addr = SIFSLV_IPPC + SSUSB_IP_SPAR0; |
||||
temp = 0x1; |
||||
writel(temp, addr); |
||||
|
||||
/* Set SW PLL Stable mode to 1 for U2 LPM device remote wakeup */ |
||||
/* Port 0 */ |
||||
addr = U2_PHY_BASE + U2_PHYD_CR1; |
||||
temp = readl(addr); |
||||
temp &= ~(0x3 << 18); |
||||
temp |= (1 << 18); |
||||
writel(temp, addr); |
||||
|
||||
/* Port 1 */ |
||||
addr = U2_PHY_BASE_P1 + U2_PHYD_CR1; |
||||
temp = readl(addr); |
||||
temp &= ~(0x3 << 18); |
||||
temp |= (1 << 18); |
||||
writel(temp, addr); |
||||
} |
||||
|
||||
|
||||
void setLatchSel(void){ |
||||
__u32 __iomem *latch_sel_addr; |
||||
u32 latch_sel_value; |
||||
latch_sel_addr = U3_PIPE_LATCH_SEL_ADD; |
||||
latch_sel_value = ((U3_PIPE_LATCH_TX)<<2) | (U3_PIPE_LATCH_RX); |
||||
writel(latch_sel_value, latch_sel_addr); |
||||
} |
||||
|
||||
void reinitIP(void){ |
||||
__u32 __iomem *ip_reset_addr; |
||||
u32 ip_reset_value; |
||||
|
||||
enableAllClockPower(); |
||||
mtk_xhci_scheduler_init(); |
||||
} |
||||
|
||||
void dbg_prb_out(void){ |
||||
mtk_probe_init(0x0f0f0f0f); |
||||
mtk_probe_out(0xffffffff); |
||||
mtk_probe_out(0x01010101); |
||||
mtk_probe_out(0x02020202); |
||||
mtk_probe_out(0x04040404); |
||||
mtk_probe_out(0x08080808); |
||||
mtk_probe_out(0x10101010); |
||||
mtk_probe_out(0x20202020); |
||||
mtk_probe_out(0x40404040); |
||||
mtk_probe_out(0x80808080); |
||||
mtk_probe_out(0x55555555); |
||||
mtk_probe_out(0xaaaaaaaa); |
||||
} |
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define RET_SUCCESS 0 |
||||
#define RET_FAIL 1 |
||||
|
||||
static int dbg_u3w(int argc, char**argv) |
||||
{ |
||||
int u4TimingValue; |
||||
char u1TimingValue; |
||||
int u4TimingAddress; |
||||
|
||||
if (argc<3) |
||||
{ |
||||
printk(KERN_ERR "Arg: address value\n"); |
||||
return RET_FAIL; |
||||
} |
||||
u3phy_init(); |
||||
|
||||
u4TimingAddress = (int)simple_strtol(argv[1], &argv[1], 16); |
||||
u4TimingValue = (int)simple_strtol(argv[2], &argv[2], 16); |
||||
u1TimingValue = u4TimingValue & 0xff; |
||||
/* access MMIO directly */ |
||||
writel(u1TimingValue, u4TimingAddress); |
||||
printk(KERN_ERR "Write done\n"); |
||||
return RET_SUCCESS; |
||||
|
||||
} |
||||
|
||||
static int dbg_u3r(int argc, char**argv) |
||||
{ |
||||
char u1ReadTimingValue; |
||||
int u4TimingAddress; |
||||
if (argc<2) |
||||
{ |
||||
printk(KERN_ERR "Arg: address\n"); |
||||
return 0; |
||||
} |
||||
u3phy_init(); |
||||
mdelay(500); |
||||
u4TimingAddress = (int)simple_strtol(argv[1], &argv[1], 16); |
||||
/* access MMIO directly */ |
||||
u1ReadTimingValue = readl(u4TimingAddress); |
||||
printk(KERN_ERR "Value = 0x%x\n", u1ReadTimingValue); |
||||
return 0; |
||||
} |
||||
|
||||
static int dbg_u3init(int argc, char**argv) |
||||
{ |
||||
int ret; |
||||
ret = u3phy_init(); |
||||
printk(KERN_ERR "phy registers and operations initial done\n"); |
||||
if(u3phy_ops->u2_slew_rate_calibration){ |
||||
u3phy_ops->u2_slew_rate_calibration(u3phy); |
||||
} |
||||
else{ |
||||
printk(KERN_ERR "WARN: PHY doesn't implement u2 slew rate calibration function\n"); |
||||
} |
||||
if(u3phy_ops->init(u3phy) == PHY_TRUE) |
||||
return RET_SUCCESS; |
||||
return RET_FAIL; |
||||
} |
||||
|
||||
void dbg_setU1U2(int argc, char**argv){ |
||||
struct xhci_hcd *xhci; |
||||
int u1_value; |
||||
int u2_value; |
||||
u32 port_id, temp; |
||||
u32 __iomem *addr; |
||||
|
||||
if (argc<3) |
||||
{ |
||||
printk(KERN_ERR "Arg: u1value u2value\n"); |
||||
return RET_FAIL; |
||||
} |
||||
|
||||
u1_value = (int)simple_strtol(argv[1], &argv[1], 10); |
||||
u2_value = (int)simple_strtol(argv[2], &argv[2], 10); |
||||
addr = (SSUSB_U3_XHCI_BASE + 0x424); |
||||
temp = readl(addr); |
||||
temp = temp & (~(0x0000ffff)); |
||||
temp = temp | u1_value | (u2_value<<8); |
||||
writel(temp, addr); |
||||
} |
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int call_function(char *buf) |
||||
{ |
||||
int i; |
||||
int argc; |
||||
char *argv[80]; |
||||
|
||||
argc = 0; |
||||
do |
||||
{ |
||||
argv[argc] = strsep(&buf, " "); |
||||
printk(KERN_DEBUG "[%d] %s\r\n", argc, argv[argc]); |
||||
argc++; |
||||
} while (buf); |
||||
if (!strcmp("dbg.r", argv[0])) |
||||
dbg_prb_out(); |
||||
else if (!strcmp("dbg.u3w", argv[0])) |
||||
dbg_u3w(argc, argv); |
||||
else if (!strcmp("dbg.u3r", argv[0])) |
||||
dbg_u3r(argc, argv); |
||||
else if (!strcmp("dbg.u3i", argv[0])) |
||||
dbg_u3init(argc, argv); |
||||
else if (!strcmp("pw.u1u2", argv[0])) |
||||
dbg_setU1U2(argc, argv); |
||||
return 0; |
||||
} |
||||
|
||||
long xhci_mtk_test_unlock_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
||||
{ |
||||
char w_buf[200]; |
||||
char r_buf[200] = "this is a test"; |
||||
int len = 200; |
||||
|
||||
switch (cmd) { |
||||
case IOCTL_READ: |
||||
copy_to_user((char *) arg, r_buf, len); |
||||
printk(KERN_DEBUG "IOCTL_READ: %s\r\n", r_buf); |
||||
break; |
||||
case IOCTL_WRITE: |
||||
copy_from_user(w_buf, (char *) arg, len); |
||||
printk(KERN_DEBUG "IOCTL_WRITE: %s\r\n", w_buf); |
||||
|
||||
//invoke function
|
||||
return call_function(w_buf); |
||||
break; |
||||
default: |
||||
return -ENOTTY; |
||||
} |
||||
|
||||
return len; |
||||
} |
||||
|
||||
int xhci_mtk_test_open(struct inode *inode, struct file *file) |
||||
{ |
||||
|
||||
printk(KERN_DEBUG "xhci_mtk_test open: successful\n"); |
||||
return 0; |
||||
} |
||||
|
||||
int xhci_mtk_test_release(struct inode *inode, struct file *file) |
||||
{ |
||||
|
||||
printk(KERN_DEBUG "xhci_mtk_test release: successful\n"); |
||||
return 0; |
||||
} |
||||
|
||||
ssize_t xhci_mtk_test_read(struct file *file, char *buf, size_t count, loff_t *ptr) |
||||
{ |
||||
|
||||
printk(KERN_DEBUG "xhci_mtk_test read: returning zero bytes\n"); |
||||
return 0; |
||||
} |
||||
|
||||
ssize_t xhci_mtk_test_write(struct file *file, const char *buf, size_t count, loff_t * ppos) |
||||
{ |
||||
|
||||
printk(KERN_DEBUG "xhci_mtk_test write: accepting zero bytes\n"); |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,120 @@ |
||||
#ifndef _XHCI_MTK_H |
||||
#define _XHCI_MTK_H |
||||
|
||||
#include <linux/usb.h> |
||||
#include "xhci.h" |
||||
|
||||
#define SSUSB_U3_XHCI_BASE 0xBE1C0000 |
||||
#define SSUSB_U3_MAC_BASE 0xBE1C2400 |
||||
#define SSUSB_U3_SYS_BASE 0xBE1C2600 |
||||
#define SSUSB_U2_SYS_BASE 0xBE1C3400 |
||||
#define SSUB_SIF_SLV_TOP 0xBE1D0000 |
||||
#define SIFSLV_IPPC (SSUB_SIF_SLV_TOP + 0x700) |
||||
|
||||
#define U3_PIPE_LATCH_SEL_ADD SSUSB_U3_MAC_BASE + 0x130 |
||||
#define U3_PIPE_LATCH_TX 0 |
||||
#define U3_PIPE_LATCH_RX 0 |
||||
|
||||
#define U3_UX_EXIT_LFPS_TIMING_PAR 0xa0 |
||||
#define U3_REF_CK_PAR 0xb0 |
||||
#define U3_RX_UX_EXIT_LFPS_REF_OFFSET 8 |
||||
#define U3_RX_UX_EXIT_LFPS_REF 3 |
||||
#define U3_REF_CK_VAL 10 |
||||
|
||||
#define U3_TIMING_PULSE_CTRL 0xb4 |
||||
#define CNT_1US_VALUE 63 //62.5MHz:63, 70MHz:70, 80MHz:80, 100MHz:100, 125MHz:125
|
||||
|
||||
#define USB20_TIMING_PARAMETER 0x40 |
||||
#define TIME_VALUE_1US 63 //62.5MHz:63, 80MHz:80, 100MHz:100, 125MHz:125
|
||||
|
||||
#define LINK_PM_TIMER 0x8 |
||||
#define PM_LC_TIMEOUT_VALUE 3 |
||||
|
||||
#define XHCI_IMOD 0x624 |
||||
#define XHCI_IMOD_MT7621_VALUE 0x10 |
||||
|
||||
#define SSUSB_HDMA_CFG 0x950 |
||||
#define SSUSB_HDMA_CFG_MT7621_VALUE 0x10E0E0C |
||||
|
||||
#define U3_LTSSM_TIMING_PARAMETER3 0x2514 |
||||
#define U3_LTSSM_TIMING_PARAMETER3_VALUE 0x3E8012C |
||||
|
||||
#define U2_PHYD_CR1 0x64 |
||||
|
||||
#define SSUSB_IP_SPAR0 0xC8 |
||||
|
||||
#define SYNC_HS_EOF 0x938 |
||||
#define SYNC_HS_EOF_VALUE 0x201F3 |
||||
|
||||
#define HSCH_CFG1 0x960 |
||||
#define SCH2_FIFO_DEPTH_OFFSET 16 |
||||
|
||||
|
||||
#define SSUSB_IP_PW_CTRL (SIFSLV_IPPC+0x0) |
||||
#define SSUSB_IP_SW_RST (1<<0) |
||||
#define SSUSB_IP_PW_CTRL_1 (SIFSLV_IPPC+0x4) |
||||
#define SSUSB_IP_PDN (1<<0) |
||||
#define SSUSB_U3_CTRL(p) (SIFSLV_IPPC+0x30+(p*0x08)) |
||||
#define SSUSB_U3_PORT_DIS (1<<0) |
||||
#define SSUSB_U3_PORT_PDN (1<<1) |
||||
#define SSUSB_U3_PORT_HOST_SEL (1<<2) |
||||
#define SSUSB_U3_PORT_CKBG_EN (1<<3) |
||||
#define SSUSB_U3_PORT_MAC_RST (1<<4) |
||||
#define SSUSB_U3_PORT_PHYD_RST (1<<5) |
||||
#define SSUSB_U2_CTRL(p) (SIFSLV_IPPC+(0x50)+(p*0x08)) |
||||
#define SSUSB_U2_PORT_DIS (1<<0) |
||||
#define SSUSB_U2_PORT_PDN (1<<1) |
||||
#define SSUSB_U2_PORT_HOST_SEL (1<<2) |
||||
#define SSUSB_U2_PORT_CKBG_EN (1<<3) |
||||
#define SSUSB_U2_PORT_MAC_RST (1<<4) |
||||
#define SSUSB_U2_PORT_PHYD_RST (1<<5) |
||||
#define SSUSB_IP_CAP (SIFSLV_IPPC+0x024) |
||||
|
||||
#define SSUSB_U3_PORT_NUM(p) (p & 0xff) |
||||
#define SSUSB_U2_PORT_NUM(p) ((p>>8) & 0xff) |
||||
|
||||
|
||||
#define XHCI_MTK_TEST_MAJOR 234 |
||||
#define DEVICE_NAME "xhci_mtk_test" |
||||
|
||||
#define CLI_MAGIC 'CLI' |
||||
#define IOCTL_READ _IOR(CLI_MAGIC, 0, int) |
||||
#define IOCTL_WRITE _IOW(CLI_MAGIC, 1, int) |
||||
|
||||
void reinitIP(void); |
||||
void setInitialReg(void); |
||||
void dbg_prb_out(void); |
||||
int call_function(char *buf); |
||||
|
||||
long xhci_mtk_test_unlock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
||||
int xhci_mtk_test_open(struct inode *inode, struct file *file); |
||||
int xhci_mtk_test_release(struct inode *inode, struct file *file); |
||||
ssize_t xhci_mtk_test_read(struct file *file, char *buf, size_t count, loff_t *ptr); |
||||
ssize_t xhci_mtk_test_write(struct file *file, const char *buf, size_t count, loff_t * ppos); |
||||
|
||||
/*
|
||||
mediatek probe out |
||||
*/ |
||||
/************************************************************************************/ |
||||
|
||||
#define SW_PRB_OUT_ADDR (SIFSLV_IPPC+0xc0) |
||||
#define PRB_MODULE_SEL_ADDR (SIFSLV_IPPC+0xbc) |
||||
|
||||
static inline void mtk_probe_init(const u32 byte){ |
||||
__u32 __iomem *ptr = (__u32 __iomem *) PRB_MODULE_SEL_ADDR; |
||||
writel(byte, ptr); |
||||
} |
||||
|
||||
static inline void mtk_probe_out(const u32 value){ |
||||
__u32 __iomem *ptr = (__u32 __iomem *) SW_PRB_OUT_ADDR; |
||||
writel(value, ptr); |
||||
} |
||||
|
||||
static inline u32 mtk_probe_value(void){ |
||||
__u32 __iomem *ptr = (__u32 __iomem *) SW_PRB_OUT_ADDR; |
||||
|
||||
return readl(ptr); |
||||
} |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,862 @@ |
||||
Index: linux-3.10.26/drivers/usb/core/hub.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/core/hub.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/core/hub.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -1259,7 +1259,7 @@
|
||||
if (type != HUB_SUSPEND) {
|
||||
/* Disconnect all the children */
|
||||
for (i = 0; i < hdev->maxchild; ++i) {
|
||||
- if (hub->ports[i]->child)
|
||||
+ if (hub->ports[i] && hub->ports[i]->child)
|
||||
usb_disconnect(&hub->ports[i]->child);
|
||||
}
|
||||
}
|
||||
Index: linux-3.10.26/drivers/usb/core/port.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/core/port.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/core/port.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -193,6 +193,7 @@
|
||||
void usb_hub_remove_port_device(struct usb_hub *hub,
|
||||
int port1)
|
||||
{
|
||||
- device_unregister(&hub->ports[port1 - 1]->dev);
|
||||
+ if (hub->ports[port1 - 1])
|
||||
+ device_unregister(&hub->ports[port1 - 1]->dev);
|
||||
}
|
||||
|
||||
Index: linux-3.10.26/drivers/usb/host/Kconfig
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/Kconfig 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/Kconfig 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -28,7 +28,11 @@
|
||||
if USB_XHCI_HCD
|
||||
|
||||
config USB_XHCI_PLATFORM
|
||||
- tristate
|
||||
+ bool "xHCI platform"
|
||||
+
|
||||
+config USB_MT7621_XHCI_PLATFORM
|
||||
+ bool "MTK MT7621 xHCI"
|
||||
+ depends on USB_XHCI_PLATFORM
|
||||
|
||||
config USB_XHCI_HCD_DEBUGGING
|
||||
bool "Debugging for the xHCI host controller"
|
||||
Index: linux-3.10.26/drivers/usb/host/Makefile
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/Makefile 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/Makefile 2014-01-19 16:30:54.964617843 +0000
|
||||
@@ -13,15 +13,23 @@
|
||||
|
||||
xhci-hcd-y := xhci.o xhci-mem.o
|
||||
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
|
||||
+ifndef CONFIG_USB_MT7621_XHCI_PLATFORM
|
||||
xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
|
||||
+endif
|
||||
+
|
||||
+ifdef CONFIG_USB_MT7621_XHCI_PLATFORM
|
||||
+xhci-hcd-y += mtk-phy.o xhci-mtk-scheduler.o xhci-mtk-power.o xhci-mtk.o mtk-phy-7621.o mtk-phy-ahb.o
|
||||
+endif
|
||||
|
||||
ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
|
||||
- xhci-hcd-y += xhci-plat.o
|
||||
+xhci-hcd-y += xhci-plat.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
+ifndef CONFIG_USB_MT7621_XHCI_PLATFORM
|
||||
obj-$(CONFIG_PCI) += pci-quirks.o
|
||||
+endif
|
||||
|
||||
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
|
||||
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
||||
Index: linux-3.10.26/drivers/usb/host/pci-quirks.h
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/pci-quirks.h 2014-01-19 16:29:17.392615927 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/pci-quirks.h 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __LINUX_USB_PCI_QUIRKS_H
|
||||
#define __LINUX_USB_PCI_QUIRKS_H
|
||||
|
||||
-#ifdef CONFIG_PCI
|
||||
+#if defined (CONFIG_PCI) && !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
|
||||
Index: linux-3.10.26/drivers/usb/host/xhci.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/xhci.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/xhci.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -30,6 +30,16 @@
|
||||
|
||||
#include "xhci.h"
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+#include <asm/uaccess.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include "mtk-phy.h"
|
||||
+#include "xhci-mtk-scheduler.h"
|
||||
+#include "xhci-mtk-power.h"
|
||||
+#include "xhci-mtk.h"
|
||||
+#endif
|
||||
+
|
||||
#define DRIVER_AUTHOR "Sarah Sharp"
|
||||
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
|
||||
|
||||
@@ -38,6 +48,18 @@
|
||||
module_param(link_quirk, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+long xhci_mtk_test_unlock_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
+static struct file_operations xhci_mtk_test_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .read = xhci_mtk_test_read,
|
||||
+ .write = xhci_mtk_test_write,
|
||||
+ .unlocked_ioctl = xhci_mtk_test_unlock_ioctl,
|
||||
+ .open = xhci_mtk_test_open,
|
||||
+ .release = xhci_mtk_test_release,
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
/* TODO: copied from ehci-hcd.c - can this be refactored? */
|
||||
/*
|
||||
* xhci_handshake - spin reading hc until handshake completes or fails
|
||||
@@ -189,7 +211,7 @@
|
||||
return ret;
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_PCI
|
||||
+#if defined (CONFIG_PCI) && !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
static int xhci_free_msi(struct xhci_hcd *xhci)
|
||||
{
|
||||
int i;
|
||||
@@ -386,6 +408,7 @@
|
||||
return ret;
|
||||
}
|
||||
hcd->irq = pdev->irq;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -427,6 +450,11 @@
|
||||
xhci_dbg(xhci, "Attempting compliance mode recovery\n");
|
||||
hcd = xhci->shared_hcd;
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ temp |= (1 << 31);
|
||||
+ xhci_writel(xhci, temp, xhci->usb3_ports[i]);
|
||||
+#endif
|
||||
+
|
||||
if (hcd->state == HC_STATE_SUSPENDED)
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
|
||||
@@ -475,6 +503,9 @@
|
||||
{
|
||||
const char *dmi_product_name, *dmi_sys_vendor;
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ return true;
|
||||
+#endif
|
||||
dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||||
dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
|
||||
if (!dmi_product_name || !dmi_sys_vendor)
|
||||
@@ -518,6 +549,10 @@
|
||||
} else {
|
||||
xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
|
||||
}
|
||||
+
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ mtk_xhci_scheduler_init();
|
||||
+#endif
|
||||
retval = xhci_mem_init(xhci, GFP_KERNEL);
|
||||
xhci_dbg(xhci, "Finished xhci_init\n");
|
||||
|
||||
@@ -661,7 +696,11 @@
|
||||
xhci_dbg(xhci, "// Set the interrupt modulation register\n");
|
||||
temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
|
||||
temp &= ~ER_IRQ_INTERVAL_MASK;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ temp |= (u32) 16;
|
||||
+#else
|
||||
temp |= (u32) 160;
|
||||
+#endif
|
||||
xhci_writel(xhci, temp, &xhci->ir_set->irq_control);
|
||||
|
||||
/* Set the HCD state before we enable the irqs */
|
||||
@@ -682,6 +721,9 @@
|
||||
xhci_queue_vendor_command(xhci, 0, 0, 0,
|
||||
TRB_TYPE(TRB_NEC_GET_FW));
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ enableXhciAllPortPower(xhci);
|
||||
+#endif
|
||||
xhci_dbg(xhci, "Finished xhci_run for USB2 roothub\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -999,7 +1041,6 @@
|
||||
|
||||
/* If restore operation fails, re-initialize the HC during resume */
|
||||
if ((temp & STS_SRE) || hibernated) {
|
||||
-
|
||||
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
|
||||
!(xhci_all_ports_seen_u0(xhci))) {
|
||||
del_timer_sync(&xhci->comp_mode_recovery_timer);
|
||||
@@ -1583,6 +1624,13 @@
|
||||
u32 drop_flag;
|
||||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||
int ret;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+#if MTK_SCH_NEW
|
||||
+ struct sch_ep *sch_ep = NULL;
|
||||
+ int isTT;
|
||||
+ int ep_type;
|
||||
+#endif
|
||||
+#endif
|
||||
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
||||
if (ret <= 0)
|
||||
@@ -1634,6 +1682,40 @@
|
||||
|
||||
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+#if MTK_SCH_NEW
|
||||
+ slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[udev->slot_id]->out_ctx);
|
||||
+ if ((slot_ctx->tt_info & 0xff) > 0) {
|
||||
+ isTT = 1;
|
||||
+ }
|
||||
+ else {
|
||||
+ isTT = 0;
|
||||
+ }
|
||||
+ if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||
+ ep_type = USB_EP_INT;
|
||||
+ }
|
||||
+ else if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
+ ep_type = USB_EP_ISOC;
|
||||
+ }
|
||||
+ else if (usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||
+ ep_type = USB_EP_BULK;
|
||||
+ }
|
||||
+ else
|
||||
+ ep_type = USB_EP_CONTROL;
|
||||
+
|
||||
+ sch_ep = mtk_xhci_scheduler_remove_ep(udev->speed, usb_endpoint_dir_in(&ep->desc)
|
||||
+ , isTT, ep_type, (mtk_u32 *)ep);
|
||||
+ if (sch_ep != NULL) {
|
||||
+ kfree(sch_ep);
|
||||
+ }
|
||||
+ else {
|
||||
+ xhci_dbg(xhci, "[MTK]Doesn't find ep_sch instance when removing endpoint\n");
|
||||
+ }
|
||||
+#else
|
||||
+ mtk_xhci_scheduler_remove_ep(xhci, udev, ep);
|
||||
+#endif
|
||||
+#endif
|
||||
+
|
||||
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
|
||||
(unsigned int) ep->desc.bEndpointAddress,
|
||||
udev->slot_id,
|
||||
@@ -1669,6 +1751,18 @@
|
||||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
int ret = 0;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ struct xhci_ep_ctx *in_ep_ctx;
|
||||
+#if MTK_SCH_NEW
|
||||
+ struct sch_ep *sch_ep;
|
||||
+ int isTT;
|
||||
+ int ep_type;
|
||||
+ int maxp = 0;
|
||||
+ int burst = 0;
|
||||
+ int mult = 0;
|
||||
+ int interval;
|
||||
+#endif
|
||||
+#endif
|
||||
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
||||
if (ret <= 0) {
|
||||
@@ -1731,6 +1825,56 @@
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ in_ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
|
||||
+#if MTK_SCH_NEW
|
||||
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
+ if ((slot_ctx->tt_info & 0xff) > 0) {
|
||||
+ isTT = 1;
|
||||
+ }
|
||||
+ else {
|
||||
+ isTT = 0;
|
||||
+ }
|
||||
+ if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||
+ ep_type = USB_EP_INT;
|
||||
+ }
|
||||
+ else if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
+ ep_type = USB_EP_ISOC;
|
||||
+ }
|
||||
+ else if (usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||
+ ep_type = USB_EP_BULK;
|
||||
+ }
|
||||
+ else
|
||||
+ ep_type = USB_EP_CONTROL;
|
||||
+
|
||||
+ if (udev->speed == USB_SPEED_FULL || udev->speed == USB_SPEED_HIGH
|
||||
+ || udev->speed == USB_SPEED_LOW) {
|
||||
+ maxp = ep->desc.wMaxPacketSize & 0x7FF;
|
||||
+ burst = ep->desc.wMaxPacketSize >> 11;
|
||||
+ mult = 0;
|
||||
+ }
|
||||
+ else if (udev->speed == USB_SPEED_SUPER) {
|
||||
+ maxp = ep->desc.wMaxPacketSize & 0x7FF;
|
||||
+ burst = ep->ss_ep_comp.bMaxBurst;
|
||||
+ mult = ep->ss_ep_comp.bmAttributes & 0x3;
|
||||
+ }
|
||||
+ interval = (1 << ((in_ep_ctx->ep_info >> 16) & 0xff));
|
||||
+ sch_ep = kmalloc(sizeof(struct sch_ep), GFP_KERNEL);
|
||||
+ if (mtk_xhci_scheduler_add_ep(udev->speed, usb_endpoint_dir_in(&ep->desc),
|
||||
+ isTT, ep_type, maxp, interval, burst, mult, (mtk_u32 *)ep
|
||||
+ , (mtk_u32 *)in_ep_ctx, sch_ep) != SCH_SUCCESS) {
|
||||
+ xhci_err(xhci, "[MTK] not enough bandwidth\n");
|
||||
+
|
||||
+ return -ENOSPC;
|
||||
+ }
|
||||
+#else
|
||||
+ if (mtk_xhci_scheduler_add_ep(xhci, udev, ep, in_ep_ctx) != SCH_SUCCESS) {
|
||||
+ xhci_err(xhci, "[MTK] not enough bandwidth\n");
|
||||
+
|
||||
+ return -ENOSPC;
|
||||
+ }
|
||||
+#endif
|
||||
+#endif
|
||||
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
|
||||
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
|
||||
|
||||
@@ -2694,7 +2838,7 @@
|
||||
if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) &&
|
||||
ctrl_ctx->drop_flags == 0)
|
||||
return 0;
|
||||
-
|
||||
+
|
||||
xhci_dbg(xhci, "New Input Control Context:\n");
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
||||
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
|
||||
@@ -4230,10 +4374,14 @@
|
||||
u16 *timeout)
|
||||
{
|
||||
if (state == USB3_LPM_U1) {
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
if (xhci->quirks & XHCI_INTEL_HOST)
|
||||
+#endif
|
||||
return xhci_calculate_intel_u1_timeout(udev, desc);
|
||||
} else {
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
if (xhci->quirks & XHCI_INTEL_HOST)
|
||||
+#endif
|
||||
return xhci_calculate_intel_u2_timeout(udev, desc);
|
||||
}
|
||||
|
||||
@@ -4659,7 +4807,9 @@
|
||||
/* Accept arbitrarily long scatter-gather lists */
|
||||
hcd->self.sg_tablesize = ~0;
|
||||
/* XHCI controllers don't stop the ep queue on short packets :| */
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
hcd->self.no_stop_on_short = 1;
|
||||
+#endif
|
||||
|
||||
if (usb_hcd_is_primary_hcd(hcd)) {
|
||||
xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
|
||||
@@ -4728,6 +4878,10 @@
|
||||
goto error;
|
||||
xhci_dbg(xhci, "Reset complete\n");
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ setInitialReg();
|
||||
+#endif
|
||||
+
|
||||
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
||||
if (HCC_64BIT_ADDR(temp)) {
|
||||
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
|
||||
@@ -4752,8 +4906,21 @@
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+static struct platform_device xhci_platform_dev = {
|
||||
+ .name = "xhci-hcd",
|
||||
+ .id = -1,
|
||||
+ .dev = {
|
||||
+ .coherent_dma_mask = 0xffffffff,
|
||||
+ },
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
static int __init xhci_hcd_init(void)
|
||||
{
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ struct platform_device *pPlatformDev;
|
||||
+#endif
|
||||
int retval;
|
||||
|
||||
retval = xhci_register_pci();
|
||||
@@ -4766,6 +4933,33 @@
|
||||
printk(KERN_DEBUG "Problem registering platform driver.");
|
||||
goto unreg_pci;
|
||||
}
|
||||
+
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ retval = register_chrdev(XHCI_MTK_TEST_MAJOR, DEVICE_NAME, &xhci_mtk_test_fops);
|
||||
+
|
||||
+ u3phy_init();
|
||||
+ if (u3phy_ops->u2_slew_rate_calibration) {
|
||||
+ u3phy_ops->u2_slew_rate_calibration(u3phy);
|
||||
+ u3phy_ops->u2_slew_rate_calibration(u3phy_p1);
|
||||
+ }
|
||||
+ else{
|
||||
+ printk(KERN_ERR "WARN: PHY doesn't implement u2 slew rate calibration function\n");
|
||||
+ }
|
||||
+ u3phy_ops->init(u3phy);
|
||||
+ reinitIP();
|
||||
+
|
||||
+ pPlatformDev = &xhci_platform_dev;
|
||||
+ memset(pPlatformDev, 0, sizeof(struct platform_device));
|
||||
+ pPlatformDev->name = "xhci-hcd";
|
||||
+ pPlatformDev->id = -1;
|
||||
+ pPlatformDev->dev.coherent_dma_mask = 0xffffffff;
|
||||
+ pPlatformDev->dev.dma_mask = &pPlatformDev->dev.coherent_dma_mask;
|
||||
+
|
||||
+ retval = platform_device_register(&xhci_platform_dev);
|
||||
+ if (retval < 0)
|
||||
+ xhci_unregister_plat();
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Check the compiler generated sizes of structures that must be laid
|
||||
* out in specific ways for hardware access.
|
||||
@@ -4783,6 +4977,7 @@
|
||||
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
|
||||
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
|
||||
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
|
||||
+
|
||||
return 0;
|
||||
unreg_pci:
|
||||
xhci_unregister_pci();
|
||||
Index: linux-3.10.26/drivers/usb/host/xhci-dbg.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/xhci-dbg.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/xhci-dbg.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -21,6 +21,9 @@
|
||||
*/
|
||||
|
||||
#include "xhci.h"
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+#include "xhci-mtk.h"
|
||||
+#endif
|
||||
|
||||
#define XHCI_INIT_VALUE 0x0
|
||||
|
||||
Index: linux-3.10.26/drivers/usb/host/xhci.h
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/xhci.h 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/xhci.h 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -29,9 +29,24 @@
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
/* Code sharing between pci-quirks and xhci hcd */
|
||||
-#include "xhci-ext-caps.h"
|
||||
+#include "xhci-ext-caps.h"
|
||||
#include "pci-quirks.h"
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+#define XHC_IRQ (22 + 8)
|
||||
+#define XHC_IO_START 0x1E1C0000
|
||||
+#define XHC_IO_LENGTH 0x10000
|
||||
+/* mtk scheduler bitmasks */
|
||||
+#define BPKTS(p) ((p) & 0x3f)
|
||||
+#define BCSCOUNT(p) (((p) & 0x7) << 8)
|
||||
+#define BBM(p) ((p) << 11)
|
||||
+#define BOFFSET(p) ((p) & 0x3fff)
|
||||
+#define BREPEAT(p) (((p) & 0x7fff) << 16)
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
/* xHCI PCI Configuration Registers */
|
||||
#define XHCI_SBRN_OFFSET (0x60)
|
||||
|
||||
@@ -1536,8 +1551,12 @@
|
||||
/* Compliance Mode Recovery Data */
|
||||
struct timer_list comp_mode_recovery_timer;
|
||||
u32 port_status_u0;
|
||||
+#ifdef CONFIG_USB_MT7621_XHCI_PLATFORM
|
||||
+#define COMP_MODE_RCVRY_MSECS 5000
|
||||
+#else
|
||||
/* Compliance Mode Timer Triggered every 2 seconds */
|
||||
#define COMP_MODE_RCVRY_MSECS 2000
|
||||
+#endif
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
@@ -1703,7 +1722,7 @@
|
||||
void xhci_free_command(struct xhci_hcd *xhci,
|
||||
struct xhci_command *command);
|
||||
|
||||
-#ifdef CONFIG_PCI
|
||||
+#if defined (CONFIG_PCI) && !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
/* xHCI PCI glue */
|
||||
int xhci_register_pci(void);
|
||||
void xhci_unregister_pci(void);
|
||||
Index: linux-3.10.26/drivers/usb/host/xhci-mem.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/xhci-mem.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/xhci-mem.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -65,6 +65,9 @@
|
||||
|
||||
static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
|
||||
{
|
||||
+ if (!seg)
|
||||
+ return;
|
||||
+
|
||||
if (seg->trbs) {
|
||||
dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
|
||||
seg->trbs = NULL;
|
||||
@@ -1446,9 +1449,17 @@
|
||||
max_burst = (usb_endpoint_maxp(&ep->desc)
|
||||
& 0x1800) >> 11;
|
||||
}
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ if ((max_packet % 4 == 2) && (max_packet % 16 != 14) && (max_burst == 0) && usb_endpoint_dir_in(&ep->desc))
|
||||
+ max_packet += 2;
|
||||
+#endif
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ if ((max_packet % 4 == 2) && (max_packet % 16 != 14) && (max_burst == 0) && usb_endpoint_dir_in(&ep->desc))
|
||||
+ max_packet += 2;
|
||||
+#endif
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
Index: linux-3.10.26/drivers/usb/host/xhci-plat.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/xhci-plat.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/xhci-plat.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -25,6 +25,13 @@
|
||||
* dev struct in order to setup MSI
|
||||
*/
|
||||
xhci->quirks |= XHCI_PLAT;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ /* MTK host controller gives a spurious successful event after a
|
||||
+ * short transfer. Ignore it.
|
||||
+ */
|
||||
+ xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
|
||||
+ xhci->quirks |= XHCI_LPM_SUPPORT;
|
||||
+#endif
|
||||
}
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
@@ -96,20 +103,32 @@
|
||||
|
||||
driver = &xhci_plat_xhci_driver;
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ irq = XHC_IRQ;
|
||||
+#else
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
+#endif
|
||||
+
|
||||
if (irq < 0)
|
||||
return -ENODEV;
|
||||
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
+#endif
|
||||
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ hcd->rsrc_start = (uint32_t)XHC_IO_START;
|
||||
+ hcd->rsrc_len = XHC_IO_LENGTH;
|
||||
+#else
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
+#endif
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
|
||||
driver->description)) {
|
||||
Index: linux-3.10.26/drivers/usb/host/xhci-ring.c
|
||||
===================================================================
|
||||
--- linux-3.10.26.orig/drivers/usb/host/xhci-ring.c 2014-01-09 20:25:15.000000000 +0000
|
||||
+++ linux-3.10.26/drivers/usb/host/xhci-ring.c 2014-01-19 16:29:18.548615960 +0000
|
||||
@@ -236,7 +236,6 @@
|
||||
*/
|
||||
if (!chain && !more_trbs_coming)
|
||||
break;
|
||||
-
|
||||
/* If we're not dealing with 0.95 hardware or
|
||||
* isoc rings on AMD 0.96 host,
|
||||
* carry over the chain bit of the previous TRB
|
||||
@@ -273,16 +272,20 @@
|
||||
static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
|
||||
unsigned int num_trbs)
|
||||
{
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
int num_trbs_in_deq_seg;
|
||||
+#endif
|
||||
|
||||
if (ring->num_trbs_free < num_trbs)
|
||||
return 0;
|
||||
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
|
||||
num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
|
||||
if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
|
||||
return 0;
|
||||
}
|
||||
+#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2910,6 +2913,7 @@
|
||||
next = ring->enqueue;
|
||||
|
||||
while (last_trb(xhci, ring, ring->enq_seg, next)) {
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
/* If we're not dealing with 0.95 hardware or isoc rings
|
||||
* on AMD 0.96 host, clear the chain bit.
|
||||
*/
|
||||
@@ -2919,7 +2923,9 @@
|
||||
next->link.control &= cpu_to_le32(~TRB_CHAIN);
|
||||
else
|
||||
next->link.control |= cpu_to_le32(TRB_CHAIN);
|
||||
-
|
||||
+#else
|
||||
+ next->link.control &= cpu_to_le32(~TRB_CHAIN);
|
||||
+#endif
|
||||
wmb();
|
||||
next->link.control ^= cpu_to_le32(TRB_CYCLE);
|
||||
|
||||
@@ -3049,6 +3055,9 @@
|
||||
start_trb->field[3] |= cpu_to_le32(start_cycle);
|
||||
else
|
||||
start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ wmb();
|
||||
+#endif
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
|
||||
}
|
||||
|
||||
@@ -3108,6 +3117,29 @@
|
||||
return (remainder >> 10) << 17;
|
||||
}
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+static u32 mtk_xhci_td_remainder(unsigned int td_transfer_size, unsigned int td_running_total, unsigned int maxp, unsigned trb_buffer_length)
|
||||
+{
|
||||
+ u32 max = 31;
|
||||
+ int remainder, td_packet_count, packet_transferred;
|
||||
+
|
||||
+ //0 for the last TRB
|
||||
+ //FIXME: need to workaround if there is ZLP in this TD
|
||||
+ if (td_running_total + trb_buffer_length == td_transfer_size)
|
||||
+ return 0;
|
||||
+
|
||||
+ //FIXME: need to take care of high-bandwidth (MAX_ESIT)
|
||||
+ packet_transferred = (td_running_total /*+ trb_buffer_length*/) / maxp;
|
||||
+ td_packet_count = DIV_ROUND_UP(td_transfer_size, maxp);
|
||||
+ remainder = td_packet_count - packet_transferred;
|
||||
+
|
||||
+ if (remainder > max)
|
||||
+ return max << 17;
|
||||
+ else
|
||||
+ return remainder << 17;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* For xHCI 1.0 host controllers, TD size is the number of max packet sized
|
||||
* packets remaining in the TD (*not* including this TRB).
|
||||
@@ -3245,6 +3277,7 @@
|
||||
}
|
||||
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
if (xhci->hci_version < 0x100) {
|
||||
remainder = xhci_td_remainder(
|
||||
urb->transfer_buffer_length -
|
||||
@@ -3254,6 +3287,13 @@
|
||||
trb_buff_len, total_packet_count, urb,
|
||||
num_trbs - 1);
|
||||
}
|
||||
+#else
|
||||
+ if (num_trbs > 1)
|
||||
+ remainder = mtk_xhci_td_remainder(urb->transfer_buffer_length,
|
||||
+ running_total, urb->ep->desc.wMaxPacketSize, trb_buff_len);
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
remainder |
|
||||
TRB_INTR_TARGET(0);
|
||||
@@ -3316,6 +3356,9 @@
|
||||
int running_total, trb_buff_len, ret;
|
||||
unsigned int total_packet_count;
|
||||
u64 addr;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ int max_packet;
|
||||
+#endif
|
||||
|
||||
if (urb->num_sgs)
|
||||
return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||
@@ -3341,6 +3384,25 @@
|
||||
running_total += TRB_MAX_BUFF_SIZE;
|
||||
}
|
||||
/* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ switch(urb->dev->speed){
|
||||
+ case USB_SPEED_SUPER:
|
||||
+ max_packet = urb->ep->desc.wMaxPacketSize;
|
||||
+ break;
|
||||
+ case USB_SPEED_HIGH:
|
||||
+ case USB_SPEED_FULL:
|
||||
+ case USB_SPEED_LOW:
|
||||
+ case USB_SPEED_WIRELESS:
|
||||
+ case USB_SPEED_UNKNOWN:
|
||||
+ default:
|
||||
+ max_packet = urb->ep->desc.wMaxPacketSize & 0x7ff;
|
||||
+ break;
|
||||
+ }
|
||||
+ if((urb->transfer_flags & URB_ZERO_PACKET)
|
||||
+ && ((urb->transfer_buffer_length % max_packet) == 0)){
|
||||
+ num_trbs++;
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
ret = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
@@ -3400,6 +3462,7 @@
|
||||
field |= TRB_ISP;
|
||||
|
||||
/* Set the TRB length, TD size, and interrupter fields. */
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
if (xhci->hci_version < 0x100) {
|
||||
remainder = xhci_td_remainder(
|
||||
urb->transfer_buffer_length -
|
||||
@@ -3409,6 +3472,10 @@
|
||||
trb_buff_len, total_packet_count, urb,
|
||||
num_trbs - 1);
|
||||
}
|
||||
+#else
|
||||
+ remainder = mtk_xhci_td_remainder(urb->transfer_buffer_length, running_total, max_packet, trb_buff_len);
|
||||
+#endif
|
||||
+
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
remainder |
|
||||
TRB_INTR_TARGET(0);
|
||||
@@ -3498,7 +3565,11 @@
|
||||
field |= 0x1;
|
||||
|
||||
/* xHCI 1.0 6.4.1.2.1: Transfer Type field */
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ if (1) {
|
||||
+#else
|
||||
if (xhci->hci_version == 0x100) {
|
||||
+#endif
|
||||
if (urb->transfer_buffer_length > 0) {
|
||||
if (setup->bRequestType & USB_DIR_IN)
|
||||
field |= TRB_TX_TYPE(TRB_DATA_IN);
|
||||
@@ -3522,7 +3593,12 @@
|
||||
field = TRB_TYPE(TRB_DATA);
|
||||
|
||||
length_field = TRB_LEN(urb->transfer_buffer_length) |
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
xhci_td_remainder(urb->transfer_buffer_length) |
|
||||
+#else
|
||||
+ //CC: MTK style, no scatter-gather for control transfer
|
||||
+ 0 |
|
||||
+#endif
|
||||
TRB_INTR_TARGET(0);
|
||||
if (urb->transfer_buffer_length > 0) {
|
||||
if (setup->bRequestType & USB_DIR_IN)
|
||||
@@ -3533,7 +3609,7 @@
|
||||
length_field,
|
||||
field | ep_ring->cycle_state);
|
||||
}
|
||||
-
|
||||
+
|
||||
/* Save the DMA address of the last TRB in the TD */
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
|
||||
@@ -3645,6 +3721,9 @@
|
||||
u64 start_addr, addr;
|
||||
int i, j;
|
||||
bool more_trbs_coming;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ int max_packet;
|
||||
+#endif
|
||||
|
||||
ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
|
||||
|
||||
@@ -3658,6 +3737,21 @@
|
||||
start_trb = &ep_ring->enqueue->generic;
|
||||
start_cycle = ep_ring->cycle_state;
|
||||
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ switch(urb->dev->speed){
|
||||
+ case USB_SPEED_SUPER:
|
||||
+ max_packet = urb->ep->desc.wMaxPacketSize;
|
||||
+ break;
|
||||
+ case USB_SPEED_HIGH:
|
||||
+ case USB_SPEED_FULL:
|
||||
+ case USB_SPEED_LOW:
|
||||
+ case USB_SPEED_WIRELESS:
|
||||
+ case USB_SPEED_UNKNOWN:
|
||||
+ max_packet = urb->ep->desc.wMaxPacketSize & 0x7ff;
|
||||
+ break;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
urb_priv = urb->hcpriv;
|
||||
/* Queue the first TRB, even if it's zero-length */
|
||||
for (i = 0; i < num_tds; i++) {
|
||||
@@ -3729,9 +3823,13 @@
|
||||
} else {
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
field |= TRB_IOC;
|
||||
+#if defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
+ if (!(xhci->quirks & XHCI_AVOID_BEI)) {
|
||||
+#else
|
||||
if (xhci->hci_version == 0x100 &&
|
||||
!(xhci->quirks &
|
||||
XHCI_AVOID_BEI)) {
|
||||
+#endif
|
||||
/* Set BEI bit except for the last td */
|
||||
if (i < num_tds - 1)
|
||||
field |= TRB_BEI;
|
||||
@@ -3746,6 +3844,7 @@
|
||||
trb_buff_len = td_remain_len;
|
||||
|
||||
/* Set the TRB length, TD size, & interrupter fields. */
|
||||
+#if !defined (CONFIG_USB_MT7621_XHCI_PLATFORM)
|
||||
if (xhci->hci_version < 0x100) {
|
||||
remainder = xhci_td_remainder(
|
||||
td_len - running_total);
|
||||
@@ -3755,6 +3854,10 @@
|
||||
total_packet_count, urb,
|
||||
(trbs_per_td - j - 1));
|
||||
}
|
||||
+#else
|
||||
+ remainder = mtk_xhci_td_remainder(urb->transfer_buffer_length, running_total, max_packet, trb_buff_len);
|
||||
+#endif
|
||||
+
|
||||
length_field = TRB_LEN(trb_buff_len) |
|
||||
remainder |
|
||||
TRB_INTR_TARGET(0);
|
Loading…
Reference in new issue