linuxOS_D21X/source/uboot-2021.10/board/artinchip/d211/usb_device_check.c
2024-11-29 16:13:46 +08:00

153 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022 ArtInChip Technology Co., Ltd
*
* Wu Dehuang
*/
#include <common.h>
#include <command.h>
#include <console.h>
#include <malloc.h>
#include <env.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <asm/arch/usb_detect.h>
#define SYSCFG_USB0_CFG ((void *)0x1800040CUL)
#define USB0_DEV_MODE (0x01)
#define CMU_MOD_AHB0_USB_DEV ((void *)0x1802041CUL)
#define CMU_MOD_AHB0_USB_PHY0 ((void *)0x18020430UL)
#define USB_DEV_CONF ((void *)0x10200200UL)
#define USB_DEV_FUNC ((void *)0x10200204UL)
#define USB_DEV_INTSTS ((void *)0x10200010UL)
#define USB_DEV_INTMSK ((void *)0x10200014UL)
#define USB_DEV_INTSTS_ENUMDNE (0x1U << 13)
#define USB_DEV_INIT ((void *)0x10200004UL)
#define USB_DEV_DIEPMSK ((void *)0x1020020CUL)
#define USB_DEV_DOEPMSK ((void *)0x10200210UL)
#define USB_DEV_DAINT ((void *)0x10200214UL)
#define USB_DEV_DAINTMSK ((void *)0x10200218UL)
#define USB_DEV_SPEED_HIGH 0x00
#define USB_DEV_SPEED_FULL2 0x01
#define USB_DEV_SPEED_LOW 0x10
#define USB_DEV_SPEED_FULL1 0x11
#define USB_DEV_GINTMSK_ENUMDNE (0x1U << 13)
static void usb_dev_init(void)
{
u32 val;
/* USB0 Switch to Device mode */
val = readl(SYSCFG_USB0_CFG);
val |= USB0_DEV_MODE;
writel(0x0, CMU_MOD_AHB0_USB_DEV);
writel(0x0, CMU_MOD_AHB0_USB_PHY0);
udelay(100);
/* Enable Device and Phy
* 1. Enable device and phy's clock
* 2. Delay more than 40us
* 3. Release the reset signal
*/
writel(0x1100, CMU_MOD_AHB0_USB_DEV);
writel(0x1100, CMU_MOD_AHB0_USB_PHY0);
udelay(100);
writel(0x3100, CMU_MOD_AHB0_USB_PHY0);
udelay(1);
writel(0x3100, CMU_MOD_AHB0_USB_DEV);
udelay(1);
val = 0xFFFFFFFF;
writel(val, USB_DEV_INTSTS);
val = readl(USB_DEV_INTMSK);
val |= USB_DEV_GINTMSK_ENUMDNE;
writel(val, USB_DEV_INTMSK);
/*
* Ummask/Enable the global interrupt
*/
val = readl(USB_DEV_INIT);
val |= (0x1U << 9);
writel(val, USB_DEV_INIT);
/* Set DCFG Register bit[1:0], Device Speed to High speed */
val = readl(USB_DEV_CONF);
val &= ~(0x3 << 0);
val |= USB_DEV_SPEED_HIGH;
writel(val, USB_DEV_CONF);
}
void usb_dev_soft_disconnect(void)
{
u32 val;
/* Set Soft Disconnect bit to signal the usb device controller to do a
* soft disconnect.
*
* Bit[1]: Default is 1, disconnect.
*/
val = readl(USB_DEV_FUNC);
val |= (0x1U << 1);
writel(val, USB_DEV_FUNC);
}
static void usb_dev_soft_connect(void)
{
u32 val;
val = readl(USB_DEV_FUNC);
val &= ~(0x1U << 1);
writel(val, USB_DEV_FUNC);
}
static u32 usb_dev_get_intsts(void)
{
u32 val, msk;
val = readl(USB_DEV_INTSTS);
msk = readl(USB_DEV_INTMSK);
return val & msk;
}
/*
* When the USB0 works as device, checking if it is connecting with PC will
* spend about 200ms, it is too long if we just waiting here.
*
* To save the waiting time, we split the checking to 2 parts:
* 1. Initialize it when bus clock is set
* 2. Double check after Linux image is loaded(for Falcon mode)
* 3. If the status is connecting, than force to load u-boot again to force
* run u-boot
*/
void usb_dev_connection_check_start(int id)
{
usb_dev_init();
usb_dev_soft_connect();
}
void usb_dev_connection_check_end(int id)
{
usb_dev_soft_disconnect();
writel(0x0, CMU_MOD_AHB0_USB_DEV);
writel(0x0, CMU_MOD_AHB0_USB_PHY0);
}
int usb_dev_connection_check_status(int id)
{
u32 sts;
int ret = 0;
sts = usb_dev_get_intsts();
if (sts & USB_DEV_INTSTS_ENUMDNE)
ret = 1;
return ret;
}