306 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 016#define H 117#define CLK 018#define DATA 119#define INFINITY 0xffffffff20#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 75026#define VCO_BAND_MID 110027#define VCO_BAND_HIGH 150028#define PHY_REF_CLK 2600029 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, 0x0f89 };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-01232 * 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] * factor260 + ((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 control303 * reg 0x21 default value: 0x03, which is good.304 */305}306