nt9856x/rtos/BSP/u-boot/drivers/usb/host/xhci-nvtivot.c
2023-03-28 15:07:53 +08:00

458 lines
12 KiB
C
Executable File

/*
* Copyright (c) 2021, Novatek Microelectronics Corp.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <asm/io.h>
#include <errno.h>
#include <usb.h>
#include "xhci.h"
#ifdef CONFIG_DM_USB
#include <dm.h>
#include <fdtdec.h>
#endif
#include <asm/arch/IOAddress.h>
#include <asm/arch/hardware.h>
#include <asm/gpio.h>
#include <asm/nvt-common/nvt_types.h>
#include <asm/nvt-common/nvt_common.h>
#include <linux/libfdt.h>
#define DRV_VERSION "1.00.00"
#ifdef CONFIG_DM_USB
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
struct uboot_xhci_priv {
struct xhci_ctrl ctrl; /* Needed by EHCI */
struct xhci_hccr *hccr;
struct xhci_hcor *hcor;
};
#endif
#define USB3PHY_SETREG(ofs,value) writel((value), (volatile void __iomem *)(IOADDR_USB3CTRL_REG_BASE+0x2000+((ofs)<<2)))
#define USB3PHY_GETREG(ofs) readl((volatile void __iomem *)(IOADDR_USB3CTRL_REG_BASE+0x2000+((ofs)<<2)))
#define USB3U2PHY_SETREG(ofs,value) writel((value), (volatile void __iomem *)(IOADDR_USB3CTRL_REG_BASE+0x1000+((ofs)<<2)))
#define USB3U2PHY_GETREG(ofs) readl((volatile void __iomem *)(IOADDR_USB3CTRL_REG_BASE+0x1000+((ofs)<<2)))
static void nvtim_set_gpio_power(void)
{
/* Enable it after dts parsing ready*/
ulong fdt_addr = nvt_readl((ulong)nvt_shminfo_boot_fdt_addr);
int nodeoffset;
u32 *cell = NULL;
char path[20] = {0};
int gpio_pin, gpio_value, err;
sprintf(path,"/u3hst@2,%lx",(IOADDR_USB3_REG_BASE & 0xFFFFFFFF));
nodeoffset = fdt_path_offset((const void*)fdt_addr, path);
cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "power_gpio", NULL);
if (cell > 0) {
gpio_pin = __be32_to_cpu(cell[0]);
gpio_value = __be32_to_cpu(cell[1]);
#if defined(CONFIG_TARGET_NA51090_A64)
if ((gpio_pin >= J_GPIO(0)) && (gpio_pin <= J_GPIO(4))) {
u32 pinmux_value;
unsigned long tmpval;
sprintf(path,"/top@%lx/misc",(IOADDR_TOP_REG_BASE & 0xFFFFFFFF));
nodeoffset = fdt_path_offset((const void*)fdt_addr, path);
cell = (u32*)fdt_getprop((const void*)fdt_addr, nodeoffset, "pinmux", NULL);
pinmux_value = __be32_to_cpu(cell[0]);
if ((pinmux_value & 0x1) == 0x0) {
tmpval = readl((volatile unsigned long *)(IOADDR_TOP_REG_BASE+0x04));
tmpval &= ~(0x1 << 16);
writel(tmpval, (volatile unsigned long *)(IOADDR_TOP_REG_BASE+0x04));
tmpval = readl((volatile unsigned long *)(IOADDR_TOP_REG_BASE+0xA4));
tmpval |= (0x1 << (gpio_pin & 0xF));
writel(tmpval, (volatile unsigned long *)(IOADDR_TOP_REG_BASE+0xA4));
}
}
#endif
err = gpio_request(gpio_pin, "vbus");
if (err) {
printf("#### failed to request vbus, %d\n", gpio_pin);
return;
}
gpio_direction_output(gpio_pin, gpio_value);
gpio_free(gpio_pin);
}
}
#ifndef CONFIG_DM_USB
/*
* Create the appropriate control structures to manage a new XHCI host
* controller.
*/
int xhci_hcd_init(int index, struct xhci_hccr **ret_hccr,
struct xhci_hcor **ret_hcor)
{
struct xhci_hccr *hccr;
struct xhci_hcor *hcor;
int len;
unsigned long tmpval, temp;
u8 u3_trim_rint_sel=8,u3_trim_swctrl=4, u3_trim_sqsel=4,u3_trim_icdr=0xB;
/* init OTG controller */
/* Enable phy clk*/
tmpval = readl((volatile unsigned long *)IOADDR_CG_REG_BASE);
tmpval |= (0x1<<20);
writel(tmpval, (volatile unsigned long *)IOADDR_CG_REG_BASE);
/* Enable Reset*/
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval &= ~(0x1<<18);
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
tmpval &= ~(0x1<<15);
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
udelay(10);
/* Disable Reset*/
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval |= 0x1<<18;
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
tmpval |= 0x1<<15;
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
/* Release sram shutdown*/
tmpval = readl((volatile unsigned long *)(IOADDR_TOP_REG_BASE+0x1000));
tmpval &= ~(0x1<<7);
writel(tmpval, (volatile unsigned long *)(IOADDR_TOP_REG_BASE+0x1000));
/* Enable clock*/
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x74));
tmpval |= (0x1<<26);
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x74));
mdelay(10);
tmpval = readl((volatile unsigned long *)(IOADDR_USB3CTRL_REG_BASE+0x28));
tmpval = 0x1;
writel(tmpval, (volatile unsigned long *)(IOADDR_USB3CTRL_REG_BASE+0x28));
tmpval = readl((volatile unsigned long *)(IOADDR_USB3CTRL_REG_BASE+0x10));
tmpval &= ~0x2;
tmpval &= ~(0x1 << 11);
tmpval |= (0x1 << 0);
tmpval &= ~((0x7 << 16) | (0x7 << 24) | (0x1 << 4));
tmpval |= ((0x4 << 16) | (0x4 << 24));
writel(tmpval, (volatile unsigned long *)(IOADDR_USB3CTRL_REG_BASE+0x10));
USB3PHY_SETREG(0x0D, 0x01);
{
// UINT16 data=0;
// INT32 result;
// result= efuse_readParamOps(EFUSE_USBC_TRIM_DATA, &data);
// if(result >= 0) {
// u3_trim_swctrl = data&0x7;
// u3_trim_sqsel = (data>>3)&0x7;
// u3_trim_rint_sel = (data>>6)&0x1F;
// }
//usb3_validateTrim();
USB3PHY_SETREG(0x1A0, 0x40+u3_trim_rint_sel);
USB3PHY_SETREG(0x1A3, 0x60);
temp = USB3U2PHY_GETREG(0x06);
temp &= ~(0x7<<1);
temp |= (u3_trim_swctrl<<1);
USB3U2PHY_SETREG(0x06, temp);
temp = USB3U2PHY_GETREG(0x05);
temp &= ~(0x7<<2);
temp |= (u3_trim_sqsel<<2);
USB3U2PHY_SETREG(0x05, temp);
}
/* asd_mode=1 (toggle rate) */
USB3PHY_SETREG(0x198, 0x04);
/* RX_ICTRL's offset = 0 */
USB3PHY_SETREG(0x1BF, 0x40);
/* TX_AMP_CTL=2, TX_DEC_EM_CTL=8 */
USB3PHY_SETREG(0x014, 0x8a);
/* TX_LFPS_AMP_CTL = 1 */
USB3PHY_SETREG(0x034, 0xfc);//default 0xfc
/* PHY Power Mode Change ready reponse time. (3 is 1ms.)(4 is 1.3ms.) */
USB3PHY_SETREG(0x114, 0x0B);
USB3PHY_SETREG(0x152, 0x2E);
USB3PHY_SETREG(0x153, 0x01);
USB3PHY_SETREG(0x1B0, 0xC0);
USB3PHY_SETREG(0x1B1, 0x91);
USB3PHY_SETREG(0x1B2, 0x00);
USB3PHY_SETREG(0x135, 0x88);
USB3PHY_SETREG(0x12A, 0x50);
USB3PHY_SETREG(0x1F0, 0x80);
USB3PHY_SETREG(0x1F5, 0x01|(u3_trim_icdr<<4));//0xB1
USB3PHY_SETREG(0x105, 0x01);
USB3PHY_SETREG(0x056, 0x74);//disconnect level to 0x3
udelay(2);
USB3PHY_SETREG(0x102, 0x20);
udelay(10);
USB3PHY_SETREG(0x102, 0x00);
udelay(300);
USB3PHY_SETREG(0x103, 0x01);
udelay(100);
USB3U2PHY_SETREG(0x51, 0x20);
udelay(2);
USB3U2PHY_SETREG(0x51, 0x00);
udelay(2);
if(1) {
temp = USB3PHY_GETREG(0x011);
temp |= 0x1;
USB3PHY_SETREG(0x011, temp);
temp = USB3PHY_GETREG(0x031);
temp |= 0x1;
USB3PHY_SETREG(0x031, temp);
}
USB3PHY_SETREG(0x029, 0x1);
hccr = (struct xhci_hccr *)IOADDR_USB3_REG_BASE;
len = HC_LENGTH(xhci_readl(&hccr->cr_capbase));
hcor = (struct xhci_hcor *)((unsigned long)hccr + len);
printk("XHCI init hccr 0x%lx and hcor 0x%lx hc_length 0x%x ver %s\n",
(unsigned long)hccr, (unsigned long)hcor, len, DRV_VERSION);
*ret_hccr = hccr;
*ret_hcor = hcor;
nvtim_set_gpio_power();
return 0;
}
/*
* Destroy the appropriate control structures corresponding * to the XHCI host
* controller
*/
void xhci_hcd_stop(int index)
{
}
#else
/*
* Create the appropriate control structures to manage a new XHCI host
* controller.
*/
int dm_xhci_hcd_init(int index, struct xhci_hccr **ret_hccr,
struct xhci_hcor **ret_hcor)
{
struct xhci_hccr *hccr;
struct xhci_hcor *hcor;
int len;
unsigned long tmpval = 0, temp = 0;
u8 u3_trim_rint_sel=8,u3_trim_swctrl=4, u3_trim_sqsel=4,u3_trim_icdr=0xB;
/* init OTG controller */
/* Enable phy clk*/
tmpval = readl((volatile unsigned long *)IOADDR_CG_REG_BASE);
tmpval |= (0x1<<20);
writel(tmpval, (volatile unsigned long *)IOADDR_CG_REG_BASE);
/* Enable Reset*/
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval &= ~(0x1<<18);
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
tmpval &= ~(0x1<<15);
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
udelay(10);
/* Disable Reset*/
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval |= 0x1<<18;
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x98));
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
tmpval |= 0x1<<15;
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x9C));
/* Release sram shutdown*/
tmpval = readl((volatile unsigned long *)(IOADDR_TOP_REG_BASE+0x1000));
tmpval &= ~(0x1<<25);
writel(tmpval, (volatile unsigned long *)(IOADDR_TOP_REG_BASE+0x1000));
/* Enable clock*/
tmpval = readl((volatile unsigned long *)(IOADDR_CG_REG_BASE+0x74));
tmpval |= (0x1<<26);
writel(tmpval, (volatile unsigned long *)(IOADDR_CG_REG_BASE+0x74));
mdelay(10);
tmpval = readl((volatile unsigned long *)(IOADDR_USB3CTRL_REG_BASE+0x10));
tmpval &= ~0x2;
tmpval &= ~(0x1 << 11);
tmpval |= (0x1 << 0);
tmpval &= ~((0x7 << 16) | (0x7 << 24) | (0x1 << 4));
tmpval |= ((0x4 << 16) | (0x4 << 24));
writel(tmpval, (volatile unsigned long *)(IOADDR_USB3CTRL_REG_BASE+0x10));
udelay(100);
USB3PHY_SETREG(0x0D, 0x01);
{
// UINT16 data=0;
// INT32 result;
// result= efuse_readParamOps(EFUSE_USBC_TRIM_DATA, &data);
// if(result >= 0) {
// u3_trim_swctrl = data&0x7;
// u3_trim_sqsel = (data>>3)&0x7;
// u3_trim_rint_sel = (data>>6)&0x1F;
// }
//usb3_validateTrim();
USB3PHY_SETREG(0x1A0, 0x40+u3_trim_rint_sel);
USB3PHY_SETREG(0x1A3, 0x60);
temp = USB3U2PHY_GETREG(0x06);
temp &= ~(0x7<<1);
temp |= (u3_trim_swctrl<<1);
USB3U2PHY_SETREG(0x06, temp);
temp = USB3U2PHY_GETREG(0x05);
temp &= ~(0x7<<2);
temp |= (u3_trim_sqsel<<2);
USB3U2PHY_SETREG(0x05, temp);
}
/* asd_mode=1 (toggle rate) */
USB3PHY_SETREG(0x198, 0x04);
/* RX_ICTRL's offset = 0 */
USB3PHY_SETREG(0x1BF, 0x40);
/* TX_AMP_CTL=2, TX_DEC_EM_CTL=8 */
USB3PHY_SETREG(0x014, 0x8a);
/* TX_LFPS_AMP_CTL = 1 */
USB3PHY_SETREG(0x034, 0xfc);//default 0xfc
/* PHY Power Mode Change ready reponse time. (3 is 1ms.)(4 is 1.3ms.) */
USB3PHY_SETREG(0x114, 0x0B);
USB3PHY_SETREG(0x152, 0x2E);
USB3PHY_SETREG(0x153, 0x01);
USB3PHY_SETREG(0x1B0, 0xC0);
USB3PHY_SETREG(0x1B1, 0x91);
USB3PHY_SETREG(0x1B2, 0x00);
USB3PHY_SETREG(0x135, 0x88);
USB3PHY_SETREG(0x12A, 0x50);
USB3PHY_SETREG(0x1F0, 0x80);
USB3PHY_SETREG(0x1F5, 0x01|(u3_trim_icdr<<4));//0xB1
USB3PHY_SETREG(0x105, 0x01);
USB3PHY_SETREG(0x056, 0x74);//disconnect level to 0x3
udelay(2);
USB3PHY_SETREG(0x102, 0x20);
udelay(10);
USB3PHY_SETREG(0x102, 0x00);
udelay(300);
USB3PHY_SETREG(0x103, 0x01);
udelay(100);
USB3U2PHY_SETREG(0x51, 0x20);
udelay(2);
USB3U2PHY_SETREG(0x51, 0x00);
udelay(2);
if(1) {
temp = USB3PHY_GETREG(0x011);
temp |= 0x1;
USB3PHY_SETREG(0x011, temp);
temp = USB3PHY_GETREG(0x031);
temp |= 0x1;
USB3PHY_SETREG(0x031, temp);
}
USB3PHY_SETREG(0x029, 0x1);
hccr = (struct xhci_hccr *)IOADDR_USB3_REG_BASE;
len = HC_LENGTH(xhci_readl(&hccr->cr_capbase));
hcor = (struct xhci_hcor *)((unsigned long)hccr + len);
printk("XHCI init hccr 0x%lx and hcor 0x%lx hc_length 0x%x ver %s\n",
(unsigned long)hccr, (unsigned long)hcor, len, DRV_VERSION);
*ret_hccr = hccr;
*ret_hcor = hcor;
return 0;
}
static int xhci_usb_probe(struct udevice *dev)
{
struct uboot_xhci_priv *ctx = dev_get_priv(dev);
int ret = 0;
ret = dm_xhci_hcd_init(0 , &ctx->hccr, &ctx->hcor);
if (ret) {
puts("XHCI: failed to initialize controller\n");
return -EINVAL;
}
nvtim_set_gpio_power();
debug("%s hccr 0x%lx and hcor 0x%lx hc_length %ld\n", __func__,
(unsigned long)ctx->hccr, (unsigned long)ctx->hcor,
(unsigned long)HC_LENGTH(xhci_readl(&ctx->hccr->cr_capbase)));
return xhci_register(dev, ctx->hccr, ctx->hcor);
}
static int xhci_usb_remove(struct udevice *dev)
{
int ret;
ret = xhci_deregister(dev);
if (ret)
return ret;
return 0;
}
static const struct udevice_id xhci_usb_ids[] = {
{ .compatible = "nvt,nvt_usb3xhci" },
{ }
};
U_BOOT_DRIVER(usb_xhci) = {
.name = "xhci_nvtivot",
.id = UCLASS_USB,
.of_match = xhci_usb_ids,
.probe = xhci_usb_probe,
.remove = xhci_usb_remove,
.ops = &xhci_usb_ops,
.platdata_auto_alloc_size = sizeof(struct usb_platdata),
.priv_auto_alloc_size = sizeof(struct uboot_xhci_priv),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
#endif