.. | .. |
---|
3 | 3 | * (C) Copyright 2008-2016 Fuzhou Rockchip Electronics Co., Ltd |
---|
4 | 4 | */ |
---|
5 | 5 | |
---|
| 6 | +#include <clk-uclass.h> |
---|
6 | 7 | #include <config.h> |
---|
7 | 8 | #include <common.h> |
---|
8 | 9 | #include <errno.h> |
---|
.. | .. |
---|
11 | 12 | #include <fdtdec.h> |
---|
12 | 13 | #include <fdt_support.h> |
---|
13 | 14 | #include <asm/unaligned.h> |
---|
| 15 | +#include <asm/arch/clock.h> |
---|
14 | 16 | #include <dm/device.h> |
---|
| 17 | +#include <dm/lists.h> |
---|
15 | 18 | #include <dm/read.h> |
---|
16 | 19 | #include <asm/io.h> |
---|
17 | 20 | #include <linux/list.h> |
---|
.. | .. |
---|
20 | 23 | |
---|
21 | 24 | #include "rockchip_display.h" |
---|
22 | 25 | #include "rockchip_crtc.h" |
---|
| 26 | +#include "rockchip_connector.h" |
---|
23 | 27 | #include "rockchip_phy.h" |
---|
24 | 28 | |
---|
25 | 29 | #define INNO_HDMI_PHY_TIMEOUT_LOOP_COUNT 1000 |
---|
.. | .. |
---|
145 | 149 | |
---|
146 | 150 | enum inno_hdmi_phy_type { |
---|
147 | 151 | INNO_HDMI_PHY_RK3228, |
---|
148 | | - INNO_HDMI_PHY_RK3328 |
---|
| 152 | + INNO_HDMI_PHY_RK3328, |
---|
| 153 | + INNO_HDMI_PHY_RK3528 |
---|
149 | 154 | }; |
---|
150 | 155 | |
---|
151 | 156 | struct inno_hdmi_phy_drv_data; |
---|
.. | .. |
---|
214 | 219 | const void *data; |
---|
215 | 220 | }; |
---|
216 | 221 | |
---|
| 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 | + |
---|
217 | 230 | static const struct pre_pll_config pre_pll_cfg_table[] = { |
---|
218 | 231 | { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, |
---|
219 | 232 | { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, |
---|
.. | .. |
---|
249 | 262 | {33750000, 1, 10, 2, 4}, |
---|
250 | 263 | {74250000, 1, 40, 8, 1}, |
---|
251 | 264 | {74250000, 18, 80, 8, 2}, |
---|
| 265 | + {74250000, 1, 20, 4, 8}, |
---|
252 | 266 | {148500000, 2, 40, 4, 3}, |
---|
| 267 | + {148500000, 1, 10, 2, 8}, |
---|
253 | 268 | {297000000, 4, 40, 2, 3}, |
---|
| 269 | + {297000000, 2, 20, 2, 8}, |
---|
254 | 270 | {594000000, 8, 40, 1, 3}, |
---|
| 271 | + {594000000, 4, 20, 1, 8}, |
---|
255 | 272 | { ~0UL, 0, 0, 0, 0} |
---|
256 | 273 | }; |
---|
257 | 274 | |
---|
.. | .. |
---|
292 | 309 | 594000000, { |
---|
293 | 310 | 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08, |
---|
294 | 311 | 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, |
---|
295 | 336 | }, |
---|
296 | 337 | }, { |
---|
297 | 338 | ~0UL, { |
---|
.. | .. |
---|
398 | 439 | |
---|
399 | 440 | static int inno_hdmi_phy_power_on(struct rockchip_phy *phy) |
---|
400 | 441 | { |
---|
| 442 | +#ifdef CONFIG_SPL_BUILD |
---|
| 443 | + struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data; |
---|
| 444 | +#else |
---|
401 | 445 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); |
---|
| 446 | +#endif |
---|
402 | 447 | const struct post_pll_config *cfg = post_pll_cfg_table; |
---|
403 | 448 | const struct phy_config *phy_cfg = inno->plat_data->phy_cfg_table; |
---|
404 | 449 | u32 tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, inno->pixclock); |
---|
.. | .. |
---|
420 | 465 | else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3228 && |
---|
421 | 466 | tmdsclock <= 33750000) |
---|
422 | 467 | chipversion = 4; |
---|
| 468 | + else if (inno->plat_data->dev_type == INNO_HDMI_PHY_RK3528) |
---|
| 469 | + chipversion = 8; |
---|
423 | 470 | |
---|
424 | 471 | printf("tmdsclock = %d; chipversion = %d\n", tmdsclock, chipversion); |
---|
425 | 472 | |
---|
.. | .. |
---|
444 | 491 | |
---|
445 | 492 | static int inno_hdmi_phy_power_off(struct rockchip_phy *phy) |
---|
446 | 493 | { |
---|
| 494 | +#ifdef CONFIG_SPL_BUILD |
---|
| 495 | + struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data; |
---|
| 496 | +#else |
---|
447 | 497 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); |
---|
| 498 | +#endif |
---|
448 | 499 | |
---|
449 | 500 | if (inno->plat_data->ops->power_off) |
---|
450 | 501 | inno->plat_data->ops->power_off(inno); |
---|
.. | .. |
---|
858 | 909 | return rate; |
---|
859 | 910 | } |
---|
860 | 911 | |
---|
| 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 |
---|
861 | 1135 | #define PHY_TAB_LEN 60 |
---|
862 | 1136 | |
---|
863 | 1137 | static |
---|
.. | .. |
---|
889 | 1163 | |
---|
890 | 1164 | return 0; |
---|
891 | 1165 | } |
---|
| 1166 | +#endif |
---|
892 | 1167 | |
---|
893 | 1168 | static const struct inno_hdmi_phy_ops rk3228_hdmi_phy_ops = { |
---|
894 | 1169 | .init = inno_hdmi_phy_rk3228_init, |
---|
.. | .. |
---|
905 | 1180 | .recalc_rate = inno_hdmi_3328_phy_pll_recalc_rate, |
---|
906 | 1181 | }; |
---|
907 | 1182 | |
---|
| 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 | + |
---|
908 | 1191 | static const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = { |
---|
909 | 1192 | .dev_type = INNO_HDMI_PHY_RK3228, |
---|
910 | 1193 | .ops = &rk3228_hdmi_phy_ops, |
---|
.. | .. |
---|
917 | 1200 | .phy_cfg_table = rk3328_phy_cfg, |
---|
918 | 1201 | }; |
---|
919 | 1202 | |
---|
| 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 | + |
---|
920 | 1209 | static const struct rockchip_inno_data inno_hdmi_phy_of_match[] = { |
---|
921 | 1210 | { .compatible = "rockchip,rk3228-hdmi-phy", |
---|
922 | 1211 | .data = &rk3228_hdmi_phy_drv_data |
---|
.. | .. |
---|
924 | 1213 | { .compatible = "rockchip,rk3328-hdmi-phy", |
---|
925 | 1214 | .data = &rk3328_hdmi_phy_drv_data |
---|
926 | 1215 | }, |
---|
| 1216 | + { .compatible = "rockchip,rk3528-hdmi-phy", |
---|
| 1217 | + .data = &rk3528_hdmi_phy_drv_data |
---|
| 1218 | + }, |
---|
927 | 1219 | {} |
---|
928 | 1220 | }; |
---|
929 | 1221 | |
---|
930 | 1222 | static int inno_hdmi_phy_init(struct rockchip_phy *phy) |
---|
931 | 1223 | { |
---|
| 1224 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1225 | + struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data; |
---|
| 1226 | +#else |
---|
932 | 1227 | struct udevice *dev = phy->dev; |
---|
933 | 1228 | 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; |
---|
936 | 1230 | u32 *phy_config; |
---|
| 1231 | +#endif |
---|
| 1232 | + int i; |
---|
| 1233 | + const char *name; |
---|
937 | 1234 | |
---|
938 | | - inno->node = dev->node; |
---|
939 | | - |
---|
| 1235 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1236 | + inno->regs = (void *)RK3528_HDMIPHY_BASE; |
---|
| 1237 | +#else |
---|
940 | 1238 | inno->regs = dev_read_addr_ptr(dev); |
---|
| 1239 | + inno->node = dev->node; |
---|
| 1240 | +#endif |
---|
941 | 1241 | if (!inno->regs) { |
---|
942 | 1242 | printf("%s: failed to get phy address\n", __func__); |
---|
943 | 1243 | return -ENOMEM; |
---|
944 | 1244 | } |
---|
945 | 1245 | |
---|
| 1246 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1247 | + name = "rockchip,rk3528-hdmi-phy"; |
---|
| 1248 | +#else |
---|
946 | 1249 | name = dev_read_string(dev, "compatible"); |
---|
| 1250 | +#endif |
---|
947 | 1251 | for (i = 0; i < ARRAY_SIZE(inno_hdmi_phy_of_match); i++) { |
---|
948 | 1252 | if (!strcmp(name, inno_hdmi_phy_of_match[i].compatible)) { |
---|
949 | 1253 | inno->plat_data = inno_hdmi_phy_of_match[i].data; |
---|
.. | .. |
---|
951 | 1255 | } |
---|
952 | 1256 | } |
---|
953 | 1257 | |
---|
| 1258 | +#ifndef CONFIG_SPL_BUILD |
---|
954 | 1259 | dev_read_prop(dev, "rockchip,phy-table", &val); |
---|
955 | 1260 | |
---|
956 | 1261 | if (val >= 0) { |
---|
.. | .. |
---|
986 | 1291 | } else { |
---|
987 | 1292 | printf("use default hdmi phy table\n"); |
---|
988 | 1293 | } |
---|
| 1294 | +#endif |
---|
989 | 1295 | |
---|
990 | 1296 | if (i >= ARRAY_SIZE(inno_hdmi_phy_of_match)) |
---|
991 | 1297 | return 0; |
---|
.. | .. |
---|
1002 | 1308 | static unsigned long inno_hdmi_phy_set_pll(struct rockchip_phy *phy, |
---|
1003 | 1309 | unsigned long rate) |
---|
1004 | 1310 | { |
---|
| 1311 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1312 | + struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data; |
---|
| 1313 | +#else |
---|
1005 | 1314 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); |
---|
| 1315 | +#endif |
---|
1006 | 1316 | |
---|
| 1317 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1318 | + if (!inno) |
---|
| 1319 | + inno = g_inno; |
---|
| 1320 | +#endif |
---|
1007 | 1321 | inno_hdmi_phy_clk_prepare(inno); |
---|
1008 | 1322 | inno_hdmi_phy_clk_is_prepared(inno); |
---|
1009 | 1323 | inno_hdmi_phy_clk_set_rate(inno, rate); |
---|
.. | .. |
---|
1013 | 1327 | static int |
---|
1014 | 1328 | inno_hdmi_phy_set_bus_width(struct rockchip_phy *phy, u32 bus_width) |
---|
1015 | 1329 | { |
---|
| 1330 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1331 | + struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data; |
---|
| 1332 | +#else |
---|
1016 | 1333 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); |
---|
| 1334 | +#endif |
---|
1017 | 1335 | |
---|
1018 | 1336 | inno->bus_width = bus_width; |
---|
1019 | 1337 | |
---|
.. | .. |
---|
1023 | 1341 | static long |
---|
1024 | 1342 | inno_hdmi_phy_clk_round_rate(struct rockchip_phy *phy, unsigned long rate) |
---|
1025 | 1343 | { |
---|
| 1344 | +#ifdef CONFIG_SPL_BUILD |
---|
| 1345 | + struct inno_hdmi_phy *inno = (struct inno_hdmi_phy *)phy->data; |
---|
| 1346 | +#else |
---|
1026 | 1347 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); |
---|
| 1348 | +#endif |
---|
1027 | 1349 | int i; |
---|
1028 | 1350 | const struct pre_pll_config *cfg = pre_pll_cfg_table; |
---|
1029 | 1351 | u32 tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); |
---|
.. | .. |
---|
1082 | 1404 | .compatible = "rockchip,rk3228-hdmi-phy", |
---|
1083 | 1405 | .data = (ulong)&inno_hdmi_phy_driver_data, |
---|
1084 | 1406 | }, |
---|
| 1407 | + { |
---|
| 1408 | + .compatible = "rockchip,rk3528-hdmi-phy", |
---|
| 1409 | + .data = (ulong)&inno_hdmi_phy_driver_data, |
---|
| 1410 | + }, |
---|
1085 | 1411 | {} |
---|
1086 | 1412 | }; |
---|
1087 | 1413 | |
---|
| 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 |
---|
1088 | 1427 | static int inno_hdmi_phy_probe(struct udevice *dev) |
---|
1089 | 1428 | { |
---|
1090 | 1429 | struct inno_hdmi_phy *inno = dev_get_priv(dev); |
---|
.. | .. |
---|
1094 | 1433 | inno->dev = dev; |
---|
1095 | 1434 | phy->dev = dev; |
---|
1096 | 1435 | |
---|
| 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 | + |
---|
1097 | 1462 | return 0; |
---|
1098 | 1463 | } |
---|
1099 | 1464 | |
---|
.. | .. |
---|
1101 | 1466 | .name = "inno_hdmi_phy", |
---|
1102 | 1467 | .id = UCLASS_PHY, |
---|
1103 | 1468 | .of_match = inno_hdmi_phy_ids, |
---|
| 1469 | +#ifndef CONFIG_SPL_BUILD |
---|
1104 | 1470 | .probe = inno_hdmi_phy_probe, |
---|
| 1471 | +#endif |
---|
| 1472 | + .bind = rockchip_inno_phy_hdmi_bind, |
---|
1105 | 1473 | .priv_auto_alloc_size = sizeof(struct inno_hdmi_phy), |
---|
1106 | 1474 | }; |
---|
| 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 | +}; |
---|