dp_catalog_v420.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
  6. #include "dp_catalog.h"
  7. #include "dp_reg.h"
  8. #define dp_catalog_get_priv_v420(x) ({ \
  9. struct dp_catalog *dp_catalog; \
  10. dp_catalog = container_of(x, struct dp_catalog, x); \
  11. dp_catalog->priv.data; \
  12. })
  13. #define MAX_VOLTAGE_LEVELS 4
  14. #define MAX_PRE_EMP_LEVELS 4
  15. static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  16. {0x00, 0x0E, 0x16, 0xFF}, /* pe0, 0 db */
  17. {0x00, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */
  18. {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */
  19. {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
  20. };
  21. /* voltage swing, 0.2v and 1.0v are not support */
  22. static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
  23. {0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */
  24. {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */
  25. {0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
  26. {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
  27. };
  28. struct dp_catalog_io {
  29. struct dp_io_data *dp_ahb;
  30. struct dp_io_data *dp_aux;
  31. struct dp_io_data *dp_link;
  32. struct dp_io_data *dp_p0;
  33. struct dp_io_data *dp_phy;
  34. struct dp_io_data *dp_ln_tx0;
  35. struct dp_io_data *dp_ln_tx1;
  36. struct dp_io_data *dp_mmss_cc;
  37. struct dp_io_data *dp_pll;
  38. struct dp_io_data *usb3_dp_com;
  39. struct dp_io_data *hdcp_physical;
  40. struct dp_io_data *dp_p1;
  41. };
  42. struct dp_catalog_private_v420 {
  43. struct device *dev;
  44. struct dp_catalog_io *io;
  45. char exe_mode[SZ_4];
  46. };
  47. static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux,
  48. struct dp_aux_cfg *cfg)
  49. {
  50. struct dp_catalog_private_v420 *catalog;
  51. struct dp_io_data *io_data;
  52. int i = 0;
  53. if (!aux || !cfg) {
  54. pr_err("invalid input\n");
  55. return;
  56. }
  57. catalog = dp_catalog_get_priv_v420(aux);
  58. io_data = catalog->io->dp_phy;
  59. dp_write(catalog->exe_mode, io_data, DP_PHY_PD_CTL, 0x67);
  60. wmb(); /* make sure PD programming happened */
  61. /* Turn on BIAS current for PHY/PLL */
  62. io_data = catalog->io->dp_pll;
  63. dp_write(catalog->exe_mode, io_data, QSERDES_COM_BIAS_EN_CLKBUFLR_EN,
  64. 0x17);
  65. wmb(); /* make sure BIAS programming happened */
  66. io_data = catalog->io->dp_phy;
  67. /* DP AUX CFG register programming */
  68. for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
  69. pr_debug("%s: offset=0x%08x, value=0x%08x\n",
  70. dp_phy_aux_config_type_to_string(i),
  71. cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
  72. dp_write(catalog->exe_mode, io_data, cfg[i].offset,
  73. cfg[i].lut[cfg[i].current_index]);
  74. }
  75. wmb(); /* make sure DP AUX CFG programming happened */
  76. dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_MASK_V420,
  77. 0x1F);
  78. }
  79. static void dp_catalog_aux_clear_hw_interrupts_v420(struct dp_catalog_aux *aux)
  80. {
  81. struct dp_catalog_private_v420 *catalog;
  82. struct dp_io_data *io_data;
  83. u32 data = 0;
  84. if (!aux) {
  85. pr_err("invalid input\n");
  86. return;
  87. }
  88. catalog = dp_catalog_get_priv_v420(aux);
  89. io_data = catalog->io->dp_phy;
  90. data = dp_read(catalog->exe_mode, io_data,
  91. DP_PHY_AUX_INTERRUPT_STATUS_V420);
  92. dp_write(catalog->exe_mode, io_data,
  93. DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f);
  94. wmb(); /* make sure 0x1f is written before next write */
  95. dp_write(catalog->exe_mode, io_data,
  96. DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x9f);
  97. wmb(); /* make sure 0x9f is written before next write */
  98. dp_write(catalog->exe_mode, io_data,
  99. DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0);
  100. wmb(); /* make sure register is cleared */
  101. }
  102. static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel,
  103. u32 rate, u32 stream_rate_khz)
  104. {
  105. u32 pixel_m, pixel_n;
  106. u32 mvid, nvid, reg_off = 0, mvid_off = 0, nvid_off = 0;
  107. u32 const nvid_fixed = 0x8000;
  108. u32 const link_rate_hbr2 = 540000;
  109. u32 const link_rate_hbr3 = 810000;
  110. struct dp_catalog_private_v420 *catalog;
  111. struct dp_io_data *io_data;
  112. if (!panel || !rate) {
  113. pr_err("invalid input\n");
  114. return;
  115. }
  116. if (panel->stream_id >= DP_STREAM_MAX) {
  117. pr_err("invalid stream id:%d\n", panel->stream_id);
  118. return;
  119. }
  120. catalog = dp_catalog_get_priv_v420(panel);
  121. io_data = catalog->io->dp_mmss_cc;
  122. if (panel->stream_id == DP_STREAM_1)
  123. reg_off = MMSS_DP_PIXEL1_M_V420 - MMSS_DP_PIXEL_M_V420;
  124. pixel_m = dp_read(catalog->exe_mode, io_data,
  125. MMSS_DP_PIXEL_M_V420 + reg_off);
  126. pixel_n = dp_read(catalog->exe_mode, io_data,
  127. MMSS_DP_PIXEL_N_V420 + reg_off);
  128. pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
  129. mvid = (pixel_m & 0xFFFF) * 5;
  130. nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
  131. if (nvid < nvid_fixed) {
  132. u32 temp;
  133. temp = (nvid_fixed / nvid) * nvid;
  134. mvid = (nvid_fixed / nvid) * mvid;
  135. nvid = temp;
  136. }
  137. pr_debug("rate = %d\n", rate);
  138. if (panel->widebus_en)
  139. mvid <<= 1;
  140. if (link_rate_hbr2 == rate)
  141. nvid *= 2;
  142. if (link_rate_hbr3 == rate)
  143. nvid *= 3;
  144. io_data = catalog->io->dp_link;
  145. if (panel->stream_id == DP_STREAM_1) {
  146. mvid_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
  147. nvid_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID;
  148. }
  149. pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
  150. dp_write(catalog->exe_mode, io_data, DP_SOFTWARE_MVID + mvid_off, mvid);
  151. dp_write(catalog->exe_mode, io_data, DP_SOFTWARE_NVID + nvid_off, nvid);
  152. }
  153. static void dp_catalog_ctrl_phy_lane_cfg_v420(struct dp_catalog_ctrl *ctrl,
  154. bool flipped, u8 ln_cnt)
  155. {
  156. u32 info = 0x0;
  157. struct dp_catalog_private_v420 *catalog;
  158. u8 orientation = BIT(!!flipped);
  159. struct dp_io_data *io_data;
  160. if (!ctrl) {
  161. pr_err("invalid input\n");
  162. return;
  163. }
  164. catalog = dp_catalog_get_priv_v420(ctrl);
  165. io_data = catalog->io->dp_phy;
  166. info |= (ln_cnt & 0x0F);
  167. info |= ((orientation & 0x0F) << 4);
  168. pr_debug("Shared Info = 0x%x\n", info);
  169. dp_write(catalog->exe_mode, io_data, DP_PHY_SPARE0_V420, info);
  170. }
  171. static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
  172. u8 v_level, u8 p_level)
  173. {
  174. struct dp_catalog_private_v420 *catalog;
  175. struct dp_io_data *io_data;
  176. u8 value0, value1;
  177. if (!ctrl || !((v_level < MAX_VOLTAGE_LEVELS)
  178. && (p_level < MAX_PRE_EMP_LEVELS))) {
  179. pr_err("invalid input\n");
  180. return;
  181. }
  182. catalog = dp_catalog_get_priv_v420(ctrl);
  183. pr_debug("hw: v=%d p=%d\n", v_level, p_level);
  184. value0 = vm_voltage_swing[v_level][p_level];
  185. value1 = vm_pre_emphasis[v_level][p_level];
  186. /* program default setting first */
  187. io_data = catalog->io->dp_ln_tx0;
  188. dp_write(catalog->exe_mode, io_data, TXn_TX_DRV_LVL_V420, 0x2A);
  189. dp_write(catalog->exe_mode, io_data, TXn_TX_EMP_POST1_LVL, 0x20);
  190. io_data = catalog->io->dp_ln_tx1;
  191. dp_write(catalog->exe_mode, io_data, TXn_TX_DRV_LVL_V420, 0x2A);
  192. dp_write(catalog->exe_mode, io_data, TXn_TX_EMP_POST1_LVL, 0x20);
  193. /* Enable MUX to use Cursor values from these registers */
  194. value0 |= BIT(5);
  195. value1 |= BIT(5);
  196. /* Configure host and panel only if both values are allowed */
  197. if (value0 != 0xFF && value1 != 0xFF) {
  198. io_data = catalog->io->dp_ln_tx0;
  199. dp_write(catalog->exe_mode, io_data, TXn_TX_DRV_LVL_V420,
  200. value0);
  201. dp_write(catalog->exe_mode, io_data, TXn_TX_EMP_POST1_LVL,
  202. value1);
  203. io_data = catalog->io->dp_ln_tx1;
  204. dp_write(catalog->exe_mode, io_data, TXn_TX_DRV_LVL_V420,
  205. value0);
  206. dp_write(catalog->exe_mode, io_data, TXn_TX_EMP_POST1_LVL,
  207. value1);
  208. pr_debug("hw: vx_value=0x%x px_value=0x%x\n",
  209. value0, value1);
  210. } else {
  211. pr_err("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
  212. v_level, value0, p_level, value1);
  213. }
  214. }
  215. static void dp_catalog_ctrl_lane_pnswap_v420(struct dp_catalog_ctrl *ctrl,
  216. u8 ln_pnswap)
  217. {
  218. struct dp_catalog_private_v420 *catalog;
  219. struct dp_io_data *io_data;
  220. u32 cfg0, cfg1;
  221. catalog = dp_catalog_get_priv_v420(ctrl);
  222. cfg0 = 0x0a;
  223. cfg1 = 0x0a;
  224. cfg0 |= ((ln_pnswap >> 0) & 0x1) << 0;
  225. cfg0 |= ((ln_pnswap >> 1) & 0x1) << 2;
  226. cfg1 |= ((ln_pnswap >> 2) & 0x1) << 0;
  227. cfg1 |= ((ln_pnswap >> 3) & 0x1) << 2;
  228. io_data = catalog->io->dp_ln_tx0;
  229. dp_write(catalog->exe_mode, io_data, TXn_TX_POL_INV_V420, cfg0);
  230. io_data = catalog->io->dp_ln_tx1;
  231. dp_write(catalog->exe_mode, io_data, TXn_TX_POL_INV_V420, cfg1);
  232. }
  233. static void dp_catalog_put_v420(struct dp_catalog *catalog)
  234. {
  235. struct dp_catalog_private_v420 *catalog_priv;
  236. if (!catalog || !catalog->priv.data)
  237. return;
  238. catalog_priv = catalog->priv.data;
  239. devm_kfree(catalog_priv->dev, catalog_priv);
  240. }
  241. static void dp_catalog_set_exe_mode_v420(struct dp_catalog *catalog, char *mode)
  242. {
  243. struct dp_catalog_private_v420 *catalog_priv;
  244. if (!catalog || !catalog->priv.data)
  245. return;
  246. catalog_priv = catalog->priv.data;
  247. strlcpy(catalog_priv->exe_mode, mode, sizeof(catalog_priv->exe_mode));
  248. }
  249. int dp_catalog_get_v420(struct device *dev, struct dp_catalog *catalog,
  250. void *io)
  251. {
  252. struct dp_catalog_private_v420 *catalog_priv;
  253. if (!dev || !catalog) {
  254. pr_err("invalid input\n");
  255. return -EINVAL;
  256. }
  257. catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL);
  258. if (!catalog_priv)
  259. return -ENOMEM;
  260. catalog_priv->dev = dev;
  261. catalog_priv->io = io;
  262. catalog->priv.data = catalog_priv;
  263. catalog->priv.put = dp_catalog_put_v420;
  264. catalog->priv.set_exe_mode = dp_catalog_set_exe_mode_v420;
  265. catalog->aux.setup = dp_catalog_aux_setup_v420;
  266. catalog->aux.clear_hw_interrupts =
  267. dp_catalog_aux_clear_hw_interrupts_v420;
  268. catalog->panel.config_msa = dp_catalog_panel_config_msa_v420;
  269. catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v420;
  270. catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v420;
  271. catalog->ctrl.lane_pnswap = dp_catalog_ctrl_lane_pnswap_v420;
  272. /* Set the default execution mode to hardware mode */
  273. dp_catalog_set_exe_mode_v420(catalog, "hw");
  274. return 0;
  275. }