linux/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/platform_device.h>
  15
  16#include "dsi_phy.h"
  17
  18#define S_DIV_ROUND_UP(n, d)    \
  19        (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
  20
  21static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
  22                                s32 min_result, bool even)
  23{
  24        s32 v;
  25
  26        v = (tmax - tmin) * percent;
  27        v = S_DIV_ROUND_UP(v, 100) + tmin;
  28        if (even && (v & 0x1))
  29                return max_t(s32, min_result, v - 1);
  30        else
  31                return max_t(s32, min_result, v);
  32}
  33
  34static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
  35                                        s32 ui, s32 coeff, s32 pcnt)
  36{
  37        s32 tmax, tmin, clk_z;
  38        s32 temp;
  39
  40        /* reset */
  41        temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
  42        tmin = S_DIV_ROUND_UP(temp, ui) - 2;
  43        if (tmin > 255) {
  44                tmax = 511;
  45                clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
  46        } else {
  47                tmax = 255;
  48                clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
  49        }
  50
  51        /* adjust */
  52        temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
  53        timing->clk_zero = clk_z + 8 - temp;
  54}
  55
  56int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
  57                             struct msm_dsi_phy_clk_request *clk_req)
  58{
  59        const unsigned long bit_rate = clk_req->bitclk_rate;
  60        const unsigned long esc_rate = clk_req->escclk_rate;
  61        s32 ui, lpx;
  62        s32 tmax, tmin;
  63        s32 pcnt0 = 10;
  64        s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
  65        s32 pcnt2 = 10;
  66        s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
  67        s32 coeff = 1000; /* Precision, should avoid overflow */
  68        s32 temp;
  69
  70        if (!bit_rate || !esc_rate)
  71                return -EINVAL;
  72
  73        ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
  74        lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
  75
  76        tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
  77        tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
  78        timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
  79
  80        temp = lpx / ui;
  81        if (temp & 0x1)
  82                timing->hs_rqst = temp;
  83        else
  84                timing->hs_rqst = max_t(s32, 0, temp - 2);
  85
  86        /* Calculate clk_zero after clk_prepare and hs_rqst */
  87        dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
  88
  89        temp = 105 * coeff + 12 * ui - 20 * coeff;
  90        tmax = S_DIV_ROUND_UP(temp, ui) - 2;
  91        tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
  92        timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
  93
  94        temp = 85 * coeff + 6 * ui;
  95        tmax = S_DIV_ROUND_UP(temp, ui) - 2;
  96        temp = 40 * coeff + 4 * ui;
  97        tmin = S_DIV_ROUND_UP(temp, ui) - 2;
  98        timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
  99
 100        tmax = 255;
 101        temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
 102        temp = 145 * coeff + 10 * ui - temp;
 103        tmin = S_DIV_ROUND_UP(temp, ui) - 2;
 104        timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
 105
 106        temp = 105 * coeff + 12 * ui - 20 * coeff;
 107        tmax = S_DIV_ROUND_UP(temp, ui) - 2;
 108        temp = 60 * coeff + 4 * ui;
 109        tmin = DIV_ROUND_UP(temp, ui) - 2;
 110        timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
 111
 112        tmax = 255;
 113        tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
 114        timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
 115
 116        tmax = 63;
 117        temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
 118        temp = 60 * coeff + 52 * ui - 24 * ui - temp;
 119        tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
 120        timing->shared_timings.clk_post = linear_inter(tmax, tmin, pcnt2, 0,
 121                                                       false);
 122        tmax = 63;
 123        temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
 124        temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
 125        temp += 8 * ui + lpx;
 126        tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
 127        if (tmin > tmax) {
 128                temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
 129                timing->shared_timings.clk_pre = temp >> 1;
 130                timing->shared_timings.clk_pre_inc_by_2 = true;
 131        } else {
 132                timing->shared_timings.clk_pre =
 133                                linear_inter(tmax, tmin, pcnt2, 0, false);
 134                timing->shared_timings.clk_pre_inc_by_2 = false;
 135        }
 136
 137        timing->ta_go = 3;
 138        timing->ta_sure = 0;
 139        timing->ta_get = 4;
 140
 141        DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
 142                timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
 143                timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
 144                timing->clk_trail, timing->clk_prepare, timing->hs_exit,
 145                timing->hs_zero, timing->hs_prepare, timing->hs_trail,
 146                timing->hs_rqst);
 147
 148        return 0;
 149}
 150
 151int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing,
 152                                struct msm_dsi_phy_clk_request *clk_req)
 153{
 154        const unsigned long bit_rate = clk_req->bitclk_rate;
 155        const unsigned long esc_rate = clk_req->escclk_rate;
 156        s32 ui, ui_x8, lpx;
 157        s32 tmax, tmin;
 158        s32 pcnt0 = 50;
 159        s32 pcnt1 = 50;
 160        s32 pcnt2 = 10;
 161        s32 pcnt3 = 30;
 162        s32 pcnt4 = 10;
 163        s32 pcnt5 = 2;
 164        s32 coeff = 1000; /* Precision, should avoid overflow */
 165        s32 hb_en, hb_en_ckln, pd_ckln, pd;
 166        s32 val, val_ckln;
 167        s32 temp;
 168
 169        if (!bit_rate || !esc_rate)
 170                return -EINVAL;
 171
 172        timing->hs_halfbyte_en = 0;
 173        hb_en = 0;
 174        timing->hs_halfbyte_en_ckln = 0;
 175        hb_en_ckln = 0;
 176        timing->hs_prep_dly_ckln = (bit_rate > 100000000) ? 0 : 3;
 177        pd_ckln = timing->hs_prep_dly_ckln;
 178        timing->hs_prep_dly = (bit_rate > 120000000) ? 0 : 1;
 179        pd = timing->hs_prep_dly;
 180
 181        val = (hb_en << 2) + (pd << 1);
 182        val_ckln = (hb_en_ckln << 2) + (pd_ckln << 1);
 183
 184        ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
 185        ui_x8 = ui << 3;
 186        lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
 187
 188        temp = S_DIV_ROUND_UP(38 * coeff - val_ckln * ui, ui_x8);
 189        tmin = max_t(s32, temp, 0);
 190        temp = (95 * coeff - val_ckln * ui) / ui_x8;
 191        tmax = max_t(s32, temp, 0);
 192        timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
 193
 194        temp = 300 * coeff - ((timing->clk_prepare << 3) + val_ckln) * ui;
 195        tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
 196        tmax = (tmin > 255) ? 511 : 255;
 197        timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
 198
 199        tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
 200        temp = 105 * coeff + 12 * ui - 20 * coeff;
 201        tmax = (temp + 3 * ui) / ui_x8;
 202        timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
 203
 204        temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui - val * ui, ui_x8);
 205        tmin = max_t(s32, temp, 0);
 206        temp = (85 * coeff + 6 * ui - val * ui) / ui_x8;
 207        tmax = max_t(s32, temp, 0);
 208        timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
 209
 210        temp = 145 * coeff + 10 * ui - ((timing->hs_prepare << 3) + val) * ui;
 211        tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
 212        tmax = 255;
 213        timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
 214
 215        tmin = DIV_ROUND_UP(60 * coeff + 4 * ui + 3 * ui, ui_x8);
 216        temp = 105 * coeff + 12 * ui - 20 * coeff;
 217        tmax = (temp + 3 * ui) / ui_x8;
 218        timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
 219
 220        temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
 221        timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
 222
 223        tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
 224        tmax = 255;
 225        timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
 226
 227        temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
 228        timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
 229
 230        temp = 60 * coeff + 52 * ui - 43 * ui;
 231        tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
 232        tmax = 63;
 233        timing->shared_timings.clk_post =
 234                                linear_inter(tmax, tmin, pcnt2, 0, false);
 235
 236        temp = 8 * ui + ((timing->clk_prepare << 3) + val_ckln) * ui;
 237        temp += (((timing->clk_zero + 3) << 3) + 11 - (pd_ckln << 1)) * ui;
 238        temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
 239                                (((timing->hs_rqst_ckln << 3) + 8) * ui);
 240        tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
 241        tmax = 63;
 242        if (tmin > tmax) {
 243                temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
 244                timing->shared_timings.clk_pre = temp >> 1;
 245                timing->shared_timings.clk_pre_inc_by_2 = 1;
 246        } else {
 247                timing->shared_timings.clk_pre =
 248                                linear_inter(tmax, tmin, pcnt2, 0, false);
 249                timing->shared_timings.clk_pre_inc_by_2 = 0;
 250        }
 251
 252        timing->ta_go = 3;
 253        timing->ta_sure = 0;
 254        timing->ta_get = 4;
 255
 256        DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
 257            timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
 258            timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
 259            timing->clk_trail, timing->clk_prepare, timing->hs_exit,
 260            timing->hs_zero, timing->hs_prepare, timing->hs_trail,
 261            timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
 262            timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
 263            timing->hs_prep_dly_ckln);
 264
 265        return 0;
 266}
 267
 268int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
 269        struct msm_dsi_phy_clk_request *clk_req)
 270{
 271        const unsigned long bit_rate = clk_req->bitclk_rate;
 272        const unsigned long esc_rate = clk_req->escclk_rate;
 273        s32 ui, ui_x8, lpx;
 274        s32 tmax, tmin;
 275        s32 pcnt0 = 50;
 276        s32 pcnt1 = 50;
 277        s32 pcnt2 = 10;
 278        s32 pcnt3 = 30;
 279        s32 pcnt4 = 10;
 280        s32 pcnt5 = 2;
 281        s32 coeff = 1000; /* Precision, should avoid overflow */
 282        s32 hb_en, hb_en_ckln;
 283        s32 temp;
 284
 285        if (!bit_rate || !esc_rate)
 286                return -EINVAL;
 287
 288        timing->hs_halfbyte_en = 0;
 289        hb_en = 0;
 290        timing->hs_halfbyte_en_ckln = 0;
 291        hb_en_ckln = 0;
 292
 293        ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
 294        ui_x8 = ui << 3;
 295        lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
 296
 297        temp = S_DIV_ROUND_UP(38 * coeff, ui_x8);
 298        tmin = max_t(s32, temp, 0);
 299        temp = (95 * coeff) / ui_x8;
 300        tmax = max_t(s32, temp, 0);
 301        timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
 302
 303        temp = 300 * coeff - (timing->clk_prepare << 3) * ui;
 304        tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
 305        tmax = (tmin > 255) ? 511 : 255;
 306        timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
 307
 308        tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
 309        temp = 105 * coeff + 12 * ui - 20 * coeff;
 310        tmax = (temp + 3 * ui) / ui_x8;
 311        timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
 312
 313        temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui, ui_x8);
 314        tmin = max_t(s32, temp, 0);
 315        temp = (85 * coeff + 6 * ui) / ui_x8;
 316        tmax = max_t(s32, temp, 0);
 317        timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
 318
 319        temp = 145 * coeff + 10 * ui - (timing->hs_prepare << 3) * ui;
 320        tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
 321        tmax = 255;
 322        timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
 323
 324        tmin = DIV_ROUND_UP(60 * coeff + 4 * ui, ui_x8) - 1;
 325        temp = 105 * coeff + 12 * ui - 20 * coeff;
 326        tmax = (temp / ui_x8) - 1;
 327        timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
 328
 329        temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
 330        timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
 331
 332        tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
 333        tmax = 255;
 334        timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
 335
 336        temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
 337        timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
 338
 339        temp = 60 * coeff + 52 * ui - 43 * ui;
 340        tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
 341        tmax = 63;
 342        timing->shared_timings.clk_post =
 343                linear_inter(tmax, tmin, pcnt2, 0, false);
 344
 345        temp = 8 * ui + (timing->clk_prepare << 3) * ui;
 346        temp += (((timing->clk_zero + 3) << 3) + 11) * ui;
 347        temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
 348                (((timing->hs_rqst_ckln << 3) + 8) * ui);
 349        tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
 350        tmax = 63;
 351        if (tmin > tmax) {
 352                temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
 353                timing->shared_timings.clk_pre = temp >> 1;
 354                timing->shared_timings.clk_pre_inc_by_2 = 1;
 355        } else {
 356                timing->shared_timings.clk_pre =
 357                        linear_inter(tmax, tmin, pcnt2, 0, false);
 358                        timing->shared_timings.clk_pre_inc_by_2 = 0;
 359        }
 360
 361        timing->ta_go = 3;
 362        timing->ta_sure = 0;
 363        timing->ta_get = 4;
 364
 365        DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
 366                timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
 367                timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
 368                timing->clk_trail, timing->clk_prepare, timing->hs_exit,
 369                timing->hs_zero, timing->hs_prepare, timing->hs_trail,
 370                timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
 371                timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
 372                timing->hs_prep_dly_ckln);
 373
 374        return 0;
 375}
 376
 377void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
 378                                u32 bit_mask)
 379{
 380        int phy_id = phy->id;
 381        u32 val;
 382
 383        if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
 384                return;
 385
 386        val = dsi_phy_read(phy->base + reg);
 387
 388        if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
 389                dsi_phy_write(phy->base + reg, val | bit_mask);
 390        else
 391                dsi_phy_write(phy->base + reg, val & (~bit_mask));
 392}
 393
 394static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
 395{
 396        struct regulator_bulk_data *s = phy->supplies;
 397        const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
 398        struct device *dev = &phy->pdev->dev;
 399        int num = phy->cfg->reg_cfg.num;
 400        int i, ret;
 401
 402        for (i = 0; i < num; i++)
 403                s[i].supply = regs[i].name;
 404
 405        ret = devm_regulator_bulk_get(dev, num, s);
 406        if (ret < 0) {
 407                dev_err(dev, "%s: failed to init regulator, ret=%d\n",
 408                                                __func__, ret);
 409                return ret;
 410        }
 411
 412        return 0;
 413}
 414
 415static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
 416{
 417        struct regulator_bulk_data *s = phy->supplies;
 418        const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
 419        int num = phy->cfg->reg_cfg.num;
 420        int i;
 421
 422        DBG("");
 423        for (i = num - 1; i >= 0; i--)
 424                if (regs[i].disable_load >= 0)
 425                        regulator_set_load(s[i].consumer, regs[i].disable_load);
 426
 427        regulator_bulk_disable(num, s);
 428}
 429
 430static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
 431{
 432        struct regulator_bulk_data *s = phy->supplies;
 433        const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
 434        struct device *dev = &phy->pdev->dev;
 435        int num = phy->cfg->reg_cfg.num;
 436        int ret, i;
 437
 438        DBG("");
 439        for (i = 0; i < num; i++) {
 440                if (regs[i].enable_load >= 0) {
 441                        ret = regulator_set_load(s[i].consumer,
 442                                                        regs[i].enable_load);
 443                        if (ret < 0) {
 444                                dev_err(dev,
 445                                        "regulator %d set op mode failed, %d\n",
 446                                        i, ret);
 447                                goto fail;
 448                        }
 449                }
 450        }
 451
 452        ret = regulator_bulk_enable(num, s);
 453        if (ret < 0) {
 454                dev_err(dev, "regulator enable failed, %d\n", ret);
 455                goto fail;
 456        }
 457
 458        return 0;
 459
 460fail:
 461        for (i--; i >= 0; i--)
 462                regulator_set_load(s[i].consumer, regs[i].disable_load);
 463        return ret;
 464}
 465
 466static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
 467{
 468        struct device *dev = &phy->pdev->dev;
 469        int ret;
 470
 471        pm_runtime_get_sync(dev);
 472
 473        ret = clk_prepare_enable(phy->ahb_clk);
 474        if (ret) {
 475                dev_err(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
 476                pm_runtime_put_sync(dev);
 477        }
 478
 479        return ret;
 480}
 481
 482static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
 483{
 484        clk_disable_unprepare(phy->ahb_clk);
 485        pm_runtime_put_autosuspend(&phy->pdev->dev);
 486}
 487
 488static const struct of_device_id dsi_phy_dt_match[] = {
 489#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
 490        { .compatible = "qcom,dsi-phy-28nm-hpm",
 491          .data = &dsi_phy_28nm_hpm_cfgs },
 492        { .compatible = "qcom,dsi-phy-28nm-lp",
 493          .data = &dsi_phy_28nm_lp_cfgs },
 494#endif
 495#ifdef CONFIG_DRM_MSM_DSI_20NM_PHY
 496        { .compatible = "qcom,dsi-phy-20nm",
 497          .data = &dsi_phy_20nm_cfgs },
 498#endif
 499#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
 500        { .compatible = "qcom,dsi-phy-28nm-8960",
 501          .data = &dsi_phy_28nm_8960_cfgs },
 502#endif
 503#ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
 504        { .compatible = "qcom,dsi-phy-14nm",
 505          .data = &dsi_phy_14nm_cfgs },
 506#endif
 507#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
 508        { .compatible = "qcom,dsi-phy-10nm",
 509          .data = &dsi_phy_10nm_cfgs },
 510#endif
 511        {}
 512};
 513
 514/*
 515 * Currently, we only support one SoC for each PHY type. When we have multiple
 516 * SoCs for the same PHY, we can try to make the index searching a bit more
 517 * clever.
 518 */
 519static int dsi_phy_get_id(struct msm_dsi_phy *phy)
 520{
 521        struct platform_device *pdev = phy->pdev;
 522        const struct msm_dsi_phy_cfg *cfg = phy->cfg;
 523        struct resource *res;
 524        int i;
 525
 526        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dsi_phy");
 527        if (!res)
 528                return -EINVAL;
 529
 530        for (i = 0; i < cfg->num_dsi_phy; i++) {
 531                if (cfg->io_start[i] == res->start)
 532                        return i;
 533        }
 534
 535        return -EINVAL;
 536}
 537
 538int msm_dsi_phy_init_common(struct msm_dsi_phy *phy)
 539{
 540        struct platform_device *pdev = phy->pdev;
 541        int ret = 0;
 542
 543        phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
 544                                "DSI_PHY_REG");
 545        if (IS_ERR(phy->reg_base)) {
 546                dev_err(&pdev->dev, "%s: failed to map phy regulator base\n",
 547                        __func__);
 548                ret = -ENOMEM;
 549                goto fail;
 550        }
 551
 552fail:
 553        return ret;
 554}
 555
 556static int dsi_phy_driver_probe(struct platform_device *pdev)
 557{
 558        struct msm_dsi_phy *phy;
 559        struct device *dev = &pdev->dev;
 560        const struct of_device_id *match;
 561        int ret;
 562
 563        phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
 564        if (!phy)
 565                return -ENOMEM;
 566
 567        match = of_match_node(dsi_phy_dt_match, dev->of_node);
 568        if (!match)
 569                return -ENODEV;
 570
 571        phy->cfg = match->data;
 572        phy->pdev = pdev;
 573
 574        phy->id = dsi_phy_get_id(phy);
 575        if (phy->id < 0) {
 576                ret = phy->id;
 577                dev_err(dev, "%s: couldn't identify PHY index, %d\n",
 578                        __func__, ret);
 579                goto fail;
 580        }
 581
 582        phy->regulator_ldo_mode = of_property_read_bool(dev->of_node,
 583                                "qcom,dsi-phy-regulator-ldo-mode");
 584
 585        phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
 586        if (IS_ERR(phy->base)) {
 587                dev_err(dev, "%s: failed to map phy base\n", __func__);
 588                ret = -ENOMEM;
 589                goto fail;
 590        }
 591
 592        ret = dsi_phy_regulator_init(phy);
 593        if (ret) {
 594                dev_err(dev, "%s: failed to init regulator\n", __func__);
 595                goto fail;
 596        }
 597
 598        phy->ahb_clk = msm_clk_get(pdev, "iface");
 599        if (IS_ERR(phy->ahb_clk)) {
 600                dev_err(dev, "%s: Unable to get ahb clk\n", __func__);
 601                ret = PTR_ERR(phy->ahb_clk);
 602                goto fail;
 603        }
 604
 605        if (phy->cfg->ops.init) {
 606                ret = phy->cfg->ops.init(phy);
 607                if (ret)
 608                        goto fail;
 609        }
 610
 611        /* PLL init will call into clk_register which requires
 612         * register access, so we need to enable power and ahb clock.
 613         */
 614        ret = dsi_phy_enable_resource(phy);
 615        if (ret)
 616                goto fail;
 617
 618        phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
 619        if (IS_ERR_OR_NULL(phy->pll))
 620                dev_info(dev,
 621                        "%s: pll init failed: %ld, need separate pll clk driver\n",
 622                        __func__, PTR_ERR(phy->pll));
 623
 624        dsi_phy_disable_resource(phy);
 625
 626        platform_set_drvdata(pdev, phy);
 627
 628        return 0;
 629
 630fail:
 631        return ret;
 632}
 633
 634static int dsi_phy_driver_remove(struct platform_device *pdev)
 635{
 636        struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
 637
 638        if (phy && phy->pll) {
 639                msm_dsi_pll_destroy(phy->pll);
 640                phy->pll = NULL;
 641        }
 642
 643        platform_set_drvdata(pdev, NULL);
 644
 645        return 0;
 646}
 647
 648static struct platform_driver dsi_phy_platform_driver = {
 649        .probe      = dsi_phy_driver_probe,
 650        .remove     = dsi_phy_driver_remove,
 651        .driver     = {
 652                .name   = "msm_dsi_phy",
 653                .of_match_table = dsi_phy_dt_match,
 654        },
 655};
 656
 657void __init msm_dsi_phy_driver_register(void)
 658{
 659        platform_driver_register(&dsi_phy_platform_driver);
 660}
 661
 662void __exit msm_dsi_phy_driver_unregister(void)
 663{
 664        platform_driver_unregister(&dsi_phy_platform_driver);
 665}
 666
 667int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
 668                        struct msm_dsi_phy_clk_request *clk_req)
 669{
 670        struct device *dev = &phy->pdev->dev;
 671        int ret;
 672
 673        if (!phy || !phy->cfg->ops.enable)
 674                return -EINVAL;
 675
 676        ret = dsi_phy_enable_resource(phy);
 677        if (ret) {
 678                dev_err(dev, "%s: resource enable failed, %d\n",
 679                        __func__, ret);
 680                goto res_en_fail;
 681        }
 682
 683        ret = dsi_phy_regulator_enable(phy);
 684        if (ret) {
 685                dev_err(dev, "%s: regulator enable failed, %d\n",
 686                        __func__, ret);
 687                goto reg_en_fail;
 688        }
 689
 690        ret = phy->cfg->ops.enable(phy, src_pll_id, clk_req);
 691        if (ret) {
 692                dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
 693                goto phy_en_fail;
 694        }
 695
 696        /*
 697         * Resetting DSI PHY silently changes its PLL registers to reset status,
 698         * which will confuse clock driver and result in wrong output rate of
 699         * link clocks. Restore PLL status if its PLL is being used as clock
 700         * source.
 701         */
 702        if (phy->usecase != MSM_DSI_PHY_SLAVE) {
 703                ret = msm_dsi_pll_restore_state(phy->pll);
 704                if (ret) {
 705                        dev_err(dev, "%s: failed to restore pll state, %d\n",
 706                                __func__, ret);
 707                        goto pll_restor_fail;
 708                }
 709        }
 710
 711        return 0;
 712
 713pll_restor_fail:
 714        if (phy->cfg->ops.disable)
 715                phy->cfg->ops.disable(phy);
 716phy_en_fail:
 717        dsi_phy_regulator_disable(phy);
 718reg_en_fail:
 719        dsi_phy_disable_resource(phy);
 720res_en_fail:
 721        return ret;
 722}
 723
 724void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
 725{
 726        if (!phy || !phy->cfg->ops.disable)
 727                return;
 728
 729        /* Save PLL status if it is a clock source */
 730        if (phy->usecase != MSM_DSI_PHY_SLAVE)
 731                msm_dsi_pll_save_state(phy->pll);
 732
 733        phy->cfg->ops.disable(phy);
 734
 735        dsi_phy_regulator_disable(phy);
 736        dsi_phy_disable_resource(phy);
 737}
 738
 739void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy,
 740                        struct msm_dsi_phy_shared_timings *shared_timings)
 741{
 742        memcpy(shared_timings, &phy->timing.shared_timings,
 743               sizeof(*shared_timings));
 744}
 745
 746struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
 747{
 748        if (!phy)
 749                return NULL;
 750
 751        return phy->pll;
 752}
 753
 754void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy,
 755                             enum msm_dsi_phy_usecase uc)
 756{
 757        if (phy)
 758                phy->usecase = uc;
 759}
 760