dp_catalog_v420.c 10 KB

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