kernel_samsung_a34x-permissive/drivers/misc/mediatek/mu3phy/mt6768/mtk-phy-asic.c

1458 lines
42 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "mtk-phy.h"
#ifdef CONFIG_PROJECT_PHY
/*#include <mach/mt_pm_ldo.h>*/
#include <linux/clk.h>
#include <linux/io.h>
#include "mtk-phy-asic.h"
#include "mu3d_hal_osal.h"
#ifdef CONFIG_MTK_UART_USB_SWITCH
#include "mu3d_hal_usb_drv.h"
#endif
#include <mt-plat/upmu_common.h>
/* k414 FIXME */
//#include "mtk_spm_resource_req.h"
//#include "mtk_idle.h"
#//include "mtk_clk_id.h"
#include "musb_core.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/regulator/consumer.h>
#include <mt-plat/mtk_chip.h>
#include "mtk_devinfo.h"
static int usb20_phy_rev6;
static struct clk *ssusb_clk;
static struct clk *sys_ck;
static DEFINE_SPINLOCK(mu3phy_clock_lock);
bool sib_mode;
static struct regulator *reg_vusb;
static struct regulator *reg_va09;
enum VA09_OP {
VA09_OP_OFF = 0,
VA09_OP_ON,
};
static void VA09_operation(int op, bool force)
{
int ret = 0;
static bool on;
/* only musb_speed or force could pass it */
if (!musb_speed && !force)
return;
if (!reg_va09)
return;
if (op == VA09_OP_ON && !on) {
ret = regulator_enable(reg_va09);
if (ret < 0) {
pr_notice("regulator_enable va09 failed: %d\n", ret);
return;
}
on = true;
} else if (op == VA09_OP_OFF && on) {
ret = regulator_disable(reg_va09);
if (ret < 0) {
pr_notice("regulator_enable va09 failed: %d\n", ret);
return;
}
on = false;
}
}
static int dpidle_status = USB_DPIDLE_ALLOWED;
/* k414 FIXME */
//static DEFINE_SPINLOCK(usb_hal_dpidle_lock);
#define DPIDLE_TIMER_INTERVAL_MS 30
static void issue_dpidle_timer(void);
static void dpidle_timer_wakeup_func(unsigned long data)
{
struct timer_list *timer = (struct timer_list *)data;
{
static DEFINE_RATELIMIT_STATE(ratelimit, 1 * HZ, 1);
static int skip_cnt;
if (__ratelimit(&ratelimit)) {
os_printk(K_INFO, "dpidle_timer<%p> alive, skip_cnt<%d>\n", timer, skip_cnt);
skip_cnt = 0;
} else
skip_cnt++;
}
os_printk(K_DEBUG, "dpidle_timer<%p> alive...\n", timer);
if (dpidle_status == USB_DPIDLE_TIMER)
issue_dpidle_timer();
kfree(timer);
}
static void issue_dpidle_timer(void)
{
struct timer_list *timer;
timer = kzalloc(sizeof(struct timer_list), GFP_ATOMIC);
if (!timer)
return;
os_printk(K_DEBUG, "add dpidle_timer<%p>\n", timer);
init_timer(timer);
timer->function = dpidle_timer_wakeup_func;
timer->data = (unsigned long)timer;
timer->expires = jiffies + msecs_to_jiffies(DPIDLE_TIMER_INTERVAL_MS);
add_timer(timer);
}
void usb_hal_dpidle_request(int mode)
{
/* k414 FIXME */
#if 0
unsigned long flags;
#ifdef U3_COMPLIANCE
os_printk(K_INFO, "%s, U3_COMPLIANCE, fake to USB_DPIDLE_FORBIDDEN\n", __func__);
mode = USB_DPIDLE_FORBIDDEN;
#endif
spin_lock_irqsave(&usb_hal_dpidle_lock, flags);
/* update dpidle_status */
dpidle_status = mode;
switch (mode) {
case USB_DPIDLE_ALLOWED:
spm_resource_req(SPM_RESOURCE_USER_SSUSB, SPM_RESOURCE_RELEASE);
os_printk(K_INFO, "USB_DPIDLE_ALLOWED\n");
break;
case USB_DPIDLE_FORBIDDEN:
spm_resource_req(SPM_RESOURCE_USER_SSUSB, SPM_RESOURCE_ALL);
{
static DEFINE_RATELIMIT_STATE(ratelimit, 1 * HZ, 3);
if (__ratelimit(&ratelimit))
os_printk(K_INFO, "USB_DPIDLE_FORBIDDEN\n");
}
break;
case USB_DPIDLE_SRAM:
spm_resource_req(SPM_RESOURCE_USER_SSUSB,
SPM_RESOURCE_CK_26M | SPM_RESOURCE_MAINPLL);
{
static DEFINE_RATELIMIT_STATE(ratelimit, 1 * HZ, 3);
static int skip_cnt;
if (__ratelimit(&ratelimit)) {
os_printk(K_INFO, "USB_DPIDLE_SRAM, skip_cnt<%d>\n", skip_cnt);
skip_cnt = 0;
} else
skip_cnt++;
}
break;
case USB_DPIDLE_TIMER:
spm_resource_req(SPM_RESOURCE_USER_SSUSB,
SPM_RESOURCE_CK_26M | SPM_RESOURCE_MAINPLL);
os_printk(K_INFO, "USB_DPIDLE_TIMER\n");
issue_dpidle_timer();
break;
default:
os_printk(K_WARNIN, "[ERROR] Are you kidding!?!?\n");
break;
}
spin_unlock_irqrestore(&usb_hal_dpidle_lock, flags);
#endif
}
static bool usb_enable_clock(bool enable)
{
static int count;
unsigned long flags;
if (!ssusb_clk || IS_ERR(ssusb_clk)) {
pr_notice("clock not ready, ssusb_clk:%p", ssusb_clk);
return -1;
}
if (!sys_ck || IS_ERR(sys_ck)) {
pr_notice("clock not ready, sys_ck:%p", sys_ck);
return -1;
}
spin_lock_irqsave(&mu3phy_clock_lock, flags);
os_printk(K_INFO, "CG, enable<%d>, count<%d>\n", enable, count);
if (enable && count == 0) {
usb_hal_dpidle_request(USB_DPIDLE_FORBIDDEN);
if (clk_enable(ssusb_clk) != 0)
pr_notice("ssusb_ref_clk enable fail\n");
if (clk_enable(sys_ck) != 0)
pr_notice("sys_ck enable fail\n");
} else if (!enable && count == 1) {
clk_disable(ssusb_clk);
clk_disable(sys_ck);
usb_hal_dpidle_request(USB_DPIDLE_ALLOWED);
}
if (enable)
count++;
else
count = (count == 0) ? 0 : (count - 1);
spin_unlock_irqrestore(&mu3phy_clock_lock, flags);
return 0;
}
void usb20_pll_settings(bool host, bool forceOn)
{
}
void usb20_rev6_setting(int value, bool is_update)
{
if (is_update)
usb20_phy_rev6 = value;
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_PHY_REV_6_OFST,
RG_USB20_PHY_REV_6, value);
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
bool in_uart_mode;
void uart_usb_switch_dump_register(void)
{
/* f_fusb30_ck:125MHz */
usb_enable_clock(true);
udelay(250);
# ifdef CONFIG_MTK_FPGA
pr_debug("[MUSB]addr: 0x6B, value: %x\n",
USB_PHY_Read_Register8((phys_addr_t) (uintptr_t)U3D_U2PHYDTM0 + 0x3));
pr_debug("[MUSB]addr: 0x6E, value: %x\n",
USB_PHY_Read_Register8((phys_addr_t) (uintptr_t)U3D_U2PHYDTM1 + 0x2));
pr_debug("[MUSB]addr: 0x22, value: %x\n",
USB_PHY_Read_Register8((phys_addr_t) (uintptr_t)U3D_U2PHYACR4 + 0x2));
pr_debug("[MUSB]addr: 0x68, value: %x\n",
USB_PHY_Read_Register8((phys_addr_t) (uintptr_t)U3D_U2PHYDTM0));
pr_debug("[MUSB]addr: 0x6A, value: %x\n",
USB_PHY_Read_Register8((phys_addr_t) (uintptr_t)U3D_U2PHYDTM0 + 0x2));
pr_debug("[MUSB]addr: 0x1A, value: %x\n",
USB_PHY_Read_Register8((phys_addr_t) (uintptr_t)U3D_U2PHYACR6 + 0x2));
#else
#if 0
os_printk(K_INFO, "[MUSB]addr: 0x6B, value: %x\n", U3PhyReadReg8(U3D_U2PHYDTM0 + 0x3));
os_printk(K_INFO, "[MUSB]addr: 0x6E, value: %x\n", U3PhyReadReg8(U3D_U2PHYDTM1 + 0x2));
os_printk(K_INFO, "[MUSB]addr: 0x22, value: %x\n", U3PhyReadReg8(U3D_U2PHYACR4 + 0x2));
os_printk(K_INFO, "[MUSB]addr: 0x68, value: %x\n", U3PhyReadReg8(U3D_U2PHYDTM0));
os_printk(K_INFO, "[MUSB]addr: 0x6A, value: %x\n", U3PhyReadReg8(U3D_U2PHYDTM0 + 0x2));
os_printk(K_INFO, "[MUSB]addr: 0x1A, value: %x\n", U3PhyReadReg8(U3D_USBPHYACR6 + 0x2));
#else
os_printk(K_INFO, "[MUSB]addr: 0x18, value: 0x%x\n",
U3PhyReadReg32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6));
os_printk(K_INFO, "[MUSB]addr: 0x20, value: 0x%x\n",
U3PhyReadReg32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4));
os_printk(K_INFO, "[MUSB]addr: 0x68, value: 0x%x\n",
U3PhyReadReg32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0));
os_printk(K_INFO, "[MUSB]addr: 0x6C, value: 0x%x\n",
U3PhyReadReg32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1));
#endif
#endif
/* f_fusb30_ck:125MHz */
usb_enable_clock(false);
/*os_printk(K_INFO, "[MUSB]addr: 0x110020B0 (UART0), value: %x\n\n", */
/* DRV_Reg8(ap_uart0_base + 0xB0)); */
}
bool usb_phy_check_in_uart_mode(void)
{
PHY_INT32 usb_port_mode;
/* f_fusb30_ck:125MHz */
usb_enable_clock(true);
udelay(250);
usb_port_mode = U3PhyReadReg32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0) >> RG_UART_MODE_OFST;
/* f_fusb30_ck:125MHz */
usb_enable_clock(false);
os_printk(K_INFO, "%s+ usb_port_mode = %d\n", __func__, usb_port_mode);
if (usb_port_mode == 0x1)
return true;
else
return false;
}
void usb_phy_switch_to_uart(void)
{
if (usb_phy_check_in_uart_mode()) {
os_printk(K_INFO, "%s+ UART_MODE\n", __func__);
return;
}
os_printk(K_INFO, "%s+ USB_MODE\n", __func__);
VA09_operation(VA09_OP_ON, false);
/* f_fusb30_ck:125MHz */
usb_enable_clock(true);
udelay(250);
/* RG_USB20_BC11_SW_EN = 1'b0 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_BC11_SW_EN_OFST,
RG_USB20_BC11_SW_EN, 0);
/* RG_SUSPENDM to 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_SUSPENDM_OFST, RG_SUSPENDM, 1);
/* force suspendm = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_SUSPENDM_OFST, FORCE_SUSPENDM, 1);
/* rg_uart_mode = 2'b01 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_UART_MODE_OFST, RG_UART_MODE, 1);
/* force_uart_i = 1'b0 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_I_OFST, FORCE_UART_I, 0);
/* force_uart_bias_en = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_BIAS_EN_OFST, FORCE_UART_BIAS_EN, 1);
/* force_uart_tx_oe = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_TX_OE_OFST, FORCE_UART_TX_OE, 1);
/* force_uart_en = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_EN_OFST, FORCE_UART_EN, 1);
/* RG_UART_BIAS_EN = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_BIAS_EN_OFST, RG_UART_BIAS_EN, 1);
/* RG_UART_TX_OE = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_TX_OE_OFST, RG_UART_TX_OE, 1);
/* RG_UART_EN = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_EN_OFST, RG_UART_EN, 1);
/* RG_USB20_DM_100K_EN = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_DM_100K_EN_OFST,
RG_USB20_DM_100K_EN, 1);
/* force_linestate = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, FORCE_LINESTATE_OFST, FORCE_LINESTATE, 1);
/* RG_LINESTATE = 2'b01 (J State) */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_LINESTATE_OFST, RG_LINESTATE, 0x1);
/* f_fusb30_ck:125MHz */
usb_enable_clock(false);
/* SET USB to UART GPIO to UART0 */
DRV_WriteReg32(ap_uart0_base + 0x6E0, (DRV_Reg32(ap_uart0_base + 0x6E0) | (1<<20)));
in_uart_mode = true;
}
void usb_phy_switch_to_usb(void)
{
in_uart_mode = false;
/* force_uart_i = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_I_OFST, FORCE_UART_I, 1);
/* force_uart_en = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_EN_OFST, FORCE_UART_EN, 1);
/* RG_UART_EN = 1'b0 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_EN_OFST, RG_UART_EN, 0);
/* RG_USB20_DM_100K_EN = 1'b0 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_DM_100K_EN_OFST,
RG_USB20_DM_100K_EN, 0);
/* rg_uart_mode = 2'b00 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_UART_MODE_OFST, RG_UART_MODE, 0);
/* force_dp_pulldown 1'b0 */
/* U3D_U2PHYDTM0 FORCE_DP_PULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DP_PULLDOWN_OFST, FORCE_DP_PULLDOWN,
0);
/* force_dm_pulldown 1'b0 */
/* U3D_U2PHYDTM0 FORCE_DM_PULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DM_PULLDOWN_OFST, FORCE_DM_PULLDOWN,
0);
/* force_xcversel 1'b0 */
/* U3D_U2PHYDTM0 FORCE_XCVRSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_XCVRSEL_OFST, FORCE_XCVRSEL, 0);
/* force_termsel 1'b0 */
/* U3D_U2PHYDTM0 FORCE_TERMSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_TERMSEL_OFST, FORCE_TERMSEL, 0);
/* force_datain 1'b0 */
/* U3D_U2PHYDTM0 FORCE_DATAIN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DATAIN_OFST, FORCE_DATAIN, 0);
/* force_linestate = 1'b0 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, FORCE_LINESTATE_OFST, FORCE_LINESTATE, 0);
/* CLEAR USB to UART GPIO to UART0 */
DRV_WriteReg32(ap_uart0_base + 0x6E0, (DRV_Reg32(ap_uart0_base + 0x6E0) & ~(1<<20)));
phy_init_soc(u3phy);
/* f_fusb30_ck:125MHz */
usb_enable_clock(false);
}
#endif
#ifdef CONFIG_U3_PHY_SMT_LOOP_BACK_SUPPORT
#define USB30_PHYD_PIPE0 (SSUSB_SIFSLV_U3PHYD_BASE+0x40)
#define USB30_PHYD_RX0 (SSUSB_SIFSLV_U3PHYD_BASE+0x2c)
#define USB30_PHYD_MIX0 (SSUSB_SIFSLV_U3PHYD_BASE+0x0)
#define USB30_PHYD_T2RLB (SSUSB_SIFSLV_U3PHYD_BASE+0x30)
bool u3_loop_back_test(void)
{
int reg;
bool loop_back_ret = false;
VA09_operation(VA09_OP_ON, true);
usb_enable_clock(true);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG1, RG_SSUSB_VUSB09_ON_OFST,
RG_SSUSB_VUSB09_ON, 1);
/*SSUSB_IP_SW_RST = 0*/
writel(readl(U3D_SSUSB_IP_PW_CTRL0)&~(SSUSB_IP_SW_RST), U3D_SSUSB_IP_PW_CTRL0);
/*SSUSB_IP_HOST_PDN = 0*/
writel(readl(U3D_SSUSB_IP_PW_CTRL1)&~(SSUSB_IP_HOST_PDN), U3D_SSUSB_IP_PW_CTRL1);
/*SSUSB_IP_DEV_PDN = 0*/
writel(readl(U3D_SSUSB_IP_PW_CTRL2)&~(SSUSB_IP_DEV_PDN), U3D_SSUSB_IP_PW_CTRL2);
/*SSUSB_IP_PCIE_PDN = 0*/
writel(readl(U3D_SSUSB_IP_PW_CTRL3)&~(SSUSB_IP_PCIE_PDN), U3D_SSUSB_IP_PW_CTRL3);
/*SSUSB_U3_PORT_DIS/SSUSB_U3_PORT_PDN = 0*/
writel(readl(U3D_SSUSB_U3_CTRL_0P)&~(SSUSB_IP_PCIE_PDN | SSUSB_U3_PORT_PDN),
U3D_SSUSB_U3_CTRL_0P);
mdelay(10);
writel((readl(USB30_PHYD_PIPE0)&~(0x01<<30))|0x01<<30,
USB30_PHYD_PIPE0);
writel((readl(USB30_PHYD_PIPE0)&~(0x01<<28))|0x00<<28,
USB30_PHYD_PIPE0);
writel((readl(USB30_PHYD_PIPE0)&~(0x03<<26))|0x01<<26,
USB30_PHYD_PIPE0);
writel((readl(USB30_PHYD_PIPE0)&~(0x03<<24))|0x00<<24,
USB30_PHYD_PIPE0);
writel((readl(USB30_PHYD_PIPE0)&~(0x01<<22))|0x00<<22,
USB30_PHYD_PIPE0);
writel((readl(USB30_PHYD_PIPE0)&~(0x01<<21))|0x00<<21,
USB30_PHYD_PIPE0);
writel((readl(USB30_PHYD_PIPE0)&~(0x01<<20))|0x01<<20,
USB30_PHYD_PIPE0);
mdelay(10);
/*T2R loop back disable*/
writel((readl(USB30_PHYD_RX0)&~(0x01<<15))|0x00<<15,
USB30_PHYD_RX0);
mdelay(10);
/* TSEQ lock detect threshold */
writel((readl(USB30_PHYD_MIX0)&~(0x07<<24))|0x07<<24,
USB30_PHYD_MIX0);
/* set default TSEQ polarity check value = 1 */
writel((readl(USB30_PHYD_MIX0)&~(0x01<<28))|0x01<<28,
USB30_PHYD_MIX0);
/* TSEQ polarity check enable */
writel((readl(USB30_PHYD_MIX0)&~(0x01<<29))|0x01<<29,
USB30_PHYD_MIX0);
/* TSEQ decoder enable */
writel((readl(USB30_PHYD_MIX0)&~(0x01<<30))|0x01<<30,
USB30_PHYD_MIX0);
mdelay(10);
/* set T2R loop back TSEQ length (x 16us) */
writel((readl(USB30_PHYD_T2RLB)&~(0xff<<0))|0xF0<<0,
USB30_PHYD_T2RLB);
/* set T2R loop back BDAT reset period (x 16us) */
writel((readl(USB30_PHYD_T2RLB)&~(0x0f<<12))|0x0F<<12,
USB30_PHYD_T2RLB);
/* T2R loop back pattern select */
writel((readl(USB30_PHYD_T2RLB)&~(0x03<<8))|0x00<<8,
USB30_PHYD_T2RLB);
mdelay(10);
/* T2R loop back serial mode */
writel((readl(USB30_PHYD_RX0)&~(0x01<<13))|0x01<<13,
USB30_PHYD_RX0);
/* T2R loop back parallel mode = 0 */
writel((readl(USB30_PHYD_RX0)&~(0x01<<12))|0x00<<12,
USB30_PHYD_RX0);
/* T2R loop back mode enable */
writel((readl(USB30_PHYD_RX0)&~(0x01<<11))|0x01<<11,
USB30_PHYD_RX0);
/* T2R loop back enable */
writel((readl(USB30_PHYD_RX0)&~(0x01<<15))|0x01<<15,
USB30_PHYD_RX0);
mdelay(100);
reg = U3PhyReadReg32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_U3PHYD_BASE+0xb4));
os_printk(K_INFO, "read back : 0x%x\n", reg);
os_printk(K_INFO, "read back t2rlb_lock : %d\n", (reg>>2)&0x01);
os_printk(K_INFO, "read back t2rlb_pass : %d\n", (reg>>3)&0x01);
os_printk(K_INFO, "read back t2rlb_passth: %d\n", (reg>>4)&0x01);
if ((reg&0x0E) == 0x0E)
loop_back_ret = true;
else
loop_back_ret = false;
return loop_back_ret;
}
#endif
#ifdef CONFIG_MTK_SIB_USB_SWITCH
#include <linux/wakelock.h>
static struct wake_lock sib_wakelock;
void usb_phy_sib_enable_switch(bool enable)
{
static int inited;
if (!inited) {
os_printk(K_INFO, "%s wake_lock_init\n", __func__);
wake_lock_init(&sib_wakelock, WAKE_LOCK_SUSPEND, "SIB.lock");
inited = 1;
}
VA09_operation(VA09_OP_ON, true);
usb_enable_clock(true);
udelay(250);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG1, RG_SSUSB_VUSB09_ON_OFST,
RG_SSUSB_VUSB09_ON, 1);
/* SSUSB_IP_SW_RST = 0 */
U3PhyWriteReg32((phys_addr_t) (uintptr_t) (u3_ippc_base + 0x0), 0x00031000);
/* SSUSB_IP_HOST_PDN = 0 */
U3PhyWriteReg32((phys_addr_t) (uintptr_t) (u3_ippc_base + 0x4), 0x00000000);
/* SSUSB_IP_DEV_PDN = 0 */
U3PhyWriteReg32((phys_addr_t) (uintptr_t) (u3_ippc_base + 0x8), 0x00000000);
/* SSUSB_IP_PCIE_PDN = 0 */
U3PhyWriteReg32((phys_addr_t) (uintptr_t) (u3_ippc_base + 0xC), 0x00000000);
/* SSUSB_U3_PORT_DIS/SSUSB_U3_PORT_PDN = 0*/
U3PhyWriteReg32((phys_addr_t) (uintptr_t) (u3_ippc_base + 0x30), 0x0000000C);
/*
* USBMAC mode is 0x62910002 (bit 1)
* MDSIB mode is 0x62910008 (bit 3)
* 0x0629 just likes a signature. Can't be removed.
*/
if (enable) {
U3PhyWriteReg32((phys_addr_t) (uintptr_t) SSUSB_SIFSLV_CHIP_BASE, 0x62910008);
sib_mode = true;
if (!wake_lock_active(&sib_wakelock))
wake_lock(&sib_wakelock);
} else {
U3PhyWriteReg32((phys_addr_t) (uintptr_t) SSUSB_SIFSLV_CHIP_BASE, 0x62910002);
sib_mode = false;
if (wake_lock_active(&sib_wakelock))
wake_unlock(&sib_wakelock);
}
}
bool usb_phy_sib_enable_switch_status(void)
{
int reg;
bool ret;
VA09_operation(VA09_OP_ON, true);
usb_enable_clock(true);
udelay(250);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG1, RG_SSUSB_VUSB09_ON_OFST,
RG_SSUSB_VUSB09_ON, 1);
reg = U3PhyReadReg32((phys_addr_t) (uintptr_t) SSUSB_SIFSLV_CHIP_BASE);
if (reg == 0x62910008)
ret = true;
else
ret = false;
return ret;
}
#endif
#ifdef CONFIG_MTK_USB2JTAG_SUPPORT
int usb2jtag_usb_init(void)
{
struct device_node *node = NULL;
void __iomem *usb3_sif2_base;
u32 temp;
node = of_find_compatible_node(NULL, NULL, "mediatek,usb3");
if (!node) {
pr_notice("[USB2JTAG] map node @ mediatek,usb3 failed\n");
return -1;
}
usb3_sif2_base = of_iomap(node, 2);
if (!usb3_sif2_base) {
pr_notice("[USB2JTAG] iomap usb3_sif2_base failed\n");
return -1;
}
/* rg_usb20_gpio_ctl: bit[9] = 1 */
temp = readl(usb3_sif2_base + 0x320);
writel(temp | (1 << 9), usb3_sif2_base + 0x320);
/* RG_USB20_BC11_SW_EN: bit[23] = 0 */
temp = readl(usb3_sif2_base + 0x318);
writel(temp & ~(1 << 23), usb3_sif2_base + 0x318);
/* RG_USB20_BGR_EN: bit[0] = 1 */
temp = readl(usb3_sif2_base + 0x300);
writel(temp | (1 << 0), usb3_sif2_base + 0x300);
/* rg_sifslv_mac_bandgap_en: bit[17] = 0 */
temp = readl(usb3_sif2_base + 0x308);
writel(temp & ~(1 << 17), usb3_sif2_base + 0x308);
/* wait stable */
mdelay(1);
iounmap(usb3_sif2_base);
return 0;
}
#endif
#define VAL_MAX_WIDTH_2 0x3
#define VAL_MAX_WIDTH_3 0x7
void usb_phy_tuning(void)
{
static bool inited;
static s32 u2_vrt_ref, u2_term_ref, u2_enhance;
static struct device_node *of_node;
if (!inited) {
u2_vrt_ref = u2_term_ref = u2_enhance = -1;
of_node = of_find_compatible_node(NULL, NULL, "mediatek,phy_tuning");
if (of_node) {
/* value won't be updated if property not being found */
of_property_read_u32(of_node, "u2_vrt_ref", (u32 *) &u2_vrt_ref);
of_property_read_u32(of_node, "u2_term_ref", (u32 *) &u2_term_ref);
of_property_read_u32(of_node, "u2_enhance", (u32 *) &u2_enhance);
}
inited = true;
} else if (!of_node)
return;
if (u2_vrt_ref != -1) {
if (u2_vrt_ref <= VAL_MAX_WIDTH_3) {
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR1, RG_USB20_VRT_VREF_SEL_OFST,
RG_USB20_VRT_VREF_SEL, u2_vrt_ref);
}
}
if (u2_term_ref != -1) {
if (u2_term_ref <= VAL_MAX_WIDTH_3) {
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR1, RG_USB20_TERM_VREF_SEL_OFST,
RG_USB20_TERM_VREF_SEL, u2_term_ref);
}
}
if (u2_enhance != -1) {
if (u2_enhance <= VAL_MAX_WIDTH_2) {
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_PHY_REV_6_OFST,
RG_USB20_PHY_REV_6, u2_enhance);
}
}
}
PHY_INT32 phy_init_soc(struct u3phy_info *info)
{
os_printk(K_INFO, "%s+\n", __func__);
/*This power on sequence refers to Sheet .1 of "6593_USB_PORT0_PWR Sequence 20130729.xls" */
VA09_operation(VA09_OP_ON, false);
/* f_fusb30_ck:125MHz */
usb_enable_clock(true);
/*Wait 50 usec */
udelay(250);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG1, RG_SSUSB_VUSB09_ON_OFST,
RG_SSUSB_VUSB09_ON, 1);
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode)
goto reg_done;
#endif
/*switch to USB function. (system register, force ip into usb mode) */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_EN_OFST, FORCE_UART_EN, 0);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_EN_OFST, RG_UART_EN, 0);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_GPIO_CTL_OFST, RG_USB20_GPIO_CTL,
0);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, USB20_GPIO_MODE_OFST, USB20_GPIO_MODE, 0);
/*DP/DM BC1.1 path Disable */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_BC11_SW_EN_OFST,
RG_USB20_BC11_SW_EN, 0);
/*dp_100k disable */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_DP_100K_MODE_OFST,
RG_USB20_DP_100K_MODE, 1);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, USB20_DP_100K_EN_OFST, USB20_DP_100K_EN, 0);
/*dm_100k disable */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_DM_100K_EN_OFST,
RG_USB20_DM_100K_EN, 0);
/*OTG Enable */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_OTG_VBUSCMP_EN_OFST,
RG_USB20_OTG_VBUSCMP_EN, 1);
/*Release force suspendm. (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_SUSPENDM_OFST, FORCE_SUSPENDM, 0);
/*Wait 800 usec */
udelay(800);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, FORCE_VBUSVALID_OFST, FORCE_VBUSVALID, 1);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, FORCE_AVALID_OFST, FORCE_AVALID, 1);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, FORCE_SESSEND_OFST, FORCE_SESSEND, 1);
/* USB PLL Force settings */
usb20_pll_settings(false, false);
#ifdef CONFIG_MTK_UART_USB_SWITCH
reg_done:
#endif
os_printk(K_DEBUG, "%s-\n", __func__);
return PHY_TRUE;
}
PHY_INT32 u2_slew_rate_calibration(struct u3phy_info *info)
{
PHY_INT32 i = 0;
PHY_INT32 fgRet = 0;
PHY_INT32 u4FmOut = 0;
PHY_INT32 u4Tmp = 0;
os_printk(K_DEBUG, "%s\n", __func__);
/* => RG_USB20_HSTX_SRCAL_EN = 1 */
/* enable USB ring oscillator */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR5, RG_USB20_HSTX_SRCAL_EN_OFST,
RG_USB20_HSTX_SRCAL_EN, 1);
/* wait 1us */
udelay(1);
/* => USBPHY base address + 0x110 = 1 */
/* Enable free run clock */
U3PhyWriteField32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE + 0x10)
, RG_FRCK_EN_OFST, RG_FRCK_EN, 0x1);
/* => USBPHY base address + 0x100 = 0x04 */
/* Setting cyclecnt */
U3PhyWriteField32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE)
, RG_CYCLECNT_OFST, RG_CYCLECNT, 0x400);
/* => USBPHY base address + 0x100 = 0x01 */
/* Enable frequency meter */
U3PhyWriteField32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE)
, RG_FREQDET_EN_OFST, RG_FREQDET_EN, 0x1);
/* USB_FM_VLD, should be 1'b1, Read frequency valid */
os_printk(K_DEBUG, "Freq_Valid=(0x%08X)\n",
U3PhyReadReg32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE + 0x10)));
mdelay(1);
/* wait for FM detection done, set 10ms timeout */
for (i = 0; i < 10; i++) {
/* => USBPHY base address + 0x10C = FM_OUT */
/* Read result */
u4FmOut = U3PhyReadReg32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE + 0xC));
os_printk(K_DEBUG, "FM_OUT value: u4FmOut = %d(0x%08X)\n", u4FmOut, u4FmOut);
/* check if FM detection done */
if (u4FmOut != 0) {
fgRet = 0;
os_printk(K_DEBUG, "FM detection done! loop = %d\n", i);
break;
}
fgRet = 1;
mdelay(1);
}
/* => USBPHY base address + 0x100 = 0x00 */
/* Disable Frequency meter */
U3PhyWriteField32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE)
, RG_FREQDET_EN_OFST, RG_FREQDET_EN, 0);
/* => USBPHY base address + 0x110 = 0x00 */
/* Disable free run clock */
U3PhyWriteField32((phys_addr_t) (uintptr_t) (SSUSB_SIFSLV_FM_BASE + 0x10)
, RG_FRCK_EN_OFST, RG_FRCK_EN, 0);
/* RG_USB20_HSTX_SRCTRL[2:0] = (1024/FM_OUT) * reference clock frequency * 0.028 */
if (u4FmOut == 0) {
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR5, RG_USB20_HSTX_SRCTRL_OFST,
RG_USB20_HSTX_SRCTRL, 0x4);
fgRet = 1;
} else {
/* set reg = (1024/FM_OUT) * REF_CK * U2_SR_COEF_E60802 / 1000 (round to the nearest digits) */
/* u4Tmp = (((1024 * REF_CK * U2_SR_COEF_E60802) / u4FmOut) + 500) / 1000; */
u4Tmp = (1024 * REF_CK * U2_SR_COEF_E60802) / (u4FmOut * 1000);
os_printk(K_DEBUG, "SR calibration value u1SrCalVal = %d\n", (PHY_UINT8) u4Tmp);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR5, RG_USB20_HSTX_SRCTRL_OFST,
RG_USB20_HSTX_SRCTRL, u4Tmp);
}
/* => RG_USB20_HSTX_SRCAL_EN = 0 */
/* disable USB ring oscillator */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR5, RG_USB20_HSTX_SRCAL_EN_OFST,
RG_USB20_HSTX_SRCAL_EN, 0);
return fgRet;
}
void usb_phy_savecurrent(unsigned int clk_on)
{
os_printk(K_INFO, "%s clk_on=%d+\n", __func__, clk_on);
if (sib_mode) {
pr_notice("%s sib_mode can't savecurrent\n", __func__);
return;
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode)
goto reg_done;
#endif
/*switch to USB function. (system register, force ip into usb mode) */
/* force_uart_en 1'b0 */
/* U3D_U2PHYDTM0 FORCE_UART_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_EN_OFST, FORCE_UART_EN, 0);
/* RG_UART_EN 1'b0 */
/* U3D_U2PHYDTM1 RG_UART_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_EN_OFST, RG_UART_EN, 0);
/* rg_usb20_gpio_ctl 1'b0 */
/* U3D_U2PHYACR4 RG_USB20_GPIO_CTL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_GPIO_CTL_OFST, RG_USB20_GPIO_CTL,
0);
/* usb20_gpio_mode 1'b0 */
/* U3D_U2PHYACR4 USB20_GPIO_MODE */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, USB20_GPIO_MODE_OFST, USB20_GPIO_MODE, 0);
/*DP/DM BC1.1 path Disable */
/* RG_USB20_BC11_SW_EN 1'b0 */
/* U3D_USBPHYACR6 RG_USB20_BC11_SW_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_BC11_SW_EN_OFST,
RG_USB20_BC11_SW_EN, 0);
/*OTG Disable */
/* RG_USB20_OTG_VBUSCMP_EN 1b0 */
/* U3D_USBPHYACR6 RG_USB20_OTG_VBUSCMP_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_OTG_VBUSCMP_EN_OFST,
RG_USB20_OTG_VBUSCMP_EN, 0);
/*let suspendm=1, enable usb 480MHz pll */
/* RG_SUSPENDM 1'b1 */
/* U3D_U2PHYDTM0 RG_SUSPENDM */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_SUSPENDM_OFST, RG_SUSPENDM, 1);
/*force_suspendm=1 */
/* force_suspendm 1'b1 */
/* U3D_U2PHYDTM0 FORCE_SUSPENDM */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_SUSPENDM_OFST, FORCE_SUSPENDM, 1);
/*Wait USBPLL stable. */
/* Wait 2 ms. */
udelay(2000);
/* RG_DPPULLDOWN 1'b1 */
/* U3D_U2PHYDTM0 RG_DPPULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_DPPULLDOWN_OFST, RG_DPPULLDOWN, 1);
/* RG_DMPULLDOWN 1'b1 */
/* U3D_U2PHYDTM0 RG_DMPULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_DMPULLDOWN_OFST, RG_DMPULLDOWN, 1);
/* RG_XCVRSEL[1:0] 2'b01 */
/* U3D_U2PHYDTM0 RG_XCVRSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_XCVRSEL_OFST, RG_XCVRSEL, 0x1);
/* RG_TERMSEL 1'b1 */
/* U3D_U2PHYDTM0 RG_TERMSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_TERMSEL_OFST, RG_TERMSEL, 1);
/* RG_DATAIN[3:0] 4'b0000 */
/* U3D_U2PHYDTM0 RG_DATAIN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_DATAIN_OFST, RG_DATAIN, 0);
/* force_dp_pulldown 1'b1 */
/* U3D_U2PHYDTM0 FORCE_DP_PULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DP_PULLDOWN_OFST, FORCE_DP_PULLDOWN,
1);
/* force_dm_pulldown 1'b1 */
/* U3D_U2PHYDTM0 FORCE_DM_PULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DM_PULLDOWN_OFST, FORCE_DM_PULLDOWN,
1);
/* force_xcversel 1'b1 */
/* U3D_U2PHYDTM0 FORCE_XCVRSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_XCVRSEL_OFST, FORCE_XCVRSEL, 1);
/* force_termsel 1'b1 */
/* U3D_U2PHYDTM0 FORCE_TERMSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_TERMSEL_OFST, FORCE_TERMSEL, 1);
/* force_datain 1'b1 */
/* U3D_U2PHYDTM0 FORCE_DATAIN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DATAIN_OFST, FORCE_DATAIN, 1);
/* wait 800us */
udelay(800);
/*let suspendm=0, set utmi into analog power down */
/* RG_SUSPENDM 1'b0 */
/* U3D_U2PHYDTM0 RG_SUSPENDM */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_SUSPENDM_OFST, RG_SUSPENDM, 0);
/* wait 1us */
udelay(1);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_VBUSVALID_OFST, RG_VBUSVALID, 0);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_AVALID_OFST, RG_AVALID, 0);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_SESSEND_OFST, RG_SESSEND, 1);
/* USB PLL Force settings */
usb20_pll_settings(false, false);
#ifdef CONFIG_MTK_UART_USB_SWITCH
reg_done:
#endif
/* TODO:
* Turn off internal 48Mhz PLL if there is no other hardware module is
* using the 48Mhz clock -the control register is in clock document
* Turn off SSUSB reference clock (26MHz)
*/
if (clk_on) {
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG1, RG_SSUSB_VUSB09_ON_OFST,
RG_SSUSB_VUSB09_ON, 0);
/* Wait 10 usec. */
udelay(10);
/* f_fusb30_ck:125MHz */
usb_enable_clock(false);
VA09_operation(VA09_OP_OFF, false);
}
os_printk(K_INFO, "%s-\n", __func__);
}
void usb_phy_recover(unsigned int clk_on)
{
os_printk(K_INFO, "%s clk_on=%d+\n", __func__, clk_on);
if (!clk_on) {
VA09_operation(VA09_OP_ON, false);
/* f_fusb30_ck:125MHz */
usb_enable_clock(true);
/* Wait 50 usec. (PHY 3.3v & 1.8v power stable time) */
udelay(250);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG1, RG_SSUSB_VUSB09_ON_OFST,
RG_SSUSB_VUSB09_ON, 1);
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
if (in_uart_mode)
goto reg_done;
#endif
/*switch to USB function. (system register, force ip into usb mode) */
/* force_uart_en 1'b0 */
/* U3D_U2PHYDTM0 FORCE_UART_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_UART_EN_OFST, FORCE_UART_EN, 0);
/* RG_UART_EN 1'b0 */
/* U3D_U2PHYDTM1 RG_UART_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_UART_EN_OFST, RG_UART_EN, 0);
/* rg_usb20_gpio_ctl 1'b0 */
/* U3D_U2PHYACR4 RG_USB20_GPIO_CTL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, RG_USB20_GPIO_CTL_OFST, RG_USB20_GPIO_CTL,
0);
/* usb20_gpio_mode 1'b0 */
/* U3D_U2PHYACR4 USB20_GPIO_MODE */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYACR4, USB20_GPIO_MODE_OFST, USB20_GPIO_MODE, 0);
/*Release force suspendm. (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
/*force_suspendm 1'b0 */
/* U3D_U2PHYDTM0 FORCE_SUSPENDM */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_SUSPENDM_OFST, FORCE_SUSPENDM, 0);
/* RG_DPPULLDOWN 1'b0 */
/* U3D_U2PHYDTM0 RG_DPPULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_DPPULLDOWN_OFST, RG_DPPULLDOWN, 0);
/* RG_DMPULLDOWN 1'b0 */
/* U3D_U2PHYDTM0 RG_DMPULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_DMPULLDOWN_OFST, RG_DMPULLDOWN, 0);
/* RG_XCVRSEL[1:0] 2'b00 */
/* U3D_U2PHYDTM0 RG_XCVRSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_XCVRSEL_OFST, RG_XCVRSEL, 0);
/* RG_TERMSEL 1'b0 */
/* U3D_U2PHYDTM0 RG_TERMSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_TERMSEL_OFST, RG_TERMSEL, 0);
/* RG_DATAIN[3:0] 4'b0000 */
/* U3D_U2PHYDTM0 RG_DATAIN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, RG_DATAIN_OFST, RG_DATAIN, 0);
/* force_dp_pulldown 1'b0 */
/* U3D_U2PHYDTM0 FORCE_DP_PULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DP_PULLDOWN_OFST, FORCE_DP_PULLDOWN,
0);
/* force_dm_pulldown 1'b0 */
/* U3D_U2PHYDTM0 FORCE_DM_PULLDOWN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DM_PULLDOWN_OFST, FORCE_DM_PULLDOWN,
0);
/* force_xcversel 1'b0 */
/* U3D_U2PHYDTM0 FORCE_XCVRSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_XCVRSEL_OFST, FORCE_XCVRSEL, 0);
/* force_termsel 1'b0 */
/* U3D_U2PHYDTM0 FORCE_TERMSEL */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_TERMSEL_OFST, FORCE_TERMSEL, 0);
/* force_datain 1'b0 */
/* U3D_U2PHYDTM0 FORCE_DATAIN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM0, FORCE_DATAIN_OFST, FORCE_DATAIN, 0);
/*DP/DM BC1.1 path Disable */
/* RG_USB20_BC11_SW_EN 1'b0 */
/* U3D_USBPHYACR6 RG_USB20_BC11_SW_EN */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_BC11_SW_EN_OFST,
RG_USB20_BC11_SW_EN, 0);
/*OTG Enable */
/* RG_USB20_OTG_VBUSCMP_EN 1b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_OTG_VBUSCMP_EN_OFST,
RG_USB20_OTG_VBUSCMP_EN, 1);
/* Wait 800 usec */
udelay(800);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_VBUSVALID_OFST, RG_VBUSVALID, 1);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_AVALID_OFST, RG_AVALID, 1);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_U2PHYDTM1, RG_SESSEND_OFST, RG_SESSEND, 0);
/* EFUSE related sequence */
{
u32 evalue;
/* [4:0] => RG_USB20_INTR_CAL[4:0] */
evalue = (get_devinfo_with_index(108) & (0x1f<<0)) >> 0;
if (evalue) {
os_printk(K_INFO, "apply efuse setting, RG_USB20_INTR_CAL=0x%x\n", evalue);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR1, RG_USB20_INTR_CAL_OFST,
RG_USB20_INTR_CAL, evalue);
} else
os_printk(K_DEBUG, "!evalue\n");
/* [21:16] (BGR_code) => RG_SSUSB_IEXT_INTR_CTRL[5:0] */
evalue = (get_devinfo_with_index(107) & (0x3f << 16)) >> 16;
if (evalue) {
os_printk(K_INFO, "apply efuse setting, RG_SSUSB_IEXT_INTR_CTRL=0x%x\n", evalue);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USB30_PHYA_REG0, 10,
(0x3f<<10), evalue);
} else
os_printk(K_DEBUG, "!evalue\n");
/* [12:8] (RX_50_code) => RG_SSUSB_IEXT_RX_IMPSEL[4:0] */
evalue = (get_devinfo_with_index(107) & (0x1f << 8)) >> 8;
if (evalue) {
os_printk(K_INFO, "apply efuse setting, rg_ssusb_rx_impsel=0x%x\n", evalue);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_PHYD_IMPCAL1, RG_SSUSB_RX_IMPSEL_OFST,
RG_SSUSB_RX_IMPSEL, evalue);
} else
os_printk(K_DEBUG, "!evalue\n");
/* [4:0] (TX_50_code) => RG_SSUSB_IEXT_TX_IMPSEL[4:0], don't care : 0-bit */
evalue = (get_devinfo_with_index(107) & (0x1f << 0)) >> 0;
if (evalue) {
os_printk(K_INFO, "apply efuse setting, rg_ssusb_tx_impsel=0x%x\n", evalue);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_PHYD_IMPCAL0, RG_SSUSB_TX_IMPSEL_OFST,
RG_SSUSB_TX_IMPSEL, evalue);
} else
os_printk(K_DEBUG, "!evalue\n");
}
/* For host, disconnect threshold */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_DISCTH_OFST, RG_USB20_DISCTH, 0xF);
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_PHY_REV_6_OFST,
RG_USB20_PHY_REV_6, usb20_phy_rev6);
#ifdef MTK_USB_PHY_TUNING
mtk_usb_phy_tuning();
#endif
usb_phy_tuning();
/* USB PLL Force settings */
usb20_pll_settings(false, false);
/* special request from DE */
{
u32 val, offset;
/* RG_SSUSB_TX_EIDLE_CM, 0x11F40B20[31:28], 4'b1000, ssusb_USB30_PHYA_regmap_T12FF_TPHY */
val = 0x8;
offset = 0x20;
U3PhyWriteField32((phys_addr_t) (uintptr_t) ((u3_sif2_base + 0xb00) + offset), 28,
(0xf<<28), val);
/* rg_ssusb_cdr_bir_ltr, 0x11F4095C[20:16] 5'b01101, ssusb_USB30_PHYD_regmap_T12FF_TPHY */
val = 0xd;
offset = 0x5c;
U3PhyWriteField32((phys_addr_t) (uintptr_t) ((u3_sif2_base + 0x900) + offset), 16,
(0x1f<<16), val);
}
#ifdef CONFIG_MTK_UART_USB_SWITCH
reg_done:
#endif
os_printk(K_INFO, "%s-\n", __func__);
}
/*
* This function is to solve the condition described below.
* The system boot has 3 situations.
* 1. Booting without cable, so connection work called by musb_gadget_start()
* would turn off pwr/clk by musb_stop(). [REF CNT = 0]
* 2. Booting with normal cable, the pwr/clk has already turned on at initial stage.
* and also set the flag (musb->is_clk_on=1).
* So musb_start() would not turn on again. [REF CNT = 1]
* 3. Booting with OTG cable, the pwr/clk would be turned on by host one more time.[REF CNT=2]
* So device should turn off pwr/clk which are turned on during the initial stage.
* However, does _NOT_ touch the PHY registers. So we need this fake function to keep the REF CNT correct.
* NOT FOR TURN OFF PWR/CLK.
*/
void usb_fake_powerdown(unsigned int clk_on)
{
os_printk(K_INFO, "%s clk_on=%d+\n", __func__, clk_on);
if (clk_on) {
/* f_fusb30_ck:125MHz */
usb_enable_clock(false);
}
os_printk(K_INFO, "%s-\n", __func__);
}
#ifdef CONFIG_USBIF_COMPLIANCE
static bool charger_det_en = true;
void Charger_Detect_En(bool enable)
{
charger_det_en = enable;
}
#endif
/* BC1.2 */
void Charger_Detect_Init(void)
{
os_printk(K_INFO, "%s+\n", __func__);
#ifdef U3_COMPLIANCE
os_printk(K_INFO, "%s, U3_COMPLIANCE, SKIP\n", __func__);
return;
#endif
if (mu3d_force_on || !_mu3d_musb) {
os_printk(K_INFO, "%s-, SKIP\n", __func__);
return;
}
#ifdef CONFIG_USBIF_COMPLIANCE
if (charger_det_en == true) {
#endif
/* turn on USB reference clock. */
usb_enable_clock(true);
/* wait 50 usec. */
udelay(250);
/* RG_USB20_BC11_SW_EN = 1'b1 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_BC11_SW_EN_OFST,
RG_USB20_BC11_SW_EN, 1);
udelay(1);
/* 4 14. turn off internal 48Mhz PLL. */
usb_enable_clock(false);
#ifdef CONFIG_USBIF_COMPLIANCE
} else {
os_printk(K_INFO, "%s do not init detection as charger_det_en is false\n",
__func__);
}
#endif
os_printk(K_INFO, "%s-\n", __func__);
}
void Charger_Detect_Release(void)
{
os_printk(K_INFO, "%s+\n", __func__);
#ifdef U3_COMPLIANCE
os_printk(K_INFO, "%s, U3_COMPLIANCE, SKIP\n", __func__);
return;
#endif
if (mu3d_force_on || !_mu3d_musb) {
os_printk(K_INFO, "%s-, SKIP\n", __func__);
return;
}
#ifdef CONFIG_USBIF_COMPLIANCE
if (charger_det_en == true) {
#endif
/* turn on USB reference clock. */
usb_enable_clock(true);
/* wait 50 usec. */
udelay(250);
/* RG_USB20_BC11_SW_EN = 1'b0 */
U3PhyWriteField32((phys_addr_t) (uintptr_t) U3D_USBPHYACR6, RG_USB20_BC11_SW_EN_OFST,
RG_USB20_BC11_SW_EN, 0);
udelay(1);
/* 4 14. turn off internal 48Mhz PLL. */
usb_enable_clock(false);
#ifdef CONFIG_USBIF_COMPLIANCE
} else {
os_printk(K_DEBUG, "%s do not release detection as charger_det_en is false\n",
__func__);
}
#endif
os_printk(K_INFO, "%s-\n", __func__);
}
static int mt_usb_dts_probe(struct platform_device *pdev)
{
int retval = 0;
pr_notice("%s\n", __func__);
/* POWER */
reg_vusb = regulator_get(&pdev->dev, "vusb");
if (!IS_ERR(reg_vusb)) {
retval = regulator_enable(reg_vusb);
if (retval < 0) {
pr_notice("regulator_enable vusb failed: %d\n", retval);
regulator_put(reg_vusb);
}
} else {
pr_notice("regulator_get vusb failed\n");
reg_vusb = NULL;
}
reg_va09 = regulator_get(&pdev->dev, "va09");
if (IS_ERR(reg_va09)) {
pr_notice("regulator_get va09 failed\n");
reg_va09 = NULL;
}
ssusb_clk = devm_clk_get(&pdev->dev, "ssusb_clk");
if (IS_ERR(ssusb_clk)) {
pr_notice("ssusb_clk get ssusb_clk fail\n");
} else {
retval = clk_prepare(ssusb_clk);
if (retval == 0)
pr_debug("ssusb_clk<%p> prepare done\n", ssusb_clk);
else
pr_notice("ssusb_clk prepare fail\n");
}
sys_ck = devm_clk_get(&pdev->dev, "sys_ck");
if (IS_ERR(sys_ck)) {
pr_notice("sys_ck get sys_ck fail\n");
} else {
retval = clk_prepare(sys_ck);
if (retval == 0)
pr_debug("sys_ck<%p> prepare done\n", sys_ck);
else
pr_notice("sys_ck prepare fail\n");
}
usb20_phy_rev6 = 1;
pr_notice("%s, usb20_phy_rev6 to %d\n", __func__, usb20_phy_rev6);
return retval;
}
static int mt_usb_dts_remove(struct platform_device *pdev)
{
if (!IS_ERR(ssusb_clk))
clk_unprepare(ssusb_clk);
if (!IS_ERR(sys_ck))
clk_unprepare(sys_ck);
/* POWER */
if (reg_vusb)
regulator_put(reg_vusb);
if (reg_va09)
regulator_put(reg_va09);
return 0;
}
static const struct of_device_id apusb_of_ids[] = {
{.compatible = "mediatek,usb3_phy",},
{},
};
MODULE_DEVICE_TABLE(of, apusb_of_ids);
static struct platform_driver mt_usb_dts_driver = {
.remove = mt_usb_dts_remove,
.probe = mt_usb_dts_probe,
.driver = {
.name = "mt_dts_mu3phy",
.of_match_table = apusb_of_ids,
},
};
MODULE_DESCRIPTION("mtu3phy MUSB PHY Layer");
MODULE_AUTHOR("MediaTek");
MODULE_LICENSE("GPL v2");
module_platform_driver(mt_usb_dts_driver);
static int usb_ipsleep_irqnum;
static int usb_ipsleep_init;
void mask_ipsleep(void)
{
disable_irq(usb_ipsleep_irqnum);
}
void unmask_ipsleep(void)
{
enable_irq(usb_ipsleep_irqnum);
}
void enable_ipsleep_wakeup(void)
{
if (usb_ipsleep_init)
unmask_ipsleep();
}
void disable_ipsleep_wakeup(void)
{
}
static irqreturn_t musb_ipsleep_eint_isr(int irqnum, void *data)
{
disable_irq_nosync(irqnum);
return IRQ_HANDLED;
}
static int mtk_usb_ipsleep_eint_irq_en(struct platform_device *pdev)
{
int retval = 0;
retval = request_irq(usb_ipsleep_irqnum, musb_ipsleep_eint_isr,
IRQF_TRIGGER_NONE, "usbcd_eint", pdev);
if (retval != 0)
os_printk(K_ERR, "usbcd request_irq fail, ret %d, irqnum %d!!!\n",
retval, usb_ipsleep_irqnum);
else
enable_irq_wake(usb_ipsleep_irqnum);
return retval;
}
static int mt_usb_ipsleep_probe(struct platform_device *pdev)
{
int retval = 0;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
usb_ipsleep_irqnum = irq_of_parse_and_map(node, 0);
if (usb_ipsleep_irqnum < 0)
return -ENODEV;
retval = mtk_usb_ipsleep_eint_irq_en(pdev);
if (retval != 0)
goto irqfail;
usb_ipsleep_init = 1;
irqfail:
os_printk(K_INFO, "mt_usb_ipsleep_probe done\n");
return retval;
}
static int mt_usb_ipsleep_remove(struct platform_device *pdev)
{
free_irq(usb_ipsleep_irqnum, pdev);
return 0;
}
static const struct of_device_id usb_ipsleep_of_match[] = {
{.compatible = "mediatek,usb_ipsleep"},
{},
};
MODULE_DEVICE_TABLE(of, usb_ipsleep_of_match);
static struct platform_driver mt_usb_ipsleep_driver = {
.remove = mt_usb_ipsleep_remove,
.probe = mt_usb_ipsleep_probe,
.driver = {
.name = "usb_ipsleep",
.of_match_table = usb_ipsleep_of_match,
},
};
MODULE_DESCRIPTION("musb ipsleep eint");
MODULE_AUTHOR("MediaTek");
MODULE_LICENSE("GPL v2");
module_platform_driver(mt_usb_ipsleep_driver);
#endif