| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Meson g12a,g12b etc 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 <regmap.h> |
| #include <power/regulator.h> |
| #include <clk.h> |
| #include <asm/arch/usb.h> |
| #include <asm/arch/cpu_id.h> |
| |
| |
| #include <linux/compat.h> |
| #include <linux/ioport.h> |
| |
| #define RESET_COMPLETE_TIME 500 |
| |
| static int usb_get_priv_data (struct phy *phy){ |
| struct phy_aml_usb2_priv *priv = dev_get_priv(phy->dev); |
| unsigned int dwc2_reg, u2portnum = 0; |
| int ret, i; |
| |
| priv->reset_addr = dev_read_addr_index(phy->dev, 1); |
| if (priv->reset_addr == FDT_ADDR_T_NONE) { |
| pr_err("Coun't get usb_phy2_pll_base_addr[%d]\n", i); |
| return -1; |
| } |
| *(volatile unsigned long *)(uintptr_t)priv->reset_addr |= (1<<2); |
| |
| dev_read_u32(phy->dev, "portnum", &u2portnum); |
| priv->u2_port_num = u2portnum; |
| |
| ret = dev_read_u32(phy->dev, "dwc2_a_reg", &dwc2_reg); |
| if (ret) { |
| pr_err("Coun't get dwc2_a_reg!!!!\n"); |
| return -1; |
| } |
| priv->dwc2_a_addr = dwc2_reg; |
| |
| priv->usb_phy2_pll_base_addr[1] = dev_read_addr_index(phy->dev, 3); |
| if (priv->usb_phy2_pll_base_addr[1] == FDT_ADDR_T_NONE) { |
| pr_err("Coun't get usb_phy2_pll_base_addr[%d]\n", i); |
| return -1; |
| } |
| priv->base_addr = dev_read_addr(phy->dev); |
| |
| debug("usb2 phy: portnum=%d, addr1= 0x%08x, addr2= 0x%08x\n", |
| u2portnum, priv->usb_phy2_pll_base_addr[0], |
| priv->usb_phy2_pll_base_addr[1]); |
| debug("dwc2_a base addr: 0x%08x\n", priv->dwc2_a_addr); |
| |
| return 0; |
| |
| } |
| |
| static int phy_aml_usb2_getinfo(struct phy *phy) |
| { |
| return usb_get_priv_data(phy); |
| } |
| |
| static int phy_aml_usb2_phy_init(struct phy *phy) |
| { |
| int ret = -1; |
| ret = usb_get_priv_data(phy); |
| if (ret !=0) |
| return ret; |
| |
| return usb2_phy_init(phy); |
| } |
| |
| static int phy_aml_usb2_tuning(struct phy *phy, int port) { |
| struct phy_aml_usb2_priv *priv = dev_get_priv(phy->dev); |
| unsigned long phy_reg_base; |
| |
| phy_reg_base = priv->usb_phy2_pll_base_addr[port]; |
| if (phy_reg_base == 0) |
| return 0; |
| return usb2_phy_tuning(phy_reg_base, port); |
| } |
| |
| static int phy_aml_usb2_power_on(struct phy *phy) |
| { |
| return 0; |
| } |
| |
| static int phy_aml_usb2_power_off(struct phy *phy) |
| { |
| return 0; |
| } |
| |
| struct phy_ops amlogic_usb2_phy_ops = { |
| .init = phy_aml_usb2_phy_init, |
| .power_on = phy_aml_usb2_power_on, |
| .power_off = phy_aml_usb2_power_off, |
| .tuning = phy_aml_usb2_tuning, |
| .getinfo = phy_aml_usb2_getinfo, |
| }; |
| |
| static int phy_aml_usb2_probe(struct udevice *dev) |
| { |
| return 0; |
| } |
| |
| static const struct udevice_id phy_aml_usb2_phy_ids[] = { |
| { .compatible = "amlogic, amlogic-new-usb2-v2" }, |
| { } |
| }; |
| |
| U_BOOT_DRIVER(meson_usb2_phy) = { |
| .name = "amlogic_new_usb2_phy", |
| .id = UCLASS_PHY, |
| .of_match = phy_aml_usb2_phy_ids, |
| .probe = phy_aml_usb2_probe, |
| .ops = &amlogic_usb2_phy_ops, |
| .priv_auto_alloc_size = sizeof(struct phy_aml_usb2_priv), |
| }; |