dp_catalog_v420.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include "dp_catalog.h"
  7. #include "dp_reg.h"
  8. #include "dp_debug.h"
  9. #include "dp_pll.h"
  10. #include <linux/rational.h>
  11. #include <drm/drm_fixed.h>
  12. #define dp_catalog_get_priv_v420(x) ({ \
  13. struct dp_catalog *catalog; \
  14. catalog = container_of(x, struct dp_catalog, x); \
  15. container_of(catalog->sub, \
  16. struct dp_catalog_private_v420, sub); \
  17. })
  18. #define dp_read(x) ({ \
  19. catalog->sub.read(catalog->dpc, io_data, x); \
  20. })
  21. #define dp_write(x, y) ({ \
  22. catalog->sub.write(catalog->dpc, io_data, x, y); \
  23. })
  24. #define MAX_VOLTAGE_LEVELS 4
  25. #define MAX_PRE_EMP_LEVELS 4
  26. static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  27. {0x00, 0x0E, 0x16, 0xFF}, /* pe0, 0 db */
  28. {0x00, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */
  29. {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */
  30. {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
  31. };
  32. /* voltage swing, 0.2v and 1.0v are not support */
  33. static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  34. {0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */
  35. {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */
  36. {0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
  37. {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
  38. };
  39. static u8 const dp_pre_emp_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  40. {0x00, 0x0C, 0x15, 0x1B}, /* pe0, 0 db */
  41. {0x02, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */
  42. {0x02, 0x11, 0xFF, 0xFF}, /* pe2, 6.0 db */
  43. {0x04, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
  44. };
  45. static u8 const dp_swing_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  46. {0x02, 0x12, 0x16, 0x1A}, /* sw0, 0.4v */
  47. {0x09, 0x19, 0x1F, 0xFF}, /* sw1, 0.6v */
  48. {0x10, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */
  49. {0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */
  50. };
  51. static u8 const dp_pre_emp_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  52. {0x00, 0x0D, 0x14, 0x1A}, /* pe0, 0 db */
  53. {0x00, 0x0E, 0x15, 0xFF}, /* pe1, 3.5 db */
  54. {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */
  55. {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
  56. };
  57. static u8 const dp_swing_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  58. {0x08, 0x0F, 0x16, 0x1F}, /* sw0, 0.4v */
  59. {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6v */
  60. {0x16, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */
  61. {0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */
  62. };
  63. static const u8 dp_pre_emp_hbr_rbr_v600[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  64. {0x00, 0x0D, 0x14, 0x1A}, /* pe0, 0 db */
  65. {0x00, 0x0E, 0x15, 0xFF}, /* pe1, 3.5 db */
  66. {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */
  67. {0x02, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
  68. };
  69. struct dp_catalog_private_v420 {
  70. struct device *dev;
  71. struct dp_catalog_sub sub;
  72. struct dp_catalog_io *io;
  73. struct dp_catalog *dpc;
  74. };
  75. static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux,
  76. struct dp_aux_cfg *cfg)
  77. {
  78. struct dp_catalog_private_v420 *catalog;
  79. struct dp_io_data *io_data;
  80. int i = 0;
  81. u32 phy_version;
  82. if (!aux || !cfg) {
  83. DP_ERR("invalid input\n");
  84. return;
  85. }
  86. catalog = dp_catalog_get_priv_v420(aux);
  87. io_data = catalog->io->dp_phy;
  88. dp_write(DP_PHY_PD_CTL, 0x67);
  89. wmb(); /* make sure PD programming happened */
  90. phy_version = dp_catalog_get_dp_phy_version(catalog->dpc);
  91. if (phy_version >= 0x60000000) {
  92. /* Turn on BIAS current for PHY/PLL */
  93. io_data = catalog->io->dp_pll;
  94. dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN_V600, 0x17);
  95. wmb(); /* make sure BIAS programming happened */
  96. } else {
  97. /* Turn on BIAS current for PHY/PLL */
  98. io_data = catalog->io->dp_pll;
  99. dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17);
  100. wmb(); /* make sure BIAS programming happened */
  101. }
  102. io_data = catalog->io->dp_phy;
  103. /* DP AUX CFG register programming */
  104. for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
  105. DP_DEBUG("%s: offset=0x%08x, value=0x%08x\n",
  106. dp_phy_aux_config_type_to_string(i),
  107. cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
  108. dp_write(cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
  109. }
  110. wmb(); /* make sure DP AUX CFG programming happened */
  111. dp_write(DP_PHY_AUX_INTERRUPT_MASK_V420, 0x1F);
  112. }
  113. static void dp_catalog_aux_clear_hw_int_v420(struct dp_catalog_aux *aux)
  114. {
  115. struct dp_catalog_private_v420 *catalog;
  116. struct dp_io_data *io_data;
  117. u32 data = 0;
  118. u32 phy_version;
  119. if (!aux) {
  120. DP_ERR("invalid input\n");
  121. return;
  122. }
  123. catalog = dp_catalog_get_priv_v420(aux);
  124. phy_version = dp_catalog_get_dp_phy_version(catalog->dpc);
  125. io_data = catalog->io->dp_phy;
  126. if (phy_version >= 0x60000000)
  127. data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V600);
  128. else
  129. data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V420);
  130. dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f);
  131. wmb(); /* make sure 0x1f is written before next write */
  132. dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x9f);
  133. wmb(); /* make sure 0x9f is written before next write */
  134. dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0);
  135. wmb(); /* make sure register is cleared */
  136. }
  137. static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel,
  138. u32 rate, u32 stream_rate_khz)
  139. {
  140. u32 mvid, nvid, mvid_off = 0, nvid_off = 0;
  141. u32 const nvid_fixed = 0x8000;
  142. struct dp_catalog *dp_catalog;
  143. struct dp_catalog_private_v420 *catalog;
  144. struct dp_io_data *io_data;
  145. unsigned long num, den;
  146. u32 const input_scale = 10;
  147. u64 f1, f2;
  148. if (!panel || !rate) {
  149. DP_ERR("invalid input\n");
  150. return;
  151. }
  152. if (panel->stream_id >= DP_STREAM_MAX) {
  153. DP_ERR("invalid stream id:%d\n", panel->stream_id);
  154. return;
  155. }
  156. dp_catalog = container_of(panel, struct dp_catalog, panel);
  157. catalog = container_of(dp_catalog->sub, struct dp_catalog_private_v420, sub);
  158. /*
  159. * MND calculator requires the target clock to be less than half the input clock. To meet
  160. * this requirement, the input clock is scaled here and then the resulting M value is
  161. * scaled by the same factor to offset the pre-scale.
  162. */
  163. rational_best_approximation(rate * input_scale, stream_rate_khz,
  164. (unsigned long)(1 << 16) - 1,
  165. (unsigned long)(1 << 16) - 1, &den, &num);
  166. mvid = (num & 0xFFFF);
  167. nvid = (den & 0xFFFF);
  168. mvid *= input_scale;
  169. if (nvid < nvid_fixed) {
  170. f1 = drm_fixp_from_fraction(nvid_fixed, nvid);
  171. f2 = drm_fixp_from_fraction(mvid, 1);
  172. f1 = drm_fixp_mul(f1, f2);
  173. mvid = drm_fixp2int(f1);
  174. nvid = nvid_fixed;
  175. }
  176. io_data = catalog->io->dp_link;
  177. if (panel->stream_id == DP_STREAM_1) {
  178. mvid_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
  179. nvid_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID;
  180. }
  181. DP_DEBUG("pclk=%ld, lclk=%ld, mvid=0x%x, nvid=0x%x\n", stream_rate_khz, rate, mvid, nvid);
  182. dp_write(DP_SOFTWARE_MVID + mvid_off, mvid);
  183. dp_write(DP_SOFTWARE_NVID + nvid_off, nvid);
  184. }
  185. static void dp_catalog_ctrl_phy_lane_cfg_v420(struct dp_catalog_ctrl *ctrl,
  186. bool flipped, u8 ln_cnt)
  187. {
  188. u32 info = 0x0;
  189. struct dp_catalog_private_v420 *catalog;
  190. struct dp_io_data *io_data;
  191. u8 orientation = BIT(!!flipped);
  192. if (!ctrl) {
  193. DP_ERR("invalid input\n");
  194. return;
  195. }
  196. catalog = dp_catalog_get_priv_v420(ctrl);
  197. io_data = catalog->io->dp_phy;
  198. info |= (ln_cnt & 0x0F);
  199. info |= ((orientation & 0x0F) << 4);
  200. DP_DEBUG("Shared Info = 0x%x\n", info);
  201. dp_write(DP_PHY_SPARE0_V420, info);
  202. }
  203. static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
  204. u8 v_level, u8 p_level, bool high)
  205. {
  206. struct dp_catalog_private_v420 *catalog;
  207. struct dp_io_data *io_data;
  208. u8 value0, value1;
  209. u32 version;
  210. u32 phy_version;
  211. if (!ctrl || !((v_level < MAX_VOLTAGE_LEVELS)
  212. && (p_level < MAX_PRE_EMP_LEVELS))) {
  213. DP_ERR("invalid input\n");
  214. return;
  215. }
  216. DP_DEBUG("hw: v=%d p=%d, high=%d\n", v_level, p_level, high);
  217. catalog = dp_catalog_get_priv_v420(ctrl);
  218. phy_version = dp_catalog_get_dp_phy_version(catalog->dpc);
  219. io_data = catalog->io->dp_ahb;
  220. version = dp_read(DP_HW_VERSION);
  221. DP_DEBUG("version: 0x%x\n", version);
  222. /*
  223. * For DP controller versions >= 1.2.3
  224. */
  225. if (version >= 0x10020003) {
  226. if (high) {
  227. value0 = dp_swing_hbr2_hbr3[v_level][p_level];
  228. value1 = dp_pre_emp_hbr2_hbr3[v_level][p_level];
  229. } else {
  230. value0 = dp_swing_hbr_rbr[v_level][p_level];
  231. if (phy_version >= 0x60000000)
  232. value1 = dp_pre_emp_hbr_rbr_v600[v_level][p_level];
  233. else
  234. value1 = dp_pre_emp_hbr_rbr[v_level][p_level];
  235. }
  236. } else {
  237. value0 = vm_voltage_swing[v_level][p_level];
  238. value1 = vm_pre_emphasis[v_level][p_level];
  239. }
  240. /* program default setting first */
  241. io_data = catalog->io->dp_ln_tx0;
  242. dp_write(TXn_TX_DRV_LVL_V420, 0x2A);
  243. dp_write(TXn_TX_EMP_POST1_LVL, 0x20);
  244. io_data = catalog->io->dp_ln_tx1;
  245. dp_write(TXn_TX_DRV_LVL_V420, 0x2A);
  246. dp_write(TXn_TX_EMP_POST1_LVL, 0x20);
  247. /* Enable MUX to use Cursor values from these registers */
  248. value0 |= BIT(5);
  249. value1 |= BIT(5);
  250. /* Configure host and panel only if both values are allowed */
  251. if (value0 != 0xFF && value1 != 0xFF) {
  252. io_data = catalog->io->dp_ln_tx0;
  253. dp_write(TXn_TX_DRV_LVL_V420, value0);
  254. dp_write(TXn_TX_EMP_POST1_LVL, value1);
  255. io_data = catalog->io->dp_ln_tx1;
  256. dp_write(TXn_TX_DRV_LVL_V420, value0);
  257. dp_write(TXn_TX_EMP_POST1_LVL, value1);
  258. DP_DEBUG("hw: vx_value=0x%x px_value=0x%x\n",
  259. value0, value1);
  260. } else {
  261. DP_ERR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
  262. v_level, value0, p_level, value1);
  263. }
  264. }
  265. static void dp_catalog_ctrl_lane_pnswap_v420(struct dp_catalog_ctrl *ctrl,
  266. u8 ln_pnswap)
  267. {
  268. struct dp_catalog_private_v420 *catalog;
  269. struct dp_io_data *io_data;
  270. u32 cfg0, cfg1;
  271. catalog = dp_catalog_get_priv_v420(ctrl);
  272. cfg0 = 0x0a;
  273. cfg1 = 0x0a;
  274. cfg0 |= ((ln_pnswap >> 0) & 0x1) << 0;
  275. cfg0 |= ((ln_pnswap >> 1) & 0x1) << 2;
  276. cfg1 |= ((ln_pnswap >> 2) & 0x1) << 0;
  277. cfg1 |= ((ln_pnswap >> 3) & 0x1) << 2;
  278. io_data = catalog->io->dp_ln_tx0;
  279. dp_write(TXn_TX_POL_INV_V420, cfg0);
  280. io_data = catalog->io->dp_ln_tx1;
  281. dp_write(TXn_TX_POL_INV_V420, cfg1);
  282. }
  283. static void dp_catalog_put_v420(struct dp_catalog *catalog)
  284. {
  285. struct dp_catalog_private_v420 *catalog_priv;
  286. if (!catalog)
  287. return;
  288. catalog_priv = container_of(catalog->sub,
  289. struct dp_catalog_private_v420, sub);
  290. devm_kfree(catalog_priv->dev, catalog_priv);
  291. }
  292. struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev,
  293. struct dp_catalog *catalog, struct dp_catalog_io *io)
  294. {
  295. struct dp_catalog_private_v420 *catalog_priv;
  296. if (!dev || !catalog) {
  297. DP_ERR("invalid input\n");
  298. return ERR_PTR(-EINVAL);
  299. }
  300. catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL);
  301. if (!catalog_priv)
  302. return ERR_PTR(-ENOMEM);
  303. catalog_priv->dev = dev;
  304. catalog_priv->io = io;
  305. catalog_priv->dpc = catalog;
  306. catalog_priv->sub.put = dp_catalog_put_v420;
  307. catalog->aux.setup = dp_catalog_aux_setup_v420;
  308. catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_int_v420;
  309. catalog->panel.config_msa = dp_catalog_panel_config_msa_v420;
  310. catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v420;
  311. catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v420;
  312. catalog->ctrl.lane_pnswap = dp_catalog_ctrl_lane_pnswap_v420;
  313. return &catalog_priv->sub;
  314. }