hc
2023-11-06 9df731a176aab8e03b984b681b1bea01ccff6644
u-boot/drivers/video/drm/rockchip-inno-hdmi-phy.c
....@@ -3,6 +3,7 @@
33 * (C) Copyright 2008-2016 Fuzhou Rockchip Electronics Co., Ltd
44 */
55
6
+#include <clk-uclass.h>
67 #include <config.h>
78 #include <common.h>
89 #include <errno.h>
....@@ -11,7 +12,9 @@
1112 #include <fdtdec.h>
1213 #include <fdt_support.h>
1314 #include <asm/unaligned.h>
15
+#include <asm/arch/clock.h>
1416 #include <dm/device.h>
17
+#include <dm/lists.h>
1518 #include <dm/read.h>
1619 #include <asm/io.h>
1720 #include <linux/list.h>
....@@ -20,6 +23,7 @@
2023
2124 #include "rockchip_display.h"
2225 #include "rockchip_crtc.h"
26
+#include "rockchip_connector.h"
2327 #include "rockchip_phy.h"
2428
2529 #define INNO_HDMI_PHY_TIMEOUT_LOOP_COUNT 1000
....@@ -145,7 +149,8 @@
145149
146150 enum inno_hdmi_phy_type {
147151 INNO_HDMI_PHY_RK3228,
148
- INNO_HDMI_PHY_RK3328
152
+ INNO_HDMI_PHY_RK3328,
153
+ INNO_HDMI_PHY_RK3528
149154 };
150155
151156 struct inno_hdmi_phy_drv_data;
....@@ -214,6 +219,14 @@
214219 const void *data;
215220 };
216221
222
+struct clk_inno_hdmi {
223
+ struct udevice *dev;
224
+ ulong rate;
225
+};
226
+
227
+/* global variables are used to pass reource from phy drivers to clk driver */
228
+static struct inno_hdmi_phy *g_inno;
229
+
217230 static const struct pre_pll_config pre_pll_cfg_table[] = {
218231 { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
219232 { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
....@@ -249,9 +262,13 @@
249262 {33750000, 1, 10, 2, 4},
250263 {74250000, 1, 40, 8, 1},
251264 {74250000, 18, 80, 8, 2},
265
+ {74250000, 1, 20, 4, 8},
252266 {148500000, 2, 40, 4, 3},
267
+ {148500000, 1, 10, 2, 8},
253268 {297000000, 4, 40, 2, 3},
269
+ {297000000, 2, 20, 2, 8},
254270 {594000000, 8, 40, 1, 3},
271
+ {594000000, 4, 20, 1, 8},
255272 { ~0UL, 0, 0, 0, 0}
256273 };
257274
....@@ -292,6 +309,30 @@
292309 594000000, {
293310 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08,
294311 0x00, 0xac, 0xcc, 0xcc, 0xcc,
312
+ },
313
+ }, {
314
+ ~0UL, {
315
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316
+ 0x00, 0x00, 0x00, 0x00, 0x00,
317
+ },
318
+ }
319
+};
320
+
321
+static const struct phy_config rk3528_phy_cfg[] = {
322
+ /* tmdsclk bias-clk bias-data voltage-clk voltage-data pre-emphasis-data */
323
+ { 165000000, {
324
+ 0x03, 0x04, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
325
+ 0x00, 0x00, 0x00, 0x00, 0x00,
326
+ },
327
+ }, {
328
+ 340000000, {
329
+ 0x03, 0x04, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
330
+ 0x00, 0x00, 0x00, 0x00, 0x00,
331
+ },
332
+ }, {
333
+ 594000000, {
334
+ 0x02, 0x08, 0x0d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
335
+ 0x00, 0x00, 0x00, 0x00, 0x00,
295336 },
296337 }, {
297338 ~0UL, {
....@@ -398,7 +439,11 @@
398439
399440 static int inno_hdmi_phy_power_on(struct rockchip_phy *phy)
400441 {
442
+#ifdef CONFIG_SPL_BUILD
443
+ struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data;
444
+#else
401445 struct inno_hdmi_phy *inno = dev_get_priv(phy->dev);
446
+#endif
402447 const struct post_pll_config *cfg = post_pll_cfg_table;
403448 const struct phy_config *phy_cfg = inno->plat_data->phy_cfg_table;
404449 u32 tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, inno->pixclock);
....@@ -420,6 +465,8 @@
420465 else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3228 &&
421466 tmdsclock <= 33750000)
422467 chipversion = 4;
468
+ else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3528)
469
+ chipversion = 8;
423470
424471 printf("tmdsclock = %d; chipversion = %d\n", tmdsclock, chipversion);
425472
....@@ -444,7 +491,11 @@
444491
445492 static int inno_hdmi_phy_power_off(struct rockchip_phy *phy)
446493 {
494
+#ifdef CONFIG_SPL_BUILD
495
+ struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data;
496
+#else
447497 struct inno_hdmi_phy *inno = dev_get_priv(phy->dev);
498
+#endif
448499
449500 if (inno->plat_data->ops->power_off)
450501 inno->plat_data->ops->power_off(inno);
....@@ -858,6 +909,229 @@
858909 return rate;
859910 }
860911
912
+static int
913
+inno_hdmi_phy_rk3528_power_on(struct inno_hdmi_phy *inno,
914
+ const struct post_pll_config *cfg,
915
+ const struct phy_config *phy_cfg)
916
+{
917
+ u32 val;
918
+ u64 temp;
919
+ u32 tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, inno->pixclock);
920
+
921
+ /* Power off post PLL */
922
+ inno_update_bits(inno, 0xaa, 1, 0);
923
+
924
+ val = cfg->prediv;
925
+ inno_write(inno, 0xab, val);
926
+
927
+ if (cfg->postdiv == 1) {
928
+ inno_write(inno, 0xad, 0x8);
929
+ inno_write(inno, 0xaa, 2);
930
+ } else {
931
+ val = (cfg->postdiv / 2) - 1;
932
+ inno_write(inno, 0xad, val);
933
+ inno_write(inno, 0xaa, 0x0e);
934
+ }
935
+
936
+ val = cfg->fbdiv & 0xff;
937
+ inno_write(inno, 0xac, val);
938
+ val = (cfg->fbdiv >> 8) & BIT(0);
939
+ inno_update_bits(inno, 0xad, BIT(4), val);
940
+
941
+ /* current bias clk/data 2 */
942
+ val = phy_cfg->regs[0] << 4 | phy_cfg->regs[1];
943
+ inno_write(inno, 0xbf, val);
944
+
945
+ /* current bias data 1/0 */
946
+ val = phy_cfg->regs[1] << 4 | phy_cfg->regs[1];
947
+ inno_write(inno, 0xc0, val);
948
+
949
+ /* output voltage */
950
+ inno_write(inno, 0xb5, phy_cfg->regs[2]);
951
+ inno_write(inno, 0xb6, phy_cfg->regs[3]);
952
+ inno_write(inno, 0xb7, phy_cfg->regs[3]);
953
+ inno_write(inno, 0xb8, phy_cfg->regs[3]);
954
+
955
+ /* pre-emphasis */
956
+ inno_write(inno, 0xbb, phy_cfg->regs[4]);
957
+ inno_write(inno, 0xbc, phy_cfg->regs[4]);
958
+ inno_write(inno, 0xbd, phy_cfg->regs[4]);
959
+
960
+ /* enable LDO */
961
+ inno_write(inno, 0xb4, 0x7);
962
+
963
+ /* enable serializer */
964
+ inno_write(inno, 0xbe, 0x70);
965
+
966
+ inno_write(inno, 0xb2, 0x0f);
967
+
968
+ for (val = 0; val < 5; val++) {
969
+ if (inno_read(inno, 0xaf) & 1)
970
+ break;
971
+ udelay(1000);
972
+ }
973
+ if (!(inno_read(inno, 0xaf) & 1)) {
974
+ dev_err(inno->dev, "HDMI PHY Post PLL unlock\n");
975
+ return -ETIMEDOUT;
976
+ }
977
+
978
+ /* set termination resistance */
979
+ if (phy_cfg->tmdsclock > 340000000) {
980
+ inno_write(inno, 0xc7, 0x76);
981
+ inno_write(inno, 0xc5, 0x83);
982
+ inno_write(inno, 0xc8, 0x00);
983
+ inno_write(inno, 0xc9, 0x2f);
984
+ inno_write(inno, 0xca, 0x2f);
985
+ inno_write(inno, 0xcb, 0x2f);
986
+ } else {
987
+ inno_write(inno, 0xc7, 0x76);
988
+ inno_write(inno, 0xc5, 0x83);
989
+ inno_write(inno, 0xc8, 0x00);
990
+ inno_write(inno, 0xc9, 0x0f);
991
+ inno_write(inno, 0xca, 0x0f);
992
+ inno_write(inno, 0xcb, 0x0f);
993
+ }
994
+
995
+
996
+ /* set TMDS sync detection counter length */
997
+ temp = 47520000000UL / tmdsclock;
998
+ inno_write(inno, 0xd8, (temp >> 8) & 0xff);
999
+ inno_write(inno, 0xd9, temp & 0xff);
1000
+
1001
+ if (phy_cfg->tmdsclock > 340000000)
1002
+ mdelay(100);
1003
+ /* set pdata_en to 0/1 */
1004
+ inno_update_bits(inno, 0x02, 1, 0);
1005
+ inno_update_bits(inno, 0x02, 1, 1);
1006
+
1007
+ /* Enable PHY IRQ */
1008
+ inno_write(inno, 0x05, 0x22);
1009
+ inno_write(inno, 0x07, 0x22);
1010
+ inno_write(inno, 0xcc, 0x0f);
1011
+
1012
+ return 0;
1013
+}
1014
+
1015
+static void inno_hdmi_phy_rk3528_power_off(struct inno_hdmi_phy *inno)
1016
+{
1017
+ /* Power off driver */
1018
+ inno_write(inno, 0xb2, 0);
1019
+ /* Power off band gap */
1020
+ inno_update_bits(inno, 0xb0, 4, 0);
1021
+ /* Power off post pll */
1022
+ inno_update_bits(inno, 0xaa, 1, 1);
1023
+
1024
+ /* Disable PHY IRQ */
1025
+ inno_write(inno, 0x05, 0);
1026
+ inno_write(inno, 0x07, 0);
1027
+}
1028
+
1029
+static void inno_hdmi_phy_rk3528_init(struct inno_hdmi_phy *inno)
1030
+{
1031
+ /*
1032
+ * Use phy internal register control
1033
+ * rxsense/poweron/pllpd/pdataen signal.
1034
+ */
1035
+ inno_write(inno, 0x02, 0x81);
1036
+}
1037
+
1038
+static int
1039
+inno_hdmi_phy_rk3528_pre_pll_update(struct inno_hdmi_phy *inno,
1040
+ const struct pre_pll_config *cfg)
1041
+{
1042
+ u32 val;
1043
+
1044
+ inno_update_bits(inno, 0xb0, 4, 4);
1045
+ inno_write(inno, 0xcc, 0x0f);
1046
+
1047
+ /* Power on PLL */
1048
+ inno_update_bits(inno, 0xa0, 1, 0);
1049
+ /* Configure pre-pll */
1050
+ inno_update_bits(inno, 0xa0, 2, (cfg->vco_div_5_en & 1) << 1);
1051
+ inno_write(inno, 0xa1, cfg->prediv);
1052
+ if (cfg->fracdiv)
1053
+ val = ((cfg->fbdiv >> 8) & 0x0f) | 0xc0;
1054
+ else
1055
+ val = ((cfg->fbdiv >> 8) & 0x0f) | 0xf0;
1056
+ inno_write(inno, 0xa2, val);
1057
+ inno_write(inno, 0xa3, cfg->fbdiv & 0xff);
1058
+ val = (cfg->pclk_div_a & 0x1f) |
1059
+ ((cfg->pclk_div_b & 3) << 5);
1060
+ inno_write(inno, 0xa5, val);
1061
+ val = (cfg->pclk_div_d & 0x1f) |
1062
+ ((cfg->pclk_div_c & 3) << 5);
1063
+ inno_write(inno, 0xa6, val);
1064
+ val = ((cfg->tmds_div_a & 3) << 4) |
1065
+ ((cfg->tmds_div_b & 3) << 2) |
1066
+ (cfg->tmds_div_c & 3);
1067
+ inno_write(inno, 0xa4, val);
1068
+
1069
+ if (cfg->fracdiv) {
1070
+ val = cfg->fracdiv & 0xff;
1071
+ inno_write(inno, 0xd3, val);
1072
+ val = (cfg->fracdiv >> 8) & 0xff;
1073
+ inno_write(inno, 0xd2, val);
1074
+ val = (cfg->fracdiv >> 16) & 0xff;
1075
+ inno_write(inno, 0xd1, val);
1076
+ } else {
1077
+ inno_write(inno, 0xd3, 0);
1078
+ inno_write(inno, 0xd2, 0);
1079
+ inno_write(inno, 0xd1, 0);
1080
+ }
1081
+
1082
+ /* Wait for PLL lock */
1083
+ for (val = 0; val < 5; val++) {
1084
+ if (inno_read(inno, 0xa9) & 1)
1085
+ break;
1086
+ udelay(1000);
1087
+ }
1088
+ if (val == 5) {
1089
+ dev_err(inno->dev, "Pre-PLL unlock\n");
1090
+ return -ETIMEDOUT;
1091
+ }
1092
+
1093
+ return 0;
1094
+}
1095
+
1096
+static unsigned long
1097
+inno_hdmi_rk3528_phy_pll_recalc_rate(struct inno_hdmi_phy *inno,
1098
+ unsigned long parent_rate)
1099
+{
1100
+ unsigned long frac;
1101
+ u8 nd, no_a, no_b, no_d;
1102
+ u16 nf;
1103
+ u64 vco = parent_rate;
1104
+
1105
+ nd = inno_read(inno, 0xa1) & 0x3f;
1106
+ nf = ((inno_read(inno, 0xa2) & 0x0f) << 8) | inno_read(inno, 0xa3);
1107
+ vco *= nf;
1108
+ if ((inno_read(inno, 0xa2) & 0x30) == 0) {
1109
+ frac = inno_read(inno, 0xd3) |
1110
+ (inno_read(inno, 0xd2) << 8) |
1111
+ (inno_read(inno, 0xd1) << 16);
1112
+ vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24));
1113
+ }
1114
+ if (inno_read(inno, 0xa0) & 2) {
1115
+ do_div(vco, nd * 5);
1116
+ } else {
1117
+ no_a = inno_read(inno, 0xa5) & 0x1f;
1118
+ no_b = ((inno_read(inno, 0xa5) >> 5) & 7) + 2;
1119
+ no_d = inno_read(inno, 0xa6) & 0x1f;
1120
+ if (no_a == 1)
1121
+ do_div(vco, nd * no_b * no_d * 2);
1122
+ else
1123
+ do_div(vco, nd * no_a * no_d * 2);
1124
+ }
1125
+
1126
+ frac = vco;
1127
+ inno->pixclock = DIV_ROUND_CLOSEST(frac, 1000) * 1000;
1128
+
1129
+ dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
1130
+
1131
+ return frac;
1132
+}
1133
+
1134
+#ifndef CONFIG_SPL_BUILD
8611135 #define PHY_TAB_LEN 60
8621136
8631137 static
....@@ -889,6 +1163,7 @@
8891163
8901164 return 0;
8911165 }
1166
+#endif
8921167
8931168 static const struct inno_hdmi_phy_ops rk3228_hdmi_phy_ops = {
8941169 .init = inno_hdmi_phy_rk3228_init,
....@@ -905,6 +1180,14 @@
9051180 .recalc_rate = inno_hdmi_3328_phy_pll_recalc_rate,
9061181 };
9071182
1183
+static const struct inno_hdmi_phy_ops rk3528_hdmi_phy_ops = {
1184
+ .init = inno_hdmi_phy_rk3528_init,
1185
+ .power_on = inno_hdmi_phy_rk3528_power_on,
1186
+ .power_off = inno_hdmi_phy_rk3528_power_off,
1187
+ .pre_pll_update = inno_hdmi_phy_rk3528_pre_pll_update,
1188
+ .recalc_rate = inno_hdmi_rk3528_phy_pll_recalc_rate,
1189
+};
1190
+
9081191 static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = {
9091192 .dev_type = INNO_HDMI_PHY_RK3228,
9101193 .ops = &rk3228_hdmi_phy_ops,
....@@ -917,6 +1200,12 @@
9171200 .phy_cfg_table = rk3328_phy_cfg,
9181201 };
9191202
1203
+static const struct inno_hdmi_phy_drv_data rk3528_hdmi_phy_drv_data = {
1204
+ .dev_type = INNO_HDMI_PHY_RK3528,
1205
+ .ops = &rk3528_hdmi_phy_ops,
1206
+ .phy_cfg_table = rk3528_phy_cfg,
1207
+};
1208
+
9201209 static const struct rockchip_inno_data inno_hdmi_phy_of_match[] = {
9211210 { .compatible = "rockchip,rk3228-hdmi-phy",
9221211 .data = &rk3228_hdmi_phy_drv_data
....@@ -924,26 +1213,41 @@
9241213 { .compatible = "rockchip,rk3328-hdmi-phy",
9251214 .data = &rk3328_hdmi_phy_drv_data
9261215 },
1216
+ { .compatible = "rockchip,rk3528-hdmi-phy",
1217
+ .data = &rk3528_hdmi_phy_drv_data
1218
+ },
9271219 {}
9281220 };
9291221
9301222 static int inno_hdmi_phy_init(struct rockchip_phy *phy)
9311223 {
1224
+#ifdef CONFIG_SPL_BUILD
1225
+ struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data;
1226
+#else
9321227 struct udevice *dev = phy->dev;
9331228 struct inno_hdmi_phy *inno = dev_get_priv(phy->dev);
934
- int i, val, phy_table_size, ret;
935
- const char *name;
1229
+ int val, phy_table_size, ret;
9361230 u32 *phy_config;
1231
+#endif
1232
+ int i;
1233
+ const char *name;
9371234
938
- inno->node = dev->node;
939
-
1235
+#ifdef CONFIG_SPL_BUILD
1236
+ inno->regs = (void *)RK3528_HDMIPHY_BASE;
1237
+#else
9401238 inno->regs = dev_read_addr_ptr(dev);
1239
+ inno->node = dev->node;
1240
+#endif
9411241 if (!inno->regs) {
9421242 printf("%s: failed to get phy address\n", __func__);
9431243 return -ENOMEM;
9441244 }
9451245
1246
+#ifdef CONFIG_SPL_BUILD
1247
+ name = "rockchip,rk3528-hdmi-phy";
1248
+#else
9461249 name = dev_read_string(dev, "compatible");
1250
+#endif
9471251 for (i = 0; i < ARRAY_SIZE(inno_hdmi_phy_of_match); i++) {
9481252 if (!strcmp(name, inno_hdmi_phy_of_match[i].compatible)) {
9491253 inno->plat_data = inno_hdmi_phy_of_match[i].data;
....@@ -951,6 +1255,7 @@
9511255 }
9521256 }
9531257
1258
+#ifndef CONFIG_SPL_BUILD
9541259 dev_read_prop(dev, "rockchip,phy-table", &val);
9551260
9561261 if (val >= 0) {
....@@ -986,6 +1291,7 @@
9861291 } else {
9871292 printf("use default hdmi phy table\n");
9881293 }
1294
+#endif
9891295
9901296 if (i >= ARRAY_SIZE(inno_hdmi_phy_of_match))
9911297 return 0;
....@@ -1002,8 +1308,16 @@
10021308 static unsigned long inno_hdmi_phy_set_pll(struct rockchip_phy *phy,
10031309 unsigned long rate)
10041310 {
1311
+#ifdef CONFIG_SPL_BUILD
1312
+ struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data;
1313
+#else
10051314 struct inno_hdmi_phy *inno = dev_get_priv(phy->dev);
1315
+#endif
10061316
1317
+#ifdef CONFIG_SPL_BUILD
1318
+ if (!inno)
1319
+ inno = g_inno;
1320
+#endif
10071321 inno_hdmi_phy_clk_prepare(inno);
10081322 inno_hdmi_phy_clk_is_prepared(inno);
10091323 inno_hdmi_phy_clk_set_rate(inno, rate);
....@@ -1013,7 +1327,11 @@
10131327 static int
10141328 inno_hdmi_phy_set_bus_width(struct rockchip_phy *phy, u32 bus_width)
10151329 {
1330
+#ifdef CONFIG_SPL_BUILD
1331
+ struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data;
1332
+#else
10161333 struct inno_hdmi_phy *inno = dev_get_priv(phy->dev);
1334
+#endif
10171335
10181336 inno->bus_width = bus_width;
10191337
....@@ -1023,7 +1341,11 @@
10231341 static long
10241342 inno_hdmi_phy_clk_round_rate(struct rockchip_phy *phy, unsigned long rate)
10251343 {
1344
+#ifdef CONFIG_SPL_BUILD
1345
+ struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data;
1346
+#else
10261347 struct inno_hdmi_phy *inno = dev_get_priv(phy->dev);
1348
+#endif
10271349 int i;
10281350 const struct pre_pll_config *cfg = pre_pll_cfg_table;
10291351 u32 tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate);
....@@ -1082,9 +1404,26 @@
10821404 .compatible = "rockchip,rk3228-hdmi-phy",
10831405 .data = (ulong)&inno_hdmi_phy_driver_data,
10841406 },
1407
+ {
1408
+ .compatible = "rockchip,rk3528-hdmi-phy",
1409
+ .data = (ulong)&inno_hdmi_phy_driver_data,
1410
+ },
10851411 {}
10861412 };
10871413
1414
+#ifdef CONFIG_SPL_BUILD
1415
+int inno_spl_hdmi_phy_probe(struct display_state *state)
1416
+{
1417
+ struct inno_hdmi_phy *inno = malloc(sizeof(struct inno_hdmi_phy));
1418
+
1419
+ memset(inno, 0, sizeof(*inno));
1420
+ g_inno = inno;
1421
+
1422
+ state->conn_state.connector->phy = &inno_hdmi_phy_driver_data;
1423
+ state->conn_state.connector->phy->data = (void *)inno;
1424
+ return 0;
1425
+}
1426
+#else
10881427 static int inno_hdmi_phy_probe(struct udevice *dev)
10891428 {
10901429 struct inno_hdmi_phy *inno = dev_get_priv(dev);
....@@ -1094,6 +1433,32 @@
10941433 inno->dev = dev;
10951434 phy->dev = dev;
10961435
1436
+ g_inno = inno;
1437
+ dev->driver_data = (ulong)&inno_hdmi_phy_driver_data;
1438
+ phy = &inno_hdmi_phy_driver_data;
1439
+
1440
+ return 0;
1441
+}
1442
+#endif
1443
+
1444
+static int rockchip_inno_phy_hdmi_bind(struct udevice *parent)
1445
+{
1446
+ struct udevice *child;
1447
+ ofnode subnode;
1448
+ int ret;
1449
+
1450
+ subnode = ofnode_find_subnode(parent->node, "clk-port");
1451
+ if (!ofnode_valid(subnode)) {
1452
+ printf("%s: no subnode for %s\n", __func__, parent->name);
1453
+ return -ENXIO;
1454
+ }
1455
+
1456
+ ret = device_bind_driver_to_node(parent, "clk_inno_hdmi", "inno_hdmi_pll_clk", subnode, &child);
1457
+ if (ret) {
1458
+ printf("%s: clk-port cannot bind its driver\n", __func__);
1459
+ return ret;
1460
+ }
1461
+
10971462 return 0;
10981463 }
10991464
....@@ -1101,6 +1466,57 @@
11011466 .name = "inno_hdmi_phy",
11021467 .id = UCLASS_PHY,
11031468 .of_match = inno_hdmi_phy_ids,
1469
+#ifndef CONFIG_SPL_BUILD
11041470 .probe = inno_hdmi_phy_probe,
1471
+#endif
1472
+ .bind = rockchip_inno_phy_hdmi_bind,
11051473 .priv_auto_alloc_size = sizeof(struct inno_hdmi_phy),
11061474 };
1475
+
1476
+
1477
+static ulong inno_hdmi_clk_get_rate(struct clk *clk)
1478
+{
1479
+ struct clk_inno_hdmi *priv = dev_get_priv(clk->dev);
1480
+
1481
+ return priv->rate;
1482
+}
1483
+
1484
+static ulong inno_hdmi_clk_set_rate(struct clk *clk, ulong rate)
1485
+{
1486
+ struct clk_inno_hdmi *priv = dev_get_priv(clk->dev);
1487
+ int ret;
1488
+
1489
+ inno_hdmi_phy_clk_prepare(g_inno);
1490
+ inno_hdmi_phy_clk_is_prepared(g_inno);
1491
+ ret = inno_hdmi_phy_clk_set_rate(g_inno, rate);
1492
+ if (ret < 0) {
1493
+ printf("inno hdmi set rate failed ret:%d\n", ret);
1494
+ return ret;
1495
+ }
1496
+
1497
+ priv->rate = g_inno->pixclock;
1498
+
1499
+ return priv->rate;
1500
+}
1501
+
1502
+static const struct clk_ops inno_hdmi_clk_ops = {
1503
+ .get_rate = inno_hdmi_clk_get_rate,
1504
+ .set_rate = inno_hdmi_clk_set_rate,
1505
+};
1506
+
1507
+static int inno_hdmi_clk_probe(struct udevice *dev)
1508
+{
1509
+ return 0;
1510
+}
1511
+
1512
+/*
1513
+ * In order for other display interfaces to use hdmiphy as source
1514
+ * for dclk, hdmiphy must register a virtual clock driver
1515
+ */
1516
+U_BOOT_DRIVER(clk_inno_hdmi) = {
1517
+ .name = "clk_inno_hdmi",
1518
+ .id = UCLASS_CLK,
1519
+ .priv_auto_alloc_size = sizeof(struct clk_inno_hdmi),
1520
+ .ops = &inno_hdmi_clk_ops,
1521
+ .probe = inno_hdmi_clk_probe,
1522
+};