Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * COMBPHY driver for HiSilicon STB SoCs
0004  *
0005  * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com
0006  *
0007  * Authors: Jianguo Sun <sunjianguo1@huawei.com>
0008  */
0009 
0010 #include <linux/clk.h>
0011 #include <linux/delay.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mfd/syscon.h>
0015 #include <linux/module.h>
0016 #include <linux/of_device.h>
0017 #include <linux/phy/phy.h>
0018 #include <linux/regmap.h>
0019 #include <linux/reset.h>
0020 #include <dt-bindings/phy/phy.h>
0021 
0022 #define COMBPHY_MODE_PCIE       0
0023 #define COMBPHY_MODE_USB3       1
0024 #define COMBPHY_MODE_SATA       2
0025 
0026 #define COMBPHY_CFG_REG         0x0
0027 #define COMBPHY_BYPASS_CODEC        BIT(31)
0028 #define COMBPHY_TEST_WRITE      BIT(24)
0029 #define COMBPHY_TEST_DATA_SHIFT     20
0030 #define COMBPHY_TEST_DATA_MASK      GENMASK(23, 20)
0031 #define COMBPHY_TEST_ADDR_SHIFT     12
0032 #define COMBPHY_TEST_ADDR_MASK      GENMASK(16, 12)
0033 #define COMBPHY_CLKREF_OUT_OEN      BIT(0)
0034 
0035 struct histb_combphy_mode {
0036     int fixed;
0037     int select;
0038     u32 reg;
0039     u32 shift;
0040     u32 mask;
0041 };
0042 
0043 struct histb_combphy_priv {
0044     void __iomem *mmio;
0045     struct regmap *syscon;
0046     struct reset_control *por_rst;
0047     struct clk *ref_clk;
0048     struct phy *phy;
0049     struct histb_combphy_mode mode;
0050 };
0051 
0052 static void nano_register_write(struct histb_combphy_priv *priv,
0053                 u32 addr, u32 data)
0054 {
0055     void __iomem *reg = priv->mmio + COMBPHY_CFG_REG;
0056     u32 val;
0057 
0058     /* Set up address and data for the write */
0059     val = readl(reg);
0060     val &= ~COMBPHY_TEST_ADDR_MASK;
0061     val |= addr << COMBPHY_TEST_ADDR_SHIFT;
0062     val &= ~COMBPHY_TEST_DATA_MASK;
0063     val |= data << COMBPHY_TEST_DATA_SHIFT;
0064     writel(val, reg);
0065 
0066     /* Flip strobe control to trigger the write */
0067     val &= ~COMBPHY_TEST_WRITE;
0068     writel(val, reg);
0069     val |= COMBPHY_TEST_WRITE;
0070     writel(val, reg);
0071 }
0072 
0073 static int is_mode_fixed(struct histb_combphy_mode *mode)
0074 {
0075     return (mode->fixed != PHY_NONE) ? true : false;
0076 }
0077 
0078 static int histb_combphy_set_mode(struct histb_combphy_priv *priv)
0079 {
0080     struct histb_combphy_mode *mode = &priv->mode;
0081     struct regmap *syscon = priv->syscon;
0082     u32 hw_sel;
0083 
0084     if (is_mode_fixed(mode))
0085         return 0;
0086 
0087     switch (mode->select) {
0088     case PHY_TYPE_SATA:
0089         hw_sel = COMBPHY_MODE_SATA;
0090         break;
0091     case PHY_TYPE_PCIE:
0092         hw_sel = COMBPHY_MODE_PCIE;
0093         break;
0094     case PHY_TYPE_USB3:
0095         hw_sel = COMBPHY_MODE_USB3;
0096         break;
0097     default:
0098         return -EINVAL;
0099     }
0100 
0101     return regmap_update_bits(syscon, mode->reg, mode->mask,
0102                   hw_sel << mode->shift);
0103 }
0104 
0105 static int histb_combphy_init(struct phy *phy)
0106 {
0107     struct histb_combphy_priv *priv = phy_get_drvdata(phy);
0108     u32 val;
0109     int ret;
0110 
0111     ret = histb_combphy_set_mode(priv);
0112     if (ret)
0113         return ret;
0114 
0115     /* Clear bypass bit to enable encoding/decoding */
0116     val = readl(priv->mmio + COMBPHY_CFG_REG);
0117     val &= ~COMBPHY_BYPASS_CODEC;
0118     writel(val, priv->mmio + COMBPHY_CFG_REG);
0119 
0120     ret = clk_prepare_enable(priv->ref_clk);
0121     if (ret)
0122         return ret;
0123 
0124     reset_control_deassert(priv->por_rst);
0125 
0126     /* Enable EP clock */
0127     val = readl(priv->mmio + COMBPHY_CFG_REG);
0128     val |= COMBPHY_CLKREF_OUT_OEN;
0129     writel(val, priv->mmio + COMBPHY_CFG_REG);
0130 
0131     /* Need to wait for EP clock stable */
0132     mdelay(5);
0133 
0134     /* Configure nano phy registers as suggested by vendor */
0135     nano_register_write(priv, 0x1, 0x8);
0136     nano_register_write(priv, 0xc, 0x9);
0137     nano_register_write(priv, 0x1a, 0x4);
0138 
0139     return 0;
0140 }
0141 
0142 static int histb_combphy_exit(struct phy *phy)
0143 {
0144     struct histb_combphy_priv *priv = phy_get_drvdata(phy);
0145     u32 val;
0146 
0147     /* Disable EP clock */
0148     val = readl(priv->mmio + COMBPHY_CFG_REG);
0149     val &= ~COMBPHY_CLKREF_OUT_OEN;
0150     writel(val, priv->mmio + COMBPHY_CFG_REG);
0151 
0152     reset_control_assert(priv->por_rst);
0153     clk_disable_unprepare(priv->ref_clk);
0154 
0155     return 0;
0156 }
0157 
0158 static const struct phy_ops histb_combphy_ops = {
0159     .init = histb_combphy_init,
0160     .exit = histb_combphy_exit,
0161     .owner = THIS_MODULE,
0162 };
0163 
0164 static struct phy *histb_combphy_xlate(struct device *dev,
0165                        struct of_phandle_args *args)
0166 {
0167     struct histb_combphy_priv *priv = dev_get_drvdata(dev);
0168     struct histb_combphy_mode *mode = &priv->mode;
0169 
0170     if (args->args_count < 1) {
0171         dev_err(dev, "invalid number of arguments\n");
0172         return ERR_PTR(-EINVAL);
0173     }
0174 
0175     mode->select = args->args[0];
0176 
0177     if (mode->select < PHY_TYPE_SATA || mode->select > PHY_TYPE_USB3) {
0178         dev_err(dev, "invalid phy mode select argument\n");
0179         return ERR_PTR(-EINVAL);
0180     }
0181 
0182     if (is_mode_fixed(mode) && mode->select != mode->fixed) {
0183         dev_err(dev, "mode select %d mismatch fixed phy mode %d\n",
0184             mode->select, mode->fixed);
0185         return ERR_PTR(-EINVAL);
0186     }
0187 
0188     return priv->phy;
0189 }
0190 
0191 static int histb_combphy_probe(struct platform_device *pdev)
0192 {
0193     struct phy_provider *phy_provider;
0194     struct device *dev = &pdev->dev;
0195     struct histb_combphy_priv *priv;
0196     struct device_node *np = dev->of_node;
0197     struct histb_combphy_mode *mode;
0198     u32 vals[3];
0199     int ret;
0200 
0201     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0202     if (!priv)
0203         return -ENOMEM;
0204 
0205     priv->mmio = devm_platform_ioremap_resource(pdev, 0);
0206     if (IS_ERR(priv->mmio)) {
0207         ret = PTR_ERR(priv->mmio);
0208         return ret;
0209     }
0210 
0211     priv->syscon = syscon_node_to_regmap(np->parent);
0212     if (IS_ERR(priv->syscon)) {
0213         dev_err(dev, "failed to find peri_ctrl syscon regmap\n");
0214         return PTR_ERR(priv->syscon);
0215     }
0216 
0217     mode = &priv->mode;
0218     mode->fixed = PHY_NONE;
0219 
0220     ret = of_property_read_u32(np, "hisilicon,fixed-mode", &mode->fixed);
0221     if (ret == 0)
0222         dev_dbg(dev, "found fixed phy mode %d\n", mode->fixed);
0223 
0224     ret = of_property_read_u32_array(np, "hisilicon,mode-select-bits",
0225                      vals, ARRAY_SIZE(vals));
0226     if (ret == 0) {
0227         if (is_mode_fixed(mode)) {
0228             dev_err(dev, "found select bits for fixed mode phy\n");
0229             return -EINVAL;
0230         }
0231 
0232         mode->reg = vals[0];
0233         mode->shift = vals[1];
0234         mode->mask = vals[2];
0235         dev_dbg(dev, "found mode select bits\n");
0236     } else {
0237         if (!is_mode_fixed(mode)) {
0238             dev_err(dev, "no valid select bits found for non-fixed phy\n");
0239             return -ENODEV;
0240         }
0241     }
0242 
0243     priv->ref_clk = devm_clk_get(dev, NULL);
0244     if (IS_ERR(priv->ref_clk)) {
0245         dev_err(dev, "failed to find ref clock\n");
0246         return PTR_ERR(priv->ref_clk);
0247     }
0248 
0249     priv->por_rst = devm_reset_control_get(dev, NULL);
0250     if (IS_ERR(priv->por_rst)) {
0251         dev_err(dev, "failed to get poweron reset\n");
0252         return PTR_ERR(priv->por_rst);
0253     }
0254 
0255     priv->phy = devm_phy_create(dev, NULL, &histb_combphy_ops);
0256     if (IS_ERR(priv->phy)) {
0257         dev_err(dev, "failed to create combphy\n");
0258         return PTR_ERR(priv->phy);
0259     }
0260 
0261     dev_set_drvdata(dev, priv);
0262     phy_set_drvdata(priv->phy, priv);
0263 
0264     phy_provider = devm_of_phy_provider_register(dev, histb_combphy_xlate);
0265     return PTR_ERR_OR_ZERO(phy_provider);
0266 }
0267 
0268 static const struct of_device_id histb_combphy_of_match[] = {
0269     { .compatible = "hisilicon,hi3798cv200-combphy" },
0270     { },
0271 };
0272 MODULE_DEVICE_TABLE(of, histb_combphy_of_match);
0273 
0274 static struct platform_driver histb_combphy_driver = {
0275     .probe  = histb_combphy_probe,
0276     .driver = {
0277         .name = "combphy",
0278         .of_match_table = histb_combphy_of_match,
0279     },
0280 };
0281 module_platform_driver(histb_combphy_driver);
0282 
0283 MODULE_DESCRIPTION("HiSilicon STB COMBPHY driver");
0284 MODULE_LICENSE("GPL v2");