dw_hdmi-rockchip.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/mfd/syscon.h>
  7. #include <linux/module.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/phy/phy.h>
  10. #include <linux/regmap.h>
  11. #include <linux/regulator/consumer.h>
  12. #include <drm/bridge/dw_hdmi.h>
  13. #include <drm/drm_edid.h>
  14. #include <drm/drm_of.h>
  15. #include <drm/drm_probe_helper.h>
  16. #include <drm/drm_simple_kms_helper.h>
  17. #include "rockchip_drm_drv.h"
  18. #include "rockchip_drm_vop.h"
  19. #define RK3228_GRF_SOC_CON2 0x0408
  20. #define RK3228_HDMI_SDAIN_MSK BIT(14)
  21. #define RK3228_HDMI_SCLIN_MSK BIT(13)
  22. #define RK3228_GRF_SOC_CON6 0x0418
  23. #define RK3228_HDMI_HPD_VSEL BIT(6)
  24. #define RK3228_HDMI_SDA_VSEL BIT(5)
  25. #define RK3228_HDMI_SCL_VSEL BIT(4)
  26. #define RK3288_GRF_SOC_CON6 0x025C
  27. #define RK3288_HDMI_LCDC_SEL BIT(4)
  28. #define RK3328_GRF_SOC_CON2 0x0408
  29. #define RK3328_HDMI_SDAIN_MSK BIT(11)
  30. #define RK3328_HDMI_SCLIN_MSK BIT(10)
  31. #define RK3328_HDMI_HPD_IOE BIT(2)
  32. #define RK3328_GRF_SOC_CON3 0x040c
  33. /* need to be unset if hdmi or i2c should control voltage */
  34. #define RK3328_HDMI_SDA5V_GRF BIT(15)
  35. #define RK3328_HDMI_SCL5V_GRF BIT(14)
  36. #define RK3328_HDMI_HPD5V_GRF BIT(13)
  37. #define RK3328_HDMI_CEC5V_GRF BIT(12)
  38. #define RK3328_GRF_SOC_CON4 0x0410
  39. #define RK3328_HDMI_HPD_SARADC BIT(13)
  40. #define RK3328_HDMI_CEC_5V BIT(11)
  41. #define RK3328_HDMI_SDA_5V BIT(10)
  42. #define RK3328_HDMI_SCL_5V BIT(9)
  43. #define RK3328_HDMI_HPD_5V BIT(8)
  44. #define RK3399_GRF_SOC_CON20 0x6250
  45. #define RK3399_HDMI_LCDC_SEL BIT(6)
  46. #define RK3568_GRF_VO_CON1 0x0364
  47. #define RK3568_HDMI_SDAIN_MSK BIT(15)
  48. #define RK3568_HDMI_SCLIN_MSK BIT(14)
  49. #define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
  50. /**
  51. * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips
  52. * @lcdsel_grf_reg: grf register offset of lcdc select
  53. * @lcdsel_big: reg value of selecting vop big for HDMI
  54. * @lcdsel_lit: reg value of selecting vop little for HDMI
  55. */
  56. struct rockchip_hdmi_chip_data {
  57. int lcdsel_grf_reg;
  58. u32 lcdsel_big;
  59. u32 lcdsel_lit;
  60. };
  61. struct rockchip_hdmi {
  62. struct device *dev;
  63. struct regmap *regmap;
  64. struct rockchip_encoder encoder;
  65. const struct rockchip_hdmi_chip_data *chip_data;
  66. struct clk *ref_clk;
  67. struct clk *grf_clk;
  68. struct dw_hdmi *hdmi;
  69. struct regulator *avdd_0v9;
  70. struct regulator *avdd_1v8;
  71. struct phy *phy;
  72. };
  73. static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
  74. {
  75. struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
  76. return container_of(rkencoder, struct rockchip_hdmi, encoder);
  77. }
  78. static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
  79. {
  80. 27000000, {
  81. { 0x00b3, 0x0000},
  82. { 0x2153, 0x0000},
  83. { 0x40f3, 0x0000}
  84. },
  85. }, {
  86. 36000000, {
  87. { 0x00b3, 0x0000},
  88. { 0x2153, 0x0000},
  89. { 0x40f3, 0x0000}
  90. },
  91. }, {
  92. 40000000, {
  93. { 0x00b3, 0x0000},
  94. { 0x2153, 0x0000},
  95. { 0x40f3, 0x0000}
  96. },
  97. }, {
  98. 54000000, {
  99. { 0x0072, 0x0001},
  100. { 0x2142, 0x0001},
  101. { 0x40a2, 0x0001},
  102. },
  103. }, {
  104. 65000000, {
  105. { 0x0072, 0x0001},
  106. { 0x2142, 0x0001},
  107. { 0x40a2, 0x0001},
  108. },
  109. }, {
  110. 66000000, {
  111. { 0x013e, 0x0003},
  112. { 0x217e, 0x0002},
  113. { 0x4061, 0x0002}
  114. },
  115. }, {
  116. 74250000, {
  117. { 0x0072, 0x0001},
  118. { 0x2145, 0x0002},
  119. { 0x4061, 0x0002}
  120. },
  121. }, {
  122. 83500000, {
  123. { 0x0072, 0x0001},
  124. },
  125. }, {
  126. 108000000, {
  127. { 0x0051, 0x0002},
  128. { 0x2145, 0x0002},
  129. { 0x4061, 0x0002}
  130. },
  131. }, {
  132. 106500000, {
  133. { 0x0051, 0x0002},
  134. { 0x2145, 0x0002},
  135. { 0x4061, 0x0002}
  136. },
  137. }, {
  138. 146250000, {
  139. { 0x0051, 0x0002},
  140. { 0x2145, 0x0002},
  141. { 0x4061, 0x0002}
  142. },
  143. }, {
  144. 148500000, {
  145. { 0x0051, 0x0003},
  146. { 0x214c, 0x0003},
  147. { 0x4064, 0x0003}
  148. },
  149. }, {
  150. ~0UL, {
  151. { 0x00a0, 0x000a },
  152. { 0x2001, 0x000f },
  153. { 0x4002, 0x000f },
  154. },
  155. }
  156. };
  157. static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
  158. /* pixelclk bpp8 bpp10 bpp12 */
  159. {
  160. 40000000, { 0x0018, 0x0018, 0x0018 },
  161. }, {
  162. 65000000, { 0x0028, 0x0028, 0x0028 },
  163. }, {
  164. 66000000, { 0x0038, 0x0038, 0x0038 },
  165. }, {
  166. 74250000, { 0x0028, 0x0038, 0x0038 },
  167. }, {
  168. 83500000, { 0x0028, 0x0038, 0x0038 },
  169. }, {
  170. 146250000, { 0x0038, 0x0038, 0x0038 },
  171. }, {
  172. 148500000, { 0x0000, 0x0038, 0x0038 },
  173. }, {
  174. ~0UL, { 0x0000, 0x0000, 0x0000},
  175. }
  176. };
  177. static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
  178. /*pixelclk symbol term vlev*/
  179. { 74250000, 0x8009, 0x0004, 0x0272},
  180. { 148500000, 0x802b, 0x0004, 0x028d},
  181. { 297000000, 0x8039, 0x0005, 0x028d},
  182. { ~0UL, 0x0000, 0x0000, 0x0000}
  183. };
  184. static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
  185. {
  186. struct device_node *np = hdmi->dev->of_node;
  187. hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
  188. if (IS_ERR(hdmi->regmap)) {
  189. DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n");
  190. return PTR_ERR(hdmi->regmap);
  191. }
  192. hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref");
  193. if (!hdmi->ref_clk)
  194. hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll");
  195. if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
  196. return -EPROBE_DEFER;
  197. } else if (IS_ERR(hdmi->ref_clk)) {
  198. DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
  199. return PTR_ERR(hdmi->ref_clk);
  200. }
  201. hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
  202. if (PTR_ERR(hdmi->grf_clk) == -ENOENT) {
  203. hdmi->grf_clk = NULL;
  204. } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) {
  205. return -EPROBE_DEFER;
  206. } else if (IS_ERR(hdmi->grf_clk)) {
  207. DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n");
  208. return PTR_ERR(hdmi->grf_clk);
  209. }
  210. hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
  211. if (IS_ERR(hdmi->avdd_0v9))
  212. return PTR_ERR(hdmi->avdd_0v9);
  213. hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
  214. if (IS_ERR(hdmi->avdd_1v8))
  215. return PTR_ERR(hdmi->avdd_1v8);
  216. return 0;
  217. }
  218. static enum drm_mode_status
  219. dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
  220. const struct drm_display_info *info,
  221. const struct drm_display_mode *mode)
  222. {
  223. const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
  224. int pclk = mode->clock * 1000;
  225. bool valid = false;
  226. int i;
  227. for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
  228. if (pclk == mpll_cfg[i].mpixelclock) {
  229. valid = true;
  230. break;
  231. }
  232. }
  233. return (valid) ? MODE_OK : MODE_BAD;
  234. }
  235. static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
  236. {
  237. }
  238. static bool
  239. dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
  240. const struct drm_display_mode *mode,
  241. struct drm_display_mode *adj_mode)
  242. {
  243. return true;
  244. }
  245. static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
  246. struct drm_display_mode *mode,
  247. struct drm_display_mode *adj_mode)
  248. {
  249. struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
  250. clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
  251. }
  252. static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
  253. {
  254. struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
  255. u32 val;
  256. int ret;
  257. if (hdmi->chip_data->lcdsel_grf_reg < 0)
  258. return;
  259. ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
  260. if (ret)
  261. val = hdmi->chip_data->lcdsel_lit;
  262. else
  263. val = hdmi->chip_data->lcdsel_big;
  264. ret = clk_prepare_enable(hdmi->grf_clk);
  265. if (ret < 0) {
  266. DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret);
  267. return;
  268. }
  269. ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val);
  270. if (ret != 0)
  271. DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret);
  272. clk_disable_unprepare(hdmi->grf_clk);
  273. DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n",
  274. ret ? "LIT" : "BIG");
  275. }
  276. static int
  277. dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
  278. struct drm_crtc_state *crtc_state,
  279. struct drm_connector_state *conn_state)
  280. {
  281. struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
  282. s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
  283. s->output_type = DRM_MODE_CONNECTOR_HDMIA;
  284. return 0;
  285. }
  286. static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
  287. .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
  288. .mode_set = dw_hdmi_rockchip_encoder_mode_set,
  289. .enable = dw_hdmi_rockchip_encoder_enable,
  290. .disable = dw_hdmi_rockchip_encoder_disable,
  291. .atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
  292. };
  293. static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
  294. const struct drm_display_info *display,
  295. const struct drm_display_mode *mode)
  296. {
  297. struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
  298. return phy_power_on(hdmi->phy);
  299. }
  300. static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
  301. {
  302. struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
  303. phy_power_off(hdmi->phy);
  304. }
  305. static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
  306. {
  307. struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
  308. dw_hdmi_phy_setup_hpd(dw_hdmi, data);
  309. regmap_write(hdmi->regmap,
  310. RK3228_GRF_SOC_CON6,
  311. HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
  312. RK3228_HDMI_SCL_VSEL,
  313. RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
  314. RK3228_HDMI_SCL_VSEL));
  315. regmap_write(hdmi->regmap,
  316. RK3228_GRF_SOC_CON2,
  317. HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK,
  318. RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK));
  319. }
  320. static enum drm_connector_status
  321. dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
  322. {
  323. struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
  324. enum drm_connector_status status;
  325. status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
  326. if (status == connector_status_connected)
  327. regmap_write(hdmi->regmap,
  328. RK3328_GRF_SOC_CON4,
  329. HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,
  330. RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));
  331. else
  332. regmap_write(hdmi->regmap,
  333. RK3328_GRF_SOC_CON4,
  334. HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |
  335. RK3328_HDMI_SCL_5V));
  336. return status;
  337. }
  338. static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
  339. {
  340. struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
  341. dw_hdmi_phy_setup_hpd(dw_hdmi, data);
  342. /* Enable and map pins to 3V grf-controlled io-voltage */
  343. regmap_write(hdmi->regmap,
  344. RK3328_GRF_SOC_CON4,
  345. HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |
  346. RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |
  347. RK3328_HDMI_HPD_5V));
  348. regmap_write(hdmi->regmap,
  349. RK3328_GRF_SOC_CON3,
  350. HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |
  351. RK3328_HDMI_HPD5V_GRF |
  352. RK3328_HDMI_CEC5V_GRF));
  353. regmap_write(hdmi->regmap,
  354. RK3328_GRF_SOC_CON2,
  355. HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,
  356. RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |
  357. RK3328_HDMI_HPD_IOE));
  358. }
  359. static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {
  360. .init = dw_hdmi_rockchip_genphy_init,
  361. .disable = dw_hdmi_rockchip_genphy_disable,
  362. .read_hpd = dw_hdmi_phy_read_hpd,
  363. .update_hpd = dw_hdmi_phy_update_hpd,
  364. .setup_hpd = dw_hdmi_rk3228_setup_hpd,
  365. };
  366. static struct rockchip_hdmi_chip_data rk3228_chip_data = {
  367. .lcdsel_grf_reg = -1,
  368. };
  369. static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
  370. .mode_valid = dw_hdmi_rockchip_mode_valid,
  371. .mpll_cfg = rockchip_mpll_cfg,
  372. .cur_ctr = rockchip_cur_ctr,
  373. .phy_config = rockchip_phy_config,
  374. .phy_data = &rk3228_chip_data,
  375. .phy_ops = &rk3228_hdmi_phy_ops,
  376. .phy_name = "inno_dw_hdmi_phy2",
  377. .phy_force_vendor = true,
  378. };
  379. static struct rockchip_hdmi_chip_data rk3288_chip_data = {
  380. .lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
  381. .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
  382. .lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL),
  383. };
  384. static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
  385. .mode_valid = dw_hdmi_rockchip_mode_valid,
  386. .mpll_cfg = rockchip_mpll_cfg,
  387. .cur_ctr = rockchip_cur_ctr,
  388. .phy_config = rockchip_phy_config,
  389. .phy_data = &rk3288_chip_data,
  390. };
  391. static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
  392. .init = dw_hdmi_rockchip_genphy_init,
  393. .disable = dw_hdmi_rockchip_genphy_disable,
  394. .read_hpd = dw_hdmi_rk3328_read_hpd,
  395. .update_hpd = dw_hdmi_phy_update_hpd,
  396. .setup_hpd = dw_hdmi_rk3328_setup_hpd,
  397. };
  398. static struct rockchip_hdmi_chip_data rk3328_chip_data = {
  399. .lcdsel_grf_reg = -1,
  400. };
  401. static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
  402. .mode_valid = dw_hdmi_rockchip_mode_valid,
  403. .mpll_cfg = rockchip_mpll_cfg,
  404. .cur_ctr = rockchip_cur_ctr,
  405. .phy_config = rockchip_phy_config,
  406. .phy_data = &rk3328_chip_data,
  407. .phy_ops = &rk3328_hdmi_phy_ops,
  408. .phy_name = "inno_dw_hdmi_phy2",
  409. .phy_force_vendor = true,
  410. .use_drm_infoframe = true,
  411. };
  412. static struct rockchip_hdmi_chip_data rk3399_chip_data = {
  413. .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
  414. .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
  415. .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL),
  416. };
  417. static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
  418. .mode_valid = dw_hdmi_rockchip_mode_valid,
  419. .mpll_cfg = rockchip_mpll_cfg,
  420. .cur_ctr = rockchip_cur_ctr,
  421. .phy_config = rockchip_phy_config,
  422. .phy_data = &rk3399_chip_data,
  423. .use_drm_infoframe = true,
  424. };
  425. static struct rockchip_hdmi_chip_data rk3568_chip_data = {
  426. .lcdsel_grf_reg = -1,
  427. };
  428. static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
  429. .mode_valid = dw_hdmi_rockchip_mode_valid,
  430. .mpll_cfg = rockchip_mpll_cfg,
  431. .cur_ctr = rockchip_cur_ctr,
  432. .phy_config = rockchip_phy_config,
  433. .phy_data = &rk3568_chip_data,
  434. .use_drm_infoframe = true,
  435. };
  436. static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
  437. { .compatible = "rockchip,rk3228-dw-hdmi",
  438. .data = &rk3228_hdmi_drv_data
  439. },
  440. { .compatible = "rockchip,rk3288-dw-hdmi",
  441. .data = &rk3288_hdmi_drv_data
  442. },
  443. { .compatible = "rockchip,rk3328-dw-hdmi",
  444. .data = &rk3328_hdmi_drv_data
  445. },
  446. { .compatible = "rockchip,rk3399-dw-hdmi",
  447. .data = &rk3399_hdmi_drv_data
  448. },
  449. { .compatible = "rockchip,rk3568-dw-hdmi",
  450. .data = &rk3568_hdmi_drv_data
  451. },
  452. {},
  453. };
  454. MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
  455. static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
  456. void *data)
  457. {
  458. struct platform_device *pdev = to_platform_device(dev);
  459. struct dw_hdmi_plat_data *plat_data;
  460. const struct of_device_id *match;
  461. struct drm_device *drm = data;
  462. struct drm_encoder *encoder;
  463. struct rockchip_hdmi *hdmi;
  464. int ret;
  465. if (!pdev->dev.of_node)
  466. return -ENODEV;
  467. hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
  468. if (!hdmi)
  469. return -ENOMEM;
  470. match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
  471. plat_data = devm_kmemdup(&pdev->dev, match->data,
  472. sizeof(*plat_data), GFP_KERNEL);
  473. if (!plat_data)
  474. return -ENOMEM;
  475. hdmi->dev = &pdev->dev;
  476. hdmi->chip_data = plat_data->phy_data;
  477. plat_data->phy_data = hdmi;
  478. encoder = &hdmi->encoder.encoder;
  479. encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
  480. rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
  481. dev->of_node, 0, 0);
  482. /*
  483. * If we failed to find the CRTC(s) which this encoder is
  484. * supposed to be connected to, it's because the CRTC has
  485. * not been registered yet. Defer probing, and hope that
  486. * the required CRTC is added later.
  487. */
  488. if (encoder->possible_crtcs == 0)
  489. return -EPROBE_DEFER;
  490. ret = rockchip_hdmi_parse_dt(hdmi);
  491. if (ret) {
  492. if (ret != -EPROBE_DEFER)
  493. DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n");
  494. return ret;
  495. }
  496. hdmi->phy = devm_phy_optional_get(dev, "hdmi");
  497. if (IS_ERR(hdmi->phy)) {
  498. ret = PTR_ERR(hdmi->phy);
  499. if (ret != -EPROBE_DEFER)
  500. DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
  501. return ret;
  502. }
  503. ret = regulator_enable(hdmi->avdd_0v9);
  504. if (ret) {
  505. DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
  506. goto err_avdd_0v9;
  507. }
  508. ret = regulator_enable(hdmi->avdd_1v8);
  509. if (ret) {
  510. DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
  511. goto err_avdd_1v8;
  512. }
  513. ret = clk_prepare_enable(hdmi->ref_clk);
  514. if (ret) {
  515. DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
  516. ret);
  517. goto err_clk;
  518. }
  519. if (hdmi->chip_data == &rk3568_chip_data) {
  520. regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
  521. HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
  522. RK3568_HDMI_SCLIN_MSK,
  523. RK3568_HDMI_SDAIN_MSK |
  524. RK3568_HDMI_SCLIN_MSK));
  525. }
  526. drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
  527. drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
  528. platform_set_drvdata(pdev, hdmi);
  529. hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
  530. /*
  531. * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
  532. * which would have called the encoder cleanup. Do it manually.
  533. */
  534. if (IS_ERR(hdmi->hdmi)) {
  535. ret = PTR_ERR(hdmi->hdmi);
  536. goto err_bind;
  537. }
  538. return 0;
  539. err_bind:
  540. drm_encoder_cleanup(encoder);
  541. clk_disable_unprepare(hdmi->ref_clk);
  542. err_clk:
  543. regulator_disable(hdmi->avdd_1v8);
  544. err_avdd_1v8:
  545. regulator_disable(hdmi->avdd_0v9);
  546. err_avdd_0v9:
  547. return ret;
  548. }
  549. static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
  550. void *data)
  551. {
  552. struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
  553. dw_hdmi_unbind(hdmi->hdmi);
  554. drm_encoder_cleanup(&hdmi->encoder.encoder);
  555. clk_disable_unprepare(hdmi->ref_clk);
  556. regulator_disable(hdmi->avdd_1v8);
  557. regulator_disable(hdmi->avdd_0v9);
  558. }
  559. static const struct component_ops dw_hdmi_rockchip_ops = {
  560. .bind = dw_hdmi_rockchip_bind,
  561. .unbind = dw_hdmi_rockchip_unbind,
  562. };
  563. static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
  564. {
  565. return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
  566. }
  567. static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
  568. {
  569. component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
  570. return 0;
  571. }
  572. static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev)
  573. {
  574. struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
  575. dw_hdmi_resume(hdmi->hdmi);
  576. return 0;
  577. }
  578. static const struct dev_pm_ops dw_hdmi_rockchip_pm = {
  579. SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume)
  580. };
  581. struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
  582. .probe = dw_hdmi_rockchip_probe,
  583. .remove = dw_hdmi_rockchip_remove,
  584. .driver = {
  585. .name = "dwhdmi-rockchip",
  586. .pm = &dw_hdmi_rockchip_pm,
  587. .of_match_table = dw_hdmi_rockchip_dt_ids,
  588. },
  589. };