13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * Rockchip PIPE USB3.0 PCIE SATA combphy driver
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (C) 2020 Rockchip Electronics Co., Ltd.
63d0407baSopenharmony_ci */
73d0407baSopenharmony_ci
83d0407baSopenharmony_ci#include <linux/clk.h>
93d0407baSopenharmony_ci#include <linux/delay.h>
103d0407baSopenharmony_ci#include <linux/io.h>
113d0407baSopenharmony_ci#include <linux/iopoll.h>
123d0407baSopenharmony_ci#include <linux/kernel.h>
133d0407baSopenharmony_ci#include <linux/mfd/syscon.h>
143d0407baSopenharmony_ci#include <linux/module.h>
153d0407baSopenharmony_ci#include <linux/of_device.h>
163d0407baSopenharmony_ci#include <linux/phy/phy.h>
173d0407baSopenharmony_ci#include <linux/regmap.h>
183d0407baSopenharmony_ci#include <linux/reset.h>
193d0407baSopenharmony_ci#include <dt-bindings/phy/phy.h>
203d0407baSopenharmony_ci
213d0407baSopenharmony_ci#define BIT_WRITEABLE_SHIFT 16
223d0407baSopenharmony_ci
233d0407baSopenharmony_cistruct rockchip_combphy_priv;
243d0407baSopenharmony_ci
253d0407baSopenharmony_cistruct combphy_reg {
263d0407baSopenharmony_ci    u16 offset;
273d0407baSopenharmony_ci    u16 bitend;
283d0407baSopenharmony_ci    u16 bitstart;
293d0407baSopenharmony_ci    u16 disable;
303d0407baSopenharmony_ci    u16 enable;
313d0407baSopenharmony_ci};
323d0407baSopenharmony_ci
333d0407baSopenharmony_cistruct rockchip_combphy_grfcfg {
343d0407baSopenharmony_ci    struct combphy_reg pcie_mode_set;
353d0407baSopenharmony_ci    struct combphy_reg usb_mode_set;
363d0407baSopenharmony_ci    struct combphy_reg sgmii_mode_set;
373d0407baSopenharmony_ci    struct combphy_reg qsgmii_mode_set;
383d0407baSopenharmony_ci    struct combphy_reg pipe_rxterm_set;
393d0407baSopenharmony_ci    struct combphy_reg pipe_txelec_set;
403d0407baSopenharmony_ci    struct combphy_reg pipe_txcomp_set;
413d0407baSopenharmony_ci    struct combphy_reg pipe_clk_25m;
423d0407baSopenharmony_ci    struct combphy_reg pipe_clk_100m;
433d0407baSopenharmony_ci    struct combphy_reg pipe_phymode_sel;
443d0407baSopenharmony_ci    struct combphy_reg pipe_rate_sel;
453d0407baSopenharmony_ci    struct combphy_reg pipe_rxterm_sel;
463d0407baSopenharmony_ci    struct combphy_reg pipe_txelec_sel;
473d0407baSopenharmony_ci    struct combphy_reg pipe_txcomp_sel;
483d0407baSopenharmony_ci    struct combphy_reg pipe_clk_ext;
493d0407baSopenharmony_ci    struct combphy_reg pipe_sel_usb;
503d0407baSopenharmony_ci    struct combphy_reg pipe_sel_qsgmii;
513d0407baSopenharmony_ci    struct combphy_reg pipe_phy_status;
523d0407baSopenharmony_ci    struct combphy_reg con0_for_pcie;
533d0407baSopenharmony_ci    struct combphy_reg con1_for_pcie;
543d0407baSopenharmony_ci    struct combphy_reg con2_for_pcie;
553d0407baSopenharmony_ci    struct combphy_reg con3_for_pcie;
563d0407baSopenharmony_ci    struct combphy_reg con0_for_sata;
573d0407baSopenharmony_ci    struct combphy_reg con1_for_sata;
583d0407baSopenharmony_ci    struct combphy_reg con2_for_sata;
593d0407baSopenharmony_ci    struct combphy_reg con3_for_sata;
603d0407baSopenharmony_ci    struct combphy_reg pipe_con0_for_sata;
613d0407baSopenharmony_ci    struct combphy_reg pipe_con1_for_sata;
623d0407baSopenharmony_ci    struct combphy_reg pipe_sgmii_mac_sel;
633d0407baSopenharmony_ci    struct combphy_reg pipe_xpcs_phy_ready;
643d0407baSopenharmony_ci    struct combphy_reg u3otg0_port_en;
653d0407baSopenharmony_ci    struct combphy_reg u3otg1_port_en;
663d0407baSopenharmony_ci};
673d0407baSopenharmony_ci
683d0407baSopenharmony_cistruct rockchip_combphy_cfg {
693d0407baSopenharmony_ci    const int num_clks;
703d0407baSopenharmony_ci    const struct clk_bulk_data *clks;
713d0407baSopenharmony_ci    const struct rockchip_combphy_grfcfg *grfcfg;
723d0407baSopenharmony_ci    bool force_det_out; /* Tx detect Rx errata */
733d0407baSopenharmony_ci    int (*combphy_cfg)(struct rockchip_combphy_priv *priv);
743d0407baSopenharmony_ci};
753d0407baSopenharmony_ci
763d0407baSopenharmony_cistruct rockchip_combphy_priv {
773d0407baSopenharmony_ci    u8 mode;
783d0407baSopenharmony_ci    void __iomem *mmio;
793d0407baSopenharmony_ci    int num_clks;
803d0407baSopenharmony_ci    struct clk_bulk_data *clks;
813d0407baSopenharmony_ci    struct device *dev;
823d0407baSopenharmony_ci    struct regmap *pipe_grf;
833d0407baSopenharmony_ci    struct regmap *phy_grf;
843d0407baSopenharmony_ci    struct phy *phy;
853d0407baSopenharmony_ci    struct reset_control *apb_rst;
863d0407baSopenharmony_ci    struct reset_control *phy_rst;
873d0407baSopenharmony_ci    const struct rockchip_combphy_cfg *cfg;
883d0407baSopenharmony_ci};
893d0407baSopenharmony_ci
903d0407baSopenharmony_cistatic inline bool param_read(struct regmap *base, const struct combphy_reg *reg, u32 val)
913d0407baSopenharmony_ci{
923d0407baSopenharmony_ci    int ret;
933d0407baSopenharmony_ci    u32 mask, orig, tmp;
943d0407baSopenharmony_ci
953d0407baSopenharmony_ci    ret = regmap_read(base, reg->offset, &orig);
963d0407baSopenharmony_ci    if (ret) {
973d0407baSopenharmony_ci        return false;
983d0407baSopenharmony_ci    }
993d0407baSopenharmony_ci
1003d0407baSopenharmony_ci    mask = GENMASK(reg->bitend, reg->bitstart);
1013d0407baSopenharmony_ci    tmp = (orig & mask) >> reg->bitstart;
1023d0407baSopenharmony_ci
1033d0407baSopenharmony_ci    return tmp == val;
1043d0407baSopenharmony_ci}
1053d0407baSopenharmony_ci
1063d0407baSopenharmony_cistatic int param_write(struct regmap *base, const struct combphy_reg *reg, bool en)
1073d0407baSopenharmony_ci{
1083d0407baSopenharmony_ci    u32 val, mask, tmp;
1093d0407baSopenharmony_ci
1103d0407baSopenharmony_ci    tmp = en ? reg->enable : reg->disable;
1113d0407baSopenharmony_ci    mask = GENMASK(reg->bitend, reg->bitstart);
1123d0407baSopenharmony_ci    val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
1133d0407baSopenharmony_ci
1143d0407baSopenharmony_ci    return regmap_write(base, reg->offset, val);
1153d0407baSopenharmony_ci}
1163d0407baSopenharmony_ci
1173d0407baSopenharmony_cistatic u32 rockchip_combphy_is_ready(struct rockchip_combphy_priv *priv)
1183d0407baSopenharmony_ci{
1193d0407baSopenharmony_ci    const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
1203d0407baSopenharmony_ci    u32 mask, val;
1213d0407baSopenharmony_ci
1223d0407baSopenharmony_ci    mask = GENMASK(cfg->pipe_phy_status.bitend, cfg->pipe_phy_status.bitstart);
1233d0407baSopenharmony_ci
1243d0407baSopenharmony_ci    regmap_read(priv->phy_grf, cfg->pipe_phy_status.offset, &val);
1253d0407baSopenharmony_ci    val = (val & mask) >> cfg->pipe_phy_status.bitstart;
1263d0407baSopenharmony_ci
1273d0407baSopenharmony_ci    return val;
1283d0407baSopenharmony_ci}
1293d0407baSopenharmony_ci
1303d0407baSopenharmony_cistatic int rockchip_combphy_pcie_init(struct rockchip_combphy_priv *priv)
1313d0407baSopenharmony_ci{
1323d0407baSopenharmony_ci    int ret = 0;
1333d0407baSopenharmony_ci    u32 val;
1343d0407baSopenharmony_ci
1353d0407baSopenharmony_ci    if (priv->cfg->combphy_cfg) {
1363d0407baSopenharmony_ci        ret = priv->cfg->combphy_cfg(priv);
1373d0407baSopenharmony_ci        if (ret) {
1383d0407baSopenharmony_ci            dev_err(priv->dev, "failed to init phy for pcie\n");
1393d0407baSopenharmony_ci            return ret;
1403d0407baSopenharmony_ci        }
1413d0407baSopenharmony_ci    }
1423d0407baSopenharmony_ci
1433d0407baSopenharmony_ci    if (priv->cfg->force_det_out) {
1443d0407baSopenharmony_ci        val = readl(priv->mmio + (0x19 << 0x02));
1453d0407baSopenharmony_ci        val |= BIT(0x05);
1463d0407baSopenharmony_ci        writel(val, priv->mmio + (0x19 << 0x02));
1473d0407baSopenharmony_ci    }
1483d0407baSopenharmony_ci
1493d0407baSopenharmony_ci    return ret;
1503d0407baSopenharmony_ci}
1513d0407baSopenharmony_ci
1523d0407baSopenharmony_cistatic int rockchip_combphy_usb3_init(struct rockchip_combphy_priv *priv)
1533d0407baSopenharmony_ci{
1543d0407baSopenharmony_ci    int ret = 0;
1553d0407baSopenharmony_ci
1563d0407baSopenharmony_ci    if (priv->cfg->combphy_cfg) {
1573d0407baSopenharmony_ci        ret = priv->cfg->combphy_cfg(priv);
1583d0407baSopenharmony_ci        if (ret) {
1593d0407baSopenharmony_ci            dev_err(priv->dev, "failed to init phy for usb3\n");
1603d0407baSopenharmony_ci            return ret;
1613d0407baSopenharmony_ci        }
1623d0407baSopenharmony_ci    }
1633d0407baSopenharmony_ci
1643d0407baSopenharmony_ci    return ret;
1653d0407baSopenharmony_ci}
1663d0407baSopenharmony_ci
1673d0407baSopenharmony_cistatic int rockchip_combphy_sata_init(struct rockchip_combphy_priv *priv)
1683d0407baSopenharmony_ci{
1693d0407baSopenharmony_ci    int ret = 0;
1703d0407baSopenharmony_ci
1713d0407baSopenharmony_ci    if (priv->cfg->combphy_cfg) {
1723d0407baSopenharmony_ci        ret = priv->cfg->combphy_cfg(priv);
1733d0407baSopenharmony_ci        if (ret) {
1743d0407baSopenharmony_ci            dev_err(priv->dev, "failed to init phy for sata\n");
1753d0407baSopenharmony_ci            return ret;
1763d0407baSopenharmony_ci        }
1773d0407baSopenharmony_ci    }
1783d0407baSopenharmony_ci
1793d0407baSopenharmony_ci    return ret;
1803d0407baSopenharmony_ci}
1813d0407baSopenharmony_ci
1823d0407baSopenharmony_cistatic int rockchip_combphy_sgmii_init(struct rockchip_combphy_priv *priv)
1833d0407baSopenharmony_ci{
1843d0407baSopenharmony_ci    int ret = 0;
1853d0407baSopenharmony_ci
1863d0407baSopenharmony_ci    if (priv->cfg->combphy_cfg) {
1873d0407baSopenharmony_ci        ret = priv->cfg->combphy_cfg(priv);
1883d0407baSopenharmony_ci        if (ret) {
1893d0407baSopenharmony_ci            dev_err(priv->dev, "failed to init phy for sgmii\n");
1903d0407baSopenharmony_ci            return ret;
1913d0407baSopenharmony_ci        }
1923d0407baSopenharmony_ci    }
1933d0407baSopenharmony_ci
1943d0407baSopenharmony_ci    return ret;
1953d0407baSopenharmony_ci}
1963d0407baSopenharmony_ci
1973d0407baSopenharmony_cistatic int rockchip_combphy_set_mode(struct rockchip_combphy_priv *priv)
1983d0407baSopenharmony_ci{
1993d0407baSopenharmony_ci    switch (priv->mode) {
2003d0407baSopenharmony_ci        case PHY_TYPE_PCIE:
2013d0407baSopenharmony_ci            rockchip_combphy_pcie_init(priv);
2023d0407baSopenharmony_ci            break;
2033d0407baSopenharmony_ci        case PHY_TYPE_USB3:
2043d0407baSopenharmony_ci            rockchip_combphy_usb3_init(priv);
2053d0407baSopenharmony_ci            break;
2063d0407baSopenharmony_ci        case PHY_TYPE_SATA:
2073d0407baSopenharmony_ci            rockchip_combphy_sata_init(priv);
2083d0407baSopenharmony_ci            break;
2093d0407baSopenharmony_ci        case PHY_TYPE_SGMII:
2103d0407baSopenharmony_ci        case PHY_TYPE_QSGMII:
2113d0407baSopenharmony_ci            return rockchip_combphy_sgmii_init(priv);
2123d0407baSopenharmony_ci        default:
2133d0407baSopenharmony_ci            dev_err(priv->dev, "incompatible PHY type\n");
2143d0407baSopenharmony_ci            return -EINVAL;
2153d0407baSopenharmony_ci    }
2163d0407baSopenharmony_ci
2173d0407baSopenharmony_ci    return 0;
2183d0407baSopenharmony_ci}
2193d0407baSopenharmony_ci
2203d0407baSopenharmony_cistatic int rockchip_combphy_init(struct phy *phy)
2213d0407baSopenharmony_ci{
2223d0407baSopenharmony_ci    struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
2233d0407baSopenharmony_ci    const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
2243d0407baSopenharmony_ci    u32 val;
2253d0407baSopenharmony_ci    int ret;
2263d0407baSopenharmony_ci
2273d0407baSopenharmony_ci    ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
2283d0407baSopenharmony_ci    if (ret) {
2293d0407baSopenharmony_ci        dev_err(priv->dev, "failed to enable clks\n");
2303d0407baSopenharmony_ci        return ret;
2313d0407baSopenharmony_ci    }
2323d0407baSopenharmony_ci
2333d0407baSopenharmony_ci    ret = rockchip_combphy_set_mode(priv);
2343d0407baSopenharmony_ci    if (ret) {
2353d0407baSopenharmony_ci        goto err_clk;
2363d0407baSopenharmony_ci    }
2373d0407baSopenharmony_ci
2383d0407baSopenharmony_ci    ret = reset_control_deassert(priv->phy_rst);
2393d0407baSopenharmony_ci    if (ret) {
2403d0407baSopenharmony_ci        goto err_clk;
2413d0407baSopenharmony_ci    }
2423d0407baSopenharmony_ci
2433d0407baSopenharmony_ci    if (priv->mode == PHY_TYPE_USB3) {
2443d0407baSopenharmony_ci        ret = readx_poll_timeout_atomic(rockchip_combphy_is_ready, priv, val, val == cfg->pipe_phy_status.enable, 0xA,
2453d0407baSopenharmony_ci                                        0x3E8);
2463d0407baSopenharmony_ci        if (ret) {
2473d0407baSopenharmony_ci            dev_warn(priv->dev, "wait phy status ready timeout\n");
2483d0407baSopenharmony_ci        }
2493d0407baSopenharmony_ci    }
2503d0407baSopenharmony_ci
2513d0407baSopenharmony_ci    return 0;
2523d0407baSopenharmony_ci
2533d0407baSopenharmony_cierr_clk:
2543d0407baSopenharmony_ci    clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
2553d0407baSopenharmony_ci
2563d0407baSopenharmony_ci    return ret;
2573d0407baSopenharmony_ci}
2583d0407baSopenharmony_ci
2593d0407baSopenharmony_cistatic int rockchip_combphy_exit(struct phy *phy)
2603d0407baSopenharmony_ci{
2613d0407baSopenharmony_ci    struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
2623d0407baSopenharmony_ci
2633d0407baSopenharmony_ci    clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
2643d0407baSopenharmony_ci    reset_control_assert(priv->phy_rst);
2653d0407baSopenharmony_ci
2663d0407baSopenharmony_ci    return 0;
2673d0407baSopenharmony_ci}
2683d0407baSopenharmony_ci
2693d0407baSopenharmony_cistatic const struct phy_ops rochchip_combphy_ops = {
2703d0407baSopenharmony_ci    .init = rockchip_combphy_init,
2713d0407baSopenharmony_ci    .exit = rockchip_combphy_exit,
2723d0407baSopenharmony_ci    .owner = THIS_MODULE,
2733d0407baSopenharmony_ci};
2743d0407baSopenharmony_ci
2753d0407baSopenharmony_cistatic struct phy *rockchip_combphy_xlate(struct device *dev, struct of_phandle_args *args)
2763d0407baSopenharmony_ci{
2773d0407baSopenharmony_ci    struct rockchip_combphy_priv *priv = dev_get_drvdata(dev);
2783d0407baSopenharmony_ci
2793d0407baSopenharmony_ci    if (args->args_count != 1) {
2803d0407baSopenharmony_ci        dev_err(dev, "invalid number of arguments\n");
2813d0407baSopenharmony_ci        return ERR_PTR(-EINVAL);
2823d0407baSopenharmony_ci    }
2833d0407baSopenharmony_ci
2843d0407baSopenharmony_ci    if (priv->mode != PHY_NONE && priv->mode != args->args[0]) {
2853d0407baSopenharmony_ci        dev_warn(dev, "phy type select %d overwriting type %d\n", args->args[0], priv->mode);
2863d0407baSopenharmony_ci    }
2873d0407baSopenharmony_ci
2883d0407baSopenharmony_ci    priv->mode = args->args[0];
2893d0407baSopenharmony_ci
2903d0407baSopenharmony_ci    return priv->phy;
2913d0407baSopenharmony_ci}
2923d0407baSopenharmony_ci
2933d0407baSopenharmony_cistatic int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy_priv *priv)
2943d0407baSopenharmony_ci{
2953d0407baSopenharmony_ci    const struct rockchip_combphy_cfg *phy_cfg = priv->cfg;
2963d0407baSopenharmony_ci    int ret, mac_id;
2973d0407baSopenharmony_ci    u32 vals[4];
2983d0407baSopenharmony_ci
2993d0407baSopenharmony_ci    ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
3003d0407baSopenharmony_ci    if (ret == -EPROBE_DEFER) {
3013d0407baSopenharmony_ci        return -EPROBE_DEFER;
3023d0407baSopenharmony_ci    }
3033d0407baSopenharmony_ci    if (ret) {
3043d0407baSopenharmony_ci        priv->num_clks = 0;
3053d0407baSopenharmony_ci    }
3063d0407baSopenharmony_ci
3073d0407baSopenharmony_ci    priv->pipe_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pipe-grf");
3083d0407baSopenharmony_ci    if (IS_ERR(priv->pipe_grf)) {
3093d0407baSopenharmony_ci        dev_err(dev, "failed to find peri_ctrl pipe-grf regmap\n");
3103d0407baSopenharmony_ci        return PTR_ERR(priv->pipe_grf);
3113d0407baSopenharmony_ci    }
3123d0407baSopenharmony_ci
3133d0407baSopenharmony_ci    priv->phy_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pipe-phy-grf");
3143d0407baSopenharmony_ci    if (IS_ERR(priv->phy_grf)) {
3153d0407baSopenharmony_ci        dev_err(dev, "failed to find peri_ctrl pipe-phy-grf regmap\n");
3163d0407baSopenharmony_ci        return PTR_ERR(priv->phy_grf);
3173d0407baSopenharmony_ci    }
3183d0407baSopenharmony_ci
3193d0407baSopenharmony_ci    if (device_property_present(dev, "rockchip,dis-u3otg0-port")) {
3203d0407baSopenharmony_ci        param_write(priv->pipe_grf, &phy_cfg->grfcfg->u3otg0_port_en, false);
3213d0407baSopenharmony_ci    } else if (device_property_present(dev, "rockchip,dis-u3otg1-port")) {
3223d0407baSopenharmony_ci        param_write(priv->pipe_grf, &phy_cfg->grfcfg->u3otg1_port_en, false);
3233d0407baSopenharmony_ci    }
3243d0407baSopenharmony_ci
3253d0407baSopenharmony_ci    if (!device_property_read_u32(dev, "rockchip,sgmii-mac-sel", &mac_id) && (mac_id > 0)) {
3263d0407baSopenharmony_ci        param_write(priv->pipe_grf, &phy_cfg->grfcfg->pipe_sgmii_mac_sel, true);
3273d0407baSopenharmony_ci    }
3283d0407baSopenharmony_ci
3293d0407baSopenharmony_ci    if (!device_property_read_u32_array(dev, "rockchip,pcie1ln-sel-bits", vals, ARRAY_SIZE(vals))) {
3303d0407baSopenharmony_ci        regmap_write(priv->pipe_grf, vals[0], (GENMASK(vals[0x02], vals[1]) << 0x10) | (vals[0x03] << vals[1]));
3313d0407baSopenharmony_ci    }
3323d0407baSopenharmony_ci
3333d0407baSopenharmony_ci    priv->apb_rst = devm_reset_control_get_optional(dev, "combphy-apb");
3343d0407baSopenharmony_ci    if (IS_ERR(priv->apb_rst)) {
3353d0407baSopenharmony_ci        ret = PTR_ERR(priv->apb_rst);
3363d0407baSopenharmony_ci        if (ret != -EPROBE_DEFER) {
3373d0407baSopenharmony_ci            dev_warn(dev, "failed to get apb reset\n");
3383d0407baSopenharmony_ci        }
3393d0407baSopenharmony_ci
3403d0407baSopenharmony_ci        return ret;
3413d0407baSopenharmony_ci    }
3423d0407baSopenharmony_ci
3433d0407baSopenharmony_ci    priv->phy_rst = devm_reset_control_get_optional(dev, "combphy");
3443d0407baSopenharmony_ci    if (IS_ERR(priv->phy_rst)) {
3453d0407baSopenharmony_ci        ret = PTR_ERR(priv->phy_rst);
3463d0407baSopenharmony_ci        if (ret != -EPROBE_DEFER) {
3473d0407baSopenharmony_ci            dev_warn(dev, "failed to get phy reset\n");
3483d0407baSopenharmony_ci        }
3493d0407baSopenharmony_ci
3503d0407baSopenharmony_ci        return ret;
3513d0407baSopenharmony_ci    }
3523d0407baSopenharmony_ci
3533d0407baSopenharmony_ci    return reset_control_assert(priv->phy_rst);
3543d0407baSopenharmony_ci}
3553d0407baSopenharmony_ci
3563d0407baSopenharmony_cistatic int rockchip_combphy_probe(struct platform_device *pdev)
3573d0407baSopenharmony_ci{
3583d0407baSopenharmony_ci    struct phy_provider *phy_provider;
3593d0407baSopenharmony_ci    struct device *dev = &pdev->dev;
3603d0407baSopenharmony_ci    struct rockchip_combphy_priv *priv;
3613d0407baSopenharmony_ci    const struct rockchip_combphy_cfg *phy_cfg;
3623d0407baSopenharmony_ci    struct resource *res;
3633d0407baSopenharmony_ci    int ret;
3643d0407baSopenharmony_ci
3653d0407baSopenharmony_ci    phy_cfg = of_device_get_match_data(dev);
3663d0407baSopenharmony_ci    if (!phy_cfg) {
3673d0407baSopenharmony_ci        dev_err(dev, "No OF match data provided\n");
3683d0407baSopenharmony_ci        return -EINVAL;
3693d0407baSopenharmony_ci    }
3703d0407baSopenharmony_ci
3713d0407baSopenharmony_ci    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3723d0407baSopenharmony_ci    if (!priv) {
3733d0407baSopenharmony_ci        return -ENOMEM;
3743d0407baSopenharmony_ci    }
3753d0407baSopenharmony_ci
3763d0407baSopenharmony_ci    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3773d0407baSopenharmony_ci    priv->mmio = devm_ioremap_resource(dev, res);
3783d0407baSopenharmony_ci    if (IS_ERR(priv->mmio)) {
3793d0407baSopenharmony_ci        ret = PTR_ERR(priv->mmio);
3803d0407baSopenharmony_ci        return ret;
3813d0407baSopenharmony_ci    }
3823d0407baSopenharmony_ci
3833d0407baSopenharmony_ci    priv->num_clks = phy_cfg->num_clks;
3843d0407baSopenharmony_ci
3853d0407baSopenharmony_ci    priv->clks = devm_kmemdup(dev, phy_cfg->clks, phy_cfg->num_clks * sizeof(struct clk_bulk_data), GFP_KERNEL);
3863d0407baSopenharmony_ci
3873d0407baSopenharmony_ci    if (!priv->clks) {
3883d0407baSopenharmony_ci        return -ENOMEM;
3893d0407baSopenharmony_ci    }
3903d0407baSopenharmony_ci
3913d0407baSopenharmony_ci    priv->dev = dev;
3923d0407baSopenharmony_ci    priv->mode = PHY_NONE;
3933d0407baSopenharmony_ci    priv->cfg = phy_cfg;
3943d0407baSopenharmony_ci
3953d0407baSopenharmony_ci    ret = rockchip_combphy_parse_dt(dev, priv);
3963d0407baSopenharmony_ci    if (ret) {
3973d0407baSopenharmony_ci        return ret;
3983d0407baSopenharmony_ci    }
3993d0407baSopenharmony_ci
4003d0407baSopenharmony_ci    priv->phy = devm_phy_create(dev, NULL, &rochchip_combphy_ops);
4013d0407baSopenharmony_ci    if (IS_ERR(priv->phy)) {
4023d0407baSopenharmony_ci        dev_err(dev, "failed to create combphy\n");
4033d0407baSopenharmony_ci        return PTR_ERR(priv->phy);
4043d0407baSopenharmony_ci    }
4053d0407baSopenharmony_ci
4063d0407baSopenharmony_ci    dev_set_drvdata(dev, priv);
4073d0407baSopenharmony_ci    phy_set_drvdata(priv->phy, priv);
4083d0407baSopenharmony_ci
4093d0407baSopenharmony_ci    phy_provider = devm_of_phy_provider_register(dev, rockchip_combphy_xlate);
4103d0407baSopenharmony_ci
4113d0407baSopenharmony_ci    return PTR_ERR_OR_ZERO(phy_provider);
4123d0407baSopenharmony_ci}
4133d0407baSopenharmony_ci
4143d0407baSopenharmony_cistatic int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
4153d0407baSopenharmony_ci{
4163d0407baSopenharmony_ci    const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
4173d0407baSopenharmony_ci    struct clk *refclk = NULL;
4183d0407baSopenharmony_ci    unsigned long rate;
4193d0407baSopenharmony_ci    int i;
4203d0407baSopenharmony_ci    u32 val;
4213d0407baSopenharmony_ci
4223d0407baSopenharmony_ci    /* Configure PHY reference clock frequency */
4233d0407baSopenharmony_ci    for (i = 0; i < priv->num_clks; i++) {
4243d0407baSopenharmony_ci        if (!strncmp(priv->clks[i].id, "refclk", 0x6)) {
4253d0407baSopenharmony_ci            refclk = priv->clks[i].clk;
4263d0407baSopenharmony_ci            break;
4273d0407baSopenharmony_ci        }
4283d0407baSopenharmony_ci    }
4293d0407baSopenharmony_ci
4303d0407baSopenharmony_ci    if (!refclk) {
4313d0407baSopenharmony_ci        dev_err(priv->dev, "No refclk found\n");
4323d0407baSopenharmony_ci        return -EINVAL;
4333d0407baSopenharmony_ci    }
4343d0407baSopenharmony_ci
4353d0407baSopenharmony_ci    switch (priv->mode) {
4363d0407baSopenharmony_ci        case PHY_TYPE_PCIE:
4373d0407baSopenharmony_ci            /* Set SSC downward spread spectrum */
4383d0407baSopenharmony_ci            val = readl(priv->mmio + (0x1f << 0x02));
4393d0407baSopenharmony_ci            val &= ~GENMASK(0x05, 0x04);
4403d0407baSopenharmony_ci            val |= 0x01 << 0x04;
4413d0407baSopenharmony_ci            writel(val, priv->mmio + 0x7c);
4423d0407baSopenharmony_ci
4433d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
4443d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
4453d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
4463d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
4473d0407baSopenharmony_ci            break;
4483d0407baSopenharmony_ci        case PHY_TYPE_USB3:
4493d0407baSopenharmony_ci            /* Set SSC downward spread spectrum */
4503d0407baSopenharmony_ci            val = readl(priv->mmio + (0x1f << 0x02));
4513d0407baSopenharmony_ci            val &= ~GENMASK(0x05, 0x04);
4523d0407baSopenharmony_ci            val |= 0x01 << 0x04;
4533d0407baSopenharmony_ci            writel(val, priv->mmio + 0x7c);
4543d0407baSopenharmony_ci
4553d0407baSopenharmony_ci            /* Enable adaptive CTLE for USB3.0 Rx */
4563d0407baSopenharmony_ci            val = readl(priv->mmio + (0x0e << 0x02));
4573d0407baSopenharmony_ci            val &= ~GENMASK(0, 0);
4583d0407baSopenharmony_ci            val |= 0x01;
4593d0407baSopenharmony_ci            writel(val, priv->mmio + (0x0e << 0x02));
4603d0407baSopenharmony_ci
4613d0407baSopenharmony_ci            /* Set PLL KVCO fine tuning signals */
4623d0407baSopenharmony_ci            val = readl(priv->mmio + (0x20 << 0x02));
4633d0407baSopenharmony_ci            val &= ~(0x7 << 0x02);
4643d0407baSopenharmony_ci            val |= 0x2 << 0x02;
4653d0407baSopenharmony_ci            writel(val, priv->mmio + (0x20 << 0x02));
4663d0407baSopenharmony_ci
4673d0407baSopenharmony_ci            /* Set PLL LPF R1 to su_trim[10:7]=1001 */
4683d0407baSopenharmony_ci            writel(0x4, priv->mmio + (0xb << 0x02));
4693d0407baSopenharmony_ci
4703d0407baSopenharmony_ci            /* Set PLL input clock divider 1/2 */
4713d0407baSopenharmony_ci            val = readl(priv->mmio + (0x5 << 2));
4723d0407baSopenharmony_ci            val &= ~(0x3 << 0x06);
4733d0407baSopenharmony_ci            val |= 0x1 << 0x06;
4743d0407baSopenharmony_ci            writel(val, priv->mmio + (0x5 << 0x02));
4753d0407baSopenharmony_ci
4763d0407baSopenharmony_ci            /* Set PLL loop divider */
4773d0407baSopenharmony_ci            writel(0x32, priv->mmio + (0x11 << 0x02));
4783d0407baSopenharmony_ci
4793d0407baSopenharmony_ci            /* Set PLL KVCO to min and set PLL charge pump current to max */
4803d0407baSopenharmony_ci            writel(0xf0, priv->mmio + (0xa << 0x02));
4813d0407baSopenharmony_ci
4823d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
4833d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
4843d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
4853d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->usb_mode_set, true);
4863d0407baSopenharmony_ci            break;
4873d0407baSopenharmony_ci        case PHY_TYPE_SATA:
4883d0407baSopenharmony_ci            writel(0x41, priv->mmio + 0x38);
4893d0407baSopenharmony_ci            writel(0x8F, priv->mmio + 0x18);
4903d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con0_for_sata, true);
4913d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con1_for_sata, true);
4923d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con2_for_sata, true);
4933d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con3_for_sata, true);
4943d0407baSopenharmony_ci            param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
4953d0407baSopenharmony_ci            break;
4963d0407baSopenharmony_ci        case PHY_TYPE_SGMII:
4973d0407baSopenharmony_ci            param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
4983d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
4993d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
5003d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->sgmii_mode_set, true);
5013d0407baSopenharmony_ci            break;
5023d0407baSopenharmony_ci        case PHY_TYPE_QSGMII:
5033d0407baSopenharmony_ci            param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
5043d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
5053d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_rate_sel, true);
5063d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
5073d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->qsgmii_mode_set, true);
5083d0407baSopenharmony_ci            break;
5093d0407baSopenharmony_ci        default:
5103d0407baSopenharmony_ci            dev_err(priv->dev, "incompatible PHY type\n");
5113d0407baSopenharmony_ci            return -EINVAL;
5123d0407baSopenharmony_ci    }
5133d0407baSopenharmony_ci
5143d0407baSopenharmony_ci    rate = clk_get_rate(refclk);
5153d0407baSopenharmony_ci
5163d0407baSopenharmony_ci    switch (rate) {
5173d0407baSopenharmony_ci        case 0x16E3600:
5183d0407baSopenharmony_ci            if (priv->mode == PHY_TYPE_USB3 || priv->mode == PHY_TYPE_SATA) {
5193d0407baSopenharmony_ci                /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */
5203d0407baSopenharmony_ci                val = readl(priv->mmio + (0x0e << 0x02));
5213d0407baSopenharmony_ci                val &= ~GENMASK(0x07, 0x06);
5223d0407baSopenharmony_ci                val |= 0x01 << 0x06;
5233d0407baSopenharmony_ci                writel(val, priv->mmio + (0x0e << 0x02));
5243d0407baSopenharmony_ci
5253d0407baSopenharmony_ci                val = readl(priv->mmio + (0x0f << 0x02));
5263d0407baSopenharmony_ci                val &= ~GENMASK(0x07, 0);
5273d0407baSopenharmony_ci                val |= 0x5f;
5283d0407baSopenharmony_ci                writel(val, priv->mmio + (0x0f << 0x02));
5293d0407baSopenharmony_ci            }
5303d0407baSopenharmony_ci            break;
5313d0407baSopenharmony_ci        case 0x17D7840:
5323d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
5333d0407baSopenharmony_ci            break;
5343d0407baSopenharmony_ci        case 0x5F5E100:
5353d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
5363d0407baSopenharmony_ci            if (priv->mode == PHY_TYPE_PCIE) {
5373d0407baSopenharmony_ci                /* PLL KVCO tuning fine */
5383d0407baSopenharmony_ci                val = readl(priv->mmio + (0x20 << 0x02));
5393d0407baSopenharmony_ci                val &= ~(0x7 << 0x02);
5403d0407baSopenharmony_ci                val |= 0x2 << 0x02;
5413d0407baSopenharmony_ci                writel(val, priv->mmio + (0x20 << 0x02));
5423d0407baSopenharmony_ci
5433d0407baSopenharmony_ci                /* Enable controlling random jitter, aka RMJ */
5443d0407baSopenharmony_ci                writel(0x4, priv->mmio + (0xb << 0x02));
5453d0407baSopenharmony_ci
5463d0407baSopenharmony_ci                val = readl(priv->mmio + (0x5 << 0x02));
5473d0407baSopenharmony_ci                val &= ~(0x3 << 0x06);
5483d0407baSopenharmony_ci                val |= 0x1 << 0x06;
5493d0407baSopenharmony_ci                writel(val, priv->mmio + (0x5 << 0x02));
5503d0407baSopenharmony_ci
5513d0407baSopenharmony_ci                writel(0x32, priv->mmio + (0x11 << 0x02));
5523d0407baSopenharmony_ci                writel(0xf0, priv->mmio + (0xa << 0x02));
5533d0407baSopenharmony_ci            } else if (priv->mode == PHY_TYPE_SATA) {
5543d0407baSopenharmony_ci                /* downward spread spectrum +500ppm */
5553d0407baSopenharmony_ci                val = readl(priv->mmio + (0x1f << 0x02));
5563d0407baSopenharmony_ci                val &= ~GENMASK(0x07, 0x04);
5573d0407baSopenharmony_ci                val |= 0x50;
5583d0407baSopenharmony_ci                writel(val, priv->mmio + (0x1f << 0x02));
5593d0407baSopenharmony_ci            }
5603d0407baSopenharmony_ci            break;
5613d0407baSopenharmony_ci        default:
5623d0407baSopenharmony_ci            dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
5633d0407baSopenharmony_ci            return -EINVAL;
5643d0407baSopenharmony_ci    }
5653d0407baSopenharmony_ci
5663d0407baSopenharmony_ci    if (device_property_read_bool(priv->dev, "rockchip,ext-refclk")) {
5673d0407baSopenharmony_ci        param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
5683d0407baSopenharmony_ci        if (priv->mode == PHY_TYPE_PCIE && rate == 0x5F5E100) {
5693d0407baSopenharmony_ci            val = readl(priv->mmio + (0xc << 0x02));
5703d0407baSopenharmony_ci            val |= (0x3 << 0x04) | (0x1 << 0x07);
5713d0407baSopenharmony_ci            writel(val, priv->mmio + (0xc << 0x02));
5723d0407baSopenharmony_ci
5733d0407baSopenharmony_ci            val = readl(priv->mmio + (0xd << 0x02));
5743d0407baSopenharmony_ci            val |= 0x1;
5753d0407baSopenharmony_ci            writel(val, priv->mmio + (0xd << 0x02));
5763d0407baSopenharmony_ci        }
5773d0407baSopenharmony_ci    }
5783d0407baSopenharmony_ci
5793d0407baSopenharmony_ci    if (device_property_read_bool(priv->dev, "rockchip,enable-ssc")) {
5803d0407baSopenharmony_ci        val = readl(priv->mmio + (0x7 << 0x02));
5813d0407baSopenharmony_ci        val |= BIT(0x04);
5823d0407baSopenharmony_ci        writel(val, priv->mmio + (0x7 << 0x02));
5833d0407baSopenharmony_ci    }
5843d0407baSopenharmony_ci
5853d0407baSopenharmony_ci    return 0;
5863d0407baSopenharmony_ci}
5873d0407baSopenharmony_ci
5883d0407baSopenharmony_cistatic const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = {
5893d0407baSopenharmony_ci    /* pipe-phy-grf */
5903d0407baSopenharmony_ci    .pcie_mode_set = {0x0000, 5, 0, 0x00, 0x11},
5913d0407baSopenharmony_ci    .usb_mode_set = {0x0000, 5, 0, 0x00, 0x04},
5923d0407baSopenharmony_ci    .sgmii_mode_set = {0x0000, 5, 0, 0x00, 0x01},
5933d0407baSopenharmony_ci    .qsgmii_mode_set = {0x0000, 5, 0, 0x00, 0x21},
5943d0407baSopenharmony_ci    .pipe_rxterm_set = {0x0000, 12, 12, 0x00, 0x01},
5953d0407baSopenharmony_ci    .pipe_txelec_set = {0x0004, 1, 1, 0x00, 0x01},
5963d0407baSopenharmony_ci    .pipe_txcomp_set = {0x0004, 4, 4, 0x00, 0x01},
5973d0407baSopenharmony_ci    .pipe_clk_25m = {0x0004, 14, 13, 0x00, 0x01},
5983d0407baSopenharmony_ci    .pipe_clk_100m = {0x0004, 14, 13, 0x00, 0x02},
5993d0407baSopenharmony_ci    .pipe_phymode_sel = {0x0008, 1, 1, 0x00, 0x01},
6003d0407baSopenharmony_ci    .pipe_rate_sel = {0x0008, 2, 2, 0x00, 0x01},
6013d0407baSopenharmony_ci    .pipe_rxterm_sel = {0x0008, 8, 8, 0x00, 0x01},
6023d0407baSopenharmony_ci    .pipe_txelec_sel = {0x0008, 12, 12, 0x00, 0x01},
6033d0407baSopenharmony_ci    .pipe_txcomp_sel = {0x0008, 15, 15, 0x00, 0x01},
6043d0407baSopenharmony_ci    .pipe_clk_ext = {0x000c, 9, 8, 0x02, 0x01},
6053d0407baSopenharmony_ci    .pipe_sel_usb = {0x000c, 14, 13, 0x00, 0x01},
6063d0407baSopenharmony_ci    .pipe_sel_qsgmii = {0x000c, 15, 13, 0x00, 0x07},
6073d0407baSopenharmony_ci    .pipe_phy_status = {0x0034, 6, 6, 0x01, 0x00},
6083d0407baSopenharmony_ci    .con0_for_pcie = {0x0000, 15, 0, 0x00, 0x1000},
6093d0407baSopenharmony_ci    .con1_for_pcie = {0x0004, 15, 0, 0x00, 0x0000},
6103d0407baSopenharmony_ci    .con2_for_pcie = {0x0008, 15, 0, 0x00, 0x0101},
6113d0407baSopenharmony_ci    .con3_for_pcie = {0x000c, 15, 0, 0x00, 0x0200},
6123d0407baSopenharmony_ci    .con0_for_sata = {0x0000, 15, 0, 0x00, 0x0119},
6133d0407baSopenharmony_ci    .con1_for_sata = {0x0004, 15, 0, 0x00, 0x0040},
6143d0407baSopenharmony_ci    .con2_for_sata = {0x0008, 15, 0, 0x00, 0x80c3},
6153d0407baSopenharmony_ci    .con3_for_sata = {0x000c, 15, 0, 0x00, 0x4407},
6163d0407baSopenharmony_ci    /* pipe-grf */
6173d0407baSopenharmony_ci    .pipe_con0_for_sata = {0x0000, 15, 0, 0x00, 0x2220},
6183d0407baSopenharmony_ci    .pipe_sgmii_mac_sel = {0x0040, 1, 1, 0x00, 0x01},
6193d0407baSopenharmony_ci    .pipe_xpcs_phy_ready = {0x0040, 2, 2, 0x00, 0x01},
6203d0407baSopenharmony_ci    .u3otg0_port_en = {0x0104, 15, 0, 0x0181, 0x1100},
6213d0407baSopenharmony_ci    .u3otg1_port_en = {0x0144, 15, 0, 0x0181, 0x1100},
6223d0407baSopenharmony_ci};
6233d0407baSopenharmony_ci
6243d0407baSopenharmony_cistatic const struct clk_bulk_data rk3568_clks[] = {
6253d0407baSopenharmony_ci    {.id = "refclk"},
6263d0407baSopenharmony_ci    {.id = "apbclk"},
6273d0407baSopenharmony_ci    {.id = "pipe_clk"},
6283d0407baSopenharmony_ci};
6293d0407baSopenharmony_ci
6303d0407baSopenharmony_cistatic const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
6313d0407baSopenharmony_ci    .num_clks = ARRAY_SIZE(rk3568_clks),
6323d0407baSopenharmony_ci    .clks = rk3568_clks,
6333d0407baSopenharmony_ci    .grfcfg = &rk3568_combphy_grfcfgs,
6343d0407baSopenharmony_ci    .combphy_cfg = rk3568_combphy_cfg,
6353d0407baSopenharmony_ci    .force_det_out = true,
6363d0407baSopenharmony_ci};
6373d0407baSopenharmony_ci
6383d0407baSopenharmony_cistatic int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv)
6393d0407baSopenharmony_ci{
6403d0407baSopenharmony_ci    const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
6413d0407baSopenharmony_ci    struct clk *refclk = NULL;
6423d0407baSopenharmony_ci    unsigned long rate;
6433d0407baSopenharmony_ci    int i;
6443d0407baSopenharmony_ci    u32 val;
6453d0407baSopenharmony_ci
6463d0407baSopenharmony_ci    /* Configure PHY reference clock frequency */
6473d0407baSopenharmony_ci    for (i = 0; i < priv->num_clks; i++) {
6483d0407baSopenharmony_ci        if (!strncmp(priv->clks[i].id, "refclk", 0x06)) {
6493d0407baSopenharmony_ci            refclk = priv->clks[i].clk;
6503d0407baSopenharmony_ci            break;
6513d0407baSopenharmony_ci        }
6523d0407baSopenharmony_ci    }
6533d0407baSopenharmony_ci
6543d0407baSopenharmony_ci    if (!refclk) {
6553d0407baSopenharmony_ci        dev_err(priv->dev, "No refclk found\n");
6563d0407baSopenharmony_ci        return -EINVAL;
6573d0407baSopenharmony_ci    }
6583d0407baSopenharmony_ci
6593d0407baSopenharmony_ci    switch (priv->mode) {
6603d0407baSopenharmony_ci        case PHY_TYPE_PCIE:
6613d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
6623d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
6633d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
6643d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
6653d0407baSopenharmony_ci            break;
6663d0407baSopenharmony_ci        case PHY_TYPE_USB3:
6673d0407baSopenharmony_ci            /* Set SSC downward spread spectrum */
6683d0407baSopenharmony_ci            val = readl(priv->mmio + (0x1f << 0x02));
6693d0407baSopenharmony_ci            val &= ~GENMASK(0x05, 0x04);
6703d0407baSopenharmony_ci            val |= 0x01 << 0x04;
6713d0407baSopenharmony_ci            writel(val, priv->mmio + 0x7c);
6723d0407baSopenharmony_ci
6733d0407baSopenharmony_ci            /* Enable adaptive CTLE for USB3.0 Rx */
6743d0407baSopenharmony_ci            val = readl(priv->mmio + (0x0e << 0x02));
6753d0407baSopenharmony_ci            val &= ~GENMASK(0, 0);
6763d0407baSopenharmony_ci            val |= 0x01;
6773d0407baSopenharmony_ci            writel(val, priv->mmio + (0x0e << 0x02));
6783d0407baSopenharmony_ci
6793d0407baSopenharmony_ci            /* Set PLL KVCO fine tuning signals */
6803d0407baSopenharmony_ci            val = readl(priv->mmio + (0x20 << 0x02));
6813d0407baSopenharmony_ci            val &= ~(0x7 << 0x02);
6823d0407baSopenharmony_ci            val |= 0x2 << 0x02;
6833d0407baSopenharmony_ci            writel(val, priv->mmio + (0x20 << 0x02));
6843d0407baSopenharmony_ci
6853d0407baSopenharmony_ci            /* Set PLL LPF R1 to su_trim[10:7]=1001 */
6863d0407baSopenharmony_ci            writel(0x4, priv->mmio + (0xb << 0x02));
6873d0407baSopenharmony_ci
6883d0407baSopenharmony_ci            /* Set PLL input clock divider 1/2 */
6893d0407baSopenharmony_ci            val = readl(priv->mmio + (0x5 << 2));
6903d0407baSopenharmony_ci            val &= ~(0x3 << 0x06);
6913d0407baSopenharmony_ci            val |= 0x1 << 0x06;
6923d0407baSopenharmony_ci            writel(val, priv->mmio + (0x5 << 0x02));
6933d0407baSopenharmony_ci
6943d0407baSopenharmony_ci            /* Set PLL loop divider */
6953d0407baSopenharmony_ci            writel(0x32, priv->mmio + (0x11 << 0x02));
6963d0407baSopenharmony_ci
6973d0407baSopenharmony_ci            /* Set PLL KVCO to min and set PLL charge pump current to max */
6983d0407baSopenharmony_ci            writel(0xf0, priv->mmio + (0xa << 0x02));
6993d0407baSopenharmony_ci
7003d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
7013d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
7023d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->usb_mode_set, true);
7033d0407baSopenharmony_ci            break;
7043d0407baSopenharmony_ci        case PHY_TYPE_SATA:
7053d0407baSopenharmony_ci            /* Enable adaptive CTLE for SATA Rx */
7063d0407baSopenharmony_ci            val = readl(priv->mmio + (0x0e << 0x02));
7073d0407baSopenharmony_ci            val &= ~GENMASK(0, 0);
7083d0407baSopenharmony_ci            val |= 0x01;
7093d0407baSopenharmony_ci            writel(val, priv->mmio + (0x0e << 0x02));
7103d0407baSopenharmony_ci            /* Set tx_rterm = 50 ohm and rx_rterm = 43.5 ohm */
7113d0407baSopenharmony_ci            writel(0x8F, priv->mmio + (0x06 << 0x02));
7123d0407baSopenharmony_ci
7133d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con0_for_sata, true);
7143d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con1_for_sata, true);
7153d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con2_for_sata, true);
7163d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->con3_for_sata, true);
7173d0407baSopenharmony_ci            param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
7183d0407baSopenharmony_ci            param_write(priv->pipe_grf, &cfg->pipe_con1_for_sata, true);
7193d0407baSopenharmony_ci            break;
7203d0407baSopenharmony_ci        case PHY_TYPE_SGMII:
7213d0407baSopenharmony_ci        case PHY_TYPE_QSGMII:
7223d0407baSopenharmony_ci        default:
7233d0407baSopenharmony_ci            dev_err(priv->dev, "incompatible PHY type\n");
7243d0407baSopenharmony_ci            return -EINVAL;
7253d0407baSopenharmony_ci    }
7263d0407baSopenharmony_ci
7273d0407baSopenharmony_ci    rate = clk_get_rate(refclk);
7283d0407baSopenharmony_ci
7293d0407baSopenharmony_ci    switch (rate) {
7303d0407baSopenharmony_ci        case 0x16E3600:
7313d0407baSopenharmony_ci            if (priv->mode == PHY_TYPE_USB3 || priv->mode == PHY_TYPE_SATA) {
7323d0407baSopenharmony_ci                /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */
7333d0407baSopenharmony_ci                val = readl(priv->mmio + (0x0e << 0x02));
7343d0407baSopenharmony_ci                val &= ~GENMASK(0x07, 0x06);
7353d0407baSopenharmony_ci                val |= 0x01 << 0x06;
7363d0407baSopenharmony_ci                writel(val, priv->mmio + (0x0e << 0x02));
7373d0407baSopenharmony_ci
7383d0407baSopenharmony_ci                val = readl(priv->mmio + (0x0f << 0x02));
7393d0407baSopenharmony_ci                val &= ~GENMASK(0x07, 0);
7403d0407baSopenharmony_ci                val |= 0x5f;
7413d0407baSopenharmony_ci                writel(val, priv->mmio + (0x0f << 0x02));
7423d0407baSopenharmony_ci            }
7433d0407baSopenharmony_ci            break;
7443d0407baSopenharmony_ci        case 0x17D7840:
7453d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
7463d0407baSopenharmony_ci            break;
7473d0407baSopenharmony_ci        case 0x5F5E100:
7483d0407baSopenharmony_ci            param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
7493d0407baSopenharmony_ci            if (priv->mode == PHY_TYPE_PCIE) {
7503d0407baSopenharmony_ci                /* PLL KVCO tuning fine */
7513d0407baSopenharmony_ci                val = readl(priv->mmio + (0x20 << 0x02));
7523d0407baSopenharmony_ci                val &= ~GENMASK(0x04, 0x02);
7533d0407baSopenharmony_ci                val |= 0x4 << 0x02;
7543d0407baSopenharmony_ci                writel(val, priv->mmio + (0x20 << 0x02));
7553d0407baSopenharmony_ci
7563d0407baSopenharmony_ci                /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */
7573d0407baSopenharmony_ci                val = 0x4c;
7583d0407baSopenharmony_ci                writel(val, priv->mmio + (0x1b << 0x02));
7593d0407baSopenharmony_ci
7603d0407baSopenharmony_ci                /* Set up su_trim:  */
7613d0407baSopenharmony_ci                val = 0xf0;
7623d0407baSopenharmony_ci                writel(val, priv->mmio + (0xa << 0x02));
7633d0407baSopenharmony_ci                val = 0x4;
7643d0407baSopenharmony_ci                writel(val, priv->mmio + (0xb << 0x02));
7653d0407baSopenharmony_ci            } else if (priv->mode == PHY_TYPE_SATA) {
7663d0407baSopenharmony_ci                /* downward spread spectrum +500ppm */
7673d0407baSopenharmony_ci                val = readl(priv->mmio + (0x1f << 0x02));
7683d0407baSopenharmony_ci                val &= ~GENMASK(0x07, 0x04);
7693d0407baSopenharmony_ci                val |= 0x50;
7703d0407baSopenharmony_ci                writel(val, priv->mmio + (0x1f << 0x02));
7713d0407baSopenharmony_ci            }
7723d0407baSopenharmony_ci            break;
7733d0407baSopenharmony_ci        default:
7743d0407baSopenharmony_ci            dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
7753d0407baSopenharmony_ci            return -EINVAL;
7763d0407baSopenharmony_ci    }
7773d0407baSopenharmony_ci
7783d0407baSopenharmony_ci    return 0;
7793d0407baSopenharmony_ci}
7803d0407baSopenharmony_ci
7813d0407baSopenharmony_cistatic const struct rockchip_combphy_grfcfg rk3588_combphy_grfcfgs = {
7823d0407baSopenharmony_ci    /* pipe-phy-grf */
7833d0407baSopenharmony_ci    .pcie_mode_set = {0x0000, 5, 0, 0x00, 0x11},
7843d0407baSopenharmony_ci    .usb_mode_set = {0x0000, 5, 0, 0x00, 0x04},
7853d0407baSopenharmony_ci    .pipe_rxterm_set = {0x0000, 12, 12, 0x00, 0x01},
7863d0407baSopenharmony_ci    .pipe_txelec_set = {0x0004, 1, 1, 0x00, 0x01},
7873d0407baSopenharmony_ci    .pipe_txcomp_set = {0x0004, 4, 4, 0x00, 0x01},
7883d0407baSopenharmony_ci    .pipe_clk_25m = {0x0004, 14, 13, 0x00, 0x01},
7893d0407baSopenharmony_ci    .pipe_clk_100m = {0x0004, 14, 13, 0x00, 0x02},
7903d0407baSopenharmony_ci    .pipe_rxterm_sel = {0x0008, 8, 8, 0x00, 0x01},
7913d0407baSopenharmony_ci    .pipe_txelec_sel = {0x0008, 12, 12, 0x00, 0x01},
7923d0407baSopenharmony_ci    .pipe_txcomp_sel = {0x0008, 15, 15, 0x00, 0x01},
7933d0407baSopenharmony_ci    .pipe_clk_ext = {0x000c, 9, 8, 0x02, 0x01},
7943d0407baSopenharmony_ci    .pipe_phy_status = {0x0034, 6, 6, 0x01, 0x00},
7953d0407baSopenharmony_ci    .con0_for_pcie = {0x0000, 15, 0, 0x00, 0x1000},
7963d0407baSopenharmony_ci    .con1_for_pcie = {0x0004, 15, 0, 0x00, 0x0000},
7973d0407baSopenharmony_ci    .con2_for_pcie = {0x0008, 15, 0, 0x00, 0x0101},
7983d0407baSopenharmony_ci    .con3_for_pcie = {0x000c, 15, 0, 0x00, 0x0200},
7993d0407baSopenharmony_ci    .con0_for_sata = {0x0000, 15, 0, 0x00, 0x0129},
8003d0407baSopenharmony_ci    .con1_for_sata = {0x0004, 15, 0, 0x00, 0x0000},
8013d0407baSopenharmony_ci    .con2_for_sata = {0x0008, 15, 0, 0x00, 0x80c1},
8023d0407baSopenharmony_ci    .con3_for_sata = {0x000c, 15, 0, 0x00, 0x0407},
8033d0407baSopenharmony_ci    /* pipe-grf */
8043d0407baSopenharmony_ci    .pipe_con0_for_sata = {0x0000, 11, 5, 0x00, 0x22},
8053d0407baSopenharmony_ci    .pipe_con1_for_sata = {0x0000, 2, 0, 0x00, 0x2},
8063d0407baSopenharmony_ci};
8073d0407baSopenharmony_ci
8083d0407baSopenharmony_cistatic const struct clk_bulk_data rk3588_clks[] = {
8093d0407baSopenharmony_ci    {.id = "refclk"},
8103d0407baSopenharmony_ci    {.id = "apbclk"},
8113d0407baSopenharmony_ci    {.id = "phpclk"},
8123d0407baSopenharmony_ci};
8133d0407baSopenharmony_ci
8143d0407baSopenharmony_cistatic const struct rockchip_combphy_cfg rk3588_combphy_cfgs = {
8153d0407baSopenharmony_ci    .num_clks = ARRAY_SIZE(rk3588_clks),
8163d0407baSopenharmony_ci    .clks = rk3588_clks,
8173d0407baSopenharmony_ci    .grfcfg = &rk3588_combphy_grfcfgs,
8183d0407baSopenharmony_ci    .combphy_cfg = rk3588_combphy_cfg,
8193d0407baSopenharmony_ci    .force_det_out = true,
8203d0407baSopenharmony_ci};
8213d0407baSopenharmony_ci
8223d0407baSopenharmony_cistatic const struct of_device_id rockchip_combphy_of_match[] = {
8233d0407baSopenharmony_ci    {
8243d0407baSopenharmony_ci        .compatible = "rockchip,rk3568-naneng-combphy",
8253d0407baSopenharmony_ci        .data = &rk3568_combphy_cfgs,
8263d0407baSopenharmony_ci    },
8273d0407baSopenharmony_ci    {
8283d0407baSopenharmony_ci        .compatible = "rockchip,rk3588-naneng-combphy",
8293d0407baSopenharmony_ci        .data = &rk3588_combphy_cfgs,
8303d0407baSopenharmony_ci    },
8313d0407baSopenharmony_ci    {},
8323d0407baSopenharmony_ci};
8333d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_combphy_of_match);
8343d0407baSopenharmony_ci
8353d0407baSopenharmony_cistatic struct platform_driver rockchip_combphy_driver = {
8363d0407baSopenharmony_ci    .probe = rockchip_combphy_probe,
8373d0407baSopenharmony_ci    .driver =
8383d0407baSopenharmony_ci        {
8393d0407baSopenharmony_ci            .name = "naneng-combphy",
8403d0407baSopenharmony_ci            .of_match_table = rockchip_combphy_of_match,
8413d0407baSopenharmony_ci        },
8423d0407baSopenharmony_ci};
8433d0407baSopenharmony_cimodule_platform_driver(rockchip_combphy_driver);
8443d0407baSopenharmony_ci
8453d0407baSopenharmony_ciMODULE_DESCRIPTION("Rockchip NANENG COMBPHY driver");
8463d0407baSopenharmony_ciMODULE_LICENSE("GPL v2");
847