summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/ipu-v3/ipu-di.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-16 15:48:00 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-16 15:48:00 -0800
commit796e1c55717e9a6ff5c81b12289ffa1ffd919b6f (patch)
tree27ce45cb1227156b72c641dbcbf2b399d23ba63d /drivers/gpu/ipu-v3/ipu-di.c
parent8c334ce8f0fec7122fc3059c52a697b669a01b41 (diff)
parent45ee2dbc65cbf6910892c480e6f428be342fa733 (diff)
downloadblackbird-op-linux-796e1c55717e9a6ff5c81b12289ffa1ffd919b6f.tar.gz
blackbird-op-linux-796e1c55717e9a6ff5c81b12289ffa1ffd919b6f.zip
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie: "This is the main drm pull, it has a shared branch with some alsa crossover but everything should be acked by relevant people. New drivers: - ATMEL HLCDC driver - designware HDMI core support (used in multiple SoCs). core: - lots more atomic modesetting work, properties and atomic ioctl (hidden under option) - bridge rework allows support for Samsung exynos chromebooks to work finally. - some more panels supported i915: - atomic plane update support - DSI uses shared DSI infrastructure - Skylake basic support is all merged now - component framework used for i915/snd-hda interactions - write-combine cpu memory mappings - engine init code refactored - full ppgtt enabled where execlists are enabled. - cherryview rps/gpu turbo and pipe CRC support. radeon: - indirect draw support for evergreen/cayman - SMC and manual fan control for SI/CI - Displayport audio support amdkfd: - SDMA usermode queue support - replace suballocator usage with more suitable one - rework for allowing interfacing to more than radeon nouveau: - major renaming in prep for later splitting work - merge arm platform driver into nouveau - GK20A reclocking support msm: - conversion to atomic modesetting - YUV support for mdp4/5 - eDP support - hw cursor for mdp5 tegra: - conversion to atomic modesetting - better suspend/resume support for child devices rcar-du: - interlaced support imx: - move to using dw_hdmi shared support - mode_fixup support sti: - DVO support - HDMI infoframe support exynos: - refactoring and cleanup, removed lots of internal unnecessary abstraction - exynos7 DECON display controller support Along with the usual bunch of fixes, cleanups etc" * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (724 commits) drm/radeon: fix voltage setup on hawaii drm/radeon/dp: Set EDP_CONFIGURATION_SET for bridge chips if necessary drm/radeon: only enable kv/kb dpm interrupts once v3 drm/radeon: workaround for CP HW bug on CIK drm/radeon: Don't try to enable write-combining without PAT drm/radeon: use 0-255 rather than 0-100 for pwm fan range drm/i915: Clamp efficient frequency to valid range drm/i915: Really ignore long HPD pulses on eDP drm/exynos: Add DECON driver drm/i915: Correct the base value while updating LP_OUTPUT_HOLD in MIPI_PORT_CTRL drm/i915: Insert a command barrier on BLT/BSD cache flushes drm/i915: Drop vblank wait from intel_dp_link_down drm/exynos: fix NULL pointer reference drm/exynos: remove exynos_plane_dpms drm/exynos: remove mode property of exynos crtc drm/exynos: Remove exynos_plane_dpms() call with no effect drm/i915: Squelch overzealous uncore reset WARN_ON drm/i915: Take runtime pm reference on hangcheck_info drm/i915: Correct the IOSF Dev_FN field for IOSF transfers drm/exynos: fix DMA_ATTR_NO_KERNEL_MAPPING usage ...
Diffstat (limited to 'drivers/gpu/ipu-v3/ipu-di.c')
-rw-r--r--drivers/gpu/ipu-v3/ipu-di.c121
1 files changed, 74 insertions, 47 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index c490ba4384fc..b61d6be97602 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -207,10 +207,10 @@ static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
static void ipu_di_sync_config_interlaced(struct ipu_di *di,
struct ipu_di_signal_cfg *sig)
{
- u32 h_total = sig->width + sig->h_sync_width +
- sig->h_start_width + sig->h_end_width;
- u32 v_total = sig->height + sig->v_sync_width +
- sig->v_start_width + sig->v_end_width;
+ u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+ sig->mode.hback_porch + sig->mode.hfront_porch;
+ u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+ sig->mode.vback_porch + sig->mode.vfront_porch;
u32 reg;
struct di_sync_config cfg[] = {
{
@@ -229,13 +229,13 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
}, {
.run_count = v_total / 2 - 1,
.run_src = DI_SYNC_HSYNC,
- .offset_count = sig->v_start_width,
+ .offset_count = sig->mode.vback_porch,
.offset_src = DI_SYNC_HSYNC,
.repeat_count = 2,
.cnt_clr_src = DI_SYNC_VSYNC,
}, {
.run_src = DI_SYNC_HSYNC,
- .repeat_count = sig->height / 2,
+ .repeat_count = sig->mode.vactive / 2,
.cnt_clr_src = 4,
}, {
.run_count = v_total - 1,
@@ -249,9 +249,9 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
.cnt_clr_src = DI_SYNC_VSYNC,
}, {
.run_src = DI_SYNC_CLK,
- .offset_count = sig->h_start_width,
+ .offset_count = sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
+ .repeat_count = sig->mode.hactive,
.cnt_clr_src = 5,
}, {
.run_count = v_total - 1,
@@ -277,10 +277,10 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
struct ipu_di_signal_cfg *sig, int div)
{
- u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
- sig->h_end_width;
- u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
- sig->v_end_width;
+ u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+ sig->mode.hback_porch + sig->mode.hfront_porch;
+ u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+ sig->mode.vback_porch + sig->mode.vfront_porch;
struct di_sync_config cfg[] = {
{
/* 1: INT_HSYNC */
@@ -294,27 +294,29 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_CLK,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
+ .cnt_down = sig->mode.hsync_len * 2,
} , {
/* PIN3: VSYNC */
.run_count = v_total - 1,
.run_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
+ .cnt_down = sig->mode.vsync_len * 2,
} , {
/* 4: Line Active */
.run_src = DI_SYNC_HSYNC,
- .offset_count = sig->v_sync_width + sig->v_start_width,
+ .offset_count = sig->mode.vsync_len +
+ sig->mode.vback_porch,
.offset_src = DI_SYNC_HSYNC,
- .repeat_count = sig->height,
+ .repeat_count = sig->mode.vactive,
.cnt_clr_src = DI_SYNC_VSYNC,
} , {
/* 5: Pixel Active, referenced by DC */
.run_src = DI_SYNC_CLK,
- .offset_count = sig->h_sync_width + sig->h_start_width,
+ .offset_count = sig->mode.hsync_len +
+ sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
+ .repeat_count = sig->mode.hactive,
.cnt_clr_src = 5, /* Line Active */
} , {
/* unused */
@@ -339,9 +341,10 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
} , {
/* 3: Line Active */
.run_src = DI_SYNC_INT_HSYNC,
- .offset_count = sig->v_sync_width + sig->v_start_width,
+ .offset_count = sig->mode.vsync_len +
+ sig->mode.vback_porch,
.offset_src = DI_SYNC_INT_HSYNC,
- .repeat_count = sig->height,
+ .repeat_count = sig->mode.vactive,
.cnt_clr_src = 3 /* VSYNC */,
} , {
/* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
@@ -351,13 +354,14 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_CLK,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
+ .cnt_down = sig->mode.hsync_len * 2,
} , {
/* 5: Pixel Active signal to DC */
.run_src = DI_SYNC_CLK,
- .offset_count = sig->h_sync_width + sig->h_start_width,
+ .offset_count = sig->mode.hsync_len +
+ sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
+ .repeat_count = sig->mode.hactive,
.cnt_clr_src = 4, /* Line Active */
} , {
/* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
@@ -367,7 +371,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
+ .cnt_down = sig->mode.vsync_len * 2,
} , {
/* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
.run_count = h_total - 1,
@@ -376,7 +380,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_CLK,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
+ .cnt_down = sig->mode.hsync_len * 2,
} , {
/* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
.run_count = v_total - 1,
@@ -385,7 +389,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
+ .cnt_down = sig->mode.vsync_len * 2,
} , {
/* unused */
},
@@ -433,10 +437,10 @@ static void ipu_di_config_clock(struct ipu_di *di,
unsigned long in_rate;
unsigned div;
- clk_set_rate(clk, sig->pixelclock);
+ clk_set_rate(clk, sig->mode.pixelclock);
in_rate = clk_get_rate(clk);
- div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
if (div == 0)
div = 1;
@@ -454,10 +458,10 @@ static void ipu_di_config_clock(struct ipu_di *di,
unsigned div, error;
clkrate = clk_get_rate(di->clk_ipu);
- div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+ div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
rate = clkrate / div;
- error = rate / (sig->pixelclock / 1000);
+ error = rate / (sig->mode.pixelclock / 1000);
dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
rate, div, (signed)(error - 1000) / 10, error % 10);
@@ -473,10 +477,10 @@ static void ipu_di_config_clock(struct ipu_di *di,
clk = di->clk_di;
- clk_set_rate(clk, sig->pixelclock);
+ clk_set_rate(clk, sig->mode.pixelclock);
in_rate = clk_get_rate(clk);
- div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
if (div == 0)
div = 1;
@@ -504,35 +508,58 @@ static void ipu_di_config_clock(struct ipu_di *di,
ipu_di_write(di, val, DI_GENERAL);
dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
- sig->pixelclock,
+ sig->mode.pixelclock,
clk_get_rate(di->clk_ipu),
clk_get_rate(di->clk_di),
clk == di->clk_di ? "DI" : "IPU",
clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
}
+/*
+ * This function is called to adjust a video mode to IPU restrictions.
+ * It is meant to be called from drm crtc mode_fixup() methods.
+ */
+int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
+{
+ u32 diff;
+
+ if (mode->vfront_porch >= 2)
+ return 0;
+
+ diff = 2 - mode->vfront_porch;
+
+ if (mode->vback_porch >= diff) {
+ mode->vfront_porch = 2;
+ mode->vback_porch -= diff;
+ } else if (mode->vsync_len > diff) {
+ mode->vfront_porch = 2;
+ mode->vsync_len = mode->vsync_len - diff;
+ } else {
+ dev_warn(di->ipu->dev, "failed to adjust videomode\n");
+ return -EINVAL;
+ }
+
+ dev_warn(di->ipu->dev, "videomode adapted for IPU restrictions\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+
int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
{
u32 reg;
u32 di_gen, vsync_cnt;
u32 div;
- u32 h_total, v_total;
dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
- di->id, sig->width, sig->height);
+ di->id, sig->mode.hactive, sig->mode.vactive);
- if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+ if ((sig->mode.vsync_len == 0) || (sig->mode.hsync_len == 0))
return -EINVAL;
- h_total = sig->width + sig->h_sync_width + sig->h_start_width +
- sig->h_end_width;
- v_total = sig->height + sig->v_sync_width + sig->v_start_width +
- sig->v_end_width;
-
dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
clk_get_rate(di->clk_ipu),
clk_get_rate(di->clk_di),
- sig->pixelclock);
+ sig->mode.pixelclock);
mutex_lock(&di_mutex);
@@ -551,7 +578,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
di_gen |= DI_GEN_DI_VSYNC_EXT;
- if (sig->interlaced) {
+ if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
ipu_di_sync_config_interlaced(di, sig);
/* set y_sel = 1 */
@@ -561,9 +588,9 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
vsync_cnt = 7;
- if (sig->Hsync_pol)
+ if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
di_gen |= DI_GEN_POLARITY_3;
- if (sig->Vsync_pol)
+ if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
di_gen |= DI_GEN_POLARITY_2;
} else {
ipu_di_sync_config_noninterlaced(di, sig, div);
@@ -577,7 +604,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
vsync_cnt = 6;
- if (sig->Hsync_pol) {
+ if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) {
if (sig->hsync_pin == 2)
di_gen |= DI_GEN_POLARITY_2;
else if (sig->hsync_pin == 4)
@@ -585,7 +612,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
else if (sig->hsync_pin == 7)
di_gen |= DI_GEN_POLARITY_7;
}
- if (sig->Vsync_pol) {
+ if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) {
if (sig->vsync_pin == 3)
di_gen |= DI_GEN_POLARITY_3;
else if (sig->vsync_pin == 6)
OpenPOWER on IntegriCloud