Hi Swapnil, On 31/08/2020 11:23, Swapnil Jakhade wrote: > +static int cdns_mhdp_validate_mode_params(struct cdns_mhdp_device *mhdp, > + const struct drm_display_mode *mode, > + struct drm_bridge_state *bridge_state) > +{ > + u32 tu_size = 30, line_thresh1, line_thresh2, line_thresh = 0; > + u32 rate, vs, vs_f, required_bandwidth, available_bandwidth; > + struct cdns_mhdp_bridge_state *state; > + int pxlclock; > + u32 bpp; > + > + state = to_cdns_mhdp_bridge_state(bridge_state); > + > + pxlclock = mode->crtc_clock; > + > + /* Get rate in MSymbols per second per lane */ > + rate = mhdp->link.rate / 1000; > + > + bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt); None of the above are used when calling cdns_mhdp_bandwidth_ok(). For clarity, I'd move the above lines a bit closer to where they are needed, as currently it makes me think the above values are used when checking the bandwidth. > + if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, > + mhdp->link.rate)) { > + dev_err(mhdp->dev, "%s: Not enough BW for %s (%u lanes at %u Mbps)\n", > + __func__, mode->name, mhdp->link.num_lanes, > + mhdp->link.rate / 100); > + return -EINVAL; > + } > + > + /* find optimal tu_size */ > + required_bandwidth = pxlclock * bpp / 8; > + available_bandwidth = mhdp->link.num_lanes * rate; > + do { > + tu_size += 2; > + > + vs_f = tu_size * required_bandwidth / available_bandwidth; > + vs = vs_f / 1000; > + vs_f = vs_f % 1000; > + /* Downspreading is unused currently */ > + } while ((vs == 1 || ((vs_f > 850 || vs_f < 100) && vs_f != 0) || > + tu_size - vs < 2) && tu_size < 64); > + > + if (vs > 64) { > + dev_err(mhdp->dev, > + "%s: No space for framing %s (%u lanes at %u Mbps)\n", > + __func__, mode->name, mhdp->link.num_lanes, > + mhdp->link.rate / 100); > + return -EINVAL; > + } > + > + if (vs == tu_size) > + vs = tu_size - 1; > + > + line_thresh1 = ((vs + 1) << 5) * 8 / bpp; > + line_thresh2 = (pxlclock << 5) / 1000 / rate * (vs + 1) - (1 << 5); > + line_thresh = line_thresh1 - line_thresh2 / mhdp->link.num_lanes; > + line_thresh = (line_thresh >> 5) + 2; > + > + state->vs = vs; > + state->tu_size = tu_size; > + state->line_thresh = line_thresh; > + > + return 0; > +} > + > +static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, > + struct drm_bridge_state *bridge_state, > + struct drm_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > +{ > + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); > + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; > + int ret; > + > + mutex_lock(&mhdp->link_mutex); > + > + if (!mhdp->plugged) { > + mhdp->link.rate = mhdp->host.link_rate; > + mhdp->link.num_lanes = mhdp->host.lanes_cnt; > + } > + > + ret = cdns_mhdp_validate_mode_params(mhdp, mode, bridge_state); > + > + mutex_unlock(&mhdp->link_mutex); > + > + return ret; > +} Laurent mentioned that atomic_check should not change state. Note that cdns_mhdp_validate_mode_params also changes state, as it calculates tu_size, vs and line_thresh. There seems to be issues with mode changes, but I think the first step would be to clarify the related code a bit. cdns_mhdp_validate_mode_params() is misnamed, I think it should be renamed to calculate_tu or something like that. cdns_mhdp_bandwidth_ok() should take display_fmt or bpp as a parameter, as currently it digs that up from the current state. Probably cdns_mhdp_validate_mode_params() would be better if it doesn't write the result to the state, but returns the values. That way it could also be used to verify if suitable settings can be found, without changing the state. The are two issues I see with some testing, which are probably related. The first one is that if I run kmstest with a new mode, I see tu-size & co being calculated. But the calculation happens before link training, which doesn't make sense. So I think what's done here is that atomic_check causes tu-size calculations, then atomic_enable does link training and enables the video. The second happens when my monitor fails with the first CR after power-on, and the driver drops number-of-lanes to 2. It goes like this: The driver is loaded. Based on EDID, fbdev is created with 1920x1200. Link training is done, which has the CR issue, and because of that the actual mode that we get is 1280x960. I get a proper picture here, so far so good. Then if I run kmstest, it only allows 1280x960 as the link doesn't support higher modes (that's ok). It the does link training and gets a 4 lane link, and enables 1280x960. But the picture is not ok. If I then exit kmstest, it goes back to fbdev, but now that picture is broken also. Running kmstest again gives me 1920x1200 (as the link has been 4 lane now), and the picture is fine. I think the above suggests that the driver is not properly updating all the registers based on the new mode and link. I tried adding cdns_mhdp_validate_mode_params() call to cdns_mhdp_atomic_enable(), so that tu-size etc will be calculated, but that did not fix the problem. Tomi -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki