linux/drivers/gpu/drm/sprd/megacores_pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2020 Unisoc Inc.
   4 */
   5
   6#include <asm/div64.h>
   7#include <linux/delay.h>
   8#include <linux/init.h>
   9#include <linux/kernel.h>
  10#include <linux/regmap.h>
  11#include <linux/string.h>
  12
  13#include "sprd_dsi.h"
  14
  15#define L                                               0
  16#define H                                               1
  17#define CLK                                             0
  18#define DATA                                    1
  19#define INFINITY                                0xffffffff
  20#define MIN_OUTPUT_FREQ                 (100)
  21
  22#define AVERAGE(a, b) (min(a, b) + abs((b) - (a)) / 2)
  23
  24/* sharkle */
  25#define VCO_BAND_LOW    750
  26#define VCO_BAND_MID    1100
  27#define VCO_BAND_HIGH   1500
  28#define PHY_REF_CLK     26000
  29
  30static int dphy_calc_pll_param(struct dphy_pll *pll)
  31{
  32        const u32 khz = 1000;
  33        const u32 mhz = 1000000;
  34        const unsigned long long factor = 100;
  35        unsigned long long tmp;
  36        int i;
  37
  38        pll->potential_fvco = pll->freq / khz;
  39        pll->ref_clk = PHY_REF_CLK / khz;
  40
  41        for (i = 0; i < 4; ++i) {
  42                if (pll->potential_fvco >= VCO_BAND_LOW &&
  43                    pll->potential_fvco <= VCO_BAND_HIGH) {
  44                        pll->fvco = pll->potential_fvco;
  45                        pll->out_sel = BIT(i);
  46                        break;
  47                }
  48                pll->potential_fvco <<= 1;
  49        }
  50        if (pll->fvco == 0)
  51                return -EINVAL;
  52
  53        if (pll->fvco >= VCO_BAND_LOW && pll->fvco <= VCO_BAND_MID) {
  54                /* vco band control */
  55                pll->vco_band = 0x0;
  56                /* low pass filter control */
  57                pll->lpf_sel = 1;
  58        } else if (pll->fvco > VCO_BAND_MID && pll->fvco <= VCO_BAND_HIGH) {
  59                pll->vco_band = 0x1;
  60                pll->lpf_sel = 0;
  61        } else {
  62                return -EINVAL;
  63        }
  64
  65        pll->nint = pll->fvco / pll->ref_clk;
  66        tmp = pll->fvco * factor * mhz;
  67        do_div(tmp, pll->ref_clk);
  68        tmp = tmp - pll->nint * factor * mhz;
  69        tmp *= BIT(20);
  70        do_div(tmp, 100000000);
  71        pll->kint = (u32)tmp;
  72        pll->refin = 3; /* pre-divider bypass */
  73        pll->sdm_en = true; /* use fraction N PLL */
  74        pll->fdk_s = 0x1; /* fraction */
  75        pll->cp_s = 0x0;
  76        pll->det_delay = 0x1;
  77
  78        return 0;
  79}
  80
  81static void dphy_set_pll_reg(struct dphy_pll *pll, struct regmap *regmap)
  82{
  83        u8 reg_val[9] = {0};
  84        int i;
  85
  86        u8 reg_addr[] = {
  87                0x03, 0x04, 0x06, 0x08, 0x09,
  88                0x0a, 0x0b, 0x0e, 0x0f
  89        };
  90
  91        reg_val[0] = 1 | (1 << 1) |  (pll->lpf_sel << 2);
  92        reg_val[1] = pll->div | (1 << 3) | (pll->cp_s << 5) | (pll->fdk_s << 7);
  93        reg_val[2] = pll->nint;
  94        reg_val[3] = pll->vco_band | (pll->sdm_en << 1) | (pll->refin << 2);
  95        reg_val[4] = pll->kint >> 12;
  96        reg_val[5] = pll->kint >> 4;
  97        reg_val[6] = pll->out_sel | ((pll->kint << 4) & 0xf);
  98        reg_val[7] = 1 << 4;
  99        reg_val[8] = pll->det_delay;
 100
 101        for (i = 0; i < sizeof(reg_addr); ++i) {
 102                regmap_write(regmap, reg_addr[i], reg_val[i]);
 103                DRM_DEBUG("%02x: %02x\n", reg_addr[i], reg_val[i]);
 104        }
 105}
 106
 107int dphy_pll_config(struct dsi_context *ctx)
 108{
 109        struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
 110        struct regmap *regmap = ctx->regmap;
 111        struct dphy_pll *pll = &ctx->pll;
 112        int ret;
 113
 114        pll->freq = dsi->slave->hs_rate;
 115
 116        /* FREQ = 26M * (NINT + KINT / 2^20) / out_sel */
 117        ret = dphy_calc_pll_param(pll);
 118        if (ret) {
 119                drm_err(dsi->drm, "failed to calculate dphy pll parameters\n");
 120                return ret;
 121        }
 122        dphy_set_pll_reg(pll, regmap);
 123
 124        return 0;
 125}
 126
 127static void dphy_set_timing_reg(struct regmap *regmap, int type, u8 val[])
 128{
 129        switch (type) {
 130        case REQUEST_TIME:
 131                regmap_write(regmap, 0x31, val[CLK]);
 132                regmap_write(regmap, 0x41, val[DATA]);
 133                regmap_write(regmap, 0x51, val[DATA]);
 134                regmap_write(regmap, 0x61, val[DATA]);
 135                regmap_write(regmap, 0x71, val[DATA]);
 136
 137                regmap_write(regmap, 0x90, val[CLK]);
 138                regmap_write(regmap, 0xa0, val[DATA]);
 139                regmap_write(regmap, 0xb0, val[DATA]);
 140                regmap_write(regmap, 0xc0, val[DATA]);
 141                regmap_write(regmap, 0xd0, val[DATA]);
 142                break;
 143        case PREPARE_TIME:
 144                regmap_write(regmap, 0x32, val[CLK]);
 145                regmap_write(regmap, 0x42, val[DATA]);
 146                regmap_write(regmap, 0x52, val[DATA]);
 147                regmap_write(regmap, 0x62, val[DATA]);
 148                regmap_write(regmap, 0x72, val[DATA]);
 149
 150                regmap_write(regmap, 0x91, val[CLK]);
 151                regmap_write(regmap, 0xa1, val[DATA]);
 152                regmap_write(regmap, 0xb1, val[DATA]);
 153                regmap_write(regmap, 0xc1, val[DATA]);
 154                regmap_write(regmap, 0xd1, val[DATA]);
 155                break;
 156        case ZERO_TIME:
 157                regmap_write(regmap, 0x33, val[CLK]);
 158                regmap_write(regmap, 0x43, val[DATA]);
 159                regmap_write(regmap, 0x53, val[DATA]);
 160                regmap_write(regmap, 0x63, val[DATA]);
 161                regmap_write(regmap, 0x73, val[DATA]);
 162
 163                regmap_write(regmap, 0x92, val[CLK]);
 164                regmap_write(regmap, 0xa2, val[DATA]);
 165                regmap_write(regmap, 0xb2, val[DATA]);
 166                regmap_write(regmap, 0xc2, val[DATA]);
 167                regmap_write(regmap, 0xd2, val[DATA]);
 168                break;
 169        case TRAIL_TIME:
 170                regmap_write(regmap, 0x34, val[CLK]);
 171                regmap_write(regmap, 0x44, val[DATA]);
 172                regmap_write(regmap, 0x54, val[DATA]);
 173                regmap_write(regmap, 0x64, val[DATA]);
 174                regmap_write(regmap, 0x74, val[DATA]);
 175
 176                regmap_write(regmap, 0x93, val[CLK]);
 177                regmap_write(regmap, 0xa3, val[DATA]);
 178                regmap_write(regmap, 0xb3, val[DATA]);
 179                regmap_write(regmap, 0xc3, val[DATA]);
 180                regmap_write(regmap, 0xd3, val[DATA]);
 181                break;
 182        case EXIT_TIME:
 183                regmap_write(regmap, 0x36, val[CLK]);
 184                regmap_write(regmap, 0x46, val[DATA]);
 185                regmap_write(regmap, 0x56, val[DATA]);
 186                regmap_write(regmap, 0x66, val[DATA]);
 187                regmap_write(regmap, 0x76, val[DATA]);
 188
 189                regmap_write(regmap, 0x95, val[CLK]);
 190                regmap_write(regmap, 0xA5, val[DATA]);
 191                regmap_write(regmap, 0xB5, val[DATA]);
 192                regmap_write(regmap, 0xc5, val[DATA]);
 193                regmap_write(regmap, 0xd5, val[DATA]);
 194                break;
 195        case CLKPOST_TIME:
 196                regmap_write(regmap, 0x35, val[CLK]);
 197                regmap_write(regmap, 0x94, val[CLK]);
 198                break;
 199
 200        /* the following just use default value */
 201        case SETTLE_TIME:
 202                fallthrough;
 203        case TA_GET:
 204                fallthrough;
 205        case TA_GO:
 206                fallthrough;
 207        case TA_SURE:
 208                fallthrough;
 209        default:
 210                break;
 211        }
 212}
 213
 214void dphy_timing_config(struct dsi_context *ctx)
 215{
 216        struct regmap *regmap = ctx->regmap;
 217        struct dphy_pll *pll = &ctx->pll;
 218        const u32 factor = 2;
 219        const u32 scale = 100;
 220        u32 t_ui, t_byteck, t_half_byteck;
 221        u32 range[2], constant;
 222        u8 val[2];
 223        u32 tmp = 0;
 224
 225        /* t_ui: 1 ui, byteck: 8 ui, half byteck: 4 ui */
 226        t_ui = 1000 * scale / (pll->freq / 1000);
 227        t_byteck = t_ui << 3;
 228        t_half_byteck = t_ui << 2;
 229        constant = t_ui << 1;
 230
 231        /* REQUEST_TIME: HS T-LPX: LP-01
 232         * For T-LPX, mipi spec defined min value is 50ns,
 233         * but maybe it shouldn't be too small, because BTA,
 234         * LP-10, LP-00, LP-01, all of this is related to T-LPX.
 235         */
 236        range[L] = 50 * scale;
 237        range[H] = INFINITY;
 238        val[CLK] = DIV_ROUND_UP(range[L] * (factor << 1), t_byteck) - 2;
 239        val[DATA] = val[CLK];
 240        dphy_set_timing_reg(regmap, REQUEST_TIME, val);
 241
 242        /* PREPARE_TIME: HS sequence: LP-00 */
 243        range[L] = 38 * scale;
 244        range[H] = 95 * scale;
 245        tmp = AVERAGE(range[L], range[H]);
 246        val[CLK] = DIV_ROUND_UP(AVERAGE(range[L], range[H]), t_half_byteck) - 1;
 247        range[L] = 40 * scale + 4 * t_ui;
 248        range[H] = 85 * scale + 6 * t_ui;
 249        tmp |= AVERAGE(range[L], range[H]) << 16;
 250        val[DATA] = DIV_ROUND_UP(AVERAGE(range[L], range[H]), t_half_byteck) - 1;
 251        dphy_set_timing_reg(regmap, PREPARE_TIME, val);
 252
 253        /* ZERO_TIME: HS-ZERO */
 254        range[L] = 300 * scale;
 255        range[H] = INFINITY;
 256        val[CLK] = DIV_ROUND_UP(range[L] * factor + (tmp & 0xffff)
 257                        - 525 * t_byteck / 100, t_byteck) - 2;
 258        range[L] = 145 * scale + 10 * t_ui;
 259        val[DATA] = DIV_ROUND_UP(range[L] * factor
 260                        + ((tmp >> 16) & 0xffff) - 525 * t_byteck / 100,
 261                        t_byteck) - 2;
 262        dphy_set_timing_reg(regmap, ZERO_TIME, val);
 263
 264        /* TRAIL_TIME: HS-TRAIL */
 265        range[L] = 60 * scale;
 266        range[H] = INFINITY;
 267        val[CLK] = DIV_ROUND_UP(range[L] * factor - constant, t_half_byteck);
 268        range[L] = max(8 * t_ui, 60 * scale + 4 * t_ui);
 269        val[DATA] = DIV_ROUND_UP(range[L] * 3 / 2 - constant, t_half_byteck) - 2;
 270        dphy_set_timing_reg(regmap, TRAIL_TIME, val);
 271
 272        /* EXIT_TIME: */
 273        range[L] = 100 * scale;
 274        range[H] = INFINITY;
 275        val[CLK] = DIV_ROUND_UP(range[L] * factor, t_byteck) - 2;
 276        val[DATA] = val[CLK];
 277        dphy_set_timing_reg(regmap, EXIT_TIME, val);
 278
 279        /* CLKPOST_TIME: */
 280        range[L] = 60 * scale + 52 * t_ui;
 281        range[H] = INFINITY;
 282        val[CLK] = DIV_ROUND_UP(range[L] * factor, t_byteck) - 2;
 283        val[DATA] = val[CLK];
 284        dphy_set_timing_reg(regmap, CLKPOST_TIME, val);
 285
 286        /* SETTLE_TIME:
 287         * This time is used for receiver. So for transmitter,
 288         * it can be ignored.
 289         */
 290
 291        /* TA_GO:
 292         * transmitter drives bridge state(LP-00) before releasing control,
 293         * reg 0x1f default value: 0x04, which is good.
 294         */
 295
 296        /* TA_SURE:
 297         * After LP-10 state and before bridge state(LP-00),
 298         * reg 0x20 default value: 0x01, which is good.
 299         */
 300
 301        /* TA_GET:
 302         * receiver drives Bridge state(LP-00) before releasing control
 303         * reg 0x21 default value: 0x03, which is good.
 304         */
 305}
 306