diff --git a/target/linux/rockchip/armv8/config-5.4 b/target/linux/rockchip/armv8/config-5.4 index 7f0fcfe824..1fceddfbfd 100644 --- a/target/linux/rockchip/armv8/config-5.4 +++ b/target/linux/rockchip/armv8/config-5.4 @@ -325,7 +325,6 @@ CONFIG_PHY_ROCKCHIP_DP=y CONFIG_PHY_ROCKCHIP_EMMC=y # CONFIG_PHY_ROCKCHIP_INNO_HDMI is not set CONFIG_PHY_ROCKCHIP_INNO_USB2=y -# CONFIG_PHY_ROCKCHIP_INNO_USB3 is not set CONFIG_PHY_ROCKCHIP_PCIE=y CONFIG_PHY_ROCKCHIP_TYPEC=y CONFIG_PHY_ROCKCHIP_USB=y diff --git a/target/linux/rockchip/files/drivers/phy/rockchip/phy-rockchip-inno-usb3.c b/target/linux/rockchip/files/drivers/phy/rockchip/phy-rockchip-inno-usb3.c deleted file mode 100644 index a84a017e4b..0000000000 --- a/target/linux/rockchip/files/drivers/phy/rockchip/phy-rockchip-inno-usb3.c +++ /dev/null @@ -1,1175 +0,0 @@ -/* - * Rockchip USB 3.0 PHY with Innosilicon IP block driver - * - * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define U3PHY_PORT_NUM 2 -#define U3PHY_MAX_CLKS 4 -#define BIT_WRITEABLE_SHIFT 16 -#define SCHEDULE_DELAY (60 * HZ) - -#define U3PHY_APB_RST BIT(0) -#define U3PHY_POR_RST BIT(1) -#define U3PHY_MAC_RST BIT(2) - -struct rockchip_u3phy; -struct rockchip_u3phy_port; - -enum rockchip_u3phy_type { - U3PHY_TYPE_PIPE, - U3PHY_TYPE_UTMI, -}; - -enum rockchip_u3phy_pipe_pwr { - PIPE_PWR_P0 = 0, - PIPE_PWR_P1 = 1, - PIPE_PWR_P2 = 2, - PIPE_PWR_P3 = 3, - PIPE_PWR_MAX = 4, -}; - -enum rockchip_u3phy_rest_req { - U3_POR_RSTN = 0, - U2_POR_RSTN = 1, - PIPE_MAC_RSTN = 2, - UTMI_MAC_RSTN = 3, - PIPE_APB_RSTN = 4, - UTMI_APB_RSTN = 5, - U3PHY_RESET_MAX = 6, -}; - -enum rockchip_u3phy_utmi_state { - PHY_UTMI_HS_ONLINE = 0, - PHY_UTMI_DISCONNECT = 1, - PHY_UTMI_CONNECT = 2, - PHY_UTMI_FS_LS_ONLINE = 4, -}; - -/* - * @rvalue: reset value - * @dvalue: desired value - */ -struct u3phy_reg { - unsigned int offset; - unsigned int bitend; - unsigned int bitstart; - unsigned int rvalue; - unsigned int dvalue; -}; - -struct rockchip_u3phy_grfcfg { - struct u3phy_reg um_suspend; - struct u3phy_reg ls_det_en; - struct u3phy_reg ls_det_st; - struct u3phy_reg um_ls; - struct u3phy_reg um_hstdct; - struct u3phy_reg u2_only_ctrl; - struct u3phy_reg u3_disable; - struct u3phy_reg pp_pwr_st; - struct u3phy_reg pp_pwr_en[PIPE_PWR_MAX]; -}; - -/** - * struct rockchip_u3phy_apbcfg: usb3-phy apb configuration. - * @u2_pre_emp: usb2-phy pre-emphasis tuning. - * @u2_pre_emp_sth: usb2-phy pre-emphasis strength tuning. - * @u2_odt_tuning: usb2-phy odt 45ohm tuning. - */ -struct rockchip_u3phy_apbcfg { - unsigned int u2_pre_emp; - unsigned int u2_pre_emp_sth; - unsigned int u2_odt_tuning; -}; - -struct rockchip_u3phy_cfg { - unsigned int reg; - const struct rockchip_u3phy_grfcfg grfcfg; - - int (*phy_pipe_power)(struct rockchip_u3phy *, - struct rockchip_u3phy_port *, - bool on); - int (*phy_tuning)(struct rockchip_u3phy *, - struct rockchip_u3phy_port *, - struct device_node *); - int (*phy_cp_test)(struct rockchip_u3phy *, - struct rockchip_u3phy_port *); -}; - -struct rockchip_u3phy_port { - struct phy *phy; - void __iomem *base; - unsigned int index; - unsigned char type; - bool suspended; - bool refclk_25m_quirk; - struct mutex mutex; /* mutex for updating register */ - struct delayed_work um_sm_work; -}; - -struct rockchip_u3phy { - struct device *dev; - struct regmap *u3phy_grf; - struct regmap *grf; - int um_ls_irq; - struct clk *clks[U3PHY_MAX_CLKS]; - struct dentry *root; - struct regulator *vbus; - struct reset_control *rsts[U3PHY_RESET_MAX]; - struct rockchip_u3phy_apbcfg apbcfg; - const struct rockchip_u3phy_cfg *cfgs; - struct rockchip_u3phy_port ports[U3PHY_PORT_NUM]; - struct usb_phy usb_phy; - bool vbus_enabled; -}; - -static inline int param_write(void __iomem *base, - const struct u3phy_reg *reg, bool desired) -{ - unsigned int val, mask; - unsigned int tmp = desired ? reg->dvalue : reg->rvalue; - int ret = 0; - - mask = GENMASK(reg->bitend, reg->bitstart); - val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); - ret = regmap_write(base, reg->offset, val); - - return ret; -} - -static inline bool param_exped(void __iomem *base, - const struct u3phy_reg *reg, - unsigned int value) -{ - int ret; - unsigned int tmp, orig; - unsigned int mask = GENMASK(reg->bitend, reg->bitstart); - - ret = regmap_read(base, reg->offset, &orig); - if (ret) - return false; - - tmp = (orig & mask) >> reg->bitstart; - return tmp == value; -} - -static int rockchip_set_vbus_power(struct rockchip_u3phy *u3phy, bool en) -{ - int ret = 0; - - if (!u3phy->vbus) - return 0; - - if (en && !u3phy->vbus_enabled) { - ret = regulator_enable(u3phy->vbus); - if (ret) - dev_err(u3phy->dev, - "Failed to enable VBUS supply\n"); - } else if (!en && u3phy->vbus_enabled) { - ret = regulator_disable(u3phy->vbus); - } - - if (ret == 0) - u3phy->vbus_enabled = en; - - return ret; -} - -static int rockchip_u3phy_usb2_only_show(struct seq_file *s, void *unused) -{ - struct rockchip_u3phy *u3phy = s->private; - - if (param_exped(u3phy->u3phy_grf, &u3phy->cfgs->grfcfg.u2_only_ctrl, 1)) - dev_info(u3phy->dev, "u2\n"); - else - dev_info(u3phy->dev, "u3\n"); - - return 0; -} - -static int rockchip_u3phy_usb2_only_open(struct inode *inode, - struct file *file) -{ - return single_open(file, rockchip_u3phy_usb2_only_show, - inode->i_private); -} - -static ssize_t rockchip_u3phy_usb2_only_write(struct file *file, - const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct rockchip_u3phy *u3phy = s->private; - struct rockchip_u3phy_port *u3phy_port; - char buf[32]; - u8 index; - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - if (!strncmp(buf, "u3", 2) && - param_exped(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.u2_only_ctrl, 1)) { - dev_info(u3phy->dev, "Set usb3.0 and usb2.0 mode successfully\n"); - - rockchip_set_vbus_power(u3phy, false); - - param_write(u3phy->grf, - &u3phy->cfgs->grfcfg.u3_disable, false); - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.u2_only_ctrl, false); - - for (index = 0; index < U3PHY_PORT_NUM; index++) { - u3phy_port = &u3phy->ports[index]; - /* enable u3 rx termimation */ - if (u3phy_port->type == U3PHY_TYPE_PIPE) - writel(0x30, u3phy_port->base + 0xd8); - } - - atomic_notifier_call_chain(&u3phy->usb_phy.notifier, 0, NULL); - - rockchip_set_vbus_power(u3phy, true); - } else if (!strncmp(buf, "u2", 2) && - param_exped(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.u2_only_ctrl, 0)) { - dev_info(u3phy->dev, "Set usb2.0 only mode successfully\n"); - - rockchip_set_vbus_power(u3phy, false); - - param_write(u3phy->grf, - &u3phy->cfgs->grfcfg.u3_disable, true); - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.u2_only_ctrl, true); - - for (index = 0; index < U3PHY_PORT_NUM; index++) { - u3phy_port = &u3phy->ports[index]; - /* disable u3 rx termimation */ - if (u3phy_port->type == U3PHY_TYPE_PIPE) - writel(0x20, u3phy_port->base + 0xd8); - } - - atomic_notifier_call_chain(&u3phy->usb_phy.notifier, 0, NULL); - - rockchip_set_vbus_power(u3phy, true); - } else { - dev_info(u3phy->dev, "Same or illegal mode\n"); - } - - return count; -} - -static const struct file_operations rockchip_u3phy_usb2_only_fops = { - .open = rockchip_u3phy_usb2_only_open, - .write = rockchip_u3phy_usb2_only_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -int rockchip_u3phy_debugfs_init(struct rockchip_u3phy *u3phy) -{ - struct dentry *root; - struct dentry *file; - int ret; - - root = debugfs_create_dir(dev_name(u3phy->dev), NULL); - if (!root) { - ret = -ENOMEM; - goto err0; - } - - u3phy->root = root; - - file = debugfs_create_file("u3phy_mode", 0644, root, - u3phy, &rockchip_u3phy_usb2_only_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - return 0; - -err1: - debugfs_remove_recursive(root); -err0: - return ret; -} - -static const char *get_rest_name(enum rockchip_u3phy_rest_req rst) -{ - switch (rst) { - case U2_POR_RSTN: - return "u3phy-u2-por"; - case U3_POR_RSTN: - return "u3phy-u3-por"; - case PIPE_MAC_RSTN: - return "u3phy-pipe-mac"; - case UTMI_MAC_RSTN: - return "u3phy-utmi-mac"; - case UTMI_APB_RSTN: - return "u3phy-utmi-apb"; - case PIPE_APB_RSTN: - return "u3phy-pipe-apb"; - default: - return "invalid"; - } -} - -static void rockchip_u3phy_rest_deassert(struct rockchip_u3phy *u3phy, - unsigned int flag) -{ - int rst; - - if (flag & U3PHY_APB_RST) { - dev_dbg(u3phy->dev, "deassert APB bus interface reset\n"); - for (rst = PIPE_APB_RSTN; rst <= UTMI_APB_RSTN; rst++) { - if (u3phy->rsts[rst]) - reset_control_deassert(u3phy->rsts[rst]); - } - } - - if (flag & U3PHY_POR_RST) { - usleep_range(12, 15); - dev_dbg(u3phy->dev, "deassert u2 and u3 phy power on reset\n"); - for (rst = U3_POR_RSTN; rst <= U2_POR_RSTN; rst++) { - if (u3phy->rsts[rst]) - reset_control_deassert(u3phy->rsts[rst]); - } - } - - if (flag & U3PHY_MAC_RST) { - usleep_range(1200, 1500); - dev_dbg(u3phy->dev, "deassert pipe and utmi MAC reset\n"); - for (rst = PIPE_MAC_RSTN; rst <= UTMI_MAC_RSTN; rst++) - if (u3phy->rsts[rst]) - reset_control_deassert(u3phy->rsts[rst]); - } -} - -static void rockchip_u3phy_rest_assert(struct rockchip_u3phy *u3phy) -{ - int rst; - - dev_dbg(u3phy->dev, "assert u3phy reset\n"); - for (rst = 0; rst < U3PHY_RESET_MAX; rst++) - if (u3phy->rsts[rst]) - reset_control_assert(u3phy->rsts[rst]); -} - -static int rockchip_u3phy_clk_enable(struct rockchip_u3phy *u3phy) -{ - int ret, clk; - - for (clk = 0; clk < U3PHY_MAX_CLKS && u3phy->clks[clk]; clk++) { - ret = clk_prepare_enable(u3phy->clks[clk]); - if (ret) - goto err_disable_clks; - } - return 0; - -err_disable_clks: - while (--clk >= 0) - clk_disable_unprepare(u3phy->clks[clk]); - return ret; -} - -static void rockchip_u3phy_clk_disable(struct rockchip_u3phy *u3phy) -{ - int clk; - - for (clk = U3PHY_MAX_CLKS - 1; clk >= 0; clk--) - if (u3phy->clks[clk]) - clk_disable_unprepare(u3phy->clks[clk]); -} - -static int rockchip_u3phy_init(struct phy *phy) -{ - return 0; -} - -static int rockchip_u3phy_exit(struct phy *phy) -{ - return 0; -} - -static int rockchip_u3phy_power_on(struct phy *phy) -{ - struct rockchip_u3phy_port *u3phy_port = phy_get_drvdata(phy); - struct rockchip_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); - int ret; - - dev_info(&u3phy_port->phy->dev, "u3phy %s power on\n", - (u3phy_port->type == U3PHY_TYPE_UTMI) ? "u2" : "u3"); - - if (!u3phy_port->suspended) - return 0; - - ret = rockchip_u3phy_clk_enable(u3phy); - if (ret) - return ret; - - if (u3phy_port->type == U3PHY_TYPE_UTMI) { - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.um_suspend, false); - } else { - /* current in p2 ? */ - if (param_exped(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.pp_pwr_st, PIPE_PWR_P2)) - goto done; - - if (u3phy->cfgs->phy_pipe_power) { - dev_dbg(u3phy->dev, "do pipe power up\n"); - u3phy->cfgs->phy_pipe_power(u3phy, u3phy_port, true); - } - - /* exit to p0 */ - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.pp_pwr_en[PIPE_PWR_P0], true); - usleep_range(90, 100); - - /* enter to p2 from p0 */ - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.pp_pwr_en[PIPE_PWR_P2], - false); - udelay(3); - } - -done: - rockchip_set_vbus_power(u3phy, true); - u3phy_port->suspended = false; - return 0; -} - -static int rockchip_u3phy_power_off(struct phy *phy) -{ - struct rockchip_u3phy_port *u3phy_port = phy_get_drvdata(phy); - struct rockchip_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); - - dev_info(&u3phy_port->phy->dev, "u3phy %s power off\n", - (u3phy_port->type == U3PHY_TYPE_UTMI) ? "u2" : "u3"); - - if (u3phy_port->suspended) - return 0; - - if (u3phy_port->type == U3PHY_TYPE_UTMI) { - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.um_suspend, true); - } else { - /* current in p3 ? */ - if (param_exped(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.pp_pwr_st, PIPE_PWR_P3)) - goto done; - - /* exit to p0 */ - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.pp_pwr_en[PIPE_PWR_P0], true); - udelay(2); - - /* enter to p3 from p0 */ - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.pp_pwr_en[PIPE_PWR_P3], true); - udelay(6); - - if (u3phy->cfgs->phy_pipe_power) { - dev_dbg(u3phy->dev, "do pipe power down\n"); - u3phy->cfgs->phy_pipe_power(u3phy, u3phy_port, false); - } - } - -done: - rockchip_u3phy_clk_disable(u3phy); - u3phy_port->suspended = true; - return 0; -} - -static __maybe_unused int rockchip_u3phy_cp_test(struct phy *phy) -{ - struct rockchip_u3phy_port *u3phy_port = phy_get_drvdata(phy); - struct rockchip_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); - int ret; - - if (u3phy->cfgs->phy_cp_test) { - /* - * When do USB3 compliance test, we may connect the oscilloscope - * front panel Aux Out to the DUT SSRX+, the Aux Out of the - * oscilloscope outputs a negative pulse whose width is between - * 300- 400 ns which may trigger some DUTs to change the CP test - * pattern. - * - * The Inno USB3 PHY disable the function to detect the negative - * pulse in SSRX+ by default, so we need to enable the function - * to toggle the CP test pattern before do USB3 compliance test. - */ - dev_dbg(u3phy->dev, "prepare for u3phy compliance test\n"); - ret = u3phy->cfgs->phy_cp_test(u3phy, u3phy_port); - if (ret) - return ret; - } - - return 0; -} - -static __maybe_unused -struct phy *rockchip_u3phy_xlate(struct device *dev, - struct of_phandle_args *args) -{ - struct rockchip_u3phy *u3phy = dev_get_drvdata(dev); - struct rockchip_u3phy_port *u3phy_port = NULL; - struct device_node *phy_np = args->np; - int index; - - if (args->args_count != 1) { - dev_err(dev, "invalid number of cells in 'phy' property\n"); - return ERR_PTR(-EINVAL); - } - - for (index = 0; index < U3PHY_PORT_NUM; index++) { - if (phy_np == u3phy->ports[index].phy->dev.of_node) { - u3phy_port = &u3phy->ports[index]; - break; - } - } - - if (!u3phy_port) { - dev_err(dev, "failed to find appropriate phy\n"); - return ERR_PTR(-EINVAL); - } - - return u3phy_port->phy; -} - -static struct phy_ops rockchip_u3phy_ops = { - .init = rockchip_u3phy_init, - .exit = rockchip_u3phy_exit, - .power_on = rockchip_u3phy_power_on, - .power_off = rockchip_u3phy_power_off, - .owner = THIS_MODULE, -}; - -/* - * The function manage host-phy port state and suspend/resume phy port - * to save power automatically. - * - * we rely on utmi_linestate and utmi_hostdisconnect to identify whether - * devices is disconnect or not. Besides, we do not need care it is FS/LS - * disconnected or HS disconnected, actually, we just only need get the - * device is disconnected at last through rearm the delayed work, - * to suspend the phy port in _PHY_STATE_DISCONNECT_ case. - */ -static void rockchip_u3phy_um_sm_work(struct work_struct *work) -{ - struct rockchip_u3phy_port *u3phy_port = - container_of(work, struct rockchip_u3phy_port, um_sm_work.work); - struct rockchip_u3phy *u3phy = - dev_get_drvdata(u3phy_port->phy->dev.parent); - unsigned int sh = u3phy->cfgs->grfcfg.um_hstdct.bitend - - u3phy->cfgs->grfcfg.um_hstdct.bitstart + 1; - unsigned int ul, uhd, state; - unsigned int ul_mask, uhd_mask; - int ret; - - mutex_lock(&u3phy_port->mutex); - - ret = regmap_read(u3phy->u3phy_grf, - u3phy->cfgs->grfcfg.um_ls.offset, &ul); - if (ret < 0) - goto next_schedule; - - ret = regmap_read(u3phy->u3phy_grf, - u3phy->cfgs->grfcfg.um_hstdct.offset, &uhd); - if (ret < 0) - goto next_schedule; - - uhd_mask = GENMASK(u3phy->cfgs->grfcfg.um_hstdct.bitend, - u3phy->cfgs->grfcfg.um_hstdct.bitstart); - ul_mask = GENMASK(u3phy->cfgs->grfcfg.um_ls.bitend, - u3phy->cfgs->grfcfg.um_ls.bitstart); - - /* stitch on um_ls and um_hstdct as phy state */ - state = ((uhd & uhd_mask) >> u3phy->cfgs->grfcfg.um_hstdct.bitstart) | - (((ul & ul_mask) >> u3phy->cfgs->grfcfg.um_ls.bitstart) << sh); - - switch (state) { - case PHY_UTMI_HS_ONLINE: - dev_dbg(&u3phy_port->phy->dev, "HS online\n"); - break; - case PHY_UTMI_FS_LS_ONLINE: - /* - * For FS/LS device, the online state share with connect state - * from um_ls and um_hstdct register, so we distinguish - * them via suspended flag. - * - * Plus, there are two cases, one is D- Line pull-up, and D+ - * line pull-down, the state is 4; another is D+ line pull-up, - * and D- line pull-down, the state is 2. - */ - if (!u3phy_port->suspended) { - /* D- line pull-up, D+ line pull-down */ - dev_dbg(&u3phy_port->phy->dev, "FS/LS online\n"); - break; - } - /* fall through */ - case PHY_UTMI_CONNECT: - if (u3phy_port->suspended) { - dev_dbg(&u3phy_port->phy->dev, "Connected\n"); - rockchip_u3phy_power_on(u3phy_port->phy); - u3phy_port->suspended = false; - } else { - /* D+ line pull-up, D- line pull-down */ - dev_dbg(&u3phy_port->phy->dev, "FS/LS online\n"); - } - break; - case PHY_UTMI_DISCONNECT: - if (!u3phy_port->suspended) { - dev_dbg(&u3phy_port->phy->dev, "Disconnected\n"); - rockchip_u3phy_power_off(u3phy_port->phy); - u3phy_port->suspended = true; - } - - /* - * activate the linestate detection to get the next device - * plug-in irq. - */ - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.ls_det_st, true); - param_write(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.ls_det_en, true); - - /* - * we don't need to rearm the delayed work when the phy port - * is suspended. - */ - mutex_unlock(&u3phy_port->mutex); - return; - default: - dev_dbg(&u3phy_port->phy->dev, "unknown phy state\n"); - break; - } - -next_schedule: - mutex_unlock(&u3phy_port->mutex); - schedule_delayed_work(&u3phy_port->um_sm_work, SCHEDULE_DELAY); -} - -static irqreturn_t rockchip_u3phy_um_ls_irq(int irq, void *data) -{ - struct rockchip_u3phy_port *u3phy_port = data; - struct rockchip_u3phy *u3phy = - dev_get_drvdata(u3phy_port->phy->dev.parent); - - if (!param_exped(u3phy->u3phy_grf, - &u3phy->cfgs->grfcfg.ls_det_st, - u3phy->cfgs->grfcfg.ls_det_st.dvalue)) - return IRQ_NONE; - - dev_dbg(u3phy->dev, "utmi linestate interrupt\n"); - mutex_lock(&u3phy_port->mutex); - - /* disable linestate detect irq and clear its status */ - param_write(u3phy->u3phy_grf, &u3phy->cfgs->grfcfg.ls_det_en, false); - param_write(u3phy->u3phy_grf, &u3phy->cfgs->grfcfg.ls_det_st, true); - - mutex_unlock(&u3phy_port->mutex); - - /* - * In this case for host phy, a new device is plugged in, meanwhile, - * if the phy port is suspended, we need rearm the work to resume it - * and mange its states; otherwise, we just return irq handled. - */ - if (u3phy_port->suspended) { - dev_dbg(u3phy->dev, "schedule utmi sm work\n"); - rockchip_u3phy_um_sm_work(&u3phy_port->um_sm_work.work); - } - - return IRQ_HANDLED; -} - -static int rockchip_u3phy_parse_dt(struct rockchip_u3phy *u3phy, - struct platform_device *pdev) - -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - int ret, i, clk; - - u3phy->um_ls_irq = platform_get_irq_byname(pdev, "linestate"); - if (u3phy->um_ls_irq < 0) { - dev_err(dev, "get utmi linestate irq failed\n"); - return -ENXIO; - } - - /* Get Vbus regulators */ - u3phy->vbus = devm_regulator_get_optional(dev, "vbus"); - if (IS_ERR(u3phy->vbus)) { - ret = PTR_ERR(u3phy->vbus); - if (ret == -EPROBE_DEFER) - return ret; - - dev_warn(dev, "Failed to get VBUS supply regulator\n"); - u3phy->vbus = NULL; - } - - for (clk = 0; clk < U3PHY_MAX_CLKS; clk++) { - u3phy->clks[clk] = of_clk_get(np, clk); - if (IS_ERR(u3phy->clks[clk])) { - ret = PTR_ERR(u3phy->clks[clk]); - if (ret == -EPROBE_DEFER) - goto err_put_clks; - u3phy->clks[clk] = NULL; - break; - } - } - - for (i = 0; i < U3PHY_RESET_MAX; i++) { - u3phy->rsts[i] = devm_reset_control_get(dev, get_rest_name(i)); - if (IS_ERR(u3phy->rsts[i])) { - dev_info(dev, "no %s reset control specified\n", - get_rest_name(i)); - u3phy->rsts[i] = NULL; - } - } - - return 0; - -err_put_clks: - while (--clk >= 0) - clk_put(u3phy->clks[clk]); - return ret; -} - -static int rockchip_u3phy_port_init(struct rockchip_u3phy *u3phy, - struct rockchip_u3phy_port *u3phy_port, - struct device_node *child_np) -{ - struct resource res; - struct phy *phy; - int ret; - - dev_dbg(u3phy->dev, "u3phy port initialize\n"); - - mutex_init(&u3phy_port->mutex); - u3phy_port->suspended = true; /* initial status */ - - phy = devm_phy_create(u3phy->dev, child_np, &rockchip_u3phy_ops); - if (IS_ERR(phy)) { - dev_err(u3phy->dev, "failed to create phy\n"); - return PTR_ERR(phy); - } - - u3phy_port->phy = phy; - - ret = of_address_to_resource(child_np, 0, &res); - if (ret) { - dev_err(u3phy->dev, "failed to get address resource(np-%s)\n", - child_np->name); - return ret; - } - - u3phy_port->base = devm_ioremap_resource(&u3phy_port->phy->dev, &res); - if (IS_ERR(u3phy_port->base)) { - dev_err(u3phy->dev, "failed to remap phy regs\n"); - return PTR_ERR(u3phy_port->base); - } - - if (!of_node_cmp(child_np->name, "pipe")) { - u3phy_port->type = U3PHY_TYPE_PIPE; - u3phy_port->refclk_25m_quirk = - of_property_read_bool(child_np, - "rockchip,refclk-25m-quirk"); - } else { - u3phy_port->type = U3PHY_TYPE_UTMI; - INIT_DELAYED_WORK(&u3phy_port->um_sm_work, - rockchip_u3phy_um_sm_work); - - ret = devm_request_threaded_irq(u3phy->dev, u3phy->um_ls_irq, - NULL, rockchip_u3phy_um_ls_irq, - IRQF_ONESHOT, "rockchip_u3phy", - u3phy_port); - if (ret) { - dev_err(u3phy->dev, "failed to request utmi linestate irq handle\n"); - return ret; - } - } - - if (u3phy->cfgs->phy_tuning) { - dev_dbg(u3phy->dev, "do u3phy tuning\n"); - ret = u3phy->cfgs->phy_tuning(u3phy, u3phy_port, child_np); - if (ret) - return ret; - } - - phy_set_drvdata(u3phy_port->phy, u3phy_port); - return 0; -} - -static int rockchip_u3phy_on_init(struct usb_phy *usb_phy) -{ - struct rockchip_u3phy *u3phy = - container_of(usb_phy, struct rockchip_u3phy, usb_phy); - - rockchip_u3phy_rest_deassert(u3phy, U3PHY_POR_RST | U3PHY_MAC_RST); - return 0; -} - -static void rockchip_u3phy_on_shutdown(struct usb_phy *usb_phy) -{ - struct rockchip_u3phy *u3phy = - container_of(usb_phy, struct rockchip_u3phy, usb_phy); - int rst; - - for (rst = 0; rst < U3PHY_RESET_MAX; rst++) - if (u3phy->rsts[rst] && rst != UTMI_APB_RSTN && - rst != PIPE_APB_RSTN) - reset_control_assert(u3phy->rsts[rst]); - udelay(1); -} - -static int rockchip_u3phy_on_disconnect(struct usb_phy *usb_phy, - enum usb_device_speed speed) -{ - struct rockchip_u3phy *u3phy = - container_of(usb_phy, struct rockchip_u3phy, usb_phy); - - dev_info(u3phy->dev, "%s device has disconnected\n", - (speed == USB_SPEED_SUPER) ? "U3" : "UW/U2/U1.1/U1"); - - if (speed == USB_SPEED_SUPER) - atomic_notifier_call_chain(&usb_phy->notifier, 0, NULL); - - return 0; -} - -static int rockchip_u3phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct device_node *child_np; - struct phy_provider *provider; - struct rockchip_u3phy *u3phy; - const struct rockchip_u3phy_cfg *phy_cfgs; - const struct of_device_id *match; - unsigned int reg[2]; - int index, ret; - - match = of_match_device(dev->driver->of_match_table, dev); - if (!match || !match->data) { - dev_err(dev, "phy-cfgs are not assigned!\n"); - return -EINVAL; - } - - u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL); - if (!u3phy) - return -ENOMEM; - - u3phy->u3phy_grf = - syscon_regmap_lookup_by_phandle(np, "rockchip,u3phygrf"); - if (IS_ERR(u3phy->u3phy_grf)) - return PTR_ERR(u3phy->u3phy_grf); - - u3phy->grf = - syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(u3phy->grf)) { - dev_err(dev, "Missing rockchip,grf property\n"); - return PTR_ERR(u3phy->grf); - } - - if (of_property_read_u32_array(np, "reg", reg, 2)) { - dev_err(dev, "the reg property is not assigned in %s node\n", - np->name); - return -EINVAL; - } - - u3phy->dev = dev; - u3phy->vbus_enabled = false; - phy_cfgs = match->data; - platform_set_drvdata(pdev, u3phy); - - /* find out a proper config which can be matched with dt. */ - index = 0; - while (phy_cfgs[index].reg) { - if (phy_cfgs[index].reg == reg[1]) { - u3phy->cfgs = &phy_cfgs[index]; - break; - } - - ++index; - } - - if (!u3phy->cfgs) { - dev_err(dev, "no phy-cfgs can be matched with %s node\n", - np->name); - return -EINVAL; - } - - ret = rockchip_u3phy_parse_dt(u3phy, pdev); - if (ret) { - dev_err(dev, "parse dt failed, ret(%d)\n", ret); - return ret; - } - - ret = rockchip_u3phy_clk_enable(u3phy); - if (ret) { - dev_err(dev, "clk enable failed, ret(%d)\n", ret); - return ret; - } - - rockchip_u3phy_rest_assert(u3phy); - rockchip_u3phy_rest_deassert(u3phy, U3PHY_APB_RST | U3PHY_POR_RST); - - index = 0; - for_each_available_child_of_node(np, child_np) { - struct rockchip_u3phy_port *u3phy_port = &u3phy->ports[index]; - - u3phy_port->index = index; - ret = rockchip_u3phy_port_init(u3phy, u3phy_port, child_np); - if (ret) { - dev_err(dev, "u3phy port init failed,ret(%d)\n", ret); - goto put_child; - } - - /* to prevent out of boundary */ - if (++index >= U3PHY_PORT_NUM) - break; - } - - provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR_OR_NULL(provider)) - goto put_child; - - rockchip_u3phy_rest_deassert(u3phy, U3PHY_MAC_RST); - rockchip_u3phy_clk_disable(u3phy); - - u3phy->usb_phy.dev = dev; - u3phy->usb_phy.init = rockchip_u3phy_on_init; - u3phy->usb_phy.shutdown = rockchip_u3phy_on_shutdown; - u3phy->usb_phy.notify_disconnect = rockchip_u3phy_on_disconnect; - usb_add_phy(&u3phy->usb_phy, USB_PHY_TYPE_USB3); - ATOMIC_INIT_NOTIFIER_HEAD(&u3phy->usb_phy.notifier); - - rockchip_u3phy_debugfs_init(u3phy); - - dev_info(dev, "Rockchip u3phy initialized successfully\n"); - return 0; - -put_child: - of_node_put(child_np); - return ret; -} - -static int rk3328_u3phy_pipe_power(struct rockchip_u3phy *u3phy, - struct rockchip_u3phy_port *u3phy_port, - bool on) -{ - unsigned int reg; - - if (on) { - reg = readl(u3phy_port->base + 0x1a8); - reg &= ~BIT(4); /* ldo power up */ - writel(reg, u3phy_port->base + 0x1a8); - - reg = readl(u3phy_port->base + 0x044); - reg &= ~BIT(4); /* bg power on */ - writel(reg, u3phy_port->base + 0x044); - - reg = readl(u3phy_port->base + 0x150); - reg |= BIT(6); /* tx bias enable */ - writel(reg, u3phy_port->base + 0x150); - - reg = readl(u3phy_port->base + 0x080); - reg &= ~BIT(2); /* tx cm power up */ - writel(reg, u3phy_port->base + 0x080); - - reg = readl(u3phy_port->base + 0x0c0); - /* tx obs enable and rx cm enable */ - reg |= (BIT(3) | BIT(4)); - writel(reg, u3phy_port->base + 0x0c0); - - udelay(1); - } else { - reg = readl(u3phy_port->base + 0x1a8); - reg |= BIT(4); /* ldo power down */ - writel(reg, u3phy_port->base + 0x1a8); - - reg = readl(u3phy_port->base + 0x044); - reg |= BIT(4); /* bg power down */ - writel(reg, u3phy_port->base + 0x044); - - reg = readl(u3phy_port->base + 0x150); - reg &= ~BIT(6); /* tx bias disable */ - writel(reg, u3phy_port->base + 0x150); - - reg = readl(u3phy_port->base + 0x080); - reg |= BIT(2); /* tx cm power down */ - writel(reg, u3phy_port->base + 0x080); - - reg = readl(u3phy_port->base + 0x0c0); - /* tx obs disable and rx cm disable */ - reg &= ~(BIT(3) | BIT(4)); - writel(reg, u3phy_port->base + 0x0c0); - } - - return 0; -} - -static int rk3328_u3phy_tuning(struct rockchip_u3phy *u3phy, - struct rockchip_u3phy_port *u3phy_port, - struct device_node *child_np) -{ - if (u3phy_port->type == U3PHY_TYPE_UTMI) { - /* - * For rk3328 SoC, pre-emphasis and pre-emphasis strength must - * be written as one fixed value as below. - * - * Dissimilarly, the odt 45ohm value should be flexibly tuninged - * for the different boards to adjust HS eye height, so its - * value can be assigned in DT in code design. - */ - - /* {bits[2:0]=111}: always enable pre-emphasis */ - u3phy->apbcfg.u2_pre_emp = 0x0f; - - /* {bits[5:3]=000}: pre-emphasis strength as the weakest */ - u3phy->apbcfg.u2_pre_emp_sth = 0x41; - - /* {bits[4:0]=10101}: odt 45ohm tuning */ - u3phy->apbcfg.u2_odt_tuning = 0xb5; - /* optional override of the odt 45ohm tuning */ - of_property_read_u32(child_np, "rockchip,odt-val-tuning", - &u3phy->apbcfg.u2_odt_tuning); - - writel(u3phy->apbcfg.u2_pre_emp, u3phy_port->base + 0x030); - writel(u3phy->apbcfg.u2_pre_emp_sth, u3phy_port->base + 0x040); - writel(u3phy->apbcfg.u2_odt_tuning, u3phy_port->base + 0x11c); - } else if (u3phy_port->type == U3PHY_TYPE_PIPE) { - if (u3phy_port->refclk_25m_quirk) { - dev_dbg(u3phy->dev, "switch to 25m refclk\n"); - /* ref clk switch to 25M */ - writel(0x64, u3phy_port->base + 0x11c); - writel(0x64, u3phy_port->base + 0x028); - writel(0x01, u3phy_port->base + 0x020); - writel(0x21, u3phy_port->base + 0x030); - writel(0x06, u3phy_port->base + 0x108); - writel(0x00, u3phy_port->base + 0x118); - } else { - /* configure for 24M ref clk */ - writel(0x80, u3phy_port->base + 0x10c); - writel(0x01, u3phy_port->base + 0x118); - writel(0x38, u3phy_port->base + 0x11c); - writel(0x83, u3phy_port->base + 0x020); - writel(0x02, u3phy_port->base + 0x108); - } - - /* Enable SSC */ - udelay(3); - writel(0x08, u3phy_port->base + 0x000); - writel(0x0c, u3phy_port->base + 0x120); - - /* Tuning Rx for compliance RJTL test */ - writel(0x70, u3phy_port->base + 0x150); - writel(0x12, u3phy_port->base + 0x0c8); - writel(0x05, u3phy_port->base + 0x148); - writel(0x08, u3phy_port->base + 0x068); - writel(0xf0, u3phy_port->base + 0x1c4); - writel(0xff, u3phy_port->base + 0x070); - writel(0x0f, u3phy_port->base + 0x06c); - writel(0xe0, u3phy_port->base + 0x060); - - /* - * Tuning Tx to increase the bias current - * used in TX driver and RX EQ, it can - * also increase the voltage of LFPS. - */ - writel(0x08, u3phy_port->base + 0x180); - } else { - dev_err(u3phy->dev, "invalid u3phy port type\n"); - return -EINVAL; - } - - return 0; -} - -static int rk322xh_u3phy_cp_test_enable(struct rockchip_u3phy *u3phy, - struct rockchip_u3phy_port *u3phy_port) -{ - if (u3phy_port->type == U3PHY_TYPE_PIPE) { - writel(0x0c, u3phy_port->base + 0x408); - } else { - dev_err(u3phy->dev, "The u3phy type is not pipe\n"); - return -EINVAL; - } - - return 0; -} - -static const struct rockchip_u3phy_cfg rk3328_u3phy_cfgs[] = { - { - .reg = 0xff470000, - .grfcfg = { - .um_suspend = { 0x0004, 15, 0, 0x1452, 0x15d1 }, - .u2_only_ctrl = { 0x0020, 15, 15, 0, 1 }, - .um_ls = { 0x0030, 5, 4, 0, 1 }, - .um_hstdct = { 0x0030, 7, 7, 0, 1 }, - .ls_det_en = { 0x0040, 0, 0, 0, 1 }, - .ls_det_st = { 0x0044, 0, 0, 0, 1 }, - .pp_pwr_st = { 0x0034, 14, 13, 0, 0}, - .pp_pwr_en = { {0x0020, 14, 0, 0x0014, 0x0005}, - {0x0020, 14, 0, 0x0014, 0x000d}, - {0x0020, 14, 0, 0x0014, 0x0015}, - {0x0020, 14, 0, 0x0014, 0x001d} }, - .u3_disable = { 0x04c4, 15, 0, 0x1100, 0x101}, - }, - .phy_pipe_power = rk3328_u3phy_pipe_power, - .phy_tuning = rk3328_u3phy_tuning, - .phy_cp_test = rk322xh_u3phy_cp_test_enable, - }, - { /* sentinel */ } -}; - -static const struct of_device_id rockchip_u3phy_dt_match[] = { - { .compatible = "rockchip,rk3328-u3phy", .data = &rk3328_u3phy_cfgs }, - {} -}; -MODULE_DEVICE_TABLE(of, rockchip_u3phy_dt_match); - -static struct platform_driver rockchip_u3phy_driver = { - .probe = rockchip_u3phy_probe, - .driver = { - .name = "rockchip-u3phy", - .of_match_table = rockchip_u3phy_dt_match, - }, -}; -module_platform_driver(rockchip_u3phy_driver); - -MODULE_AUTHOR("Frank Wang "); -MODULE_AUTHOR("William Wu "); -MODULE_DESCRIPTION("Rockchip USB 3.0 PHY driver"); -MODULE_LICENSE("GPL v2"); diff --git a/target/linux/rockchip/patches-5.4/808-phy-rockchip-add-driver-for-Rockchip-USB-3.0-PHY.patch b/target/linux/rockchip/patches-5.4/808-phy-rockchip-add-driver-for-Rockchip-USB-3.0-PHY.patch deleted file mode 100644 index 24b944f7be..0000000000 --- a/target/linux/rockchip/patches-5.4/808-phy-rockchip-add-driver-for-Rockchip-USB-3.0-PHY.patch +++ /dev/null @@ -1,52 +0,0 @@ -From faa767a9d0ced5642da0ae50b53d87de258f9525 Mon Sep 17 00:00:00 2001 -From: hmz007 -Date: Tue, 19 Nov 2019 17:24:30 +0800 -Subject: [PATCH] phy: rockchip: add driver for Rockchip USB 3.0 PHY - -Signed-off-by: hmz007 ---- - drivers/phy/rockchip/Kconfig | 8 + - drivers/phy/rockchip/Makefile | 1 + - drivers/phy/rockchip/phy-rockchip-inno-usb3.c | 1175 +++++++++++++++++ - 3 files changed, 1184 insertions(+) - create mode 100644 drivers/phy/rockchip/phy-rockchip-inno-usb3.c - ---- a/drivers/phy/rockchip/Kconfig -+++ b/drivers/phy/rockchip/Kconfig -@@ -35,6 +35,15 @@ config PHY_ROCKCHIP_INNO_USB2 - help - Support for Rockchip USB2.0 PHY with Innosilicon IP block. - -+config PHY_ROCKCHIP_INNO_USB3 -+ tristate "Rockchip INNO USB 3.0 PHY Driver" -+ depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF -+ depends on USB_SUPPORT -+ select GENERIC_PHY -+ select USB_PHY -+ help -+ Support for Rockchip USB 3.0 PHY with Innosilicon IP block. -+ - config PHY_ROCKCHIP_PCIE - tristate "Rockchip PCIe PHY Driver" - depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST ---- a/drivers/phy/rockchip/Makefile -+++ b/drivers/phy/rockchip/Makefile -@@ -3,6 +3,7 @@ obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-ro - obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o - obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o - obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o -+obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB3) += phy-rockchip-inno-usb3.o - obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o - obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o - obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o ---- a/Documentation/devicetree/bindings/soc/rockchip/grf.txt -+++ b/Documentation/devicetree/bindings/soc/rockchip/grf.txt -@@ -33,6 +33,8 @@ Required Properties: - - "rockchip,rk3328-usb2phy-grf", "syscon": for rk3328 - - compatible: USBGRF should be one of the following - - "rockchip,rv1108-usbgrf", "syscon": for rv1108 -+- compatible: USB3PHYGRF should be one of the following: -+ - "rockchip,u3phy-grf", "syscon" - - reg: physical base address of the controller and length of memory mapped - region. -