On Thu, Feb 13, 2025 at 08:33:30PM +0800, Xin Ji wrote: > As anx7625 MIPI RX bandwidth(maximum 1.5Gbps per lane) and internal > pixel clock(maximum 300M) limitation. Anx7625 must enable DSC feature > while MIPI source want to output 4K30 resolution. This commit message is pretty hard to read and understand for a non-native speaker. Please consider rewriting it so that it is easier to understand it. > > Signed-off-by: Xin Ji <xji@xxxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/bridge/analogix/anx7625.c | 300 ++++++++++++++++++---- > drivers/gpu/drm/bridge/analogix/anx7625.h | 32 +++ > 2 files changed, 284 insertions(+), 48 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c > index 4be34d5c7a3b..7d86ab02f71c 100644 > --- a/drivers/gpu/drm/bridge/analogix/anx7625.c > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c > @@ -22,6 +22,7 @@ > > #include <drm/display/drm_dp_aux_bus.h> > #include <drm/display/drm_dp_helper.h> > +#include <drm/display/drm_dsc_helper.h> > #include <drm/display/drm_hdcp_helper.h> > #include <drm/drm_atomic_helper.h> > #include <drm/drm_bridge.h> > @@ -476,6 +477,138 @@ static int anx7625_set_k_value(struct anx7625_data *ctx) > MIPI_DIGITAL_ADJ_1, 0x3D); > } > > +static int anx7625_set_dsc_params(struct anx7625_data *ctx) > +{ > + int ret, i; > + u16 htotal, vtotal; > + > + if (!ctx->dsc_en) > + return 0; > + > + /* Htotal */ > + htotal = ctx->dt.hactive.min + ctx->dt.hfront_porch.min + > + ctx->dt.hback_porch.min + ctx->dt.hsync_len.min; > + ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_TOTAL_PIXELS_L, htotal); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_TOTAL_PIXELS_H, htotal >> 8); > + /* Hactive */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_ACTIVE_PIXELS_L, > + ctx->dt.hactive.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_ACTIVE_PIXELS_H, > + ctx->dt.hactive.min >> 8); > + /* HFP */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_FRONT_PORCH_L, > + ctx->dt.hfront_porch.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_FRONT_PORCH_H, > + ctx->dt.hfront_porch.min >> 8); > + /* HWS */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_SYNC_WIDTH_L, > + ctx->dt.hsync_len.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_SYNC_WIDTH_H, > + ctx->dt.hsync_len.min >> 8); > + /* HBP */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_BACK_PORCH_L, > + ctx->dt.hback_porch.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + HORIZONTAL_BACK_PORCH_H, > + ctx->dt.hback_porch.min >> 8); > + /* Vtotal */ > + vtotal = ctx->dt.vactive.min + ctx->dt.vfront_porch.min + > + ctx->dt.vback_porch.min + ctx->dt.vsync_len.min; > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, TOTAL_LINES_L, > + vtotal); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, TOTAL_LINES_H, > + vtotal >> 8); > + /* Vactive */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, ACTIVE_LINES_L, > + ctx->dt.vactive.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, ACTIVE_LINES_H, > + ctx->dt.vactive.min >> 8); > + /* VFP */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + VERTICAL_FRONT_PORCH, ctx->dt.vfront_porch.min); > + /* VWS */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + VERTICAL_SYNC_WIDTH, ctx->dt.vsync_len.min); > + /* VBP */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, > + VERTICAL_BACK_PORCH, ctx->dt.vback_porch.min); This code mostly duplicates anx7625_dsi_video_timing_config() with the I2C client being the only difference. Please consider extracting a common helper to write the timings. > + > + /* Htotal */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, TOTAL_PIXEL_L_7E, > + htotal); > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, TOTAL_PIXEL_H_7E, > + htotal >> 8); > + /* Hactive */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + ACTIVE_PIXEL_L_7E, ctx->dt.hactive.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + ACTIVE_PIXEL_H_7E, ctx->dt.hactive.min >> 8); > + /* HFP */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + HORIZON_FRONT_PORCH_L_7E, > + ctx->dt.hfront_porch.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + HORIZON_FRONT_PORCH_H_7E, > + ctx->dt.hfront_porch.min >> 8); > + /* HWS */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + HORIZON_SYNC_WIDTH_L_7E, > + ctx->dt.hsync_len.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + HORIZON_SYNC_WIDTH_H_7E, > + ctx->dt.hsync_len.min >> 8); > + /* HBP */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + HORIZON_BACK_PORCH_L_7E, > + ctx->dt.hback_porch.min); > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, > + HORIZON_BACK_PORCH_H_7E, > + ctx->dt.hback_porch.min >> 8); > + > + /* Config DSC decoder internal blank timing for decoder to start */ > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, > + H_BLANK_L, > + dsc_div(htotal - ctx->dt.hactive.min)); > + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, > + H_BLANK_H, > + dsc_div(htotal - ctx->dt.hactive.min) >> 8); > + > + /* Compress ratio RATIO bit[7:6] */ > + ret |= anx7625_write_and(ctx, ctx->i2c.rx_p0_client, R_I2C_1, 0x3F); > + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, R_I2C_1, > + (5 - DSC_COMPRESS_RATIO) << 6); > + /*PPS table*/ > + for (i = 0; i < PPS_SIZE; i += PPS_BLOCK_SIZE) > + ret |= anx7625_reg_block_write(ctx, ctx->i2c.rx_p2_client, > + R_PPS_REG_0 + i, PPS_BLOCK_SIZE, > + &ctx->pps_table[i]); > + > + return ret; > +} > + > +static int anx7625_timing_write(struct anx7625_data *ctx, > + struct i2c_client *client, > + u8 reg_addr, u16 reg_val, bool high_byte) > +{ > + u8 reg_data; > + > + if (ctx->dsc_en) > + reg_val = dsc_div(reg_val); > + > + reg_data = (high_byte ? (reg_val >> 8) : reg_val) & 0xFF; > + > + return anx7625_reg_write(ctx, client, reg_addr, reg_data); > +} Ugh, no. Calculate htotal in the calling function and call anx7625_reg_write() as you were doing that before. > + > static int anx7625_dsi_video_timing_config(struct anx7625_data *ctx) > { > struct device *dev = ctx->dev; > @@ -506,34 +639,33 @@ static int anx7625_dsi_video_timing_config(struct anx7625_data *ctx) > ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, > MIPI_LANE_CTRL_0, ctx->pdata.mipi_lanes - 1); > > - /* Htotal */ > htotal = ctx->dt.hactive.min + ctx->dt.hfront_porch.min + > - ctx->dt.hback_porch.min + ctx->dt.hsync_len.min; > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_TOTAL_PIXELS_L, htotal & 0xFF); > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_TOTAL_PIXELS_H, htotal >> 8); > + ctx->dt.hback_porch.min + ctx->dt.hsync_len.min; > + /* Htotal */ > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_TOTAL_PIXELS_L, htotal, false); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_TOTAL_PIXELS_H, htotal, true); > /* Hactive */ > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_ACTIVE_PIXELS_L, ctx->dt.hactive.min & 0xFF); > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_ACTIVE_PIXELS_H, ctx->dt.hactive.min >> 8); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_ACTIVE_PIXELS_L, ctx->dt.hactive.min, false); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_ACTIVE_PIXELS_H, ctx->dt.hactive.min, true); > /* HFP */ > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_FRONT_PORCH_L, ctx->dt.hfront_porch.min); > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_FRONT_PORCH_H, > - ctx->dt.hfront_porch.min >> 8); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_FRONT_PORCH_L, ctx->dt.hfront_porch.min, false); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_FRONT_PORCH_H, ctx->dt.hfront_porch.min, true); Are porches also compressed? I think blanking signal timings are transferred as is, without compression. > /* HWS */ > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_SYNC_WIDTH_L, ctx->dt.hsync_len.min); > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_SYNC_WIDTH_H, ctx->dt.hsync_len.min >> 8); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_SYNC_WIDTH_L, ctx->dt.hsync_len.min, false); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_SYNC_WIDTH_H, ctx->dt.hsync_len.min, true); > /* HBP */ > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_BACK_PORCH_L, ctx->dt.hback_porch.min); > - ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, > - HORIZONTAL_BACK_PORCH_H, ctx->dt.hback_porch.min >> 8); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_BACK_PORCH_L, ctx->dt.hback_porch.min, false); > + ret |= anx7625_timing_write(ctx, ctx->i2c.rx_p2_client, > + HORIZONTAL_BACK_PORCH_H, ctx->dt.hback_porch.min, true); > /* Vactive */ > ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p2_client, ACTIVE_LINES_L, > ctx->dt.vactive.min); > @@ -663,9 +795,15 @@ static int anx7625_dsi_config(struct anx7625_data *ctx) > > DRM_DEV_DEBUG_DRIVER(dev, "config dsi.\n"); > > - /* DSC disable */ > - ret = anx7625_write_and(ctx, ctx->i2c.rx_p0_client, > - R_DSC_CTRL_0, ~DSC_EN); > + ret = anx7625_set_dsc_params(ctx); > + if (ctx->dsc_en) > + /* DSC enable */ > + ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, > + R_DSC_CTRL_0, DSC_EN); > + else > + /* DSC disable */ > + ret |= anx7625_write_and(ctx, ctx->i2c.rx_p0_client, > + R_DSC_CTRL_0, ~DSC_EN); > > ret |= anx7625_api_dsi_config(ctx); > > @@ -2083,6 +2221,7 @@ static int anx7625_setup_dsi_device(struct anx7625_data *ctx) > MIPI_DSI_MODE_VIDEO_HSE | > MIPI_DSI_HS_PKT_END_ALIGNED; > > + dsi->dsc = &ctx->dsc; > ctx->dsi = dsi; > > return 0; > @@ -2186,20 +2325,68 @@ anx7625_bridge_mode_valid(struct drm_bridge *bridge, > struct anx7625_data *ctx = bridge_to_anx7625(bridge); > struct device *dev = ctx->dev; > > - DRM_DEV_DEBUG_DRIVER(dev, "drm mode checking\n"); > + dev_dbg(dev, "drm mode checking\n"); > + if (mode->clock > SUPPORT_PIXEL_CLOCK) > + return MODE_CLOCK_HIGH; > + > + if (mode->clock < SUPPORT_MIN_PIXEL_CLOCK) > + return MODE_CLOCK_LOW; > > - /* Max 1200p at 5.4 Ghz, one lane, pixel clock 300M */ > - if (mode->clock > SUPPORT_PIXEL_CLOCK) { > - DRM_DEV_DEBUG_DRIVER(dev, > - "drm mode invalid, pixelclock too high.\n"); > + if (mode->clock > DSC_PIXEL_CLOCK && (mode->hdisplay % 3 != 0)) Magic number 3. Also is it actually required? I think DSC standard has no such requirement. > return MODE_CLOCK_HIGH; > - } > > - DRM_DEV_DEBUG_DRIVER(dev, "drm mode valid.\n"); > + dev_dbg(dev, "drm mode valid.\n"); > > return MODE_OK; > } > > +static void anx7625_dsc_enable(struct anx7625_data *ctx, bool en) > +{ > + int ret; > + struct device *dev = ctx->dev; > + > + ctx->dsc_en = en; > + > + if (en) { > + ctx->dsc.dsc_version_major = 1; > + ctx->dsc.dsc_version_minor = 1; > + ctx->dsc.slice_height = 8; > + ctx->dsc.slice_width = ctx->dt.hactive.min / DSC_SLICE_NUM; > + ctx->dsc.slice_count = DSC_SLICE_NUM; > + ctx->dsc.bits_per_component = 8; > + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ > + ctx->dsc.block_pred_enable = true; > + ctx->dsc.native_420 = false; > + ctx->dsc.native_422 = false; > + ctx->dsc.simple_422 = false; > + ctx->dsc.vbr_enable = false; > + ctx->dsc.rc_model_size = DSC_RC_MODEL_SIZE_CONST; > + ctx->dsc.pic_width = ctx->dt.hactive.min; > + ctx->dsc.pic_height = ctx->dt.vactive.min; > + ctx->dsc.convert_rgb = 1; > + ctx->dsc.vbr_enable = 0; A lot of this params should be coming from the sink device. You have to get them from the DPCD. > + > + drm_dsc_set_rc_buf_thresh(&ctx->dsc); > + drm_dsc_set_const_params(&ctx->dsc); > + > + ctx->dsc.initial_scale_value = drm_dsc_initial_scale_value(&ctx->dsc); > + ctx->dsc.line_buf_depth = ctx->dsc.bits_per_component + 1; > + ret = drm_dsc_setup_rc_params(&ctx->dsc, DRM_DSC_1_2_444); > + if (ret < 0) > + dev_warn(dev, "drm_dsc_setup_rc_params ret %d\n", ret); > + > + drm_dsc_compute_rc_parameters(&ctx->dsc); You have ignored return value. Please handle the function returning an error. > + > + drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)&ctx->pps_table, > + &ctx->dsc); > + dev_dbg(dev, "anx7625 enable dsc\n"); > + } else { > + ctx->dsc.dsc_version_major = 0; > + ctx->dsc.dsc_version_minor = 0; > + dev_dbg(dev, "anx7625 disable dsc\n"); > + } > +} > + > static void anx7625_bridge_mode_set(struct drm_bridge *bridge, > const struct drm_display_mode *old_mode, > const struct drm_display_mode *mode) > @@ -2244,6 +2431,11 @@ static void anx7625_bridge_mode_set(struct drm_bridge *bridge, > DRM_DEV_DEBUG_DRIVER(dev, "vsync_end(%d),vtotal(%d).\n", > mode->vsync_end, > mode->vtotal); > + > + if (mode->clock > DSC_PIXEL_CLOCK) What if the sink doesn't support DSC? The decision whether to enable DSC or not should be happening in the atomic_check(). Likewise mode_valid should be able to check if your bridge and the sink can agree on DSC params and reject modes if they can not. > + anx7625_dsc_enable(ctx, true); > + else > + anx7625_dsc_enable(ctx, false); > } > > static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge, > @@ -2258,26 +2450,33 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge, > > DRM_DEV_DEBUG_DRIVER(dev, "drm mode fixup set\n"); > > - /* No need fixup for external monitor */ > - if (!ctx->pdata.panel_bridge) > - return true; > - > hsync = mode->hsync_end - mode->hsync_start; > hfp = mode->hsync_start - mode->hdisplay; > hbp = mode->htotal - mode->hsync_end; > hblanking = mode->htotal - mode->hdisplay; > > - DRM_DEV_DEBUG_DRIVER(dev, "before mode fixup\n"); > - DRM_DEV_DEBUG_DRIVER(dev, "hsync(%d), hfp(%d), hbp(%d), clock(%d)\n", > - hsync, hfp, hbp, adj->clock); > - DRM_DEV_DEBUG_DRIVER(dev, "hsync_start(%d), hsync_end(%d), htot(%d)\n", > - adj->hsync_start, adj->hsync_end, adj->htotal); > - > + dev_dbg(dev, "before mode fixup\n"); > + dev_dbg(dev, "hsync(%d), hfp(%d), hbp(%d), clock(%d)\n", > + hsync, hfp, hbp, adj->clock); > + dev_dbg(dev, "hsync_start(%d), hsync_end(%d), htot(%d)\n", > + adj->hsync_start, adj->hsync_end, adj->htotal); No. Please use drm_dbg_driver(), but not dev_dbg(). And anyway, this should go to a separate commit. > adj_hfp = hfp; > adj_hsync = hsync; > adj_hbp = hbp; > adj_hblanking = hblanking; > > + if (mode->clock > DSC_PIXEL_CLOCK) { > + adj_hsync = DSC_HSYNC_LEN; > + adj_hfp = DSC_HFP_LEN; > + adj_hbp = DSC_HBP_LEN; > + vref = (u64)adj->clock * 1000 * 1000 / (adj->htotal * adj->vtotal); > + goto calculate_timing; > + } > + > + /* No need fixup for external monitor */ > + if (!ctx->pdata.panel_bridge) > + return true; > + > /* HFP needs to be even */ > if (hfp & 0x1) { > adj_hfp += 1; > @@ -2349,16 +2548,21 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge, > adj_hfp -= delta_adj; > } > > - DRM_DEV_DEBUG_DRIVER(dev, "after mode fixup\n"); > - DRM_DEV_DEBUG_DRIVER(dev, "hsync(%d), hfp(%d), hbp(%d), clock(%d)\n", > - adj_hsync, adj_hfp, adj_hbp, adj->clock); > +calculate_timing: > + > + dev_dbg(dev, "after mode fixup\n"); > + dev_dbg(dev, "hsync(%d), hfp(%d), hbp(%d), clock(%d)\n", > + adj_hsync, adj_hfp, adj_hbp, adj->clock); > > /* Reconstruct timing */ > adj->hsync_start = adj->hdisplay + adj_hfp; > adj->hsync_end = adj->hsync_start + adj_hsync; > adj->htotal = adj->hsync_end + adj_hbp; > - DRM_DEV_DEBUG_DRIVER(dev, "hsync_start(%d), hsync_end(%d), htot(%d)\n", > - adj->hsync_start, adj->hsync_end, adj->htotal); > + if (mode->clock > DSC_PIXEL_CLOCK) > + adj->clock = (u64)vref * adj->htotal * adj->vtotal / 1000 / 1000; > + > + dev_dbg(dev, "hsync_start(%d), hsync_end(%d), htot(%d), clock(%d)\n", > + adj->hsync_start, adj->hsync_end, adj->htotal, adj->clock); > > return true; > } > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h > index eb5580f1ab2f..db931f5800b1 100644 > --- a/drivers/gpu/drm/bridge/analogix/anx7625.h > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h > @@ -149,6 +149,8 @@ > #define HFP_HBP_DEF ((HBLANKING_MIN - SYNC_LEN_DEF) / 2) > #define VIDEO_CONTROL_0 0x08 > > +#define TOTAL_LINES_L 0x12 > +#define TOTAL_LINES_H 0x13 > #define ACTIVE_LINES_L 0x14 > #define ACTIVE_LINES_H 0x15 /* Bit[7:6] are reserved */ > #define VERTICAL_FRONT_PORCH 0x16 > @@ -166,6 +168,32 @@ > #define HORIZONTAL_BACK_PORCH_L 0x21 > #define HORIZONTAL_BACK_PORCH_H 0x22 /* Bit[7:4] are reserved */ > > +#define H_BLANK_L 0x3E > +#define H_BLANK_H 0x3F > +#define DSC_COMPRESS_RATIO 3 > +#define dsc_div(X) ((X) / DSC_COMPRESS_RATIO) This assumes 1:3 ratio. Does anx7625 support only 8bpp / 8bpc mode? Or does 1:3 come from some other ratio? > +#define DSC_SLICE_NUM 2 > +#define DSC_PIXEL_CLOCK 250000 > +#define DSC_HSYNC_LEN 90 > +#define DSC_HFP_LEN 177 > +#define DSC_HBP_LEN 297 > + > +#define TOTAL_PIXEL_L_7E 0x50 > +#define TOTAL_PIXEL_H_7E 0x51 /* bit[7:6] are reserved */ > +#define ACTIVE_PIXEL_L_7E 0x52 > +#define ACTIVE_PIXEL_H_7E 0x53 /* bit[7:6] are reserved */ > +#define HORIZON_FRONT_PORCH_L_7E 0x54 > +#define HORIZON_FRONT_PORCH_H_7E 0x55 > +#define HORIZON_SYNC_WIDTH_L_7E 0x56 > +#define HORIZON_SYNC_WIDTH_H_7E 0x57 > +#define HORIZON_BACK_PORCH_L_7E 0x58 > +#define HORIZON_BACK_PORCH_H_7E 0x59 > + > +#define PPS_SIZE 128 > +#define PPS_BLOCK_SIZE 32 > +#define R_PPS_REG_0 0x80 > +#define R_I2C_1 0x81 > + > /******** END of I2C Address 0x72 *********/ > > /***************************************************************/ > @@ -415,6 +443,7 @@ enum audio_wd_len { > #define MAX_EDID_BLOCK 3 > #define EDID_TRY_CNT 3 > #define SUPPORT_PIXEL_CLOCK 300000 > +#define SUPPORT_MIN_PIXEL_CLOCK 50000 > > /***************** Display End *****************/ > > @@ -454,6 +483,7 @@ struct anx7625_data { > int hpd_high_cnt; > int dp_en; > int hdcp_cp; > + bool dsc_en; > /* Lock for work queue */ > struct mutex lock; > struct device *dev; > @@ -479,6 +509,8 @@ struct anx7625_data { > struct drm_connector *connector; > struct mipi_dsi_device *dsi; > struct drm_dp_aux aux; > + struct drm_dsc_config dsc; > + char pps_table[PPS_SIZE]; pps_table and drm_dsc_config can vary depending on the mode and connected sink. THey should be a part of the atomic state rather than a long-living anx7625_data. So does dsc_en. > }; > > #endif /* __ANX7625_H__ */ > -- > 2.25.1 > -- With best wishes Dmitry