hc
2023-11-06 e3e12f52b214121840b44c91de5b3e5af5d3eb84
kernel/drivers/phy/rockchip/phy-rockchip-inno-hdmi-phy.c
....@@ -153,7 +153,8 @@
153153
154154 enum inno_hdmi_phy_type {
155155 INNO_HDMI_PHY_RK3228,
156
- INNO_HDMI_PHY_RK3328
156
+ INNO_HDMI_PHY_RK3328,
157
+ INNO_HDMI_PHY_RK3528
157158 };
158159
159160 struct phy_config {
....@@ -287,9 +288,13 @@
287288 {33750000, 1, 10, 2, 4},
288289 {74250000, 1, 40, 8, 1},
289290 {74250000, 18, 80, 8, 2},
291
+ {74250000, 1, 20, 4, 8},
290292 {148500000, 2, 40, 4, 3},
293
+ {148500000, 1, 10, 2, 8},
291294 {297000000, 4, 40, 2, 3},
295
+ {297000000, 2, 20, 2, 8},
292296 {594000000, 8, 40, 1, 3},
297
+ {594000000, 4, 20, 1, 8},
293298 { ~0UL, 0, 0, 0, 0}
294299 };
295300
....@@ -330,6 +335,30 @@
330335 594000000, {
331336 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08,
332337 0x00, 0xac, 0xcc, 0xcc, 0xcc,
338
+ },
339
+ }, {
340
+ ~0UL, {
341
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342
+ 0x00, 0x00, 0x00, 0x00, 0x00,
343
+ },
344
+ }
345
+};
346
+
347
+static const struct phy_config rk3528_phy_cfg[] = {
348
+ /* tmdsclk bias-clk bias-data voltage-clk voltage-data pre-emphasis-data */
349
+ { 165000000, {
350
+ 0x03, 0x04, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
351
+ 0x00, 0x00, 0x00, 0x00, 0x00,
352
+ },
353
+ }, {
354
+ 340000000, {
355
+ 0x03, 0x04, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
356
+ 0x00, 0x00, 0x00, 0x00, 0x00,
357
+ },
358
+ }, {
359
+ 594000000, {
360
+ 0x02, 0x08, 0x0d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
361
+ 0x00, 0x00, 0x00, 0x00, 0x00,
333362 },
334363 }, {
335364 ~0UL, {
....@@ -462,6 +491,8 @@
462491 else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3228 &&
463492 tmdsclock <= 33750000 && inno->efuse_flag)
464493 chipversion = 4;
494
+ else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3528)
495
+ chipversion = 8;
465496
466497 for (; cfg->tmdsclock != ~0UL; cfg++)
467498 if (tmdsclock <= cfg->tmdsclock &&
....@@ -631,10 +662,17 @@
631662 {
632663 struct device *dev = inno->dev;
633664 struct device_node *np = dev->of_node;
665
+ struct device_node *clk_np = NULL;
634666 struct clk_init_data init = {};
635667 struct clk *refclk;
636668 const char *parent_name;
637669 int ret;
670
+
671
+ if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3528)
672
+ clk_np = of_get_child_by_name(np, "clk-port");
673
+
674
+ if (!clk_np)
675
+ clk_np = np;
638676
639677 refclk = devm_clk_get(dev, "refclk");
640678 if (IS_ERR(refclk)) {
....@@ -651,7 +689,7 @@
651689 init.ops = &inno_hdmi_phy_clk_ops;
652690
653691 /* optional override of the clock name */
654
- of_property_read_string(np, "clock-output-names", &init.name);
692
+ of_property_read_string(clk_np, "clock-output-names", &init.name);
655693
656694 inno->hw.init = &init;
657695
....@@ -662,7 +700,7 @@
662700 return ret;
663701 }
664702
665
- ret = of_clk_add_provider(np, of_clk_src_simple_get, inno->pclk);
703
+ ret = of_clk_add_provider(clk_np, of_clk_src_simple_get, inno->pclk);
666704 if (ret) {
667705 dev_err(dev, "failed to register OF clock provider: %d\n", ret);
668706 return ret;
....@@ -1078,6 +1116,245 @@
10781116 return frac;
10791117 }
10801118
1119
+static int
1120
+inno_hdmi_phy_rk3528_power_on(struct inno_hdmi_phy *inno,
1121
+ const struct post_pll_config *cfg,
1122
+ const struct phy_config *phy_cfg)
1123
+{
1124
+ u32 val;
1125
+ u64 temp;
1126
+
1127
+ /* Power off post PLL */
1128
+ inno_update_bits(inno, 0xaa, 1, 0);
1129
+
1130
+ val = cfg->prediv;
1131
+ inno_write(inno, 0xab, val);
1132
+
1133
+ if (cfg->postdiv == 1) {
1134
+ inno_write(inno, 0xad, 0x8);
1135
+ inno_write(inno, 0xaa, 2);
1136
+ } else {
1137
+ val = (cfg->postdiv / 2) - 1;
1138
+ inno_write(inno, 0xad, val);
1139
+ inno_write(inno, 0xaa, 0x0e);
1140
+ }
1141
+
1142
+ val = cfg->fbdiv & 0xff;
1143
+ inno_write(inno, 0xac, val);
1144
+ val = (cfg->fbdiv >> 8) & BIT(0);
1145
+ inno_update_bits(inno, 0xad, BIT(4), val);
1146
+
1147
+ /* current bias clk/data 2 */
1148
+ val = phy_cfg->regs[0] << 4 | phy_cfg->regs[1];
1149
+ inno_write(inno, 0xbf, val);
1150
+
1151
+ /* current bias data 1/0 */
1152
+ val = phy_cfg->regs[1] << 4 | phy_cfg->regs[1];
1153
+ inno_write(inno, 0xc0, val);
1154
+
1155
+ /* output voltage */
1156
+ inno_write(inno, 0xb5, phy_cfg->regs[2]);
1157
+ inno_write(inno, 0xb6, phy_cfg->regs[3]);
1158
+ inno_write(inno, 0xb7, phy_cfg->regs[3]);
1159
+ inno_write(inno, 0xb8, phy_cfg->regs[3]);
1160
+
1161
+ /* pre-emphasis */
1162
+ inno_write(inno, 0xbb, phy_cfg->regs[4]);
1163
+ inno_write(inno, 0xbc, phy_cfg->regs[4]);
1164
+ inno_write(inno, 0xbd, phy_cfg->regs[4]);
1165
+
1166
+ /* enable LDO */
1167
+ inno_write(inno, 0xb4, 0x7);
1168
+
1169
+ /* enable serializer */
1170
+ inno_write(inno, 0xbe, 0x70);
1171
+
1172
+ inno_write(inno, 0xb2, 0x0f);
1173
+
1174
+ for (val = 0; val < 5; val++) {
1175
+ if (inno_read(inno, 0xaf) & 1)
1176
+ break;
1177
+ udelay(1000);
1178
+ }
1179
+ if (!(inno_read(inno, 0xaf) & 1)) {
1180
+ dev_err(inno->dev, "HDMI PHY Post PLL unlock\n");
1181
+ return -ETIMEDOUT;
1182
+ }
1183
+
1184
+ /* set termination resistance */
1185
+ if (phy_cfg->tmdsclock > 340000000) {
1186
+ inno_write(inno, 0xc7, 0x76);
1187
+ inno_write(inno, 0xc5, 0x83);
1188
+ inno_write(inno, 0xc8, 0x00);
1189
+ inno_write(inno, 0xc9, 0x2f);
1190
+ inno_write(inno, 0xca, 0x2f);
1191
+ inno_write(inno, 0xcb, 0x2f);
1192
+ } else {
1193
+ inno_write(inno, 0xc7, 0x76);
1194
+ inno_write(inno, 0xc5, 0x83);
1195
+ inno_write(inno, 0xc8, 0x00);
1196
+ inno_write(inno, 0xc9, 0x0f);
1197
+ inno_write(inno, 0xca, 0x0f);
1198
+ inno_write(inno, 0xcb, 0x0f);
1199
+ }
1200
+
1201
+ /* set TMDS sync detection counter length */
1202
+ temp = 47520000000;
1203
+ do_div(temp, inno->tmdsclock);
1204
+ inno_write(inno, 0xd8, (temp >> 8) & 0xff);
1205
+ inno_write(inno, 0xd9, temp & 0xff);
1206
+
1207
+ /* Power up post PLL */
1208
+ inno_update_bits(inno, 0xaa, 1, 0);
1209
+ /* Power up tmds driver */
1210
+ inno_update_bits(inno, 0xb0, 4, 4);
1211
+ inno_write(inno, 0xb2, 0x0f);
1212
+
1213
+ if (phy_cfg->tmdsclock > 340000000)
1214
+ msleep(100);
1215
+ /* set pdata_en to 0/1 */
1216
+ inno_update_bits(inno, 0x02, 1, 0);
1217
+ inno_update_bits(inno, 0x02, 1, 1);
1218
+
1219
+ /* Enable PHY IRQ */
1220
+ inno_write(inno, 0x05, 0x22);
1221
+ inno_write(inno, 0x07, 0x22);
1222
+ inno_write(inno, 0xcc, 0x0f);
1223
+
1224
+ return 0;
1225
+}
1226
+
1227
+static void inno_hdmi_phy_rk3528_power_off(struct inno_hdmi_phy *inno)
1228
+{
1229
+ /* Power off driver */
1230
+ inno_write(inno, 0xb2, 0);
1231
+ /* Power off serializer */
1232
+ inno_write(inno, 0xbe, 0);
1233
+ /* Power off post pll */
1234
+ inno_update_bits(inno, 0xaa, 1, 1);
1235
+ /* Power off rxsense detection circuit */
1236
+ inno_write(inno, 0xcc, 0);
1237
+ /* Power off band gap */
1238
+ inno_update_bits(inno, 0xb0, 4, 0);
1239
+ /* Disable PHY IRQ */
1240
+ inno_write(inno, 0x05, 0);
1241
+ inno_write(inno, 0x07, 0);
1242
+}
1243
+
1244
+static void inno_hdmi_phy_rk3528_init(struct inno_hdmi_phy *inno)
1245
+{
1246
+ /*
1247
+ * Use phy internal register control
1248
+ * rxsense/poweron/pllpd/pdataen signal.
1249
+ */
1250
+ inno_write(inno, 0x02, 0x81);
1251
+
1252
+ /* if phy had been set in uboot, pll is locked */
1253
+ if (inno_read(inno, 0xa9) & BIT(0)) {
1254
+ dev_info(inno->dev, "phy had been powered up\n");
1255
+ inno->phy->power_count = 1;
1256
+ } else {
1257
+ /* manual power down post-PLL */
1258
+ inno_hdmi_phy_rk3528_power_off(inno);
1259
+ }
1260
+}
1261
+
1262
+static int
1263
+inno_hdmi_phy_rk3528_pre_pll_update(struct inno_hdmi_phy *inno,
1264
+ const struct pre_pll_config *cfg)
1265
+{
1266
+ u32 val;
1267
+
1268
+ inno_update_bits(inno, 0xb0, 4, 4);
1269
+ inno_write(inno, 0xcc, 0x0f);
1270
+
1271
+ /* Power on PLL */
1272
+ inno_update_bits(inno, 0xa0, 1, 0);
1273
+ /* Configure pre-pll */
1274
+ inno_update_bits(inno, 0xa0, 2, (cfg->vco_div_5_en & 1) << 1);
1275
+ inno_write(inno, 0xa1, cfg->prediv);
1276
+ if (cfg->fracdiv)
1277
+ val = ((cfg->fbdiv >> 8) & 0x0f) | 0xc0;
1278
+ else
1279
+ val = ((cfg->fbdiv >> 8) & 0x0f) | 0xf0;
1280
+ inno_write(inno, 0xa2, val);
1281
+ inno_write(inno, 0xa3, cfg->fbdiv & 0xff);
1282
+ val = (cfg->pclk_div_a & 0x1f) |
1283
+ ((cfg->pclk_div_b & 3) << 5);
1284
+ inno_write(inno, 0xa5, val);
1285
+ val = (cfg->pclk_div_d & 0x1f) |
1286
+ ((cfg->pclk_div_c & 3) << 5);
1287
+ inno_write(inno, 0xa6, val);
1288
+ val = ((cfg->tmds_div_a & 3) << 4) |
1289
+ ((cfg->tmds_div_b & 3) << 2) |
1290
+ (cfg->tmds_div_c & 3);
1291
+ inno_write(inno, 0xa4, val);
1292
+
1293
+ if (cfg->fracdiv) {
1294
+ val = cfg->fracdiv & 0xff;
1295
+ inno_write(inno, 0xd3, val);
1296
+ val = (cfg->fracdiv >> 8) & 0xff;
1297
+ inno_write(inno, 0xd2, val);
1298
+ val = (cfg->fracdiv >> 16) & 0xff;
1299
+ inno_write(inno, 0xd1, val);
1300
+ } else {
1301
+ inno_write(inno, 0xd3, 0);
1302
+ inno_write(inno, 0xd2, 0);
1303
+ inno_write(inno, 0xd1, 0);
1304
+ }
1305
+
1306
+ /* Wait for PLL lock */
1307
+ for (val = 0; val < 5; val++) {
1308
+ if (inno_read(inno, 0xa9) & 1)
1309
+ break;
1310
+ usleep_range(1000, 2000);
1311
+ }
1312
+ if (val == 5) {
1313
+ dev_err(inno->dev, "Pre-PLL unlock\n");
1314
+ return -ETIMEDOUT;
1315
+ }
1316
+
1317
+ return 0;
1318
+}
1319
+
1320
+static unsigned long
1321
+inno_hdmi_rk3528_phy_pll_recalc_rate(struct inno_hdmi_phy *inno,
1322
+ unsigned long parent_rate)
1323
+{
1324
+ unsigned long frac;
1325
+ u8 nd, no_a, no_b, no_d;
1326
+ u16 nf;
1327
+ u64 vco = parent_rate;
1328
+
1329
+ nd = inno_read(inno, 0xa1) & 0x3f;
1330
+ nf = ((inno_read(inno, 0xa2) & 0x0f) << 8) | inno_read(inno, 0xa3);
1331
+ vco *= nf;
1332
+ if ((inno_read(inno, 0xa2) & 0x30) == 0) {
1333
+ frac = inno_read(inno, 0xd3) |
1334
+ (inno_read(inno, 0xd2) << 8) |
1335
+ (inno_read(inno, 0xd1) << 16);
1336
+ vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24));
1337
+ }
1338
+ if (inno_read(inno, 0xa0) & 2) {
1339
+ do_div(vco, nd * 5);
1340
+ } else {
1341
+ no_a = inno_read(inno, 0xa5) & 0x1f;
1342
+ no_b = ((inno_read(inno, 0xa5) >> 5) & 7) + 2;
1343
+ no_d = inno_read(inno, 0xa6) & 0x1f;
1344
+ if (no_a == 1)
1345
+ do_div(vco, nd * no_b * no_d * 2);
1346
+ else
1347
+ do_div(vco, nd * no_a * no_d * 2);
1348
+ }
1349
+
1350
+ frac = vco;
1351
+ inno->pixclock = DIV_ROUND_CLOSEST(frac, 1000) * 1000;
1352
+
1353
+ dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
1354
+
1355
+ return frac;
1356
+}
1357
+
10811358 static unsigned long
10821359 inno_hdmi_rk3228_phy_pll_recalc_rate(struct inno_hdmi_phy *inno,
10831360 unsigned long parent_rate)
....@@ -1128,6 +1405,14 @@
11281405 .recalc_rate = inno_hdmi_rk3328_phy_pll_recalc_rate,
11291406 };
11301407
1408
+static const struct inno_hdmi_phy_ops rk3528_hdmi_phy_ops = {
1409
+ .init = inno_hdmi_phy_rk3528_init,
1410
+ .power_on = inno_hdmi_phy_rk3528_power_on,
1411
+ .power_off = inno_hdmi_phy_rk3528_power_off,
1412
+ .pre_pll_update = inno_hdmi_phy_rk3528_pre_pll_update,
1413
+ .recalc_rate = inno_hdmi_rk3528_phy_pll_recalc_rate,
1414
+};
1415
+
11311416 static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = {
11321417 .dev_type = INNO_HDMI_PHY_RK3228,
11331418 .ops = &rk3228_hdmi_phy_ops,
....@@ -1140,12 +1425,21 @@
11401425 .phy_cfg_table = rk3328_phy_cfg,
11411426 };
11421427
1428
+static const struct inno_hdmi_phy_drv_data rk3528_hdmi_phy_drv_data = {
1429
+ .dev_type = INNO_HDMI_PHY_RK3528,
1430
+ .ops = &rk3528_hdmi_phy_ops,
1431
+ .phy_cfg_table = rk3528_phy_cfg,
1432
+};
1433
+
11431434 static const struct of_device_id inno_hdmi_phy_of_match[] = {
11441435 { .compatible = "rockchip,rk3228-hdmi-phy",
11451436 .data = &rk3228_hdmi_phy_drv_data
11461437 },
11471438 { .compatible = "rockchip,rk3328-hdmi-phy",
11481439 .data = &rk3328_hdmi_phy_drv_data
1440
+ },
1441
+ { .compatible = "rockchip,rk3528-hdmi-phy",
1442
+ .data = &rk3528_hdmi_phy_drv_data
11491443 },
11501444 {}
11511445 };
....@@ -1244,13 +1538,15 @@
12441538 if (of_get_property(np, "rockchip,phy-table", &val)) {
12451539 if (val % PHY_TAB_LEN || !val) {
12461540 dev_err(dev, "Invalid phy cfg table format!\n");
1247
- return -EINVAL;
1541
+ ret = -EINVAL;
1542
+ goto err_regsmap;
12481543 }
12491544
12501545 phy_config = kmalloc(val, GFP_KERNEL);
12511546 if (!phy_config) {
12521547 dev_err(dev, "kmalloc phy table failed\n");
1253
- return -ENOMEM;
1548
+ ret = -ENOMEM;
1549
+ goto err_regsmap;
12541550 }
12551551
12561552 phy_table_size = val / PHY_TAB_LEN;
....@@ -1259,7 +1555,8 @@
12591555 GFP_KERNEL);
12601556 if (!inno->phy_cfg) {
12611557 kfree(phy_config);
1262
- return -ENOMEM;
1558
+ ret = -ENOMEM;
1559
+ goto err_regsmap;
12631560 }
12641561 of_property_read_u32_array(np, "rockchip,phy-table",
12651562 phy_config, val / sizeof(u32));
....@@ -1268,7 +1565,7 @@
12681565 phy_table_size);
12691566 if (ret) {
12701567 kfree(phy_config);
1271
- return ret;
1568
+ goto err_regsmap;
12721569 }
12731570 kfree(phy_config);
12741571 } else {