summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tidss/tidss_dispc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tidss/tidss_dispc.c')
-rw-r--r--drivers/gpu/drm/tidss/tidss_dispc.c126
1 files changed, 49 insertions, 77 deletions
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 7c8c15a5c39b..58d5eb033bdb 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -27,6 +27,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include "tidss_crtc.h"
#include "tidss_dispc.h"
@@ -57,12 +58,6 @@ static const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
};
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.
@@ -145,11 +140,6 @@ static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
};
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,
@@ -245,11 +235,6 @@ static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
};
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,
@@ -316,11 +301,6 @@ const struct dispc_features dispc_j721e_feats = {
};
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,
@@ -377,15 +357,6 @@ const struct dispc_features dispc_am625_feats = {
};
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,
@@ -442,10 +413,6 @@ const struct dispc_features dispc_am62a7_feats = {
};
const struct dispc_features dispc_am62l_feats = {
- .max_pclk_khz = {
- [DISPC_VP_DPI] = 165000,
- },
-
.subrev = DISPC_AM62L,
.common = "common",
@@ -1051,20 +1018,22 @@ struct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc,
int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
const struct drm_crtc_state *state)
{
+ struct tidss_device *tidss = dispc->tidss;
+ struct drm_device *dev = &tidss->ddev;
const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
const struct dispc_bus_format *fmt;
fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
tstate->bus_flags);
if (!fmt) {
- dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n",
+ drm_dbg(dev, "%s: Unsupported bus format: %u\n",
__func__, tstate->bus_format);
return -EINVAL;
}
if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI_AM65X &&
fmt->is_oldi_fmt) {
- dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
+ drm_dbg(dev, "%s: %s is not OLDI-port\n",
__func__, dispc->feat->vp_name[hw_videoport]);
return -EINVAL;
}
@@ -1161,6 +1130,9 @@ void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
{
const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
const struct dispc_bus_format *fmt;
+ const struct drm_display_mode *mode = &state->adjusted_mode;
+ bool align, onoff, rf, ieo, ipc, ihs, ivs;
+ u32 hsw, hfp, hbp, vsw, vfp, vbp;
fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
tstate->bus_flags);
@@ -1173,22 +1145,6 @@ void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
dispc_enable_am65x_oldi(dispc, hw_videoport, fmt);
}
-}
-
-void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
- const struct drm_crtc_state *state)
-{
- const struct drm_display_mode *mode = &state->adjusted_mode;
- const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
- bool align, onoff, rf, ieo, ipc, ihs, ivs;
- const struct dispc_bus_format *fmt;
- u32 hsw, hfp, hbp, vsw, vfp, vbp;
-
- fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
- tstate->bus_flags);
-
- if (WARN_ON(!fmt))
- return;
dispc_set_num_datalines(dispc, hw_videoport, fmt->data_width);
@@ -1244,7 +1200,10 @@ void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
mode->crtc_hdisplay - 1) |
FIELD_PREP(DISPC_VP_SIZE_SCREEN_VDISPLAY_MASK,
mode->crtc_vdisplay - 1));
+}
+void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport)
+{
VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1,
DISPC_VP_CONTROL_ENABLE_MASK);
}
@@ -1331,33 +1290,61 @@ static void dispc_vp_set_default_color(struct dispc_device *dispc,
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;
+
+ /*
+ * For VP's with external clocking, clock operations must be
+ * delegated to respective driver, so we skip the check here.
+ */
+ if (dispc->tidss->is_ext_vp_clk[hw_videoport])
+ return 0;
+
+ 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;
@@ -1421,17 +1408,6 @@ void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport)
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)
{
@@ -2849,8 +2825,6 @@ int dispc_runtime_resume(struct dispc_device *dispc)
void dispc_remove(struct tidss_device *tidss)
{
- dev_dbg(tidss->dev, "%s\n", __func__);
-
tidss->dispc = NULL;
}
@@ -2992,8 +2966,6 @@ int dispc_init(struct tidss_device *tidss)
unsigned int i, num_fourccs;
int r = 0;
- dev_dbg(dev, "%s\n", __func__);
-
feat = tidss->feat;
if (feat->subrev != DISPC_K2G) {