linux/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Rockchip MIPI RX Innosilicon DPHY driver
   4 *
   5 * Copyright (C) 2021 Fuzhou Rockchip Electronics Co., Ltd.
   6 */
   7
   8#include <linux/bitfield.h>
   9#include <linux/clk.h>
  10#include <linux/delay.h>
  11#include <linux/io.h>
  12#include <linux/mfd/syscon.h>
  13#include <linux/module.h>
  14#include <linux/of.h>
  15#include <linux/of_platform.h>
  16#include <linux/phy/phy.h>
  17#include <linux/phy/phy-mipi-dphy.h>
  18#include <linux/platform_device.h>
  19#include <linux/pm_runtime.h>
  20#include <linux/regmap.h>
  21#include <linux/reset.h>
  22
  23/* GRF */
  24#define RK1808_GRF_PD_VI_CON_OFFSET     0x0430
  25
  26#define RK3326_GRF_PD_VI_CON_OFFSET     0x0430
  27
  28#define RK3368_GRF_SOC_CON6_OFFSET      0x0418
  29
  30/* PHY */
  31#define CSIDPHY_CTRL_LANE_ENABLE                0x00
  32#define CSIDPHY_CTRL_LANE_ENABLE_CK             BIT(6)
  33#define CSIDPHY_CTRL_LANE_ENABLE_MASK           GENMASK(5, 2)
  34#define CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED      BIT(0)
  35
  36/* not present on all variants */
  37#define CSIDPHY_CTRL_PWRCTL                     0x04
  38#define CSIDPHY_CTRL_PWRCTL_UNDEFINED           GENMASK(7, 5)
  39#define CSIDPHY_CTRL_PWRCTL_SYNCRST             BIT(2)
  40#define CSIDPHY_CTRL_PWRCTL_LDO_PD              BIT(1)
  41#define CSIDPHY_CTRL_PWRCTL_PLL_PD              BIT(0)
  42
  43#define CSIDPHY_CTRL_DIG_RST                    0x80
  44#define CSIDPHY_CTRL_DIG_RST_UNDEFINED          0x1e
  45#define CSIDPHY_CTRL_DIG_RST_RESET              BIT(0)
  46
  47/* offset after ths_settle_offset */
  48#define CSIDPHY_CLK_THS_SETTLE                  0
  49#define CSIDPHY_LANE_THS_SETTLE(n)              (((n) + 1) * 0x80)
  50#define CSIDPHY_THS_SETTLE_MASK                 GENMASK(6, 0)
  51
  52/* offset after calib_offset */
  53#define CSIDPHY_CLK_CALIB_EN                    0
  54#define CSIDPHY_LANE_CALIB_EN(n)                (((n) + 1) * 0x80)
  55#define CSIDPHY_CALIB_EN                        BIT(7)
  56
  57/* Configure the count time of the THS-SETTLE by protocol. */
  58#define RK1808_CSIDPHY_CLK_WR_THS_SETTLE        0x160
  59#define RK3326_CSIDPHY_CLK_WR_THS_SETTLE        0x100
  60#define RK3368_CSIDPHY_CLK_WR_THS_SETTLE        0x100
  61
  62/* Calibration reception enable */
  63#define RK1808_CSIDPHY_CLK_CALIB_EN             0x168
  64
  65/*
  66 * The higher 16-bit of this register is used for write protection
  67 * only if BIT(x + 16) set to 1 the BIT(x) can be written.
  68 */
  69#define HIWORD_UPDATE(val, mask, shift) \
  70                ((val) << (shift) | (mask) << ((shift) + 16))
  71
  72#define HZ_TO_MHZ(freq)                         div_u64(freq, 1000 * 1000)
  73
  74enum dphy_reg_id {
  75        /* rk1808 & rk3326 */
  76        GRF_DPHY_CSIPHY_FORCERXMODE,
  77        GRF_DPHY_CSIPHY_CLKLANE_EN,
  78        GRF_DPHY_CSIPHY_DATALANE_EN,
  79};
  80
  81struct dphy_reg {
  82        u32 offset;
  83        u32 mask;
  84        u32 shift;
  85};
  86
  87#define PHY_REG(_offset, _width, _shift) \
  88        { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
  89
  90static const struct dphy_reg rk1808_grf_dphy_regs[] = {
  91        [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 0),
  92        [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 1, 8),
  93        [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 4),
  94};
  95
  96static const struct dphy_reg rk3326_grf_dphy_regs[] = {
  97        [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 0),
  98        [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 1, 8),
  99        [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 4),
 100};
 101
 102static const struct dphy_reg rk3368_grf_dphy_regs[] = {
 103        [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET, 4, 8),
 104};
 105
 106struct hsfreq_range {
 107        u32 range_h;
 108        u8 cfg_bit;
 109};
 110
 111struct dphy_drv_data {
 112        int pwrctl_offset;
 113        int ths_settle_offset;
 114        int calib_offset;
 115        const struct hsfreq_range *hsfreq_ranges;
 116        int num_hsfreq_ranges;
 117        const struct dphy_reg *grf_regs;
 118};
 119
 120struct rockchip_inno_csidphy {
 121        struct device *dev;
 122        void __iomem *phy_base;
 123        struct clk *pclk;
 124        struct regmap *grf;
 125        struct reset_control *rst;
 126        const struct dphy_drv_data *drv_data;
 127        struct phy_configure_opts_mipi_dphy config;
 128        u8 hsfreq;
 129};
 130
 131static inline void write_grf_reg(struct rockchip_inno_csidphy *priv,
 132                                 int index, u8 value)
 133{
 134        const struct dphy_drv_data *drv_data = priv->drv_data;
 135        const struct dphy_reg *reg = &drv_data->grf_regs[index];
 136
 137        if (reg->offset)
 138                regmap_write(priv->grf, reg->offset,
 139                             HIWORD_UPDATE(value, reg->mask, reg->shift));
 140}
 141
 142/* These tables must be sorted by .range_h ascending. */
 143static const struct hsfreq_range rk1808_mipidphy_hsfreq_ranges[] = {
 144        { 109, 0x02}, { 149, 0x03}, { 199, 0x06}, { 249, 0x06},
 145        { 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e},
 146        { 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e},
 147        {1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37},
 148        {2199, 0x3c}, {2399, 0x41}, {2499, 0x46}
 149};
 150
 151static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges[] = {
 152        { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
 153        { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
 154        { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
 155        {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
 156};
 157
 158static const struct hsfreq_range rk3368_mipidphy_hsfreq_ranges[] = {
 159        { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
 160        { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
 161        { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
 162        {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
 163};
 164
 165static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy *priv,
 166                                             int hsfreq, int offset)
 167{
 168        const struct dphy_drv_data *drv_data = priv->drv_data;
 169        u32 val;
 170
 171        val = readl(priv->phy_base + drv_data->ths_settle_offset + offset);
 172        val &= ~CSIDPHY_THS_SETTLE_MASK;
 173        val |= hsfreq;
 174        writel(val, priv->phy_base + drv_data->ths_settle_offset + offset);
 175}
 176
 177static int rockchip_inno_csidphy_configure(struct phy *phy,
 178                                           union phy_configure_opts *opts)
 179{
 180        struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
 181        const struct dphy_drv_data *drv_data = priv->drv_data;
 182        struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy;
 183        unsigned int hsfreq = 0;
 184        unsigned int i;
 185        u64 data_rate_mbps;
 186        int ret;
 187
 188        /* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
 189        ret = phy_mipi_dphy_config_validate(config);
 190        if (ret)
 191                return ret;
 192
 193        data_rate_mbps = HZ_TO_MHZ(config->hs_clk_rate);
 194
 195        dev_dbg(priv->dev, "lanes %d - data_rate_mbps %llu\n",
 196                config->lanes, data_rate_mbps);
 197        for (i = 0; i < drv_data->num_hsfreq_ranges; i++) {
 198                if (drv_data->hsfreq_ranges[i].range_h >= data_rate_mbps) {
 199                        hsfreq = drv_data->hsfreq_ranges[i].cfg_bit;
 200                        break;
 201                }
 202        }
 203        if (!hsfreq)
 204                return -EINVAL;
 205
 206        priv->hsfreq = hsfreq;
 207        priv->config = *config;
 208        return 0;
 209}
 210
 211static int rockchip_inno_csidphy_power_on(struct phy *phy)
 212{
 213        struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
 214        const struct dphy_drv_data *drv_data = priv->drv_data;
 215        u64 data_rate_mbps = HZ_TO_MHZ(priv->config.hs_clk_rate);
 216        u32 val;
 217        int ret, i;
 218
 219        ret = clk_enable(priv->pclk);
 220        if (ret < 0)
 221                return ret;
 222
 223        ret = pm_runtime_resume_and_get(priv->dev);
 224        if (ret < 0) {
 225                clk_disable(priv->pclk);
 226                return ret;
 227        }
 228
 229        /* phy start */
 230        if (drv_data->pwrctl_offset >= 0)
 231                writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED |
 232                       CSIDPHY_CTRL_PWRCTL_SYNCRST,
 233                       priv->phy_base + drv_data->pwrctl_offset);
 234
 235        /* set data lane num and enable clock lane */
 236        val = FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_MASK, GENMASK(priv->config.lanes - 1, 0)) |
 237              FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_CK, 1) |
 238              FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED, 1);
 239        writel(val, priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
 240
 241        /* Reset dphy analog part */
 242        if (drv_data->pwrctl_offset >= 0)
 243                writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED,
 244                       priv->phy_base + drv_data->pwrctl_offset);
 245        usleep_range(500, 1000);
 246
 247        /* Reset dphy digital part */
 248        writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED,
 249               priv->phy_base + CSIDPHY_CTRL_DIG_RST);
 250        writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED + CSIDPHY_CTRL_DIG_RST_RESET,
 251               priv->phy_base + CSIDPHY_CTRL_DIG_RST);
 252
 253        /* not into receive mode/wait stopstate */
 254        write_grf_reg(priv, GRF_DPHY_CSIPHY_FORCERXMODE, 0x0);
 255
 256        /* enable calibration */
 257        if (data_rate_mbps > 1500 && drv_data->calib_offset >= 0) {
 258                writel(CSIDPHY_CALIB_EN,
 259                       priv->phy_base + drv_data->calib_offset +
 260                                        CSIDPHY_CLK_CALIB_EN);
 261                for (i = 0; i < priv->config.lanes; i++)
 262                        writel(CSIDPHY_CALIB_EN,
 263                               priv->phy_base + drv_data->calib_offset +
 264                                                CSIDPHY_LANE_CALIB_EN(i));
 265        }
 266
 267        rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
 268                                         CSIDPHY_CLK_THS_SETTLE);
 269        for (i = 0; i < priv->config.lanes; i++)
 270                rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
 271                                                 CSIDPHY_LANE_THS_SETTLE(i));
 272
 273        write_grf_reg(priv, GRF_DPHY_CSIPHY_CLKLANE_EN, 0x1);
 274        write_grf_reg(priv, GRF_DPHY_CSIPHY_DATALANE_EN,
 275                      GENMASK(priv->config.lanes - 1, 0));
 276
 277        return 0;
 278}
 279
 280static int rockchip_inno_csidphy_power_off(struct phy *phy)
 281{
 282        struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
 283        const struct dphy_drv_data *drv_data = priv->drv_data;
 284
 285        /* disable all lanes */
 286        writel(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED,
 287               priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
 288
 289        /* disable pll and ldo */
 290        if (drv_data->pwrctl_offset >= 0)
 291                writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED |
 292                       CSIDPHY_CTRL_PWRCTL_LDO_PD |
 293                       CSIDPHY_CTRL_PWRCTL_PLL_PD,
 294                       priv->phy_base + drv_data->pwrctl_offset);
 295        usleep_range(500, 1000);
 296
 297        pm_runtime_put(priv->dev);
 298        clk_disable(priv->pclk);
 299
 300        return 0;
 301}
 302
 303static int rockchip_inno_csidphy_init(struct phy *phy)
 304{
 305        struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
 306
 307        return clk_prepare(priv->pclk);
 308}
 309
 310static int rockchip_inno_csidphy_exit(struct phy *phy)
 311{
 312        struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
 313
 314        clk_unprepare(priv->pclk);
 315
 316        return 0;
 317}
 318
 319static const struct phy_ops rockchip_inno_csidphy_ops = {
 320        .power_on       = rockchip_inno_csidphy_power_on,
 321        .power_off      = rockchip_inno_csidphy_power_off,
 322        .init           = rockchip_inno_csidphy_init,
 323        .exit           = rockchip_inno_csidphy_exit,
 324        .configure      = rockchip_inno_csidphy_configure,
 325        .owner          = THIS_MODULE,
 326};
 327
 328static const struct dphy_drv_data rk1808_mipidphy_drv_data = {
 329        .pwrctl_offset = -1,
 330        .ths_settle_offset = RK1808_CSIDPHY_CLK_WR_THS_SETTLE,
 331        .calib_offset = RK1808_CSIDPHY_CLK_CALIB_EN,
 332        .hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges,
 333        .num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges),
 334        .grf_regs = rk1808_grf_dphy_regs,
 335};
 336
 337static const struct dphy_drv_data rk3326_mipidphy_drv_data = {
 338        .pwrctl_offset = CSIDPHY_CTRL_PWRCTL,
 339        .ths_settle_offset = RK3326_CSIDPHY_CLK_WR_THS_SETTLE,
 340        .calib_offset = -1,
 341        .hsfreq_ranges = rk3326_mipidphy_hsfreq_ranges,
 342        .num_hsfreq_ranges = ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges),
 343        .grf_regs = rk3326_grf_dphy_regs,
 344};
 345
 346static const struct dphy_drv_data rk3368_mipidphy_drv_data = {
 347        .pwrctl_offset = CSIDPHY_CTRL_PWRCTL,
 348        .ths_settle_offset = RK3368_CSIDPHY_CLK_WR_THS_SETTLE,
 349        .calib_offset = -1,
 350        .hsfreq_ranges = rk3368_mipidphy_hsfreq_ranges,
 351        .num_hsfreq_ranges = ARRAY_SIZE(rk3368_mipidphy_hsfreq_ranges),
 352        .grf_regs = rk3368_grf_dphy_regs,
 353};
 354
 355static const struct of_device_id rockchip_inno_csidphy_match_id[] = {
 356        {
 357                .compatible = "rockchip,px30-csi-dphy",
 358                .data = &rk3326_mipidphy_drv_data,
 359        },
 360        {
 361                .compatible = "rockchip,rk1808-csi-dphy",
 362                .data = &rk1808_mipidphy_drv_data,
 363        },
 364        {
 365                .compatible = "rockchip,rk3326-csi-dphy",
 366                .data = &rk3326_mipidphy_drv_data,
 367        },
 368        {
 369                .compatible = "rockchip,rk3368-csi-dphy",
 370                .data = &rk3368_mipidphy_drv_data,
 371        },
 372        {}
 373};
 374MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id);
 375
 376static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
 377{
 378        struct rockchip_inno_csidphy *priv;
 379        struct device *dev = &pdev->dev;
 380        struct phy_provider *phy_provider;
 381        struct phy *phy;
 382
 383        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 384        if (!priv)
 385                return -ENOMEM;
 386
 387        priv->dev = dev;
 388        platform_set_drvdata(pdev, priv);
 389
 390        priv->drv_data = of_device_get_match_data(dev);
 391        if (!priv->drv_data) {
 392                dev_err(dev, "Can't find device data\n");
 393                return -ENODEV;
 394        }
 395
 396        priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
 397                                                    "rockchip,grf");
 398        if (IS_ERR(priv->grf)) {
 399                dev_err(dev, "Can't find GRF syscon\n");
 400                return PTR_ERR(priv->grf);
 401        }
 402
 403        priv->phy_base = devm_platform_ioremap_resource(pdev, 0);
 404        if (IS_ERR(priv->phy_base))
 405                return PTR_ERR(priv->phy_base);
 406
 407        priv->pclk = devm_clk_get(dev, "pclk");
 408        if (IS_ERR(priv->pclk)) {
 409                dev_err(dev, "failed to get pclk\n");
 410                return PTR_ERR(priv->pclk);
 411        }
 412
 413        priv->rst = devm_reset_control_get(dev, "apb");
 414        if (IS_ERR(priv->rst)) {
 415                dev_err(dev, "failed to get system reset control\n");
 416                return PTR_ERR(priv->rst);
 417        }
 418
 419        phy = devm_phy_create(dev, NULL, &rockchip_inno_csidphy_ops);
 420        if (IS_ERR(phy)) {
 421                dev_err(dev, "failed to create phy\n");
 422                return PTR_ERR(phy);
 423        }
 424
 425        phy_set_drvdata(phy, priv);
 426
 427        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 428        if (IS_ERR(phy_provider)) {
 429                dev_err(dev, "failed to register phy provider\n");
 430                return PTR_ERR(phy_provider);
 431        }
 432
 433        pm_runtime_enable(dev);
 434
 435        return 0;
 436}
 437
 438static int rockchip_inno_csidphy_remove(struct platform_device *pdev)
 439{
 440        struct rockchip_inno_csidphy *priv = platform_get_drvdata(pdev);
 441
 442        pm_runtime_disable(priv->dev);
 443
 444        return 0;
 445}
 446
 447static struct platform_driver rockchip_inno_csidphy_driver = {
 448        .driver = {
 449                .name = "rockchip-inno-csidphy",
 450                .of_match_table = rockchip_inno_csidphy_match_id,
 451        },
 452        .probe = rockchip_inno_csidphy_probe,
 453        .remove = rockchip_inno_csidphy_remove,
 454};
 455
 456module_platform_driver(rockchip_inno_csidphy_driver);
 457MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
 458MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");
 459MODULE_LICENSE("GPL v2");
 460