blob: c3d03387ba17c97eef440cb0ba9d127a9e2c34f4 [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0+
/*
* Meson g12b, revB USB2 PHY driver
*
* Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
* Copyright (C) 2018 BayLibre, SAS
* Author: Neil Armstrong <narmstron@baylibre.com>
*/
#include <common.h>
#include <asm/io.h>
#include <bitfield.h>
#include <dm.h>
#include <errno.h>
#include <generic-phy.h>
#include <regmap.h>
#include <power/regulator.h>
#include <clk.h>
#include <asm/arch/usb.h>
#include <amlogic/cpu_id.h>
#include <linux/compat.h>
#include <linux/ioport.h>
#include <asm-generic/gpio.h>
#define M31_1_RESET_LEVEL_BIT 9
#define M31_0_RESET_LEVEL_BIT 10
#define M31_1_UTMI_RESET_LEVEL_BIT 1
#define M31_0_UTMI_RESET_LEVEL_BIT 2
#define CRG_U3DRD_0_RESET_LEVEL_BIT 6
#define CRG_U3DRD_1_RESET_LEVEL_BIT 5
#define CRG_U2DRD_0_RESET_LEVEL_BIT 3
//#define PHY23_RESET_LEVEL_BIT 2
//#define PHY22_RESET_LEVEL_BIT 3
#define PHY20_RESET_LEVEL_BIT 8
//#define USB_RESET_BIT 4
#define RESET_BASE 0xFE002000
#define M31_SETTING 0x1E30CEB9
#define M31_PHY_DEVICE_SETTING 0x1E30CE89
#define M31_PHY_0_BASE 0XFE074000
#define M31_PHY_1_BASE 0XFE076000
#define USB2_PHY_PLL_OFFSET_40 (0x09400414)
#define USB2_PHY_PLL_OFFSET_44 (0x927E0000)
#define USB2_PHY_PLL_OFFSET_48 (0xac5f69e5)
#define USB2_PHY_PLL_OFFSET_10 (0x80000fff)
#define USB2_PHY_PLL_OFFSET_34 (0x78000)
#define USB2_REVB_PHY_PLL_OFFSET_34 (0x70000)
#define USB2_PHY_PLL_OFFSET_38_CLEAR (0)
#define USB2_PHY_PLL_OFFSET_38_SET (0xe0004)
#define USB2_PHY_PLL_OFFSET_50 (0xfe18)
#define USB2_PHY_PLL_OFFSET_54 (0x2a)
#define TUNING_DISCONNECT_THRESHOLD 0x3C
#define DISCONNECT_THRESHOLD_ENHANCE (0x2)
#define AMLOGIC_CTR_COUNT (0x1)
static int Rev_flag;
struct ctr_info {
struct phy usb_phys[4];
unsigned int phy_count;
};
static struct ctr_info ctr[AMLOGIC_CTR_COUNT];
int get_usbphy_baseinfo(void)
{
struct udevice *bus;
struct uclass *uc;
int ret, i, j = 0;
int count;
ret = uclass_get(UCLASS_USB, &uc);
if (ret)
return ret;
uclass_foreach_dev(bus, uc) {
debug("bus->name=%s, bus->driver->name =%s\n",
bus->name, bus->driver->name);
count = dev_count_phandle_with_args(bus, "phys", "#phy-cells");
debug("usb phy cells=%d\n", count);
if (count <= 0) {
ctr[j].phy_count = 0;
continue;
}
for (i = 0; i < count; i++) {
if (ctr[j].usb_phys[i].dev)
continue;
ret = generic_phy_get_by_index(bus, i, &ctr[j].usb_phys[i]);
if (ret && ret != -ENOENT) {
pr_err("Failed to get USB PHY%d for %s\n",
i, bus->name);
return ret;
}
ret = generic_phy_getinfo(&ctr[j].usb_phys[i]);
if (ret)
return ret;
}
ctr[j].phy_count = count;
j++;
}
return 0;
}
void usb_aml_detect_operation(int argc, char * const argv[])
{
struct phy_aml_usb2_priv *usb2_priv;
struct phy_aml_usb3_priv *usb3_priv;
int ret, i, j;
ret = get_usbphy_baseinfo();
if (ret) {
printf("get usb dts failed\n");
return;
}
for (i = 0; i < AMLOGIC_CTR_COUNT; i++) {
usb2_priv = NULL;
usb3_priv = NULL;
if (ctr[i].usb_phys[0].dev)
usb2_priv = dev_get_priv(ctr[i].usb_phys[0].dev);
if (ctr[i].usb_phys[1].dev)
usb3_priv = dev_get_priv(ctr[i].usb_phys[1].dev);
printf("controller index=%d: phy-cells=%d:\n", i, ctr[i].phy_count);
if (usb3_priv) {
printf("priv->usb3 port num = %d, config addr=0x%08x\n",
usb3_priv->usb3_port_num, usb3_priv->base_addr);
}
if (usb2_priv) {
printf("usb2 phy: config addr = 0x%08x, reset addr=0x%08x\n",
usb2_priv->base_addr, usb2_priv->reset_addr);
printf("usb2 phy: portnum=%d\n", usb2_priv->u2_port_num);
for (j = 0; j < usb2_priv->u2_port_num; j++)
printf("phy%d-addr= 0x%08x\n",
j, usb2_priv->usb_phy2_pll_base_addr[j]);
}
}
printf("PHY version is 0x%02x\n", Rev_flag);
}
static void usb_set_calibration_trim(uint32_t phy2_pll_base)
{
uint32_t cali, value, i;
uint8_t cali_en;
cali = readl(SYSCTRL_SEC_STATUS_REG12);
/*****if cali_en ==0, set 0x10 to the default value: 0x1700****/
cali_en = (cali >> 12) & 0x1;
cali = cali >> 8;
if (cali_en) {
cali = cali & 0xf;
if (cali > 12)
cali = 12;
} else {
cali = 0x7;
}
value = (*(unsigned int *)(unsigned long)((unsigned long)phy2_pll_base + 0x10));
value &= (~0xfff);
for (i = 0; i < cali; i++)
value |= (1 << i);
(*(unsigned int *)(unsigned long)((unsigned long)phy2_pll_base + 0x10)) = value;
printf("0x10 trim value=0x%08x\n", value);
}
void usb_reset(unsigned int reset_addr, int bit)
{
*(unsigned int *)(unsigned long)reset_addr = (1 << bit);
}
static void usb_enable_phy_pll(u32 base_addr)
{
*(unsigned int *)(unsigned long)
RESETCTRL_RESET0_LEVEL |= (1 << PHY20_RESET_LEVEL_BIT);
}
void set_usb_pll(uint32_t phy2_pll_base)
{
int val;
val = USB2_PHY_PLL_OFFSET_40 | USB_PHY2_RESET | USB_PHY2_ENABLE;
writel(val, phy2_pll_base + 0x40);
val = USB2_PHY_PLL_OFFSET_44;
writel(val, phy2_pll_base + 0x44);
val = USB2_PHY_PLL_OFFSET_48;
writel(val, phy2_pll_base + 0x48);
udelay(100);
val = ((USB2_PHY_PLL_OFFSET_40) | (USB_PHY2_ENABLE))
& (~(USB_PHY2_RESET));
writel(val, phy2_pll_base + 0x40);
//(*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x50))
//= USB2_PHY_PLL_OFFSET_50;
writel(USB2_PHY_PLL_OFFSET_50, phy2_pll_base + 0x50);
writel(USB2_PHY_PLL_OFFSET_54, phy2_pll_base + 0x54);
usb_set_calibration_trim(phy2_pll_base);
val = readl(phy2_pll_base + 0x38);
val &= ~0x18000000;
val |= ((DISCONNECT_THRESHOLD_ENHANCE << 27) & 0x18000000);
writel(val, phy2_pll_base + 0x38);
writel(TUNING_DISCONNECT_THRESHOLD, phy2_pll_base + 0xc);
writel(USB2_PHY_PLL_OFFSET_34, phy2_pll_base + 0x34);
debug("tuning_disconnect_threshold=0x%x\n", TUNING_DISCONNECT_THRESHOLD);
}
int usb_save_phy_dev(unsigned int number, struct phy *phy)
{
int i;
for (i = 0; i < AMLOGIC_CTR_COUNT; i++) {
if (!ctr[i].usb_phys[number].dev) {
ctr[i].usb_phys[number].dev = phy->dev;
ctr[i].usb_phys[number].id = phy->id;
} else {
if (ctr[i].usb_phys[number].dev == phy->dev)
break;
}
}
return 0;
}
void power_down_usb3(void)
{
*(unsigned int *)(unsigned long)M31_PHY_0_BASE = M31_SETTING;
*(unsigned int *)(unsigned long)M31_PHY_1_BASE = M31_SETTING;
}
int usb2_phy_init(struct phy *phy)
{
struct phy_aml_usb2_priv *priv = dev_get_priv(phy->dev);
struct u2p_aml_regs *u2p_aml_reg;
u2p_r0_t dev_u2p_r0;
u2p_r1_t dev_u2p_r1;
int i, cnt;
power_down_usb3();
usb_save_phy_dev(0, phy);
usb_enable_phy_pll(priv->base_addr);
udelay(500);
priv->usbphy_reset_bit[1] = PHY20_RESET_LEVEL_BIT;
for (i = 0; i <= priv->u2_port_num; i++) {
u2p_aml_reg = (struct u2p_aml_regs *)
((ulong)(priv->base_addr + i * PHY_REGISTER_SIZE));
dev_u2p_r0.d32 = u2p_aml_reg->u2p_r0;
dev_u2p_r0.b.host_device = 1;
dev_u2p_r0.b.POR = 0;
u2p_aml_reg->u2p_r0 = dev_u2p_r0.d32;
udelay(10);
*(unsigned int *)(unsigned long)priv->reset_addr = (1 << priv->usbphy_reset_bit[i]);
udelay(50);
/* wait for phy ready */
dev_u2p_r1.d32 = u2p_aml_reg->u2p_r1;
cnt = 0;
while ((dev_u2p_r1.b.phy_rdy != 1) && (cnt <= 200)) {
dev_u2p_r1.d32 = u2p_aml_reg->u2p_r1;
/*we wait phy ready max 1ms, common is 100us*/
cnt++;
udelay(5);
}
}
for (i = 0; i < priv->u2_port_num; i++) {
debug("------set usb pll\n");
set_usb_pll(priv->usb_phy2_pll_base_addr[i]);
}
return 0;
}
int usb2_phy_tuning(uint32_t phy2_pll_base, int port)
{
return 0;
}
int m31_phy_init(unsigned int phy_num)
{
if (phy_num == 0) {
*(unsigned int *)(unsigned long)M31_PHY_0_BASE = M31_SETTING;
//udelay(20);
//usb_reset(RESET_BASE, USB_RESET_BIT);
udelay(20);
usb_reset(RESET_BASE, M31_0_RESET_LEVEL_BIT | M31_0_UTMI_RESET_LEVEL_BIT);
udelay(20);
usb_reset(RESET_BASE, CRG_U3DRD_0_RESET_LEVEL_BIT);
udelay(20);
} else if (phy_num == 1) {
*(unsigned int *)(unsigned long)M31_PHY_1_BASE = M31_SETTING;
udelay(20);
usb_reset(RESET_BASE, M31_1_RESET_LEVEL_BIT | M31_1_UTMI_RESET_LEVEL_BIT);
udelay(20);
usb_reset(RESET_BASE, CRG_U3DRD_1_RESET_LEVEL_BIT);
udelay(20);
}
return 0;
}
/**************************************************************/
/* device mode config */
/**************************************************************/
#define M31_PHY_BASE 0xFE074000
#define M31_PHY_SETTING 0x1E30CE89
#define PIPE_CLK_REGS 0xfe00015c
#define PIPE_CLK_GATE_REGS 0xfe03809c
//--------------------------------------------------------------
#define USB_RESET_REGISTER RESETCTRL_RESET0
#define USB_RESET_LEVEL_REGISTER RESETCTRL_RESET0_LEVEL
#define USB_RESET_REGISTER_1 RESETCTRL_RESET1
#define USB_RESET_LEVEL_REGISTER_1 RESETCTRL_RESET1_LEVEL
#define USB30_GENERAL_BIT 21
#define USB30_DRD_BIT 6
#define USB30_UTMI_BIT 2
#define USB30_PCIEPHY_BIT 10
void usb_device_mode_init(int phy_num) {
printf("usb_device_mode_init\n");
unsigned int val;
/*step 1: power on domain, if default is not on*/
/*default is power on*/
/*step 2: usb bus clock*/
/*sys_clk gate*/
setbits_le32(CLKCTRL_SYS_CLK_EN0_REG1, ((1 << 26) | (1 << 27)));
udelay(12);
/*step 3: power on*/
writel((readl(USB_RESET_LEVEL_REGISTER) | ((1 << USB30_DRD_BIT) |
(1 << USB30_UTMI_BIT) | (1 << USB30_PCIEPHY_BIT))), USB_RESET_LEVEL_REGISTER);
udelay(12);
/*step 4: usb controller reset*/
/*bit21: u3drd0 general reset*/
writel((1 << USB30_GENERAL_BIT), USB_RESET_REGISTER_1);
udelay(12);
/*bit2: usb3drd0 utmi reset bit6: usb3drd0 reset bit10: usb30 phy reset*/
writel(((1 << USB30_DRD_BIT) | (1 << USB30_UTMI_BIT) |
(1 << USB30_PCIEPHY_BIT)), USB_RESET_REGISTER);
udelay(12);
/*step 5: m31 phy setting*/
*(unsigned int *)(unsigned long)M31_PHY_BASE = M31_PHY_SETTING;
udelay(50);
/*setp 6: bypass usb3*/
val = readl(M31_PHY_BASE + 0x8);
val |= (0x1830 << 6);
writel(val, M31_PHY_BASE + 0x8);
udelay(12);
val = readl(M31_PHY_BASE + 0xc);
val |= (0xe0 << 3);
writel(val, M31_PHY_BASE + 0xc);
udelay(12);
/*step 7: pipe clk setting*/
writel(0x103, PIPE_CLK_REGS);
udelay(12);
val = readl(PIPE_CLK_GATE_REGS);
val |= (1 << 13);
writel(val, PIPE_CLK_GATE_REGS);
udelay(12);
/*step 8: reset u3drdx0 & M31phy*/
writel(((1 << USB30_DRD_BIT) | (1 << USB30_PCIEPHY_BIT)), USB_RESET_REGISTER);
udelay(12);
}