From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 06 Nov 2023 03:04:41 +0000 Subject: [PATCH] rk3568 rt init --- kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 254 ++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 220 insertions(+), 34 deletions(-) diff --git a/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 207e314..9d6dbbf 100644 --- a/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/kernel/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -59,6 +59,7 @@ PHY_STATE_DISCONNECT = 1, PHY_STATE_CONNECT = 2, PHY_STATE_FS_LS_ONLINE = 4, + PHY_STATE_SE1 = 6, }; /** @@ -158,6 +159,7 @@ * @utmi_ls: utmi linestate state register. * @utmi_hstdet: utmi host disconnect register. * @vbus_det_en: vbus detect function power down register. + * @port_ls_filter_con: set linestate filter time for otg port or host port. */ struct rockchip_usb2phy_port_cfg { struct usb2phy_reg phy_sus; @@ -188,6 +190,7 @@ struct usb2phy_reg utmi_ls; struct usb2phy_reg utmi_hstdet; struct usb2phy_reg vbus_det_en; + struct usb2phy_reg port_ls_filter_con; }; /** @@ -196,7 +199,9 @@ * @num_ports: specify how many ports that the phy has. * @phy_tuning: phy default parameters tunning. * @vbus_detect: vbus voltage level detection function. - * @clkout_ctl: keep on/turn off output clk of phy. + * @clkout_ctl: keep on/turn off output clk of phy via commonon bit. + * @clkout_ctl_phy: keep on/turn off output clk of phy via phy inner + * debug register. * @ls_filter_con: set linestate filter time. * @chg_det: charger detection registers. */ @@ -204,8 +209,11 @@ unsigned int reg; unsigned int num_ports; int (*phy_tuning)(struct rockchip_usb2phy *); - int (*vbus_detect)(struct rockchip_usb2phy *rphy, bool en); + int (*vbus_detect)(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *vbus_det_en, + bool en); struct usb2phy_reg clkout_ctl; + struct usb2phy_reg clkout_ctl_phy; struct usb2phy_reg ls_filter_con; const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; const struct rockchip_chg_det_reg chg_det; @@ -253,6 +261,7 @@ bool vbus_always_on; bool vbus_enabled; bool bypass_uart_en; + bool dis_u2_susphy; int bvalid_irq; int ls_irq; int id_irq; @@ -275,9 +284,10 @@ * @grf: General Register Files regmap. * @usbgrf: USB General Register Files regmap. * *phy_base: the base address of USB PHY. - * @clk: clock struct of phy input clk. + * @clks: array of phy input clocks. * @clk480m: clock struct of phy output clk. * @clk_hw: clock struct of phy output clk management. + * @num_clks: number of phy input clocks. * @chg_state: states involved in USB charger detection. * @chg_type: USB charger types. * @dcd_retries: The retry count used to track Data contact @@ -297,9 +307,10 @@ struct regmap *grf; struct regmap *usbgrf; void __iomem *phy_base; - struct clk *clk; + struct clk_bulk_data *clks; struct clk *clk480m; struct clk_hw clk480m_hw; + int num_clks; enum usb_chg_state chg_state; enum power_supply_type chg_type; u8 dcd_retries; @@ -344,6 +355,29 @@ return tmp == reg->enable; } +static inline void phy_property_enable(void __iomem *base, + const struct usb2phy_reg *reg, bool en) +{ + unsigned int val, tmp; + + val = readl(base + reg->offset); + tmp = en ? reg->enable : reg->disable; + val &= ~GENMASK(reg->bitend, reg->bitstart); + val |= tmp << reg->bitstart; + writel(val, base + reg->offset); +} + +static inline bool phy_property_enabled(void __iomem *base, + const struct usb2phy_reg *reg) +{ + unsigned int orig, tmp; + unsigned int mask = GENMASK(reg->bitend, reg->bitstart); + + orig = readl(base + reg->offset); + tmp = (orig & mask) >> reg->bitstart; + return tmp == reg->enable; +} + static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = @@ -352,7 +386,14 @@ int ret; /* turn on 480m clk output if it is off */ - if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { + if (rphy->phy_cfg->clkout_ctl_phy.enable) { + if (!phy_property_enabled(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy)) { + phy_property_enable(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy, true); + + /* waiting for the clk become stable */ + usleep_range(1200, 1300); + } + } else if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true); if (ret) return ret; @@ -371,7 +412,10 @@ struct regmap *base = get_reg_base(rphy); /* turn off 480m clk output */ - property_enable(base, &rphy->phy_cfg->clkout_ctl, false); + if (rphy->phy_cfg->clkout_ctl_phy.enable) + phy_property_enable(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy, false); + else + property_enable(base, &rphy->phy_cfg->clkout_ctl, false); } static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw) @@ -380,7 +424,10 @@ container_of(hw, struct rockchip_usb2phy, clk480m_hw); struct regmap *base = get_reg_base(rphy); - return property_enabled(base, &rphy->phy_cfg->clkout_ctl); + if (rphy->phy_cfg->clkout_ctl_phy.enable) + return phy_property_enabled(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy); + else + return property_enabled(base, &rphy->phy_cfg->clkout_ctl); } static unsigned long @@ -410,6 +457,7 @@ { struct device_node *node = rphy->dev->of_node; struct clk_init_data init = {}; + struct clk *refclk = of_clk_get_by_name(node, "phyclk"); const char *clk_name; int ret; @@ -420,8 +468,8 @@ /* optional override of the clockname */ of_property_read_string(node, "clock-output-names", &init.name); - if (rphy->clk) { - clk_name = __clk_get_name(rphy->clk); + if (!IS_ERR(refclk)) { + clk_name = __clk_get_name(refclk); init.parent_names = &clk_name; init.num_parents = 1; } else { @@ -855,7 +903,8 @@ } if (rphy->phy_cfg->vbus_detect) - rphy->phy_cfg->vbus_detect(rphy, vbus_det_en); + rphy->phy_cfg->vbus_detect(rphy, &rport->port_cfg->vbus_det_en, + vbus_det_en); else ret = property_enable(rphy->grf, &rport->port_cfg->vbus_det_en, vbus_det_en); @@ -1029,7 +1078,8 @@ rport->state = OTG_STATE_B_IDLE; if (!rport->vbus_attached) { mutex_unlock(&rport->mutex); - rockchip_usb2phy_power_off(rport->phy); + if (!rport->dis_u2_susphy) + rockchip_usb2phy_power_off(rport->phy); mutex_lock(&rport->mutex); } /* fall through */ @@ -1090,7 +1140,8 @@ rphy->chg_state = USB_CHG_STATE_UNDEFINED; rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; mutex_unlock(&rport->mutex); - rockchip_usb2phy_power_off(rport->phy); + if (!rport->dis_u2_susphy) + rockchip_usb2phy_power_off(rport->phy); mutex_lock(&rport->mutex); } break; @@ -1434,6 +1485,15 @@ dev_dbg(&rport->phy->dev, "FS/LS online\n"); } break; + case PHY_STATE_SE1: + if (rport->suspended) { + dev_dbg(&rport->phy->dev, "linestate is SE1, power on phy\n"); + mutex_unlock(&rport->mutex); + rockchip_usb2phy_power_on(rport->phy); + mutex_lock(&rport->mutex); + rport->suspended = false; + } + break; case PHY_STATE_DISCONNECT: if (!rport->suspended) { dev_dbg(&rport->phy->dev, "Disconnected\n"); @@ -1764,6 +1824,11 @@ return NOTIFY_DONE; } +static void rockchip_otg_wake_lock_destroy(void *data) +{ + wake_lock_destroy((struct wake_lock *)(data)); +} + static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, struct rockchip_usb2phy_port *rport, struct device_node *child_np) @@ -1789,6 +1854,8 @@ of_property_read_bool(child_np, "rockchip,vbus-always-on"); rport->utmi_avalid = of_property_read_bool(child_np, "rockchip,utmi-avalid"); + rport->dis_u2_susphy = + of_property_read_bool(child_np, "rockchip,dis-u2-susphy"); /* enter lower power state when suspend */ rport->low_power_en = @@ -1833,6 +1900,11 @@ property_enable(base, &rport->port_cfg->bvalid_set, false); wake_lock_init(&rport->wakelock, WAKE_LOCK_SUSPEND, "rockchip_otg"); + ret = devm_add_action_or_reset(rphy->dev, rockchip_otg_wake_lock_destroy, + &rport->wakelock); + if (ret) + return ret; + INIT_DELAYED_WORK(&rport->bypass_uart_work, rockchip_usb_bypass_uart_work); INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work); @@ -1845,7 +1917,7 @@ EXTCON_USB_HOST, &rport->event_nb); if (ret) { dev_err(rphy->dev, "register USB HOST notifier failed\n"); - goto err; + return ret; } } @@ -1861,10 +1933,6 @@ rport->suspended = true; return 0; - -err: - wake_lock_destroy(&rport->wakelock); - return ret; } static int rockchip_usb2phy_probe(struct platform_device *pdev) @@ -1963,13 +2031,19 @@ pm_runtime_enable(dev); pm_runtime_get_sync(dev); - rphy->clk = of_clk_get_by_name(np, "phyclk"); - if (!IS_ERR(rphy->clk)) { - clk_prepare_enable(rphy->clk); - } else { - dev_info(&pdev->dev, "no phyclk specified\n"); - rphy->clk = NULL; - } + ret = devm_clk_bulk_get_all(dev, &rphy->clks); + if (ret == -EPROBE_DEFER) + return ret; + + /* Clocks are optional */ + if (ret < 0) + rphy->num_clks = 0; + else + rphy->num_clks = ret; + + ret = clk_bulk_prepare_enable(rphy->num_clks, rphy->clks); + if (ret) + return ret; if (rphy->phy_cfg->phy_tuning) { ret = rphy->phy_cfg->phy_tuning(rphy); @@ -2061,10 +2135,8 @@ disable_clks: pm_runtime_put_sync(dev); pm_runtime_disable(dev); - if (rphy->clk) { - clk_disable_unprepare(rphy->clk); - clk_put(rphy->clk); - } + clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks); + return ret; } @@ -2305,6 +2377,43 @@ return ret; } +static int rk3528_usb2phy_tuning(struct rockchip_usb2phy *rphy) +{ + u32 reg; + int ret = 0; + + /* Turn off otg port differential receiver in suspend mode */ + reg = readl(rphy->phy_base + 0x30); + writel(reg & ~BIT(2), rphy->phy_base + 0x30); + + /* Turn off host port differential receiver in suspend mode */ + reg = readl(rphy->phy_base + 0x0430); + writel(reg & ~BIT(2), rphy->phy_base + 0x0430); + + /* Set otg port HS eye height to 400mv(default is 450mv) */ + reg = readl(rphy->phy_base + 0x30); + reg &= ~GENMASK(6, 4); + reg |= (0x00 << 4); + writel(reg, rphy->phy_base + 0x30); + + /* Set host port HS eye height to 400mv(default is 450mv) */ + reg = readl(rphy->phy_base + 0x430); + reg &= ~GENMASK(6, 4); + reg |= (0x00 << 4); + writel(reg, rphy->phy_base + 0x430); + + /* Choose the Tx fs/ls data as linestate from TX driver for otg port */ + reg = readl(rphy->phy_base + 0x94); + reg &= ~GENMASK(6, 3); + reg |= (0x03 << 3); + writel(reg, rphy->phy_base + 0x94); + + /* Enable otg and host ports phy irq to pmu wakeup source */ + ret |= regmap_write(rphy->grf, 0x80004, 0x00030003); + + return ret; +} + static int rk3568_usb2phy_tuning(struct rockchip_usb2phy *rphy) { u32 reg; @@ -2352,18 +2461,20 @@ return ret; } -static int rk3568_vbus_detect_control(struct rockchip_usb2phy *rphy, bool en) +static int rockchip_usb2phy_vbus_det_control(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *vbus_det_en, + bool en) { u32 reg; if (en) { - reg = readl(rphy->phy_base + 0x3c); + reg = readl(rphy->phy_base + vbus_det_en->offset); /* Enable vbus voltage level detection function */ - writel(reg & ~BIT(7), rphy->phy_base + 0x3c); + writel(reg & ~BIT(7), rphy->phy_base + vbus_det_en->offset); } else { - reg = readl(rphy->phy_base + 0x3c); + reg = readl(rphy->phy_base + vbus_det_en->offset); /* Disable vbus voltage level detection function */ - writel(reg | BIT(7), rphy->phy_base + 0x3c); + writel(reg | BIT(7), rphy->phy_base + vbus_det_en->offset); } return 0; @@ -2397,6 +2508,14 @@ rport = &rphy->ports[index]; if (!rport->phy) continue; + + if (rport->port_cfg->port_ls_filter_con.enable) { + ret = regmap_write(rphy->grf, + rport->port_cfg->port_ls_filter_con.offset, + rport->port_cfg->port_ls_filter_con.enable); + if (ret) + dev_err(rphy->dev, "failed to set port ls filter %d\n", ret); + } if (rport->port_id == USB2PHY_PORT_OTG && (rport->id_irq > 0 || rphy->irq > 0)) { @@ -2466,6 +2585,14 @@ rport = &rphy->ports[index]; if (!rport->phy) continue; + + if (rport->port_cfg->port_ls_filter_con.disable) { + ret = regmap_write(rphy->grf, + rport->port_cfg->port_ls_filter_con.offset, + rport->port_cfg->port_ls_filter_con.disable); + if (ret) + dev_err(rphy->dev, "failed to set port ls filter %d\n", ret); + } if (rport->port_id == USB2PHY_PORT_OTG && (rport->id_irq > 0 || rphy->irq > 0)) { @@ -2988,12 +3115,69 @@ { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = { + { + .reg = 0xffdf0000, + .num_ports = 2, + .phy_tuning = rk3528_usb2phy_tuning, + .vbus_detect = rockchip_usb2phy_vbus_det_control, + .clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x6004c, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x60074, 2, 2, 0, 1 }, + .bvalid_det_st = { 0x60078, 2, 2, 0, 1 }, + .bvalid_det_clr = { 0x6007c, 2, 2, 0, 1 }, + .bvalid_set = { 0x6004c, 15, 14, 0, 3 }, + .iddig_output = { 0x6004c, 10, 10, 0, 1 }, + .iddig_en = { 0x6004c, 9, 9, 0, 1 }, + .idfall_det_en = { 0x60074, 5, 5, 0, 1 }, + .idfall_det_st = { 0x60078, 5, 5, 0, 1 }, + .idfall_det_clr = { 0x6007c, 5, 5, 0, 1 }, + .idrise_det_en = { 0x60074, 4, 4, 0, 1 }, + .idrise_det_st = { 0x60078, 4, 4, 0, 1 }, + .idrise_det_clr = { 0x6007c, 4, 4, 0, 1 }, + .ls_det_en = { 0x60074, 0, 0, 0, 1 }, + .ls_det_st = { 0x60078, 0, 0, 0, 1 }, + .ls_det_clr = { 0x6007c, 0, 0, 0, 1 }, + .utmi_avalid = { 0x6006c, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x6006c, 0, 0, 0, 1 }, + .utmi_iddig = { 0x6006c, 6, 6, 0, 1 }, + .utmi_ls = { 0x6006c, 5, 4, 0, 1 }, + .vbus_det_en = { 0x003c, 7, 7, 0, 1 }, + .port_ls_filter_con = { 0x60080, 19, 0, 0x30100, 0x20 }, + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x6005c, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x60090, 0, 0, 0, 1 }, + .ls_det_st = { 0x60094, 0, 0, 0, 1 }, + .ls_det_clr = { 0x60098, 0, 0, 0, 1 }, + .utmi_ls = { 0x6006c, 13, 12, 0, 1 }, + .utmi_hstdet = { 0x6006c, 15, 15, 0, 1 }, + .port_ls_filter_con = { 0x6009c, 19, 0, 0x30100, 0x20 }, + } + }, + .chg_det = { + .chg_mode = { 0x6004c, 8, 0, 0, 0x1d7 }, + .cp_det = { 0x6006c, 19, 19, 0, 1 }, + .dcp_det = { 0x6006c, 18, 18, 0, 1 }, + .dp_det = { 0x6006c, 20, 20, 0, 1 }, + .idm_sink_en = { 0x60058, 1, 1, 0, 1 }, + .idp_sink_en = { 0x60058, 0, 0, 0, 1 }, + .idp_src_en = { 0x60058, 2, 2, 0, 1 }, + .rdm_pdwn_en = { 0x60058, 3, 3, 0, 1 }, + .vdm_src_en = { 0x60058, 5, 5, 0, 1 }, + .vdp_src_en = { 0x60058, 4, 4, 0, 1 }, + }, + } +}; + static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { .reg = 0xfe8a0000, .num_ports = 2, .phy_tuning = rk3568_usb2phy_tuning, - .vbus_detect = rk3568_vbus_detect_control, + .vbus_detect = rockchip_usb2phy_vbus_det_control, .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, .ls_filter_con = { 0x0040, 19, 0, 0x30100, 0x00020 }, .port_cfgs = { @@ -3020,6 +3204,7 @@ .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 }, .utmi_iddig = { 0x00c0, 6, 6, 0, 1 }, .utmi_ls = { 0x00c0, 5, 4, 0, 1 }, + .vbus_det_en = { 0x003c, 7, 7, 0, 1 }, }, [USB2PHY_PORT_HOST] = { /* Select suspend control from controller */ @@ -3123,6 +3308,7 @@ { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3368-usb2phy", .data = &rk3368_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, + { .compatible = "rockchip,rk3528-usb2phy", .data = &rk3528_phy_cfgs }, { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, {} -- Gitblit v1.6.2