};
const struct dispc_features dispc_k2g_feats = {
- .min_pclk_khz = 4375,
-
- .max_pclk_khz = {
- [DISPC_VP_DPI] = 150000,
- },
-
/*
* XXX According TRM the RGB input buffer width up to 2560 should
* work on 3 taps, but in practice it only works up to 1280.
};
const struct dispc_features dispc_am65x_feats = {
- .max_pclk_khz = {
- [DISPC_VP_DPI] = 165000,
- [DISPC_VP_OLDI_AM65X] = 165000,
- },
-
.scaling = {
.in_width_max_5tap_rgb = 1280,
.in_width_max_3tap_rgb = 2560,
};
const struct dispc_features dispc_j721e_feats = {
- .max_pclk_khz = {
- [DISPC_VP_DPI] = 170000,
- [DISPC_VP_INTERNAL] = 600000,
- },
-
.scaling = {
.in_width_max_5tap_rgb = 2048,
.in_width_max_3tap_rgb = 4096,
};
const struct dispc_features dispc_am625_feats = {
- .max_pclk_khz = {
- [DISPC_VP_DPI] = 165000,
- [DISPC_VP_INTERNAL] = 170000,
- },
-
.scaling = {
.in_width_max_5tap_rgb = 1280,
.in_width_max_3tap_rgb = 2560,
};
const struct dispc_features dispc_am62a7_feats = {
- /*
- * if the code reaches dispc_mode_valid with VP1,
- * it should return MODE_BAD.
- */
- .max_pclk_khz = {
- [DISPC_VP_TIED_OFF] = 0,
- [DISPC_VP_DPI] = 165000,
- },
-
.scaling = {
.in_width_max_5tap_rgb = 1280,
.in_width_max_3tap_rgb = 2560,
};
const struct dispc_features dispc_am62l_feats = {
- .max_pclk_khz = {
- [DISPC_VP_DPI] = 165000,
- },
-
.subrev = DISPC_AM62L,
.common = "common",
DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff);
}
+/*
+ * Calculate the percentage difference between the requested pixel clock rate
+ * and the effective rate resulting from calculating the clock divider value.
+ */
+unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
+{
+ int r = rate / 100, rr = real_rate / 100;
+
+ return (unsigned int)(abs(((rr - r) * 100) / r));
+}
+
+static int check_pixel_clock(struct dispc_device *dispc, u32 hw_videoport,
+ unsigned long clock)
+{
+ unsigned long round_clock;
+
+ round_clock = clk_round_rate(dispc->vp_clk[hw_videoport], clock);
+ /*
+ * To keep the check consistent with dispc_vp_set_clk_rate(), we
+ * use the same 5% check here.
+ */
+ if (dispc_pclk_diff(clock, round_clock) > 5)
+ return -EINVAL;
+
+ return 0;
+}
+
enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
u32 hw_videoport,
const struct drm_display_mode *mode)
{
u32 hsw, hfp, hbp, vsw, vfp, vbp;
enum dispc_vp_bus_type bus_type;
- int max_pclk;
bus_type = dispc->feat->vp_bus_type[hw_videoport];
- max_pclk = dispc->feat->max_pclk_khz[bus_type];
-
- if (WARN_ON(max_pclk == 0))
+ if (WARN_ON(bus_type == DISPC_VP_TIED_OFF))
return MODE_BAD;
- if (mode->clock < dispc->feat->min_pclk_khz)
- return MODE_CLOCK_LOW;
-
- if (mode->clock > max_pclk)
- return MODE_CLOCK_HIGH;
-
if (mode->hdisplay > 4096)
return MODE_BAD;
if (mode->vdisplay > 4096)
return MODE_BAD;
+ if (check_pixel_clock(dispc, hw_videoport, mode->clock * 1000))
+ return MODE_CLOCK_RANGE;
+
/* TODO: add interlace support */
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
return MODE_NO_INTERLACE;
clk_disable_unprepare(dispc->vp_clk[hw_videoport]);
}
-/*
- * Calculate the percentage difference between the requested pixel clock rate
- * and the effective rate resulting from calculating the clock divider value.
- */
-unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
-{
- int r = rate / 100, rr = real_rate / 100;
-
- return (unsigned int)(abs(((rr - r) * 100) / r));
-}
-
int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport,
unsigned long rate)
{