oleavr-rgl-a500-mini-linux-.../drivers/usb/sunxi_usb/usbc/usbc_phy.c

430 lines
10 KiB
C
Raw Permalink Normal View History

2022-05-07 01:01:45 +02:00
/*
* drivers/usb/sunxi_usb/usbc/usbc_phy.c
* (C) Copyright 2010-2015
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* daniel, 2009.10.21
*
* usb common ops.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*/
#include "usbc_i.h"
/*
* define USB PHY controller reg bit
*/
//Common Control Bits for Both PHYs
#define USBC_PHY_PLL_BW 0x03
#define USBC_PHY_RES45_CAL_EN 0x0c
//Private Control Bits for Each PHY
#define USBC_PHY_TX_AMPLITUDE_TUNE 0x20
#define USBC_PHY_TX_SLEWRATE_TUNE 0x22
#define USBC_PHY_VBUSVALID_TH_SEL 0x25
#define USBC_PHY_PULLUP_RES_SEL 0x27
#define USBC_PHY_OTG_FUNC_EN 0x28
#define USBC_PHY_VBUS_DET_EN 0x29
#define USBC_PHY_DISCON_TH_SEL 0x2a
#if 0
/*
*
* read out one bit of USB PHY register
*/
static __u32 __USBC_PHY_REG_READ(void __iomem *usbc_base_addr, __u32 usbc_phy_reg_addr)
{
__u32 reg_val = 0;
__u32 i = 0;
USBC_Writeb(usbc_phy_reg_addr, USBC_REG_PHYCTL(USBC0_REGS_BASE) + 1);
for(i=0; i<0x4; i++);
reg_val = USBC_Readb(USBC_REG_PHYCTL(USBC0_REGS_BASE) + 2);
if (usbc_base_addr == USBC0_REGS_BASE)
return (reg_val & 0x1);
else
return ((reg_val >> 1) & 0x1);
}
/*
*
* Write one bit of USB PHY register
*/
static void __USBC_PHY_REG_WRITE(void __iomem *usbc_base_addr, __u32 usbc_phy_reg_addr, __u32 usbc_phy_reg_data)
{
__u32 reg_val = 0;
USBC_Writeb(usbc_phy_reg_addr, USBC_REG_PHYCTL(USBC0_REGS_BASE) + 1);
reg_val = USBC_Readb(USBC_REG_PHYCTL(USBC0_REGS_BASE));
reg_val &= ~(0x1 << 7);
reg_val |= (usbc_phy_reg_data & 0x1) << 7;
if (usbc_base_addr == USBC0_REGS_BASE) {
reg_val &= ~0x1;
USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE));
reg_val |= 0x1;
USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE));
reg_val &= ~0x1;
USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE));
} else {
reg_val &= ~0x2;
USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE));
reg_val |= 0x2;
USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE));
reg_val &= ~0x2;
USBC_Writeb(reg_val, USBC_REG_PHYCTL(USBC0_REGS_BASE));
}
}
/*
* Set USB PLL BandWidth, val = 0~3, defualt = 0x2
*/
/*
static void __USBC_PHY_SET_PLL_BW(__u32 val)
{
__USBC_PHY_REG_WRITE(USBC0_REGS_BASE, USBC_PHY_PLL_BW, val);
__USBC_PHY_REG_WRITE(USBC0_REGS_BASE, USBC_PHY_PLL_BW + 1, val >> 1);
}
*/
/*
* Enable/Disable USB res45 Calibration, val = 0--Disable1--Enable, default = 0
*/
static void __USBC_PHY_RES45_CALIBRATION_ENABLE(__u32 val)
{
__USBC_PHY_REG_WRITE(USBC0_REGS_BASE, USBC_PHY_RES45_CAL_EN, val);
}
/*
* Set USB TX Signal Amplitude, val = 0~3, default = 0x0
*/
static void __USBC_PHY_SET_TX_AMPLITUDE(void __iomem* usbc_base_addr, __u32 val)
{
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_TX_AMPLITUDE_TUNE, val);
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_TX_AMPLITUDE_TUNE + 1, val >> 1);
}
/*
* Set USB TX Signal Slew Rate, val = 0~7, default = 0x5
*/
static void __USBC_PHY_SET_TX_SLEWRATE(void __iomem* usbc_base_addr, __u32 val)
{
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_TX_SLEWRATE_TUNE, val);
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_TX_SLEWRATE_TUNE + 1, val >> 1);
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_TX_SLEWRATE_TUNE + 2, val >> 2);
}
/*
* Set USB VBUS Valid Threshold, val = 0~3, default = 2
*/
/*
static void __USBC_PHY_SET_VBUS_VALID_THRESHOLD(void __iomem* usbc_base_addr, __u32 val)
{
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_VBUSVALID_TH_SEL, val);
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_VBUSVALID_TH_SEL + 1, val >> 1);
}
*/
/*
* Enable/Diasble USB OTG Function, val = 0--Disable1--Enable, default = 1
*/
/*
static void __USBC_PHY_OTG_FUNC_ENABLE(void __iomem* usbc_base_addr, __u32 val)
{
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_OTG_FUNC_EN, val);
}
*/
/*
* Enable/Diasble USB VBUS Detect Function, val = 0--Disable1--Enable, default = 1
*/
/*
static void __USBC_PHY_VBUS_DET_ENABLE(void __iomem* usbc_base_addr, __u32 val)
{
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_VBUS_DET_EN, val);
}
*/
/*
* Set USB Disconnect Detect Threshold, val = 0~3, default = 1
*/
static void __USBC_PHY_SET_DISCON_DET_THRESHOLD(void __iomem* usbc_base_addr, __u32 val)
{
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_DISCON_TH_SEL, val);
__USBC_PHY_REG_WRITE(usbc_base_addr, USBC_PHY_DISCON_TH_SEL + 1, val >> 1);
}
#endif
/* usb PHY common set, initialize */
void USBC_PHY_SetCommonConfig(void)
{
//__USBC_PHY_RES45_CALIBRATION_ENABLE(1);
}
/* usb PHY specific set
* @hUSB: handle returned by USBC_open_otg, include some key data that the USBC need.
*
*/
void USBC_PHY_SetPrivateConfig(__hdle hUSB)
{
//__usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB;
//
//if (usbc_otg == NULL) {
// return ;
//}
//
//USBC_REG_set_bit_l(0, USBC_REG_PHYTUNE(usbc_otg->base_addr));
//USBC_REG_set_bit_l(7, USBC_REG_PHYTUNE(usbc_otg->base_addr));
//USBC_REG_set_bit_l(6, USBC_REG_PHYTUNE(usbc_otg->base_addr));
//USBC_REG_set_bit_l(5, USBC_REG_PHYTUNE(usbc_otg->base_addr));
//USBC_REG_set_bit_l(4, USBC_REG_PHYTUNE(usbc_otg->base_addr));
////__USBC_PHY_SET_TX_AMPLITUDE(usbc_otg->base_addr, 2);
////__USBC_PHY_SET_TX_SLEWRATE(usbc_otg->base_addr, 6);
////__USBC_PHY_SET_DISCON_DET_THRESHOLD(usbc_otg->base_addr, 3);
}
/* get PHY's common setting. for debug, to see if PHY is set correctly.
*
* return the 32bit usb PHY common setting value.
*/
__u32 USBC_PHY_GetCommonConfig(void)
{
__u32 reg_val = 0;
/*
__u32 i = 0;
reg_val = 0;
for(i=0; i<0x20; i++)
{
reg_val = reg_val << 1;
reg_val |= __USBC_PHY_REG_READ(USBC0_REGS_BASE, (0x1f - i)) & 0x1;
}
*/
return reg_val;
}
/* write usb PHY0's phy reg setting. mainly for phy0 standby.
*
* return the data wrote
*/
static __u32 usb_phy0_write(__u32 addr, __u32 data, __u32 dmask, void __iomem *usbc_base_addr)
{
__u32 i=0;
data = data & 0x0f;
addr = addr & 0x0f;
dmask = dmask & 0x0f;
USBC_Writeb((dmask<<4)|data, usbc_base_addr + 0x404 + 2);
USBC_Writeb(addr|0x10, usbc_base_addr + 0x404);
for(i=0;i<5;i++);
USBC_Writeb(addr|0x30, usbc_base_addr + 0x404);
for(i=0;i<5;i++);
USBC_Writeb(addr|0x10, usbc_base_addr + 0x404);
for(i=0;i<5;i++);
return (USBC_Readb(usbc_base_addr + 0x404 + 3) & 0x0f);
}
/* Standby the usb phy with the input usb phy index number
* @phy_index: usb phy index number, which used to select the phy to standby
*
*/
void USBC_phy_Standby(__hdle hUSB, __u32 phy_index)
{
__usbc_otg_t *usbc_otg = (__usbc_otg_t *)hUSB;
if (phy_index == 0) {
usb_phy0_write(0xB, 0x8, 0xf, usbc_otg->base_addr);
usb_phy0_write(0x7, 0xf, 0xf, usbc_otg->base_addr);
usb_phy0_write(0x1, 0xf, 0xf, usbc_otg->base_addr);
usb_phy0_write(0x2, 0xf, 0xf, usbc_otg->base_addr);
}
return;
}
/* Recover the standby phy with the input index number
* @phy_index: usb phy index number
*
*/
void USBC_Phy_Standby_Recover(__hdle hUSB, __u32 phy_index)
{
__u32 i;
if (phy_index == 0) {
for(i=0; i<0x10; i++);
}
return;
}
#if 0
static __u32 USBC_Phy_TpRead(__u32 usbc_no, __u32 addr, __u32 len)
{
void __iomem *otgc_base = NULL;
void __iomem *phyctl_val = NULL;
__u32 temp = 0, ret = 0;
__u32 i=0;
__u32 j=0;
otgc_base = get_otgc_vbase();
if(otgc_base == NULL){
return 0;
}
phyctl_val = otgc_base + USBPHYC_REG_o_PHYCTL;
for(j = len; j > 0; j--)
{
/* set the bit address to be read */
temp = USBC_Readl(phyctl_val);
temp &= ~(0xff << 8);
temp |= ((addr + j -1) << 8);
USBC_Writel(temp, phyctl_val);
for(i = 0; i < 0x4; i++);
temp = USBC_Readl(phyctl_val);
ret <<= 1;
ret |= ((temp >> (16 + usbc_no)) & 0x1);
}
return ret;
}
#endif
static __u32 USBC_Phy_TpWrite(__u32 usbc_no, __u32 addr, __u32 data, __u32 len)
{
void __iomem *otgc_base = NULL;
void __iomem *phyctl_val = NULL;
__u32 temp = 0, dtmp = 0;
__u32 j=0;
otgc_base = get_otgc_vbase();
if(otgc_base == NULL){
return 0;
}
phyctl_val = otgc_base + USBPHYC_REG_o_PHYCTL;
dtmp = data;
for(j = 0; j < len; j++)
{
/* set the bit address to be write */
temp = USBC_Readl(phyctl_val);
temp &= ~(0xff << 8);
temp |= ((addr + j) << 8);
USBC_Writel(temp, phyctl_val);
temp = USBC_Readb(phyctl_val);
temp &= ~(0x1 << 7);
temp |= (dtmp & 0x1) << 7;
temp &= ~(0x1 << (usbc_no << 1));
USBC_Writeb(temp, phyctl_val);
temp = USBC_Readb(phyctl_val);
temp |= (0x1 << (usbc_no << 1));
USBC_Writeb( temp, phyctl_val);
temp = USBC_Readb(phyctl_val);
temp &= ~(0x1 << (usbc_no <<1 ));
USBC_Writeb(temp, phyctl_val);
dtmp >>= 1;
}
return data;
}
#if 0
static __u32 USBC_Phy_Read(__u32 usbc_no, __u32 addr, __u32 len)
{
return USBC_Phy_TpRead(usbc_no, addr, len);
}
#endif
static __u32 USBC_Phy_Write(__u32 usbc_no, __u32 addr, __u32 data, __u32 len)
{
return USBC_Phy_TpWrite(usbc_no, addr, data, len);
}
void UsbPhyCtl(void __iomem *regs)
{
__u32 reg_val = 0;
reg_val = USBC_Readl(regs + USBPHYC_REG_o_PHYCTL);
reg_val |= (0x01 << USBC_PHY_CTL_VBUSVLDEXT);
USBC_Writel(reg_val, (regs + USBPHYC_REG_o_PHYCTL));
return;
}
void USBC_PHY_Set_Ctl(void __iomem *regs, __u32 mask)
{
__u32 reg_val = 0;
reg_val = USBC_Readl(regs + USBPHYC_REG_o_PHYCTL);
reg_val |= (0x01 << mask);
USBC_Writel(reg_val, (regs + USBPHYC_REG_o_PHYCTL));
return;
}
void USBC_PHY_Clear_Ctl(void __iomem *regs, __u32 mask)
{
__u32 reg_val = 0;
reg_val = USBC_Readl(regs + USBPHYC_REG_o_PHYCTL);
reg_val &= ~(0x01 << mask);
USBC_Writel(reg_val, (regs + USBPHYC_REG_o_PHYCTL));
return;
}
void UsbPhyInit(__u32 usbc_no)
{
/* adjust the 45 ohm resistor */
if (usbc_no == 0) {
USBC_Phy_Write(usbc_no, 0x0c, 0x01, 1);
}
/* adjust USB0 PHY range and rate */
USBC_Phy_Write(usbc_no, 0x20, 0x14, 5);
/* adjust disconnect threshold */
USBC_Phy_Write(usbc_no, 0x2a, 3, 2);
/*by wangjx*/
return;
}
void UsbPhyEndReset(__u32 usbc_no)
{
int i;
if (usbc_no == 0) {
//Disable Sequelch Detect for a while before Release USB Reset
USBC_Phy_Write(usbc_no, 0x3c, 0x2, 2);
for(i=0; i<0x100; i++);
USBC_Phy_Write(usbc_no, 0x3c, 0x0, 2);
}
return;
}
void usb_otg_phy_txtune(void __iomem *regs)
{
__u32 reg_val = 0;
reg_val = USBC_Readl(regs + USBC_REG_o_PHYTUNE);
reg_val |= 0x03 << 2; /* TXRESTUNE */
reg_val &= ~(0xf << 8);
reg_val |= 0xc << 8; /* TXVREFTUNE */
USBC_Writel(reg_val, (regs + USBC_REG_o_PHYTUNE));
}