1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun * Author: Algea Cao <algea.cao@rock-chips.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <boot_rkimg.h>
9*4882a593Smuzhiyun #include <clk.h>
10*4882a593Smuzhiyun #include <fdtdec.h>
11*4882a593Smuzhiyun #include <regmap.h>
12*4882a593Smuzhiyun #include <syscon.h>
13*4882a593Smuzhiyun #include <asm/arch-rockchip/clock.h>
14*4882a593Smuzhiyun #include <asm/io.h>
15*4882a593Smuzhiyun #include <asm-generic/gpio.h>
16*4882a593Smuzhiyun #include <dm/of_access.h>
17*4882a593Smuzhiyun #include <dm/device.h>
18*4882a593Smuzhiyun #include <linux/dw_hdmi.h>
19*4882a593Smuzhiyun #include <linux/hdmi.h>
20*4882a593Smuzhiyun #include <linux/media-bus-format.h>
21*4882a593Smuzhiyun #include "rockchip_display.h"
22*4882a593Smuzhiyun #include "rockchip_crtc.h"
23*4882a593Smuzhiyun #include "rockchip_connector.h"
24*4882a593Smuzhiyun #include "rockchip_phy.h"
25*4882a593Smuzhiyun #include "dw_hdmi_qp.h"
26*4882a593Smuzhiyun #include "rockchip_dw_hdmi_qp.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16)
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define RK3588_GRF_SOC_CON2 0x0308
31*4882a593Smuzhiyun #define RK3588_HDMI1_HPD_INT_MSK BIT(15)
32*4882a593Smuzhiyun #define RK3588_HDMI1_HPD_INT_CLR BIT(14)
33*4882a593Smuzhiyun #define RK3588_HDMI0_HPD_INT_MSK BIT(13)
34*4882a593Smuzhiyun #define RK3588_HDMI0_HPD_INT_CLR BIT(12)
35*4882a593Smuzhiyun #define RK3588_GRF_SOC_CON7 0x031c
36*4882a593Smuzhiyun #define RK3588_SET_HPD_PATH_MASK (0x3 << 12)
37*4882a593Smuzhiyun #define RK3588_GRF_SOC_STATUS1 0x0384
38*4882a593Smuzhiyun #define RK3588_HDMI0_LOW_MORETHAN100MS BIT(20)
39*4882a593Smuzhiyun #define RK3588_HDMI0_HPD_PORT_LEVEL BIT(19)
40*4882a593Smuzhiyun #define RK3588_HDMI0_IHPD_PORT BIT(18)
41*4882a593Smuzhiyun #define RK3588_HDMI0_OHPD_INT BIT(17)
42*4882a593Smuzhiyun #define RK3588_HDMI0_LEVEL_INT BIT(16)
43*4882a593Smuzhiyun #define RK3588_HDMI0_INTR_CHANGE_CNT (0x7 << 13)
44*4882a593Smuzhiyun #define RK3588_HDMI1_LOW_MORETHAN100MS BIT(28)
45*4882a593Smuzhiyun #define RK3588_HDMI1_HPD_PORT_LEVEL BIT(27)
46*4882a593Smuzhiyun #define RK3588_HDMI1_IHPD_PORT BIT(26)
47*4882a593Smuzhiyun #define RK3588_HDMI1_OHPD_INT BIT(25)
48*4882a593Smuzhiyun #define RK3588_HDMI1_LEVEL_INT BIT(24)
49*4882a593Smuzhiyun #define RK3588_HDMI1_INTR_CHANGE_CNT (0x7 << 21)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON3 0x000c
52*4882a593Smuzhiyun #define RK3588_COLOR_FORMAT_MASK 0xf
53*4882a593Smuzhiyun #define RK3588_YUV422 0x1
54*4882a593Smuzhiyun #define RK3588_YUV444 0x2
55*4882a593Smuzhiyun #define RK3588_YUV420 0x3
56*4882a593Smuzhiyun #define RK3588_COMPRESSED_DATA 0xb
57*4882a593Smuzhiyun #define RK3588_COLOR_DEPTH_MASK (0xf << 4)
58*4882a593Smuzhiyun #define RK3588_8BPC 0
59*4882a593Smuzhiyun #define RK3588_10BPC (0x6 << 4)
60*4882a593Smuzhiyun #define RK3588_CECIN_MASK BIT(8)
61*4882a593Smuzhiyun #define RK3588_SCLIN_MASK BIT(9)
62*4882a593Smuzhiyun #define RK3588_SDAIN_MASK BIT(10)
63*4882a593Smuzhiyun #define RK3588_MODE_MASK BIT(11)
64*4882a593Smuzhiyun #define RK3588_COMPRESS_MODE_MASK BIT(12)
65*4882a593Smuzhiyun #define RK3588_I2S_SEL_MASK BIT(13)
66*4882a593Smuzhiyun #define RK3588_SPDIF_SEL_MASK BIT(14)
67*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON4 0x0010
68*4882a593Smuzhiyun #define RK3588_HDMI21_MASK BIT(0)
69*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON9 0x0024
70*4882a593Smuzhiyun #define RK3588_HDMI0_GRANT_SEL BIT(10)
71*4882a593Smuzhiyun #define RK3588_HDMI0_GRANT_SW BIT(11)
72*4882a593Smuzhiyun #define RK3588_HDMI1_GRANT_SEL BIT(12)
73*4882a593Smuzhiyun #define RK3588_HDMI1_GRANT_SW BIT(13)
74*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON6 0x0018
75*4882a593Smuzhiyun #define RK3588_GRF_VO1_CON7 0x001c
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define PPS_TABLE_LEN 8
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun #define COLOR_DEPTH_10BIT BIT(31)
80*4882a593Smuzhiyun #define HDMI_FRL_MODE BIT(30)
81*4882a593Smuzhiyun #define HDMI_EARC_MODE BIT(29)
82*4882a593Smuzhiyun #define DATA_RATE_MASK 0xFFFFFFF
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun #define HDMI20_MAX_RATE 600000
85*4882a593Smuzhiyun #define HDMI_8K60_RATE 2376000
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun enum device_type {
88*4882a593Smuzhiyun RK3588_HDMI
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun struct pps_data {
92*4882a593Smuzhiyun u32 pic_width;
93*4882a593Smuzhiyun u32 pic_height;
94*4882a593Smuzhiyun u32 slice_width;
95*4882a593Smuzhiyun u32 slice_height;
96*4882a593Smuzhiyun bool convert_rgb;
97*4882a593Smuzhiyun u8 bpc;
98*4882a593Smuzhiyun u8 bpp;
99*4882a593Smuzhiyun u8 raw_pps[128];
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun enum hdmi_frl_rate_per_lane {
103*4882a593Smuzhiyun FRL_12G_PER_LANE = 12,
104*4882a593Smuzhiyun FRL_10G_PER_LANE = 10,
105*4882a593Smuzhiyun FRL_8G_PER_LANE = 8,
106*4882a593Smuzhiyun FRL_6G_PER_LANE = 6,
107*4882a593Smuzhiyun FRL_3G_PER_LANE = 3,
108*4882a593Smuzhiyun };
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun struct rockchip_hdmi {
111*4882a593Smuzhiyun struct rockchip_connector connector;
112*4882a593Smuzhiyun int id;
113*4882a593Smuzhiyun struct udevice *dev;
114*4882a593Smuzhiyun struct regmap *regmap;
115*4882a593Smuzhiyun struct regmap *vo1_regmap;
116*4882a593Smuzhiyun void *grf;
117*4882a593Smuzhiyun void *vo1_grf;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun unsigned long bus_format;
120*4882a593Smuzhiyun unsigned long output_bus_format;
121*4882a593Smuzhiyun unsigned long enc_out_encoding;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun u8 max_frl_rate_per_lane;
124*4882a593Smuzhiyun u8 max_lanes;
125*4882a593Smuzhiyun bool allm_en;
126*4882a593Smuzhiyun u32 bus_width;
127*4882a593Smuzhiyun struct drm_hdmi_dsc_cap dsc_cap;
128*4882a593Smuzhiyun struct dw_hdmi_link_config link_cfg;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun struct clk link_clk;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun struct gpio_desc enable_gpio;
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /*
136*4882a593Smuzhiyun * Selected Rate Control Related Parameter Recommended Values
137*4882a593Smuzhiyun * from DSC_v1.11 spec & C Model release: DSC_model_20161212
138*4882a593Smuzhiyun */
139*4882a593Smuzhiyun static struct pps_data pps_datas[PPS_TABLE_LEN] = {
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 8bpc 12bpp */
142*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 8, 192,
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0x8d, 0x30, 0xc0, 0x10, 0xe0,
145*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0,
146*4882a593Smuzhiyun 0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9,
147*4882a593Smuzhiyun 0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa,
148*4882a593Smuzhiyun 0x08, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00,
149*4882a593Smuzhiyun 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
150*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
151*4882a593Smuzhiyun 0x7d, 0x7e, 0x00, 0x82, 0x00, 0xc0, 0x09, 0x00,
152*4882a593Smuzhiyun 0x09, 0x7e, 0x19, 0xbc, 0x19, 0xba, 0x19, 0xf8,
153*4882a593Smuzhiyun 0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76,
154*4882a593Smuzhiyun 0x2a, 0x76, 0x2a, 0x74, 0x3a, 0xb4, 0x52, 0xf4,
155*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
160*4882a593Smuzhiyun },
161*4882a593Smuzhiyun },
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 8bpc 11bpp */
164*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 8, 176,
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0x8d, 0x30, 0xb0, 0x10, 0xe0,
167*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28,
168*4882a593Smuzhiyun 0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0,
169*4882a593Smuzhiyun 0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33,
170*4882a593Smuzhiyun 0x0f, 0x00, 0x10, 0xf4, 0x03, 0x0c, 0x20, 0x00,
171*4882a593Smuzhiyun 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
172*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
173*4882a593Smuzhiyun 0x7d, 0x7e, 0x00, 0x82, 0x01, 0x00, 0x09, 0x40,
174*4882a593Smuzhiyun 0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
175*4882a593Smuzhiyun 0x1a, 0x38, 0x1a, 0x38, 0x1a, 0x76, 0x2a, 0x76,
176*4882a593Smuzhiyun 0x2a, 0x76, 0x2a, 0xb4, 0x3a, 0xb4, 0x52, 0xf4,
177*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
182*4882a593Smuzhiyun },
183*4882a593Smuzhiyun },
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 8bpc 10bpp */
186*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 8, 160,
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0x8d, 0x30, 0xa0, 0x10, 0xe0,
189*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0,
190*4882a593Smuzhiyun 0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0,
191*4882a593Smuzhiyun 0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb,
192*4882a593Smuzhiyun 0x16, 0x00, 0x10, 0xec, 0x03, 0x0c, 0x20, 0x00,
193*4882a593Smuzhiyun 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
194*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
195*4882a593Smuzhiyun 0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40,
196*4882a593Smuzhiyun 0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
197*4882a593Smuzhiyun 0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6,
198*4882a593Smuzhiyun 0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x5b, 0x34,
199*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
204*4882a593Smuzhiyun },
205*4882a593Smuzhiyun },
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 8bpc 9bpp */
208*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 8, 144,
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0x8d, 0x30, 0x90, 0x10, 0xe0,
211*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38,
212*4882a593Smuzhiyun 0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7,
213*4882a593Smuzhiyun 0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa,
214*4882a593Smuzhiyun 0x17, 0x00, 0x10, 0xf1, 0x03, 0x0c, 0x20, 0x00,
215*4882a593Smuzhiyun 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
216*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
217*4882a593Smuzhiyun 0x7d, 0x7e, 0x00, 0xc2, 0x01, 0x00, 0x09, 0x40,
218*4882a593Smuzhiyun 0x09, 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8,
219*4882a593Smuzhiyun 0x1a, 0x38, 0x1a, 0x78, 0x1a, 0x76, 0x2a, 0xb6,
220*4882a593Smuzhiyun 0x2a, 0xb6, 0x2a, 0xf4, 0x3a, 0xf4, 0x63, 0x74,
221*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
226*4882a593Smuzhiyun },
227*4882a593Smuzhiyun },
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 10bpc 12bpp */
230*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 10, 192,
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0xad, 0x30, 0xc0, 0x10, 0xe0,
233*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0xa0,
234*4882a593Smuzhiyun 0x01, 0x55, 0x03, 0x90, 0x00, 0x0a, 0x05, 0xc9,
235*4882a593Smuzhiyun 0x00, 0xa0, 0x00, 0x0f, 0x01, 0x44, 0x01, 0xaa,
236*4882a593Smuzhiyun 0x08, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00,
237*4882a593Smuzhiyun 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
238*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
239*4882a593Smuzhiyun 0x7d, 0x7e, 0x01, 0x02, 0x11, 0x80, 0x22, 0x00,
240*4882a593Smuzhiyun 0x22, 0x7e, 0x32, 0xbc, 0x32, 0xba, 0x3a, 0xf8,
241*4882a593Smuzhiyun 0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76,
242*4882a593Smuzhiyun 0x4b, 0x76, 0x4b, 0x74, 0x5b, 0xb4, 0x73, 0xf4,
243*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
248*4882a593Smuzhiyun },
249*4882a593Smuzhiyun },
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 10bpc 11bpp */
252*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 10, 176,
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0xad, 0x30, 0xb0, 0x10, 0xe0,
255*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x05, 0x28,
256*4882a593Smuzhiyun 0x01, 0x74, 0x03, 0x40, 0x00, 0x0f, 0x06, 0xe0,
257*4882a593Smuzhiyun 0x00, 0x2d, 0x00, 0x0f, 0x01, 0x44, 0x01, 0x33,
258*4882a593Smuzhiyun 0x0f, 0x00, 0x10, 0xf4, 0x07, 0x10, 0x20, 0x00,
259*4882a593Smuzhiyun 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
260*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
261*4882a593Smuzhiyun 0x7d, 0x7e, 0x01, 0x42, 0x19, 0xc0, 0x2a, 0x40,
262*4882a593Smuzhiyun 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
263*4882a593Smuzhiyun 0x3b, 0x38, 0x3b, 0x38, 0x3b, 0x76, 0x4b, 0x76,
264*4882a593Smuzhiyun 0x4b, 0x76, 0x4b, 0xb4, 0x5b, 0xb4, 0x73, 0xf4,
265*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
270*4882a593Smuzhiyun },
271*4882a593Smuzhiyun },
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 10bpc 10bpp */
274*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 10, 160,
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0xad, 0x30, 0xa0, 0x10, 0xe0,
277*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0xb0,
278*4882a593Smuzhiyun 0x01, 0x9a, 0x02, 0xe0, 0x00, 0x19, 0x09, 0xb0,
279*4882a593Smuzhiyun 0x00, 0x12, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xbb,
280*4882a593Smuzhiyun 0x16, 0x00, 0x10, 0xec, 0x07, 0x10, 0x20, 0x00,
281*4882a593Smuzhiyun 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
282*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
283*4882a593Smuzhiyun 0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40,
284*4882a593Smuzhiyun 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
285*4882a593Smuzhiyun 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6,
286*4882a593Smuzhiyun 0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x7c, 0x34,
287*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
292*4882a593Smuzhiyun },
293*4882a593Smuzhiyun },
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun /* 7680x4320/960X96 rgb 10bpc 9bpp */
296*4882a593Smuzhiyun 7680, 4320, 960, 96, 1, 10, 144,
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 0x12, 0x00, 0x00, 0xad, 0x30, 0x90, 0x10, 0xe0,
299*4882a593Smuzhiyun 0x1e, 0x00, 0x00, 0x60, 0x03, 0xc0, 0x04, 0x38,
300*4882a593Smuzhiyun 0x01, 0xc7, 0x03, 0x16, 0x00, 0x1c, 0x08, 0xc7,
301*4882a593Smuzhiyun 0x00, 0x10, 0x00, 0x0f, 0x01, 0x44, 0x00, 0xaa,
302*4882a593Smuzhiyun 0x17, 0x00, 0x10, 0xf1, 0x07, 0x10, 0x20, 0x00,
303*4882a593Smuzhiyun 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c, 0x2a, 0x38,
304*4882a593Smuzhiyun 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b,
305*4882a593Smuzhiyun 0x7d, 0x7e, 0x01, 0xc2, 0x22, 0x00, 0x2a, 0x40,
306*4882a593Smuzhiyun 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
307*4882a593Smuzhiyun 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0x76, 0x4b, 0xb6,
308*4882a593Smuzhiyun 0x4b, 0xb6, 0x4b, 0xf4, 0x63, 0xf4, 0x84, 0x74,
309*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
314*4882a593Smuzhiyun },
315*4882a593Smuzhiyun },
316*4882a593Smuzhiyun };
317*4882a593Smuzhiyun
hdmi_bus_fmt_is_rgb(unsigned int bus_format)318*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun switch (bus_format) {
321*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB888_1X24:
322*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB101010_1X30:
323*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB121212_1X36:
324*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB161616_1X48:
325*4882a593Smuzhiyun return true;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun default:
328*4882a593Smuzhiyun return false;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
hdmi_bus_fmt_is_yuv444(unsigned int bus_format)332*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun switch (bus_format) {
335*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV8_1X24:
336*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV10_1X30:
337*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV12_1X36:
338*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV16_1X48:
339*4882a593Smuzhiyun return true;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun default:
342*4882a593Smuzhiyun return false;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
hdmi_bus_fmt_is_yuv422(unsigned int bus_format)346*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun switch (bus_format) {
349*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY8_1X16:
350*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY10_1X20:
351*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY12_1X24:
352*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV8_1X16:
353*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV10_1X20:
354*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV12_1X24:
355*4882a593Smuzhiyun return true;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun default:
358*4882a593Smuzhiyun return false;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
hdmi_bus_fmt_is_yuv420(unsigned int bus_format)362*4882a593Smuzhiyun static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun switch (bus_format) {
365*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
366*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
367*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
368*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
369*4882a593Smuzhiyun return true;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun default:
372*4882a593Smuzhiyun return false;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
hdmi_bus_fmt_color_depth(unsigned int bus_format)376*4882a593Smuzhiyun static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun switch (bus_format) {
379*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB888_1X24:
380*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV8_1X24:
381*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY8_1X16:
382*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV8_1X16:
383*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
384*4882a593Smuzhiyun return 8;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB101010_1X30:
387*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV10_1X30:
388*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY10_1X20:
389*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV10_1X20:
390*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
391*4882a593Smuzhiyun return 10;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB121212_1X36:
394*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV12_1X36:
395*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYVY12_1X24:
396*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV12_1X24:
397*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
398*4882a593Smuzhiyun return 12;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB161616_1X48:
401*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV16_1X48:
402*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
403*4882a593Smuzhiyun return 16;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun default:
406*4882a593Smuzhiyun return 0;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun static unsigned int
hdmi_get_tmdsclock(struct rockchip_hdmi * hdmi,unsigned long pixelclock)411*4882a593Smuzhiyun hdmi_get_tmdsclock(struct rockchip_hdmi *hdmi, unsigned long pixelclock)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun unsigned int tmdsclock = pixelclock;
414*4882a593Smuzhiyun unsigned int depth =
415*4882a593Smuzhiyun hdmi_bus_fmt_color_depth(hdmi->output_bus_format);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (!hdmi_bus_fmt_is_yuv422(hdmi->output_bus_format)) {
418*4882a593Smuzhiyun switch (depth) {
419*4882a593Smuzhiyun case 16:
420*4882a593Smuzhiyun tmdsclock = pixelclock * 2;
421*4882a593Smuzhiyun break;
422*4882a593Smuzhiyun case 12:
423*4882a593Smuzhiyun tmdsclock = pixelclock * 3 / 2;
424*4882a593Smuzhiyun break;
425*4882a593Smuzhiyun case 10:
426*4882a593Smuzhiyun tmdsclock = pixelclock * 5 / 4;
427*4882a593Smuzhiyun break;
428*4882a593Smuzhiyun default:
429*4882a593Smuzhiyun break;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun return tmdsclock;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
hdmi_select_link_config(struct rockchip_hdmi * hdmi,struct drm_display_mode * mode,unsigned int tmdsclk)436*4882a593Smuzhiyun static void hdmi_select_link_config(struct rockchip_hdmi *hdmi,
437*4882a593Smuzhiyun struct drm_display_mode *mode,
438*4882a593Smuzhiyun unsigned int tmdsclk)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun int max_lanes, max_rate_per_lane;
441*4882a593Smuzhiyun int max_dsc_lanes, max_dsc_rate_per_lane;
442*4882a593Smuzhiyun unsigned long max_frl_rate;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun max_lanes = hdmi->max_lanes;
445*4882a593Smuzhiyun max_rate_per_lane = hdmi->max_frl_rate_per_lane;
446*4882a593Smuzhiyun max_frl_rate = max_lanes * max_rate_per_lane * 1000000;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun hdmi->link_cfg.dsc_mode = false;
449*4882a593Smuzhiyun hdmi->link_cfg.frl_lanes = max_lanes;
450*4882a593Smuzhiyun hdmi->link_cfg.rate_per_lane = max_rate_per_lane;
451*4882a593Smuzhiyun hdmi->link_cfg.allm_en = hdmi->allm_en;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (!max_frl_rate ||
454*4882a593Smuzhiyun (tmdsclk < HDMI20_MAX_RATE && mode->clock < HDMI20_MAX_RATE)) {
455*4882a593Smuzhiyun printf("%s use tmds mode\n", __func__);
456*4882a593Smuzhiyun hdmi->link_cfg.frl_mode = false;
457*4882a593Smuzhiyun return;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun hdmi->link_cfg.frl_mode = true;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if (!hdmi->dsc_cap.v_1p2)
463*4882a593Smuzhiyun return;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun max_dsc_lanes = hdmi->dsc_cap.max_lanes;
466*4882a593Smuzhiyun max_dsc_rate_per_lane =
467*4882a593Smuzhiyun hdmi->dsc_cap.max_frl_rate_per_lane;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun if (mode->clock >= HDMI_8K60_RATE &&
470*4882a593Smuzhiyun !hdmi_bus_fmt_is_yuv420(hdmi->bus_format) &&
471*4882a593Smuzhiyun !hdmi_bus_fmt_is_yuv422(hdmi->bus_format)) {
472*4882a593Smuzhiyun hdmi->link_cfg.dsc_mode = true;
473*4882a593Smuzhiyun hdmi->link_cfg.frl_lanes = max_dsc_lanes;
474*4882a593Smuzhiyun hdmi->link_cfg.rate_per_lane = max_dsc_rate_per_lane;
475*4882a593Smuzhiyun } else {
476*4882a593Smuzhiyun hdmi->link_cfg.dsc_mode = false;
477*4882a593Smuzhiyun hdmi->link_cfg.frl_lanes = max_lanes;
478*4882a593Smuzhiyun hdmi->link_cfg.rate_per_lane = max_rate_per_lane;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /////////////////////////////////////////////////////////////////////////////////////
483*4882a593Smuzhiyun
hdmi_dsc_get_slice_height(int vactive)484*4882a593Smuzhiyun static int hdmi_dsc_get_slice_height(int vactive)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun int slice_height;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun /*
489*4882a593Smuzhiyun * Slice Height determination : HDMI2.1 Section 7.7.5.2
490*4882a593Smuzhiyun * Select smallest slice height >=96, that results in a valid PPS and
491*4882a593Smuzhiyun * requires minimum padding lines required for final slice.
492*4882a593Smuzhiyun *
493*4882a593Smuzhiyun * Assumption : Vactive is even.
494*4882a593Smuzhiyun */
495*4882a593Smuzhiyun for (slice_height = 96; slice_height <= vactive; slice_height += 2)
496*4882a593Smuzhiyun if (vactive % slice_height == 0)
497*4882a593Smuzhiyun return slice_height;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
hdmi_dsc_get_num_slices(struct rockchip_hdmi * hdmi,struct drm_display_mode * mode,int src_max_slices,int src_max_slice_width,int hdmi_max_slices,int hdmi_throughput)502*4882a593Smuzhiyun static int hdmi_dsc_get_num_slices(struct rockchip_hdmi *hdmi,
503*4882a593Smuzhiyun struct drm_display_mode *mode,
504*4882a593Smuzhiyun int src_max_slices, int src_max_slice_width,
505*4882a593Smuzhiyun int hdmi_max_slices, int hdmi_throughput)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun /* Pixel rates in KPixels/sec */
508*4882a593Smuzhiyun #define HDMI_DSC_PEAK_PIXEL_RATE 2720000
509*4882a593Smuzhiyun /*
510*4882a593Smuzhiyun * Rates at which the source and sink are required to process pixels in each
511*4882a593Smuzhiyun * slice, can be two levels: either at least 340000KHz or at least 40000KHz.
512*4882a593Smuzhiyun */
513*4882a593Smuzhiyun #define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000
514*4882a593Smuzhiyun #define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /* Spec limits the slice width to 2720 pixels */
517*4882a593Smuzhiyun #define MAX_HDMI_SLICE_WIDTH 2720
518*4882a593Smuzhiyun int kslice_adjust;
519*4882a593Smuzhiyun int adjusted_clk_khz;
520*4882a593Smuzhiyun int min_slices;
521*4882a593Smuzhiyun int target_slices;
522*4882a593Smuzhiyun int max_throughput; /* max clock freq. in khz per slice */
523*4882a593Smuzhiyun int max_slice_width;
524*4882a593Smuzhiyun int slice_width;
525*4882a593Smuzhiyun int pixel_clock = mode->clock;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (!hdmi_throughput)
528*4882a593Smuzhiyun return 0;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /*
531*4882a593Smuzhiyun * Slice Width determination : HDMI2.1 Section 7.7.5.1
532*4882a593Smuzhiyun * kslice_adjust factor for 4:2:0, and 4:2:2 formats is 0.5, where as
533*4882a593Smuzhiyun * for 4:4:4 is 1.0. Multiplying these factors by 10 and later
534*4882a593Smuzhiyun * dividing adjusted clock value by 10.
535*4882a593Smuzhiyun */
536*4882a593Smuzhiyun if (hdmi_bus_fmt_is_yuv444(hdmi->output_bus_format) ||
537*4882a593Smuzhiyun hdmi_bus_fmt_is_rgb(hdmi->output_bus_format))
538*4882a593Smuzhiyun kslice_adjust = 10;
539*4882a593Smuzhiyun else
540*4882a593Smuzhiyun kslice_adjust = 5;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun /*
543*4882a593Smuzhiyun * As per spec, the rate at which the source and the sink process
544*4882a593Smuzhiyun * the pixels per slice are at two levels: at least 340Mhz or 400Mhz.
545*4882a593Smuzhiyun * This depends upon the pixel clock rate and output formats
546*4882a593Smuzhiyun * (kslice adjust).
547*4882a593Smuzhiyun * If pixel clock * kslice adjust >= 2720MHz slices can be processed
548*4882a593Smuzhiyun * at max 340MHz, otherwise they can be processed at max 400MHz.
549*4882a593Smuzhiyun */
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun adjusted_clk_khz = DIV_ROUND_UP(kslice_adjust * pixel_clock, 10);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (adjusted_clk_khz <= HDMI_DSC_PEAK_PIXEL_RATE)
554*4882a593Smuzhiyun max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_0;
555*4882a593Smuzhiyun else
556*4882a593Smuzhiyun max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_1;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /*
559*4882a593Smuzhiyun * Taking into account the sink's capability for maximum
560*4882a593Smuzhiyun * clock per slice (in MHz) as read from HF-VSDB.
561*4882a593Smuzhiyun */
562*4882a593Smuzhiyun max_throughput = min(max_throughput, hdmi_throughput * 1000);
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun min_slices = DIV_ROUND_UP(adjusted_clk_khz, max_throughput);
565*4882a593Smuzhiyun max_slice_width = min(MAX_HDMI_SLICE_WIDTH, src_max_slice_width);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /*
568*4882a593Smuzhiyun * Keep on increasing the num of slices/line, starting from min_slices
569*4882a593Smuzhiyun * per line till we get such a number, for which the slice_width is
570*4882a593Smuzhiyun * just less than max_slice_width. The slices/line selected should be
571*4882a593Smuzhiyun * less than or equal to the max horizontal slices that the combination
572*4882a593Smuzhiyun * of PCON encoder and HDMI decoder can support.
573*4882a593Smuzhiyun */
574*4882a593Smuzhiyun do {
575*4882a593Smuzhiyun if (min_slices <= 1 && src_max_slices >= 1 && hdmi_max_slices >= 1)
576*4882a593Smuzhiyun target_slices = 1;
577*4882a593Smuzhiyun else if (min_slices <= 2 && src_max_slices >= 2 && hdmi_max_slices >= 2)
578*4882a593Smuzhiyun target_slices = 2;
579*4882a593Smuzhiyun else if (min_slices <= 4 && src_max_slices >= 4 && hdmi_max_slices >= 4)
580*4882a593Smuzhiyun target_slices = 4;
581*4882a593Smuzhiyun else if (min_slices <= 8 && src_max_slices >= 8 && hdmi_max_slices >= 8)
582*4882a593Smuzhiyun target_slices = 8;
583*4882a593Smuzhiyun else if (min_slices <= 12 && src_max_slices >= 12 && hdmi_max_slices >= 12)
584*4882a593Smuzhiyun target_slices = 12;
585*4882a593Smuzhiyun else if (min_slices <= 16 && src_max_slices >= 16 && hdmi_max_slices >= 16)
586*4882a593Smuzhiyun target_slices = 16;
587*4882a593Smuzhiyun else
588*4882a593Smuzhiyun return 0;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun slice_width = DIV_ROUND_UP(mode->hdisplay, target_slices);
591*4882a593Smuzhiyun if (slice_width > max_slice_width)
592*4882a593Smuzhiyun min_slices = target_slices + 1;
593*4882a593Smuzhiyun } while (slice_width > max_slice_width);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun return target_slices;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
hdmi_dsc_slices(struct rockchip_hdmi * hdmi,struct drm_display_mode * mode)598*4882a593Smuzhiyun static int hdmi_dsc_slices(struct rockchip_hdmi *hdmi,
599*4882a593Smuzhiyun struct drm_display_mode *mode)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun int hdmi_throughput = hdmi->dsc_cap.clk_per_slice;
602*4882a593Smuzhiyun int hdmi_max_slices = hdmi->dsc_cap.max_slices;
603*4882a593Smuzhiyun int rk_max_slices = 8;
604*4882a593Smuzhiyun int rk_max_slice_width = 2048;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun return hdmi_dsc_get_num_slices(hdmi, mode, rk_max_slices,
607*4882a593Smuzhiyun rk_max_slice_width,
608*4882a593Smuzhiyun hdmi_max_slices, hdmi_throughput);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun static int
hdmi_dsc_get_bpp(struct rockchip_hdmi * hdmi,int src_fractional_bpp,int slice_width,int num_slices,bool hdmi_all_bpp,int hdmi_max_chunk_bytes)612*4882a593Smuzhiyun hdmi_dsc_get_bpp(struct rockchip_hdmi *hdmi, int src_fractional_bpp,
613*4882a593Smuzhiyun int slice_width, int num_slices, bool hdmi_all_bpp,
614*4882a593Smuzhiyun int hdmi_max_chunk_bytes)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun int max_dsc_bpp, min_dsc_bpp;
617*4882a593Smuzhiyun int target_bytes;
618*4882a593Smuzhiyun bool bpp_found = false;
619*4882a593Smuzhiyun int bpp_decrement_x16;
620*4882a593Smuzhiyun int bpp_target;
621*4882a593Smuzhiyun int bpp_target_x16;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun /*
624*4882a593Smuzhiyun * Get min bpp and max bpp as per Table 7.23, in HDMI2.1 spec
625*4882a593Smuzhiyun * Start with the max bpp and keep on decrementing with
626*4882a593Smuzhiyun * fractional bpp, if supported by PCON DSC encoder
627*4882a593Smuzhiyun *
628*4882a593Smuzhiyun * for each bpp we check if no of bytes can be supported by HDMI sink
629*4882a593Smuzhiyun */
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /* only 9\10\12 bpp was tested */
632*4882a593Smuzhiyun min_dsc_bpp = 9;
633*4882a593Smuzhiyun max_dsc_bpp = 12;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun /*
636*4882a593Smuzhiyun * Taking into account if all dsc_all_bpp supported by HDMI2.1 sink
637*4882a593Smuzhiyun * Section 7.7.34 : Source shall not enable compressed Video
638*4882a593Smuzhiyun * Transport with bpp_target settings above 12 bpp unless
639*4882a593Smuzhiyun * DSC_all_bpp is set to 1.
640*4882a593Smuzhiyun */
641*4882a593Smuzhiyun if (!hdmi_all_bpp)
642*4882a593Smuzhiyun max_dsc_bpp = min(max_dsc_bpp, 12);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /*
645*4882a593Smuzhiyun * The Sink has a limit of compressed data in bytes for a scanline,
646*4882a593Smuzhiyun * as described in max_chunk_bytes field in HFVSDB block of edid.
647*4882a593Smuzhiyun * The no. of bytes depend on the target bits per pixel that the
648*4882a593Smuzhiyun * source configures. So we start with the max_bpp and calculate
649*4882a593Smuzhiyun * the target_chunk_bytes. We keep on decrementing the target_bpp,
650*4882a593Smuzhiyun * till we get the target_chunk_bytes just less than what the sink's
651*4882a593Smuzhiyun * max_chunk_bytes, or else till we reach the min_dsc_bpp.
652*4882a593Smuzhiyun *
653*4882a593Smuzhiyun * The decrement is according to the fractional support from PCON DSC
654*4882a593Smuzhiyun * encoder. For fractional BPP we use bpp_target as a multiple of 16.
655*4882a593Smuzhiyun *
656*4882a593Smuzhiyun * bpp_target_x16 = bpp_target * 16
657*4882a593Smuzhiyun * So we need to decrement by {1, 2, 4, 8, 16} for fractional bpps
658*4882a593Smuzhiyun * {1/16, 1/8, 1/4, 1/2, 1} respectively.
659*4882a593Smuzhiyun */
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun bpp_target = max_dsc_bpp;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun /* src does not support fractional bpp implies decrement by 16 for bppx16 */
664*4882a593Smuzhiyun if (!src_fractional_bpp)
665*4882a593Smuzhiyun src_fractional_bpp = 1;
666*4882a593Smuzhiyun bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp);
667*4882a593Smuzhiyun bpp_target_x16 = bpp_target * 16;
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun while (bpp_target_x16 > (min_dsc_bpp * 16)) {
670*4882a593Smuzhiyun int bpp;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun bpp = DIV_ROUND_UP(bpp_target_x16, 16);
673*4882a593Smuzhiyun target_bytes = DIV_ROUND_UP((num_slices * slice_width * bpp), 8);
674*4882a593Smuzhiyun if (target_bytes <= hdmi_max_chunk_bytes) {
675*4882a593Smuzhiyun bpp_found = true;
676*4882a593Smuzhiyun break;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun bpp_target_x16 -= bpp_decrement_x16;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun if (bpp_found)
681*4882a593Smuzhiyun return bpp_target_x16;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun static int
dw_hdmi_dsc_bpp(struct rockchip_hdmi * hdmi,int num_slices,int slice_width)687*4882a593Smuzhiyun dw_hdmi_dsc_bpp(struct rockchip_hdmi *hdmi,
688*4882a593Smuzhiyun int num_slices, int slice_width)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun bool hdmi_all_bpp = hdmi->dsc_cap.all_bpp;
691*4882a593Smuzhiyun int fractional_bpp = 0;
692*4882a593Smuzhiyun int hdmi_max_chunk_bytes = hdmi->dsc_cap.total_chunk_kbytes * 1024;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun return hdmi_dsc_get_bpp(hdmi, fractional_bpp, slice_width,
695*4882a593Smuzhiyun num_slices, hdmi_all_bpp,
696*4882a593Smuzhiyun hdmi_max_chunk_bytes);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
dw_hdmi_qp_set_link_cfg(struct rockchip_hdmi * hdmi,u16 pic_width,u16 pic_height,u16 slice_width,u16 slice_height,u16 bits_per_pixel,u8 bits_per_component)699*4882a593Smuzhiyun static int dw_hdmi_qp_set_link_cfg(struct rockchip_hdmi *hdmi,
700*4882a593Smuzhiyun u16 pic_width, u16 pic_height,
701*4882a593Smuzhiyun u16 slice_width, u16 slice_height,
702*4882a593Smuzhiyun u16 bits_per_pixel, u8 bits_per_component)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun int i;
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun for (i = 0; i < PPS_TABLE_LEN; i++)
707*4882a593Smuzhiyun if (pic_width == pps_datas[i].pic_width &&
708*4882a593Smuzhiyun pic_height == pps_datas[i].pic_height &&
709*4882a593Smuzhiyun slice_width == pps_datas[i].slice_width &&
710*4882a593Smuzhiyun slice_height == pps_datas[i].slice_height &&
711*4882a593Smuzhiyun bits_per_component == pps_datas[i].bpc &&
712*4882a593Smuzhiyun bits_per_pixel == pps_datas[i].bpp &&
713*4882a593Smuzhiyun hdmi_bus_fmt_is_rgb(hdmi->output_bus_format) == pps_datas[i].convert_rgb)
714*4882a593Smuzhiyun break;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun if (i == PPS_TABLE_LEN) {
717*4882a593Smuzhiyun dev_err(hdmi->dev, "can't find pps cfg!\n");
718*4882a593Smuzhiyun return -EINVAL;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun memcpy(hdmi->link_cfg.pps_payload, pps_datas[i].raw_pps, 128);
722*4882a593Smuzhiyun hdmi->link_cfg.hcactive = DIV_ROUND_UP(slice_width * (bits_per_pixel / 16), 8) *
723*4882a593Smuzhiyun (pic_width / slice_width);
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun return 0;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
dw_hdmi_qp_dsc_configure(struct rockchip_hdmi * hdmi,struct drm_display_mode * mode)728*4882a593Smuzhiyun static void dw_hdmi_qp_dsc_configure(struct rockchip_hdmi *hdmi,
729*4882a593Smuzhiyun struct drm_display_mode *mode)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun int ret;
732*4882a593Smuzhiyun int slice_height;
733*4882a593Smuzhiyun int slice_width;
734*4882a593Smuzhiyun int bits_per_pixel;
735*4882a593Smuzhiyun int slice_count;
736*4882a593Smuzhiyun bool hdmi_is_dsc_1_2;
737*4882a593Smuzhiyun unsigned int depth = hdmi_bus_fmt_color_depth(hdmi->output_bus_format);
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun hdmi_is_dsc_1_2 = hdmi->dsc_cap.v_1p2;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (!hdmi_is_dsc_1_2)
742*4882a593Smuzhiyun return;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun slice_height = hdmi_dsc_get_slice_height(mode->vdisplay);
745*4882a593Smuzhiyun if (!slice_height)
746*4882a593Smuzhiyun return;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun slice_count = hdmi_dsc_slices(hdmi, mode);
749*4882a593Smuzhiyun if (!slice_count)
750*4882a593Smuzhiyun return;
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun slice_width = DIV_ROUND_UP(mode->hdisplay, slice_count);
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun bits_per_pixel = dw_hdmi_dsc_bpp(hdmi, slice_count, slice_width);
755*4882a593Smuzhiyun if (!bits_per_pixel)
756*4882a593Smuzhiyun return;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun ret = dw_hdmi_qp_set_link_cfg(hdmi, mode->hdisplay,
759*4882a593Smuzhiyun mode->vdisplay, slice_width,
760*4882a593Smuzhiyun slice_height, bits_per_pixel, depth);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun if (ret) {
763*4882a593Smuzhiyun dev_err(hdmi->dev, "set vdsc cfg failed\n");
764*4882a593Smuzhiyun return;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun printf("dsc_enable\n");
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun
drm_rk_select_color(struct hdmi_edid_data * edid_data,struct base_screen_info * screen_info,enum dw_hdmi_devtype dev_type,bool output_bus_format_rgb)769*4882a593Smuzhiyun static unsigned int drm_rk_select_color(struct hdmi_edid_data *edid_data,
770*4882a593Smuzhiyun struct base_screen_info *screen_info,
771*4882a593Smuzhiyun enum dw_hdmi_devtype dev_type,
772*4882a593Smuzhiyun bool output_bus_format_rgb)
773*4882a593Smuzhiyun {
774*4882a593Smuzhiyun struct drm_display_info *info = &edid_data->display_info;
775*4882a593Smuzhiyun struct drm_display_mode *mode = edid_data->preferred_mode;
776*4882a593Smuzhiyun struct drm_hdmi_info *hdmi_info = &edid_data->display_info.hdmi;
777*4882a593Smuzhiyun int max_tmds_clock = info->max_tmds_clock;
778*4882a593Smuzhiyun bool support_dc = false;
779*4882a593Smuzhiyun bool mode_420 = drm_mode_is_420(info, mode);
780*4882a593Smuzhiyun unsigned int color_depth = 8;
781*4882a593Smuzhiyun unsigned int base_color = DRM_HDMI_OUTPUT_YCBCR444;
782*4882a593Smuzhiyun unsigned int color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
783*4882a593Smuzhiyun unsigned long tmdsclock, pixclock = mode->clock;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun if (screen_info)
786*4882a593Smuzhiyun base_color = screen_info->format;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun switch (base_color) {
789*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR_HQ:
790*4882a593Smuzhiyun if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
791*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR444;
792*4882a593Smuzhiyun else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
793*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR422;
794*4882a593Smuzhiyun else if (mode_420 && pixclock >= 340000)
795*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR420;
796*4882a593Smuzhiyun break;
797*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR_LQ:
798*4882a593Smuzhiyun if (mode_420 && pixclock >= 340000)
799*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR420;
800*4882a593Smuzhiyun else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
801*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR422;
802*4882a593Smuzhiyun else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
803*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR444;
804*4882a593Smuzhiyun break;
805*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR420:
806*4882a593Smuzhiyun if (mode_420 && pixclock >= 340000)
807*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR420;
808*4882a593Smuzhiyun break;
809*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR422:
810*4882a593Smuzhiyun if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
811*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR422;
812*4882a593Smuzhiyun break;
813*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR444:
814*4882a593Smuzhiyun if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
815*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR444;
816*4882a593Smuzhiyun break;
817*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_DEFAULT_RGB:
818*4882a593Smuzhiyun default:
819*4882a593Smuzhiyun break;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun if (output_bus_format_rgb)
823*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun if (color_format == DRM_HDMI_OUTPUT_DEFAULT_RGB &&
826*4882a593Smuzhiyun info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)
827*4882a593Smuzhiyun support_dc = true;
828*4882a593Smuzhiyun if (color_format == DRM_HDMI_OUTPUT_YCBCR444 &&
829*4882a593Smuzhiyun (info->edid_hdmi_dc_modes &
830*4882a593Smuzhiyun (DRM_EDID_HDMI_DC_Y444 | DRM_EDID_HDMI_DC_30)))
831*4882a593Smuzhiyun support_dc = true;
832*4882a593Smuzhiyun if (color_format == DRM_HDMI_OUTPUT_YCBCR422)
833*4882a593Smuzhiyun support_dc = true;
834*4882a593Smuzhiyun if (color_format == DRM_HDMI_OUTPUT_YCBCR420 &&
835*4882a593Smuzhiyun info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
836*4882a593Smuzhiyun support_dc = true;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun if (mode->flags & DRM_MODE_FLAG_DBLCLK)
839*4882a593Smuzhiyun pixclock *= 2;
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun if (screen_info && screen_info->depth == 10)
842*4882a593Smuzhiyun color_depth = screen_info->depth;
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun if (mode->clock >= 600000)
845*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR420;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun if (color_format == DRM_HDMI_OUTPUT_YCBCR422 || color_depth == 8)
848*4882a593Smuzhiyun tmdsclock = pixclock;
849*4882a593Smuzhiyun else
850*4882a593Smuzhiyun tmdsclock = pixclock * color_depth / 8;
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun if (color_format == DRM_HDMI_OUTPUT_YCBCR420)
853*4882a593Smuzhiyun tmdsclock /= 2;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun if (!max_tmds_clock)
856*4882a593Smuzhiyun max_tmds_clock = 340000;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun if (hdmi_info->max_frl_rate_per_lane && mode->clock > 600000)
859*4882a593Smuzhiyun max_tmds_clock =
860*4882a593Smuzhiyun hdmi_info->max_lanes * hdmi_info->max_frl_rate_per_lane *
861*4882a593Smuzhiyun 1000000;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun if (tmdsclock > max_tmds_clock) {
864*4882a593Smuzhiyun if (max_tmds_clock >= 594000) {
865*4882a593Smuzhiyun color_depth = 8;
866*4882a593Smuzhiyun } else if (max_tmds_clock > 340000) {
867*4882a593Smuzhiyun if (drm_mode_is_420(info, mode) || tmdsclock >= 594000)
868*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR420;
869*4882a593Smuzhiyun } else {
870*4882a593Smuzhiyun color_depth = 8;
871*4882a593Smuzhiyun if (drm_mode_is_420(info, mode) || tmdsclock >= 594000)
872*4882a593Smuzhiyun color_format = DRM_HDMI_OUTPUT_YCBCR420;
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun printf("color_format:%x\n", color_format);
877*4882a593Smuzhiyun if (color_depth > 8 && support_dc) {
878*4882a593Smuzhiyun switch (color_format) {
879*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR444:
880*4882a593Smuzhiyun return MEDIA_BUS_FMT_YUV10_1X30;
881*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR422:
882*4882a593Smuzhiyun return MEDIA_BUS_FMT_YUYV10_1X20;
883*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR420:
884*4882a593Smuzhiyun return MEDIA_BUS_FMT_UYYVYY10_0_5X30;
885*4882a593Smuzhiyun default:
886*4882a593Smuzhiyun return MEDIA_BUS_FMT_RGB101010_1X30;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun } else {
889*4882a593Smuzhiyun switch (color_format) {
890*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR444:
891*4882a593Smuzhiyun return MEDIA_BUS_FMT_YUV8_1X24;
892*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR422:
893*4882a593Smuzhiyun return MEDIA_BUS_FMT_YUYV8_1X16;
894*4882a593Smuzhiyun case DRM_HDMI_OUTPUT_YCBCR420:
895*4882a593Smuzhiyun return MEDIA_BUS_FMT_UYYVYY8_0_5X24;
896*4882a593Smuzhiyun default:
897*4882a593Smuzhiyun return MEDIA_BUS_FMT_RGB888_1X24;
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun #define SUPPORT_HDMI_ALLM BIT(1)
903*4882a593Smuzhiyun
dw_hdmi_qp_selete_output(struct hdmi_edid_data * edid_data,struct rockchip_connector * conn,unsigned int * bus_format,struct overscan * overscan,enum dw_hdmi_devtype dev_type,bool output_bus_format_rgb,void * data,struct display_state * state)904*4882a593Smuzhiyun void dw_hdmi_qp_selete_output(struct hdmi_edid_data *edid_data,
905*4882a593Smuzhiyun struct rockchip_connector *conn,
906*4882a593Smuzhiyun unsigned int *bus_format,
907*4882a593Smuzhiyun struct overscan *overscan,
908*4882a593Smuzhiyun enum dw_hdmi_devtype dev_type,
909*4882a593Smuzhiyun bool output_bus_format_rgb,
910*4882a593Smuzhiyun void *data, struct display_state *state)
911*4882a593Smuzhiyun {
912*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
913*4882a593Smuzhiyun struct drm_hdmi_info *hdmi_info = &edid_data->display_info.hdmi;
914*4882a593Smuzhiyun int ret, i, screen_size;
915*4882a593Smuzhiyun struct base_disp_info base_parameter;
916*4882a593Smuzhiyun struct base2_disp_info *base2_parameter = state->conn_state.disp_info;
917*4882a593Smuzhiyun const struct base_overscan *scan;
918*4882a593Smuzhiyun struct base_screen_info *screen_info = NULL;
919*4882a593Smuzhiyun struct base2_screen_info *screen_info2 = NULL;
920*4882a593Smuzhiyun int max_scan = 100;
921*4882a593Smuzhiyun int min_scan = 51;
922*4882a593Smuzhiyun int offset = 0;
923*4882a593Smuzhiyun int color_depth;
924*4882a593Smuzhiyun unsigned int tmdsclk;
925*4882a593Smuzhiyun unsigned int pixel_clk;
926*4882a593Smuzhiyun bool found = false;
927*4882a593Smuzhiyun struct blk_desc *dev_desc;
928*4882a593Smuzhiyun disk_partition_t part_info;
929*4882a593Smuzhiyun char baseparameter_buf[8 * RK_BLK_SIZE] __aligned(ARCH_DMA_MINALIGN);
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun overscan->left_margin = max_scan;
932*4882a593Smuzhiyun overscan->right_margin = max_scan;
933*4882a593Smuzhiyun overscan->top_margin = max_scan;
934*4882a593Smuzhiyun overscan->bottom_margin = max_scan;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun hdmi->max_frl_rate_per_lane = hdmi_info->max_frl_rate_per_lane;
937*4882a593Smuzhiyun hdmi->max_lanes = hdmi_info->max_lanes;
938*4882a593Smuzhiyun memcpy(&hdmi->dsc_cap, &hdmi_info->dsc_cap, sizeof(struct drm_hdmi_dsc_cap));
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun if (output_bus_format_rgb)
941*4882a593Smuzhiyun *bus_format = MEDIA_BUS_FMT_RGB888_1X24;
942*4882a593Smuzhiyun else
943*4882a593Smuzhiyun *bus_format = MEDIA_BUS_FMT_YUV8_1X24;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun if (!base2_parameter) {
946*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
947*4882a593Smuzhiyun if (!dev_desc) {
948*4882a593Smuzhiyun printf("%s: Could not find device\n", __func__);
949*4882a593Smuzhiyun goto null_basep;
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun ret = part_get_info_by_name(dev_desc, "baseparameter",
953*4882a593Smuzhiyun &part_info);
954*4882a593Smuzhiyun if (ret < 0) {
955*4882a593Smuzhiyun printf("Could not find baseparameter partition\n");
956*4882a593Smuzhiyun goto null_basep;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun read_aux:
960*4882a593Smuzhiyun ret = blk_dread(dev_desc, part_info.start + offset, 1,
961*4882a593Smuzhiyun (void *)baseparameter_buf);
962*4882a593Smuzhiyun if (ret < 0) {
963*4882a593Smuzhiyun printf("read baseparameter failed\n");
964*4882a593Smuzhiyun goto null_basep;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun memcpy(&base_parameter, baseparameter_buf,
968*4882a593Smuzhiyun sizeof(base_parameter));
969*4882a593Smuzhiyun scan = &base_parameter.scan;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun screen_size = sizeof(base_parameter.screen_list) /
972*4882a593Smuzhiyun sizeof(base_parameter.screen_list[0]);
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun for (i = 0; i < screen_size; i++) {
975*4882a593Smuzhiyun if (base_parameter.screen_list[i].type ==
976*4882a593Smuzhiyun DRM_MODE_CONNECTOR_HDMIA) {
977*4882a593Smuzhiyun found = true;
978*4882a593Smuzhiyun screen_info = &base_parameter.screen_list[i];
979*4882a593Smuzhiyun break;
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun if (!found && !offset) {
984*4882a593Smuzhiyun printf("hdmi info isn't saved in main block\n");
985*4882a593Smuzhiyun offset += 16;
986*4882a593Smuzhiyun goto read_aux;
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun } else {
989*4882a593Smuzhiyun bool allm_en = false;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun scan = &base2_parameter->overscan_info;
992*4882a593Smuzhiyun screen_size = sizeof(base2_parameter->screen_info) /
993*4882a593Smuzhiyun sizeof(base2_parameter->screen_info[0]);
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun for (i = 0; i < screen_size; i++) {
996*4882a593Smuzhiyun if (base2_parameter->screen_info[i].type ==
997*4882a593Smuzhiyun DRM_MODE_CONNECTOR_HDMIA) {
998*4882a593Smuzhiyun screen_info2 =
999*4882a593Smuzhiyun &base2_parameter->screen_info[i];
1000*4882a593Smuzhiyun break;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun screen_info = malloc(sizeof(*screen_info));
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun screen_info->type = screen_info2->type;
1006*4882a593Smuzhiyun screen_info->mode = screen_info2->resolution;
1007*4882a593Smuzhiyun screen_info->format = screen_info2->format;
1008*4882a593Smuzhiyun screen_info->depth = screen_info2->depthc;
1009*4882a593Smuzhiyun screen_info->feature = screen_info2->feature;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun /* check if allm is enabled */
1012*4882a593Smuzhiyun allm_en = base2_parameter->reserved[0] & BIT(0);
1013*4882a593Smuzhiyun if (allm_en && (hdmi_info->add_func & SUPPORT_HDMI_ALLM))
1014*4882a593Smuzhiyun hdmi->allm_en = true;
1015*4882a593Smuzhiyun else
1016*4882a593Smuzhiyun hdmi->allm_en = false;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun if (scan->leftscale < min_scan && scan->leftscale > 0)
1020*4882a593Smuzhiyun overscan->left_margin = min_scan;
1021*4882a593Smuzhiyun else if (scan->leftscale < max_scan && scan->leftscale > 0)
1022*4882a593Smuzhiyun overscan->left_margin = scan->leftscale;
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun if (scan->rightscale < min_scan && scan->rightscale > 0)
1025*4882a593Smuzhiyun overscan->right_margin = min_scan;
1026*4882a593Smuzhiyun else if (scan->rightscale < max_scan && scan->rightscale > 0)
1027*4882a593Smuzhiyun overscan->right_margin = scan->rightscale;
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun if (scan->topscale < min_scan && scan->topscale > 0)
1030*4882a593Smuzhiyun overscan->top_margin = min_scan;
1031*4882a593Smuzhiyun else if (scan->topscale < max_scan && scan->topscale > 0)
1032*4882a593Smuzhiyun overscan->top_margin = scan->topscale;
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun if (scan->bottomscale < min_scan && scan->bottomscale > 0)
1035*4882a593Smuzhiyun overscan->bottom_margin = min_scan;
1036*4882a593Smuzhiyun else if (scan->bottomscale < max_scan && scan->bottomscale > 0)
1037*4882a593Smuzhiyun overscan->bottom_margin = scan->bottomscale;
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun null_basep:
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun if (screen_info)
1042*4882a593Smuzhiyun printf("base_parameter.mode:%dx%d\n",
1043*4882a593Smuzhiyun screen_info->mode.hdisplay,
1044*4882a593Smuzhiyun screen_info->mode.vdisplay);
1045*4882a593Smuzhiyun drm_rk_select_mode(edid_data, screen_info);
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun *bus_format = drm_rk_select_color(edid_data, screen_info,
1048*4882a593Smuzhiyun dev_type, output_bus_format_rgb);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun if (state->force_output) {
1051*4882a593Smuzhiyun memcpy(edid_data->preferred_mode, &state->force_mode,
1052*4882a593Smuzhiyun sizeof(struct drm_display_mode));
1053*4882a593Smuzhiyun if (state->force_bus_format)
1054*4882a593Smuzhiyun *bus_format = state->force_bus_format;
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun hdmi->bus_format = *bus_format;
1058*4882a593Smuzhiyun color_depth = hdmi_bus_fmt_color_depth(*bus_format);
1059*4882a593Smuzhiyun pixel_clk = edid_data->preferred_mode->clock;
1060*4882a593Smuzhiyun tmdsclk = hdmi_get_tmdsclock(hdmi, pixel_clk);
1061*4882a593Smuzhiyun if (hdmi_bus_fmt_is_yuv420(hdmi->output_bus_format))
1062*4882a593Smuzhiyun tmdsclk /= 2;
1063*4882a593Smuzhiyun hdmi_select_link_config(hdmi, edid_data->preferred_mode, tmdsclk);
1064*4882a593Smuzhiyun dw_hdmi_qp_dsc_configure(hdmi, edid_data->preferred_mode);
1065*4882a593Smuzhiyun if (hdmi->link_cfg.frl_mode) {
1066*4882a593Smuzhiyun dm_gpio_set_value(&hdmi->enable_gpio, 0);
1067*4882a593Smuzhiyun /* in the current version, support max 40G frl */
1068*4882a593Smuzhiyun if (hdmi->link_cfg.rate_per_lane >= 10) {
1069*4882a593Smuzhiyun hdmi->link_cfg.frl_lanes = 4;
1070*4882a593Smuzhiyun hdmi->link_cfg.rate_per_lane = 10;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun hdmi->bus_width = hdmi->link_cfg.frl_lanes *
1073*4882a593Smuzhiyun hdmi->link_cfg.rate_per_lane * 1000000;
1074*4882a593Smuzhiyun /* 10 bit color depth and frl mode */
1075*4882a593Smuzhiyun if (color_depth == 10)
1076*4882a593Smuzhiyun hdmi->bus_width |=
1077*4882a593Smuzhiyun COLOR_DEPTH_10BIT | HDMI_FRL_MODE;
1078*4882a593Smuzhiyun else
1079*4882a593Smuzhiyun hdmi->bus_width |= HDMI_FRL_MODE;
1080*4882a593Smuzhiyun } else {
1081*4882a593Smuzhiyun dm_gpio_set_value(&hdmi->enable_gpio, 1);
1082*4882a593Smuzhiyun hdmi->bus_width =
1083*4882a593Smuzhiyun hdmi_get_tmdsclock(hdmi, pixel_clk * 10);
1084*4882a593Smuzhiyun if (hdmi_bus_fmt_is_yuv420(*bus_format))
1085*4882a593Smuzhiyun hdmi->bus_width /= 2;
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun if (color_depth == 10 && !hdmi_bus_fmt_is_yuv422(*bus_format))
1088*4882a593Smuzhiyun hdmi->bus_width |= COLOR_DEPTH_10BIT;
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun rockchip_phy_set_bus_width(conn->phy, hdmi->bus_width);
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun
rk3588_set_link_mode(struct rockchip_hdmi * hdmi)1094*4882a593Smuzhiyun static void rk3588_set_link_mode(struct rockchip_hdmi *hdmi)
1095*4882a593Smuzhiyun {
1096*4882a593Smuzhiyun int val;
1097*4882a593Smuzhiyun bool is_hdmi0;
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun if (!hdmi->id)
1100*4882a593Smuzhiyun is_hdmi0 = true;
1101*4882a593Smuzhiyun else
1102*4882a593Smuzhiyun is_hdmi0 = false;
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun if (!hdmi->link_cfg.frl_mode) {
1105*4882a593Smuzhiyun val = HIWORD_UPDATE(0, RK3588_HDMI21_MASK);
1106*4882a593Smuzhiyun if (is_hdmi0)
1107*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON4);
1108*4882a593Smuzhiyun else
1109*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON7);
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
1112*4882a593Smuzhiyun if (is_hdmi0)
1113*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON3);
1114*4882a593Smuzhiyun else
1115*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON6);
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun return;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_HDMI21_MASK, RK3588_HDMI21_MASK);
1121*4882a593Smuzhiyun if (is_hdmi0)
1122*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON4);
1123*4882a593Smuzhiyun else
1124*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON7);
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun if (hdmi->link_cfg.dsc_mode) {
1127*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_COMPRESS_MODE_MASK | RK3588_COMPRESSED_DATA,
1128*4882a593Smuzhiyun RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
1129*4882a593Smuzhiyun if (is_hdmi0)
1130*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON3);
1131*4882a593Smuzhiyun else
1132*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON6);
1133*4882a593Smuzhiyun } else {
1134*4882a593Smuzhiyun val = HIWORD_UPDATE(0, RK3588_COMPRESS_MODE_MASK | RK3588_COLOR_FORMAT_MASK);
1135*4882a593Smuzhiyun if (is_hdmi0)
1136*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON3);
1137*4882a593Smuzhiyun else
1138*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON6);
1139*4882a593Smuzhiyun }
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun
rk3588_set_color_format(struct rockchip_hdmi * hdmi,u64 bus_format,u32 depth)1142*4882a593Smuzhiyun static void rk3588_set_color_format(struct rockchip_hdmi *hdmi, u64 bus_format,
1143*4882a593Smuzhiyun u32 depth)
1144*4882a593Smuzhiyun {
1145*4882a593Smuzhiyun u32 val = 0;
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun switch (bus_format) {
1148*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB888_1X24:
1149*4882a593Smuzhiyun case MEDIA_BUS_FMT_RGB101010_1X30:
1150*4882a593Smuzhiyun val = HIWORD_UPDATE(0, RK3588_COLOR_FORMAT_MASK);
1151*4882a593Smuzhiyun break;
1152*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
1153*4882a593Smuzhiyun case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
1154*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_YUV420, RK3588_COLOR_FORMAT_MASK);
1155*4882a593Smuzhiyun break;
1156*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV8_1X24:
1157*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUV10_1X30:
1158*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_YUV444, RK3588_COLOR_FORMAT_MASK);
1159*4882a593Smuzhiyun break;
1160*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV10_1X20:
1161*4882a593Smuzhiyun case MEDIA_BUS_FMT_YUYV8_1X16:
1162*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_YUV422, RK3588_COLOR_FORMAT_MASK);
1163*4882a593Smuzhiyun break;
1164*4882a593Smuzhiyun default:
1165*4882a593Smuzhiyun dev_err(hdmi->dev, "can't set correct color format\n");
1166*4882a593Smuzhiyun return;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun if (hdmi->link_cfg.dsc_mode)
1170*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_COMPRESSED_DATA, RK3588_COLOR_FORMAT_MASK);
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun if (depth == 8 || bus_format == MEDIA_BUS_FMT_YUYV10_1X20)
1173*4882a593Smuzhiyun val |= HIWORD_UPDATE(RK3588_8BPC, RK3588_COLOR_DEPTH_MASK);
1174*4882a593Smuzhiyun else
1175*4882a593Smuzhiyun val |= HIWORD_UPDATE(RK3588_10BPC, RK3588_COLOR_DEPTH_MASK);
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun if (!hdmi->id)
1178*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON3);
1179*4882a593Smuzhiyun else
1180*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON6);
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun
rk3588_set_grf_cfg(void * data)1183*4882a593Smuzhiyun void rk3588_set_grf_cfg(void *data)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1186*4882a593Smuzhiyun int color_depth;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun rk3588_set_link_mode(hdmi);
1189*4882a593Smuzhiyun color_depth = hdmi_bus_fmt_color_depth(hdmi->bus_format);
1190*4882a593Smuzhiyun rk3588_set_color_format(hdmi, hdmi->bus_format, color_depth);
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun
dw_hdmi_qp_set_iomux(void * data)1193*4882a593Smuzhiyun void dw_hdmi_qp_set_iomux(void *data)
1194*4882a593Smuzhiyun {
1195*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1196*4882a593Smuzhiyun u32 val;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun if (!hdmi->id) {
1199*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
1200*4882a593Smuzhiyun HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
1201*4882a593Smuzhiyun HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
1202*4882a593Smuzhiyun HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
1203*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON3);
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
1206*4882a593Smuzhiyun RK3588_SET_HPD_PATH_MASK);
1207*4882a593Smuzhiyun writel(val, hdmi->grf + RK3588_GRF_SOC_CON7);
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL,
1210*4882a593Smuzhiyun RK3588_HDMI0_GRANT_SEL);
1211*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON9);
1212*4882a593Smuzhiyun } else {
1213*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) |
1214*4882a593Smuzhiyun HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) |
1215*4882a593Smuzhiyun HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) |
1216*4882a593Smuzhiyun HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK);
1217*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON6);
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK,
1220*4882a593Smuzhiyun RK3588_SET_HPD_PATH_MASK);
1221*4882a593Smuzhiyun writel(val, hdmi->grf + RK3588_GRF_SOC_CON7);
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL,
1224*4882a593Smuzhiyun RK3588_HDMI1_GRANT_SEL);
1225*4882a593Smuzhiyun writel(val, hdmi->vo1_grf + RK3588_GRF_VO1_CON9);
1226*4882a593Smuzhiyun }
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun
dw_hdmi_rockchip_get_link_cfg(void * data)1229*4882a593Smuzhiyun struct dw_hdmi_link_config *dw_hdmi_rockchip_get_link_cfg(void *data)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun return &hdmi->link_cfg;
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun
dw_hdmi_qp_rockchip_phy_disable(struct rockchip_connector * conn,void * data,void * state)1236*4882a593Smuzhiyun static void dw_hdmi_qp_rockchip_phy_disable(struct rockchip_connector *conn, void *data,
1237*4882a593Smuzhiyun void *state)
1238*4882a593Smuzhiyun {
1239*4882a593Smuzhiyun rockchip_phy_power_off(conn->phy);
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun
dw_hdmi_qp_rockchip_genphy_init(struct rockchip_connector * conn,void * data,void * state)1242*4882a593Smuzhiyun static int dw_hdmi_qp_rockchip_genphy_init(struct rockchip_connector *conn, void *data, void *state)
1243*4882a593Smuzhiyun {
1244*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun dw_hdmi_qp_rockchip_phy_disable(conn, data, state);
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun rockchip_phy_set_bus_width(conn->phy, hdmi->bus_width);
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun return rockchip_phy_power_on(conn->phy);
1251*4882a593Smuzhiyun }
1252*4882a593Smuzhiyun
dw_hdmi_rk3588_read_hpd(void * data)1253*4882a593Smuzhiyun static enum drm_connector_status dw_hdmi_rk3588_read_hpd(void *data)
1254*4882a593Smuzhiyun {
1255*4882a593Smuzhiyun u32 val;
1256*4882a593Smuzhiyun int ret;
1257*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun val = readl(hdmi->grf + RK3588_GRF_SOC_STATUS1);
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun if (!hdmi->id) {
1262*4882a593Smuzhiyun if (val & RK3588_HDMI0_LEVEL_INT)
1263*4882a593Smuzhiyun ret = connector_status_connected;
1264*4882a593Smuzhiyun else
1265*4882a593Smuzhiyun ret = connector_status_disconnected;
1266*4882a593Smuzhiyun } else {
1267*4882a593Smuzhiyun if (val & RK3588_HDMI1_LEVEL_INT)
1268*4882a593Smuzhiyun ret = connector_status_connected;
1269*4882a593Smuzhiyun else
1270*4882a593Smuzhiyun ret = connector_status_disconnected;
1271*4882a593Smuzhiyun }
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun return ret;
1274*4882a593Smuzhiyun }
1275*4882a593Smuzhiyun
dw_hdmi_rk3588_set_pll(struct rockchip_connector * conn,void * data,void * state)1276*4882a593Smuzhiyun static void dw_hdmi_rk3588_set_pll(struct rockchip_connector *conn, void *data, void *state)
1277*4882a593Smuzhiyun {
1278*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
1279*4882a593Smuzhiyun u32 rate = (hdmi->bus_width & DATA_RATE_MASK) * 100;
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun clk_set_rate(&hdmi->link_clk, rate);
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
1284*4882a593Smuzhiyun .init = dw_hdmi_qp_rockchip_genphy_init,
1285*4882a593Smuzhiyun .disable = dw_hdmi_qp_rockchip_phy_disable,
1286*4882a593Smuzhiyun .read_hpd = dw_hdmi_rk3588_read_hpd,
1287*4882a593Smuzhiyun .set_pll = dw_hdmi_rk3588_set_pll,
1288*4882a593Smuzhiyun };
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun static const struct rockchip_connector_funcs rockchip_dw_hdmi_qp_funcs = {
1291*4882a593Smuzhiyun .init = rockchip_dw_hdmi_qp_init,
1292*4882a593Smuzhiyun .deinit = rockchip_dw_hdmi_qp_deinit,
1293*4882a593Smuzhiyun .prepare = rockchip_dw_hdmi_qp_prepare,
1294*4882a593Smuzhiyun .enable = rockchip_dw_hdmi_qp_enable,
1295*4882a593Smuzhiyun .disable = rockchip_dw_hdmi_qp_disable,
1296*4882a593Smuzhiyun .get_timing = rockchip_dw_hdmi_qp_get_timing,
1297*4882a593Smuzhiyun .detect = rockchip_dw_hdmi_qp_detect,
1298*4882a593Smuzhiyun .get_edid = rockchip_dw_hdmi_qp_get_edid,
1299*4882a593Smuzhiyun };
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun const struct dw_hdmi_plat_data rk3588_hdmi_drv_data = {
1302*4882a593Smuzhiyun .qp_phy_ops = &rk3588_hdmi_phy_ops,
1303*4882a593Smuzhiyun .phy_name = "samsung_hdptx_phy",
1304*4882a593Smuzhiyun .dev_type = RK3588_HDMI,
1305*4882a593Smuzhiyun };
1306*4882a593Smuzhiyun
rockchip_dw_hdmi_qp_probe(struct udevice * dev)1307*4882a593Smuzhiyun static int rockchip_dw_hdmi_qp_probe(struct udevice *dev)
1308*4882a593Smuzhiyun {
1309*4882a593Smuzhiyun int ret;
1310*4882a593Smuzhiyun struct regmap *map;
1311*4882a593Smuzhiyun struct rockchip_hdmi *hdmi = dev_get_priv(dev);
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun hdmi->dev = dev;
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun hdmi->id = of_alias_get_id(ofnode_to_np(dev->node), "hdmi");
1316*4882a593Smuzhiyun if (hdmi->id < 0)
1317*4882a593Smuzhiyun hdmi->id = 0;
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun hdmi->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun if (hdmi->grf <= 0) {
1322*4882a593Smuzhiyun dev_err(dev, "%s: Get syscon grf failed (ret=%p)\n",
1323*4882a593Smuzhiyun __func__, hdmi->grf);
1324*4882a593Smuzhiyun return -ENXIO;
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun map = syscon_regmap_lookup_by_phandle(dev, "rockchip,vo1_grf");
1328*4882a593Smuzhiyun hdmi->vo1_grf = regmap_get_range(map, 0);
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun if (hdmi->vo1_grf <= 0) {
1331*4882a593Smuzhiyun dev_err(dev, "%s: Get syscon vo1 grf failed (ret=%p)\n",
1332*4882a593Smuzhiyun __func__, hdmi->vo1_grf);
1333*4882a593Smuzhiyun return -ENXIO;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun ret = gpio_request_by_name(dev, "enable-gpios", 0,
1337*4882a593Smuzhiyun &hdmi->enable_gpio, GPIOD_IS_OUT);
1338*4882a593Smuzhiyun if (ret) {
1339*4882a593Smuzhiyun dev_err(dev, "Cannot get enable GPIO: %d\n", ret);
1340*4882a593Smuzhiyun return ret;
1341*4882a593Smuzhiyun }
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun ret = clk_get_by_name(dev, "link_clk", &hdmi->link_clk);
1344*4882a593Smuzhiyun if (ret) {
1345*4882a593Smuzhiyun printf("%s: can't get link_clk\n", __func__);
1346*4882a593Smuzhiyun return ret;
1347*4882a593Smuzhiyun }
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun rockchip_connector_bind(&hdmi->connector, dev, hdmi->id, &rockchip_dw_hdmi_qp_funcs,
1350*4882a593Smuzhiyun NULL, DRM_MODE_CONNECTOR_HDMIA);
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun return 0;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun static const struct udevice_id rockchip_dw_hdmi_qp_ids[] = {
1356*4882a593Smuzhiyun {
1357*4882a593Smuzhiyun .compatible = "rockchip,rk3588-dw-hdmi",
1358*4882a593Smuzhiyun .data = (ulong)&rk3588_hdmi_drv_data,
1359*4882a593Smuzhiyun }, {}
1360*4882a593Smuzhiyun };
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun U_BOOT_DRIVER(rockchip_dw_hdmi_qp) = {
1363*4882a593Smuzhiyun .name = "rockchip_dw_hdmi_qp",
1364*4882a593Smuzhiyun .id = UCLASS_DISPLAY,
1365*4882a593Smuzhiyun .of_match = rockchip_dw_hdmi_qp_ids,
1366*4882a593Smuzhiyun .probe = rockchip_dw_hdmi_qp_probe,
1367*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct rockchip_hdmi),
1368*4882a593Smuzhiyun };
1369