123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Renesas RCar Gen2 USB PHY driver
- *
- * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
- */
- #include <common.h>
- #include <clk.h>
- #include <div64.h>
- #include <dm.h>
- #include <fdtdec.h>
- #include <generic-phy.h>
- #include <malloc.h>
- #include <reset.h>
- #include <syscon.h>
- #include <usb.h>
- #include <asm/io.h>
- #include <dm/device_compat.h>
- #include <linux/bitops.h>
- #include <linux/delay.h>
- #include <power/regulator.h>
- #define USBHS_LPSTS 0x02
- #define USBHS_UGCTRL 0x80
- #define USBHS_UGCTRL2 0x84
- #define USBHS_UGSTS 0x88 /* From technical update */
- /* Low Power Status register (LPSTS) */
- #define USBHS_LPSTS_SUSPM 0x4000
- /* USB General control register (UGCTRL) */
- #define USBHS_UGCTRL_CONNECT BIT(2)
- #define USBHS_UGCTRL_PLLRESET BIT(0)
- /* USB General control register 2 (UGCTRL2) */
- #define USBHS_UGCTRL2_USB2SEL 0x80000000
- #define USBHS_UGCTRL2_USB2SEL_PCI 0x00000000
- #define USBHS_UGCTRL2_USB2SEL_USB30 0x80000000
- #define USBHS_UGCTRL2_USB0SEL 0x00000030
- #define USBHS_UGCTRL2_USB0SEL_PCI 0x00000010
- #define USBHS_UGCTRL2_USB0SEL_HS_USB 0x00000030
- /* USB General status register (UGSTS) */
- #define USBHS_UGSTS_LOCK 0x00000100 /* From technical update */
- #define PHYS_PER_CHANNEL 2
- struct rcar_gen2_phy {
- fdt_addr_t regs;
- struct clk clk;
- };
- static int rcar_gen2_phy_phy_init(struct phy *phy)
- {
- struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
- u16 chan = phy->id & 0xffff;
- u16 mode = (phy->id >> 16) & 0xffff;
- u32 clrmask, setmask;
- if (chan == 0) {
- clrmask = USBHS_UGCTRL2_USB0SEL;
- setmask = mode ? USBHS_UGCTRL2_USB0SEL_HS_USB :
- USBHS_UGCTRL2_USB0SEL_PCI;
- } else {
- clrmask = USBHS_UGCTRL2_USB2SEL;
- setmask = mode ? USBHS_UGCTRL2_USB2SEL_USB30 :
- USBHS_UGCTRL2_USB2SEL_PCI;
- }
- clrsetbits_le32(priv->regs + USBHS_UGCTRL2, clrmask, setmask);
- return 0;
- }
- static int rcar_gen2_phy_phy_power_on(struct phy *phy)
- {
- struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
- int i;
- u32 value;
- /* Power on USBHS PHY */
- clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
- setbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
- for (i = 0; i < 20; i++) {
- value = readl(priv->regs + USBHS_UGSTS);
- if ((value & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {
- setbits_le32(priv->regs + USBHS_UGCTRL,
- USBHS_UGCTRL_CONNECT);
- return 0;
- }
- udelay(1);
- }
- return -ETIMEDOUT;
- }
- static int rcar_gen2_phy_phy_power_off(struct phy *phy)
- {
- struct rcar_gen2_phy *priv = dev_get_priv(phy->dev);
- /* Power off USBHS PHY */
- clrbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_CONNECT);
- clrbits_le16(priv->regs + USBHS_LPSTS, USBHS_LPSTS_SUSPM);
- setbits_le32(priv->regs + USBHS_UGCTRL, USBHS_UGCTRL_PLLRESET);
- return 0;
- }
- static int rcar_gen2_phy_of_xlate(struct phy *phy,
- struct ofnode_phandle_args *args)
- {
- if (args->args_count != 2) {
- dev_err(phy->dev, "Invalid DT PHY argument count: %d\n",
- args->args_count);
- return -EINVAL;
- }
- if (args->args[0] != 0 && args->args[0] != 2) {
- dev_err(phy->dev, "Invalid DT PHY channel: %d\n",
- args->args[0]);
- return -EINVAL;
- }
- if (args->args[1] != 0 && args->args[1] != 1) {
- dev_err(phy->dev, "Invalid DT PHY mode: %d\n",
- args->args[1]);
- return -EINVAL;
- }
- if (args->args_count)
- phy->id = args->args[0] | (args->args[1] << 16);
- else
- phy->id = 0;
- return 0;
- }
- static const struct phy_ops rcar_gen2_phy_phy_ops = {
- .init = rcar_gen2_phy_phy_init,
- .power_on = rcar_gen2_phy_phy_power_on,
- .power_off = rcar_gen2_phy_phy_power_off,
- .of_xlate = rcar_gen2_phy_of_xlate,
- };
- static int rcar_gen2_phy_probe(struct udevice *dev)
- {
- struct rcar_gen2_phy *priv = dev_get_priv(dev);
- int ret;
- priv->regs = dev_read_addr(dev);
- if (priv->regs == FDT_ADDR_T_NONE)
- return -EINVAL;
- /* Enable clock */
- ret = clk_get_by_index(dev, 0, &priv->clk);
- if (ret)
- return ret;
- ret = clk_enable(&priv->clk);
- if (ret)
- return ret;
- return 0;
- }
- static int rcar_gen2_phy_remove(struct udevice *dev)
- {
- struct rcar_gen2_phy *priv = dev_get_priv(dev);
- clk_disable(&priv->clk);
- clk_free(&priv->clk);
- return 0;
- }
- static const struct udevice_id rcar_gen2_phy_of_match[] = {
- { .compatible = "renesas,rcar-gen2-usb-phy", },
- { },
- };
- U_BOOT_DRIVER(rcar_gen2_phy) = {
- .name = "rcar-gen2-phy",
- .id = UCLASS_PHY,
- .of_match = rcar_gen2_phy_of_match,
- .ops = &rcar_gen2_phy_phy_ops,
- .probe = rcar_gen2_phy_probe,
- .remove = rcar_gen2_phy_remove,
- .priv_auto_alloc_size = sizeof(struct rcar_gen2_phy),
- };
|