summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/dc.c
diff options
context:
space:
mode:
authorJon Mayo <jmayo@nvidia.com>2012-06-26 13:53:55 -0700
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-07-02 06:19:09 -0700
commit429d909e14eefa0331b1cd30490bce4d7ff45f33 (patch)
treedc8a78c303c9a58e289ae1adea91f130782cd82e /drivers/video/tegra/dc/dc.c
parent33b50b0bf4e501a81605c4351ff163d82c87e0d1 (diff)
video: tegra: dc: split dc.c into smaller files
Moved mode setting code into mode.c Move window code info window.c Moved clock related code into clock.c Moved LUT and gamma related code into lut.c Moved csc(color space conversion) into csc.c Removed unnecessary static function prototypes from header. Moved many short inline functions to dc_priv.h Cleaned up copyright headings. Cleaned up formatting and indent in all files. Fixed build warnings. Bug 870907 Change-Id: I6ccc37150191765394f0b5629423eafd4e5e5792 Signed-off-by: Jon Mayo <jmayo@nvidia.com> Reviewed-on: http://git-master/r/111371 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dc.c')
-rw-r--r--drivers/video/tegra/dc/dc.c1110
1 files changed, 31 insertions, 1079 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index b79a6595c36f..887beb830a3e 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -4,7 +4,7 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -58,14 +58,6 @@
#define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL 0x01000000
#define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL 0x0
-#ifndef CONFIG_TEGRA_FPGA_PLATFORM
-#define ALL_UF_INT (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)
-#else
-/* ignore underflows when on simulation and fpga platform */
-#define ALL_UF_INT (0)
-#endif
-
-static int no_vsync;
static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
.refresh = 60,
.xres = 640,
@@ -83,8 +75,6 @@ static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
static void _tegra_dc_controller_disable(struct tegra_dc *dc);
-module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
-
struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
@@ -112,23 +102,6 @@ static inline void tegra_dc_clk_disable(struct tegra_dc *dc)
print(data, buff); \
} while (0)
-#define print_mode_info(dc, mode) do { \
- trace_printk("%s:Mode settings: " \
- "ref_to_sync: H = %d V = %d, " \
- "sync_width: H = %d V = %d, " \
- "back_porch: H = %d V = %d, " \
- "active: H = %d V = %d, " \
- "front_porch: H = %d V = %d, " \
- "pclk = %d, stereo mode = %d\n", \
- dc->ndev->name, \
- mode.h_ref_to_sync, mode.v_ref_to_sync, \
- mode.h_sync_width, mode.v_sync_width, \
- mode.h_back_porch, mode.v_back_porch, \
- mode.h_active, mode.v_active, \
- mode.h_front_porch, mode.v_front_porch, \
- mode.pclk, mode.stereo_mode); \
- } while (0)
-
#define print_underflow_info(dc) do { \
trace_printk("%s:Underflow stats: underflows : %llu, " \
"undeflows_a : %llu, " \
@@ -297,7 +270,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
DUMP_REG(DC_COM_PM1_DUTY_CYCLE);
DUMP_REG(DC_DISP_SD_CONTROL);
- tegra_dc_clk_disable(dc->clk);
+ tegra_dc_clk_disable(dc);
tegra_dc_io_end(dc);
}
@@ -538,18 +511,6 @@ struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
}
EXPORT_SYMBOL(tegra_dc_get_window);
-static int get_topmost_window(u32 *depths, unsigned long *wins)
-{
- int idx, best = -1;
-
- for_each_set_bit(idx, wins, DC_N_WINDOWS) {
- if (best == -1 || depths[idx] < depths[best])
- best = idx;
- }
- clear_bit(best, wins);
- return best;
-}
-
bool tegra_dc_get_connected(struct tegra_dc *dc)
{
return dc->connected;
@@ -570,222 +531,6 @@ bool tegra_dc_hpd(struct tegra_dc *dc)
}
EXPORT_SYMBOL(tegra_dc_hpd);
-static u32 blend_topwin(u32 flags)
-{
- if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
- return BLEND(NOKEY, ALPHA, 0xff, 0xff);
- else if (flags & TEGRA_WIN_FLAG_BLEND_PREMULT)
- return BLEND(NOKEY, PREMULT, 0xff, 0xff);
- else
- return BLEND(NOKEY, FIX, 0xff, 0xff);
-}
-
-static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy)
-{
- int other;
-
- for (other = 0; other < DC_N_WINDOWS; other++) {
- if (other != idx && (xy-- == 0))
- break;
- }
- if (BIT(other) & behind_mask)
- return blend_topwin(flags[idx]);
- else if (flags[other])
- return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
- else
- return BLEND(NOKEY, FIX, 0x00, 0x00);
-}
-
-static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags)
-{
- unsigned long infront_mask;
- int first;
-
- infront_mask = ~(behind_mask | BIT(idx));
- infront_mask &= (BIT(DC_N_WINDOWS) - 1);
- first = ffs(infront_mask) - 1;
-
- if (!infront_mask)
- return blend_topwin(flags[idx]);
- else if (behind_mask && first != -1 && flags[first])
- return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
- else
- return BLEND(NOKEY, FIX, 0x0, 0x0);
-}
-
-static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
-{
- unsigned long mask = BIT(DC_N_WINDOWS) - 1;
-
- while (mask) {
- int idx = get_topmost_window(blend->z, &mask);
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
- tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
- DC_WIN_BLEND_NOKEY);
- tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
- DC_WIN_BLEND_1WIN);
- tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0),
- DC_WIN_BLEND_2WIN_X);
- tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1),
- DC_WIN_BLEND_2WIN_Y);
- tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags),
- DC_WIN_BLEND_3WIN_XY);
- }
-}
-
-static void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc)
-{
- csc->yof = 0x00f0;
- csc->kyrgb = 0x012a;
- csc->kur = 0x0000;
- csc->kvr = 0x0198;
- csc->kug = 0x039b;
- csc->kvg = 0x032f;
- csc->kub = 0x0204;
- csc->kvb = 0x0000;
-}
-
-static void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc)
-{
- tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF);
- tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB);
- tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR);
- tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR);
- tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG);
- tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG);
- tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB);
- tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB);
-}
-
-int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
-{
- mutex_lock(&dc->lock);
-
- if (!dc->enabled) {
- mutex_unlock(&dc->lock);
- return -EFAULT;
- }
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
-
- tegra_dc_set_csc(dc, &dc->windows[win_idx].csc);
-
- mutex_unlock(&dc->lock);
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_update_csc);
-
-static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut)
-{
- int i;
- for (i = 0; i < 256; i++)
- lut->r[i] = lut->g[i] = lut->b[i] = (u8)i;
-}
-
-static int tegra_dc_loop_lut(struct tegra_dc *dc,
- struct tegra_dc_win *win,
- int(*lambda)(struct tegra_dc *dc, int i, u32 rgb))
-{
- struct tegra_dc_lut *lut = &win->lut;
- struct tegra_dc_lut *global_lut = &dc->fb_lut;
- int i;
- for (i = 0; i < 256; i++) {
-
- u32 r = (u32)lut->r[i];
- u32 g = (u32)lut->g[i];
- u32 b = (u32)lut->b[i];
-
- if (!(win->ppflags & TEGRA_WIN_PPFLAG_CP_FBOVERRIDE)) {
- r = (u32)global_lut->r[r];
- g = (u32)global_lut->g[g];
- b = (u32)global_lut->b[b];
- }
-
- if (!lambda(dc, i, r | (g<<8) | (b<<16)))
- return 0;
- }
- return 1;
-}
-
-static int tegra_dc_lut_isdefaults_lambda(struct tegra_dc *dc, int i, u32 rgb)
-{
- if (rgb != (i | (i<<8) | (i<<16)))
- return 0;
- return 1;
-}
-
-static int tegra_dc_set_lut_setreg_lambda(struct tegra_dc *dc, int i, u32 rgb)
-{
- tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i));
- return 1;
-}
-
-static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win)
-{
- unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-
- tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda);
-
- if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
- val |= CP_ENABLE;
- else
- val &= ~CP_ENABLE;
-
- tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
-}
-
-static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
-{
- struct tegra_dc_win *win = &dc->windows[win_idx];
-
- mutex_lock(&dc->lock);
-
- if (!dc->enabled) {
- mutex_unlock(&dc->lock);
- return -EFAULT;
- }
-
- if (fbovr > 0)
- win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
- else if (fbovr == 0)
- win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
-
- if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda))
- win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE;
- else
- win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE;
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
-
- tegra_dc_set_lut(dc, win);
-
- mutex_unlock(&dc->lock);
-
- tegra_dc_update_windows(&win, 1);
-
- return 0;
-}
-
-int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
-{
- if (win_idx > -1)
- return tegra_dc_update_winlut(dc, win_idx, fboveride);
-
- for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) {
- int err = tegra_dc_update_winlut(dc, win_idx, fboveride);
- if (err)
- return err;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_update_lut);
-
static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
{
unsigned i;
@@ -814,287 +559,10 @@ void tegra_dc_host_resume(struct tegra_dc *dc) {
tegra_dsi_host_resume(dc);
}
-static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int,
- bool v, unsigned Bpp)
-{
- /*
- * min(round((prescaled_size_in_pixels - 1) * 0x1000 /
- * (post_scaled_size_in_pixels - 1)), MAX)
- * Where the value of MAX is as follows:
- * For V_DDA_INCREMENT: 15.0 (0xF000)
- * For H_DDA_INCREMENT: 4.0 (0x4000) for 4 Bytes/pix formats.
- * 8.0 (0x8000) for 2 Bytes/pix formats.
- */
-
- fixed20_12 out = dfixed_init(out_int);
- u32 dda_inc;
- int max;
-
- if (v) {
- max = 15;
- } else {
- switch (Bpp) {
- default:
- WARN_ON_ONCE(1);
- /* fallthrough */
- case 4:
- max = 4;
- break;
- case 2:
- max = 8;
- break;
- }
- }
-
- out.full = max_t(u32, out.full - dfixed_const(1), dfixed_const(1));
- in.full -= dfixed_const(1);
-
- dda_inc = dfixed_div(in, out);
-
- dda_inc = min_t(u32, dda_inc, dfixed_const(max));
-
- return dda_inc;
-}
-
-static inline u32 compute_initial_dda(fixed20_12 in)
-{
- return dfixed_frac(in);
-}
-
-/* does not support updating windows on multiple dcs in one call */
-int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
+static inline void disable_dc_irq(unsigned int irq)
{
- struct tegra_dc *dc;
- unsigned long update_mask = GENERAL_ACT_REQ;
- unsigned long val;
- bool update_blend = false;
- int i;
-
- dc = windows[0]->dc;
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
- /* Acquire one_shot_lock to avoid race condition between
- * cancellation of old delayed work and schedule of new
- * delayed work. */
- mutex_lock(&dc->one_shot_lock);
- cancel_delayed_work_sync(&dc->one_shot_work);
- }
- mutex_lock(&dc->lock);
-
- if (!dc->enabled) {
- mutex_unlock(&dc->lock);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- mutex_unlock(&dc->one_shot_lock);
- return -EFAULT;
- }
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
- tegra_dc_host_resume(dc);
-
- if (no_vsync)
- tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE, DC_CMD_STATE_ACCESS);
- else
- tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS);
-
- for (i = 0; i < n; i++) {
- struct tegra_dc_win *win = windows[i];
- unsigned h_dda;
- unsigned v_dda;
- fixed20_12 h_offset, v_offset;
- bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
- bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
- bool yuv = tegra_dc_is_yuv(win->fmt);
- bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
- unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
- /* Bytes per pixel of bandwidth, used for dda_inc calculation */
- unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
- const bool filter_h = win_use_h_filter(dc, win);
- const bool filter_v = win_use_v_filter(dc, win);
-
- if (win->z != dc->blend.z[win->idx]) {
- dc->blend.z[win->idx] = win->z;
- update_blend = true;
- }
- if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) !=
- dc->blend.flags[win->idx]) {
- dc->blend.flags[win->idx] =
- win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
- update_blend = true;
- }
-
- tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
- DC_CMD_DISPLAY_WINDOW_HEADER);
-
- if (!no_vsync)
- update_mask |= WIN_A_ACT_REQ << win->idx;
-
- if (!WIN_IS_ENABLED(win)) {
- dc->windows[i].dirty = 1;
- tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
- continue;
- }
-
- tegra_dc_writel(dc, win->fmt & 0x1f, DC_WIN_COLOR_DEPTH);
- tegra_dc_writel(dc, win->fmt >> 6, DC_WIN_BYTE_SWAP);
-
- tegra_dc_writel(dc,
- V_POSITION(win->out_y) | H_POSITION(win->out_x),
- DC_WIN_POSITION);
- tegra_dc_writel(dc,
- V_SIZE(win->out_h) | H_SIZE(win->out_w),
- DC_WIN_SIZE);
-
- if (tegra_dc_feature_has_scaling(dc, win->idx)) {
- tegra_dc_writel(dc,
- V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
- H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
- DC_WIN_PRESCALED_SIZE);
-
- h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
- v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
- tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
- DC_WIN_DDA_INCREMENT);
- h_dda = compute_initial_dda(win->x);
- v_dda = compute_initial_dda(win->y);
- tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
- tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
- }
-
- tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
- tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
- tegra_dc_writel(dc,
- (unsigned long)win->phys_addr,
- DC_WINBUF_START_ADDR);
-
- if (!yuvp) {
- tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
- } else {
- tegra_dc_writel(dc,
- (unsigned long)win->phys_addr_u,
- DC_WINBUF_START_ADDR_U);
- tegra_dc_writel(dc,
- (unsigned long)win->phys_addr_v,
- DC_WINBUF_START_ADDR_V);
- tegra_dc_writel(dc,
- LINE_STRIDE(win->stride) |
- UV_LINE_STRIDE(win->stride_uv),
- DC_WIN_LINE_STRIDE);
- }
-
- h_offset = win->x;
- if (invert_h) {
- h_offset.full += win->w.full - dfixed_const(1);
- }
-
- v_offset = win->y;
- if (invert_v) {
- v_offset.full += win->h.full - dfixed_const(1);
- }
-
- tegra_dc_writel(dc, dfixed_trunc(h_offset) * Bpp,
- DC_WINBUF_ADDR_H_OFFSET);
- tegra_dc_writel(dc, dfixed_trunc(v_offset),
- DC_WINBUF_ADDR_V_OFFSET);
-
- if (tegra_dc_feature_has_tiling(dc, win->idx)) {
- if (WIN_IS_TILED(win))
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_TILE |
- DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
- DC_WIN_BUFFER_ADDR_MODE);
- else
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_LINEAR |
- DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
- DC_WIN_BUFFER_ADDR_MODE);
- }
-
- val = WIN_ENABLE;
- if (yuv)
- val |= CSC_ENABLE;
- else if (tegra_dc_fmt_bpp(win->fmt) < 24)
- val |= COLOR_EXPAND;
-
- if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
- val |= CP_ENABLE;
-
- if (filter_h)
- val |= H_FILTER_ENABLE;
- if (filter_v)
- val |= V_FILTER_ENABLE;
-
- if (invert_h)
- val |= H_DIRECTION_DECREMENT;
- if (invert_v)
- val |= V_DIRECTION_DECREMENT;
-
- tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- if (win->global_alpha == 255)
- tegra_dc_writel(dc, 0, DC_WIN_GLOBAL_ALPHA);
- else
- tegra_dc_writel(dc, GLOBAL_ALPHA_ENABLE |
- win->global_alpha, DC_WIN_GLOBAL_ALPHA);
-#endif
-
- win->dirty = no_vsync ? 0 : 1;
-
- dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d "
- "out_x=%u out_y=%u out_w=%u out_h=%u "
- "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d",
- __func__, win->idx, win->z,
- dfixed_trunc(win->x), dfixed_trunc(win->y),
- dfixed_trunc(win->w), dfixed_trunc(win->h),
- win->out_x, win->out_y, win->out_w, win->out_h,
- win->fmt, yuvp, Bpp, filter_h, filter_v);
- trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n",
- dc->ndev->name, win->idx, dfixed_trunc(win->w),
- dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt);
- }
-
- if (update_blend) {
- tegra_dc_set_blending(dc, &dc->blend);
- for (i = 0; i < DC_N_WINDOWS; i++) {
- if (!no_vsync)
- dc->windows[i].dirty = 1;
- update_mask |= WIN_A_ACT_REQ << i;
- }
- }
-
- tegra_dc_set_dynamic_emc(windows, n);
-
- tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
-
- tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS);
- if (!no_vsync) {
- set_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
- tegra_dc_unmask_interrupt(dc, FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
- } else {
- clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
- tegra_dc_mask_interrupt(dc, FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
- }
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- schedule_delayed_work(&dc->one_shot_work,
- msecs_to_jiffies(dc->one_shot_delay_ms));
-
- /* update EMC clock if calculated bandwidth has changed */
- tegra_dc_program_bandwidth(dc, false);
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- update_mask |= NC_HOST_TRIG;
-
- tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
- trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
-
- mutex_unlock(&dc->lock);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- mutex_unlock(&dc->one_shot_lock);
-
- return 0;
+ disable_irq(irq);
}
-EXPORT_SYMBOL(tegra_dc_update_windows);
u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc, int i)
{
@@ -1126,502 +594,6 @@ void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val)
mutex_unlock(&dc->lock);
}
-static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
- int n)
-{
- int i;
-
- for (i = 0; i < n; i++) {
- if (windows[i]->dirty)
- return false;
- }
-
- return true;
-}
-
-/* does not support syncing windows on multiple dcs in one call */
-int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
-{
- int ret;
- if (n < 1 || n > DC_N_WINDOWS)
- return -EINVAL;
-
- if (!windows[0]->dc->enabled)
- return -EFAULT;
-
-#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
- /* Don't want to timeout on simulator */
- ret = wait_event_interruptible(windows[0]->dc->wq,
- tegra_dc_windows_are_clean(windows, n));
-#else
- trace_printk("%s:Before wait_event_interruptible_timeout\n",
- windows[0]->dc->ndev->name);
- ret = wait_event_interruptible_timeout(windows[0]->dc->wq,
- tegra_dc_windows_are_clean(windows, n),
- HZ);
- trace_printk("%s:After wait_event_interruptible_timeout\n",
- windows[0]->dc->ndev->name);
-#endif
- return ret;
-}
-EXPORT_SYMBOL(tegra_dc_sync_windows);
-
-static unsigned long tegra_dc_clk_get_rate(struct tegra_dc *dc)
-{
-#ifdef CONFIG_TEGRA_SILICON_PLATFORM
- return clk_get_rate(dc->clk);
-#else
- return 27000000;
-#endif
-}
-
-static unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk)
-{
- unsigned long rate;
- unsigned long div;
-
- rate = tegra_dc_clk_get_rate(dc);
-
- div = DIV_ROUND_CLOSEST(rate * 2, pclk);
-
- if (div < 2)
- return 0;
-
- return rate * 2 / div;
-}
-
-static unsigned long tegra_dc_pclk_predict_rate(struct clk *parent, int pclk)
-{
- unsigned long rate;
- unsigned long div;
-
- rate = clk_get_rate(parent);
-
- div = DIV_ROUND_CLOSEST(rate * 2, pclk);
-
- if (div < 2)
- return 0;
-
- return rate * 2 / div;
-}
-
-void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
-{
- int pclk;
-
- if (dc->out->type == TEGRA_DC_OUT_RGB) {
- unsigned long rate;
- struct clk *parent_clk =
- clk_get_sys(NULL, dc->out->parent_clk ? : "pll_p");
-
- if (dc->out->parent_clk_backup &&
- (parent_clk == clk_get_sys(NULL, "pll_p"))) {
- rate = tegra_dc_pclk_predict_rate(
- parent_clk, dc->mode.pclk);
- /* use pll_d as last resort */
- if (rate < (dc->mode.pclk / 100 * 99) ||
- rate > (dc->mode.pclk / 100 * 109))
- parent_clk = clk_get_sys(
- NULL, dc->out->parent_clk_backup);
- }
-
- if (clk_get_parent(clk) != parent_clk)
- clk_set_parent(clk, parent_clk);
-
- if (parent_clk != clk_get_sys(NULL, "pll_p")) {
- struct clk *base_clk = clk_get_parent(parent_clk);
-
- /* Assuming either pll_d or pll_d2 is used */
- rate = dc->mode.pclk * 2;
-
- if (rate != clk_get_rate(base_clk))
- clk_set_rate(base_clk, rate);
- }
- }
-
- if (dc->out->type == TEGRA_DC_OUT_HDMI) {
- unsigned long rate;
- struct clk *parent_clk =
- clk_get_sys(NULL, dc->out->parent_clk ? : "pll_d_out0");
- struct clk *base_clk = clk_get_parent(parent_clk);
-
- /*
- * Providing dynamic frequency rate setting for T20/T30 HDMI.
- * The required rate needs to be setup at 4x multiplier,
- * as out0 is 1/2 of the actual PLL output.
- */
-
- rate = dc->mode.pclk * 4;
- if (rate != clk_get_rate(base_clk))
- clk_set_rate(base_clk, rate);
-
- if (clk_get_parent(clk) != parent_clk)
- clk_set_parent(clk, parent_clk);
- }
-
- if (dc->out->type == TEGRA_DC_OUT_DSI) {
- unsigned long rate;
- struct clk *parent_clk;
- struct clk *base_clk;
-
- if (clk == dc->clk) {
- parent_clk = clk_get_sys(NULL,
- dc->out->parent_clk ? : "pll_d_out0");
- base_clk = clk_get_parent(parent_clk);
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
- } else {
- if (dc->pdata->default_out->dsi->dsi_instance) {
- parent_clk = clk_get_sys(NULL,
- dc->out->parent_clk ? : "pll_d2_out0");
- base_clk = clk_get_parent(parent_clk);
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
- } else {
- parent_clk = clk_get_sys(NULL,
- dc->out->parent_clk ? : "pll_d_out0");
- base_clk = clk_get_parent(parent_clk);
- tegra_clk_cfg_ex(base_clk,
- TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
- }
- }
-
- rate = dc->mode.pclk * dc->shift_clk_div * 2;
- if (rate != clk_get_rate(base_clk))
- clk_set_rate(base_clk, rate);
-
- if (clk_get_parent(clk) != parent_clk)
- clk_set_parent(clk, parent_clk);
- }
-
- pclk = tegra_dc_pclk_round_rate(dc, dc->mode.pclk);
- tegra_dvfs_set_rate(clk, pclk);
-}
-
-/* return non-zero if constraint is violated */
-static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
-{
- long a, b;
-
- /* Constraint 5: H_REF_TO_SYNC >= 0 */
- a = 0;
-
- /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */
- b = mode->h_front_porch - 1;
-
- /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */
- if (a + mode->h_sync_width + mode->h_back_porch <= 11)
- a = 1 + 11 - mode->h_sync_width - mode->h_back_porch;
- /* check Constraint 1 and 6 */
- if (a > b)
- return 1;
-
- /* Constraint 4: H_SYNC_WIDTH >= 1 */
- if (mode->h_sync_width < 1)
- return 4;
-
- /* Constraint 7: H_DISP_ACTIVE >= 16 */
- if (mode->h_active < 16)
- return 7;
-
- if (href) {
- if (b > a && a % 2)
- *href = a + 1; /* use smallest even value */
- else
- *href = a; /* even or only possible value */
- }
-
- return 0;
-}
-
-static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref)
-{
- long a;
- a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */
-
- /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */
- if (a + mode->v_sync_width + mode->v_back_porch <= 1)
- a = 1 + 1 - mode->v_sync_width - mode->v_back_porch;
-
- /* Constraint 6 */
- if (mode->v_front_porch < a + 1)
- a = mode->v_front_porch - 1;
-
- /* Constraint 4: V_SYNC_WIDTH >= 1 */
- if (mode->v_sync_width < 1)
- return 4;
-
- /* Constraint 7: V_DISP_ACTIVE >= 16 */
- if (mode->v_active < 16)
- return 7;
-
- if (vref)
- *vref = a;
- return 0;
-}
-
-static int calc_ref_to_sync(struct tegra_dc_mode *mode)
-{
- int ret;
- ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync);
- if (ret)
- return ret;
- ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static bool check_ref_to_sync(struct tegra_dc_mode *mode)
-{
- /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11. */
- if (mode->h_ref_to_sync + mode->h_sync_width + mode->h_back_porch <= 11)
- return false;
-
- /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1. */
- if (mode->v_ref_to_sync + mode->v_sync_width + mode->v_back_porch <= 1)
- return false;
-
- /* Constraint 3: V_FRONT_PORCH + V_SYNC_WIDTH + V_BACK_PORCH > 1
- * (vertical blank). */
- if (mode->v_front_porch + mode->v_sync_width + mode->v_back_porch <= 1)
- return false;
-
- /* Constraint 4: V_SYNC_WIDTH >= 1; H_SYNC_WIDTH >= 1. */
- if (mode->v_sync_width < 1 || mode->h_sync_width < 1)
- return false;
-
- /* Constraint 5: V_REF_TO_SYNC >= 1; H_REF_TO_SYNC >= 0. */
- if (mode->v_ref_to_sync < 1 || mode->h_ref_to_sync < 0)
- return false;
-
- /* Constraint 6: V_FRONT_PORT >= (V_REF_TO_SYNC + 1);
- * H_FRONT_PORT >= (H_REF_TO_SYNC + 1). */
- if (mode->v_front_porch < mode->v_ref_to_sync + 1 ||
- mode->h_front_porch < mode->h_ref_to_sync + 1)
- return false;
-
- /* Constraint 7: H_DISP_ACTIVE >= 16; V_DISP_ACTIVE >= 16. */
- if (mode->h_active < 16 || mode->v_active < 16)
- return false;
-
- return true;
-}
-
-#ifdef DEBUG
-/* return in 1000ths of a Hertz */
-static int calc_refresh(const struct tegra_dc_mode *m)
-{
- long h_total, v_total, refresh;
- h_total = m->h_active + m->h_front_porch + m->h_back_porch +
- m->h_sync_width;
- v_total = m->v_active + m->v_front_porch + m->v_back_porch +
- m->v_sync_width;
- refresh = m->pclk / h_total;
- refresh *= 1000;
- refresh /= v_total;
- return refresh;
-}
-
-static void print_mode(struct tegra_dc *dc,
- const struct tegra_dc_mode *mode, const char *note)
-{
- if (mode) {
- int refresh = calc_refresh(dc, mode);
- dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n",
- note ? note : "",
- mode->h_active, mode->v_active,
- refresh / 1000, refresh % 1000,
- mode->pclk);
- }
-}
-#else /* !DEBUG */
-static inline void print_mode(struct tegra_dc *dc,
- const struct tegra_dc_mode *mode, const char *note) { }
-#endif /* DEBUG */
-
-static inline void enable_dc_irq(unsigned int irq)
-{
-#ifndef CONFIG_TEGRA_FPGA_PLATFORM
- enable_irq(irq);
-#else
- /* Always disable DC interrupts on FPGA. */
- disable_irq(irq);
-#endif
-}
-
-static inline void disable_dc_irq(unsigned int irq)
-{
- disable_irq(irq);
-}
-
-static inline void tegra_dc_unmask_interrupt(struct tegra_dc *dc, u32 int_val)
-{
- u32 val;
-
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val |= int_val;
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
-}
-
-static inline void tegra_dc_mask_interrupt(struct tegra_dc *dc, u32 int_val)
-{
- u32 val;
-
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val &= ~int_val;
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
-}
-
-static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
-{
- unsigned long val;
- unsigned long rate;
- unsigned long div;
- unsigned long pclk;
-
- print_mode(dc, mode, __func__);
-
- /* use default EMC rate when switching modes */
- dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc);
- tegra_dc_program_bandwidth(dc, true);
-
- tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
- tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
- DC_DISP_REF_TO_SYNC);
- tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
- DC_DISP_SYNC_WIDTH);
- tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
- DC_DISP_BACK_PORCH);
- tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
- DC_DISP_DISP_ACTIVE);
- tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
- DC_DISP_FRONT_PORCH);
-
- tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
- DC_DISP_DATA_ENABLE_OPTIONS);
-
- /* TODO: MIPI/CRT/HDMI clock cals */
-
- val = DISP_DATA_FORMAT_DF1P1C;
-
- if (dc->out->align == TEGRA_DC_ALIGN_MSB)
- val |= DISP_DATA_ALIGNMENT_MSB;
- else
- val |= DISP_DATA_ALIGNMENT_LSB;
-
- if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
- val |= DISP_DATA_ORDER_RED_BLUE;
- else
- val |= DISP_DATA_ORDER_BLUE_RED;
-
- tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
-
- rate = tegra_dc_clk_get_rate(dc);
-
- pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
- trace_printk("%s:pclk=%ld\n", dc->ndev->name, pclk);
- if (pclk < (mode->pclk / 100 * 99) ||
- pclk > (mode->pclk / 100 * 109)) {
- dev_err(&dc->ndev->dev,
- "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
- rate, mode->pclk,
- pclk, (mode->pclk / 100 * 99),
- (mode->pclk / 100 * 109));
- return -EINVAL;
- }
-
- div = (rate * 2 / pclk) - 2;
- trace_printk("%s:div=%ld\n", dc->ndev->name, div);
-
- tegra_dc_writel(dc, 0x00010001,
- DC_DISP_SHIFT_CLOCK_OPTIONS);
- tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
- DC_DISP_DISP_CLOCK_CONTROL);
-
-#ifdef CONFIG_SWITCH
- switch_set_state(&dc->modeset_switch,
- (mode->h_active << 16) | mode->v_active);
-#endif
-
- tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
- print_mode_info(dc, dc->mode);
- return 0;
-}
-
-
-int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
-{
- memcpy(&dc->mode, mode, sizeof(dc->mode));
-
- print_mode(dc, mode, __func__);
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_set_mode);
-
-int tegra_dc_set_fb_mode(struct tegra_dc *dc,
- const struct fb_videomode *fbmode, bool stereo_mode)
-{
- struct tegra_dc_mode mode;
-
- if (!fbmode->pixclock)
- return -EINVAL;
-
- mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
- mode.h_sync_width = fbmode->hsync_len;
- mode.v_sync_width = fbmode->vsync_len;
- mode.h_back_porch = fbmode->left_margin;
- mode.v_back_porch = fbmode->upper_margin;
- mode.h_active = fbmode->xres;
- mode.v_active = fbmode->yres;
- mode.h_front_porch = fbmode->right_margin;
- mode.v_front_porch = fbmode->lower_margin;
- mode.stereo_mode = stereo_mode;
- if (dc->out->type == TEGRA_DC_OUT_HDMI) {
- /* HDMI controller requires h_ref=1, v_ref=1 */
- mode.h_ref_to_sync = 1;
- mode.v_ref_to_sync = 1;
- } else {
- calc_ref_to_sync(&mode);
- }
- if (!check_ref_to_sync(&mode)) {
- dev_err(&dc->ndev->dev,
- "Display timing doesn't meet restrictions.\n");
- return -EINVAL;
- }
- dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
- mode.h_active, mode.v_active, mode.pclk,
- mode.h_ref_to_sync, mode.v_ref_to_sync
- );
-
-#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- /* Double the pixel clock and update v_active only for frame packed mode */
- if (mode.stereo_mode) {
- mode.pclk *= 2;
- /* total v_active = yres*2 + activespace */
- mode.v_active = fbmode->yres*2 +
- fbmode->vsync_len +
- fbmode->upper_margin +
- fbmode->lower_margin;
- }
-#endif
-
- mode.flags = 0;
-
- if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT))
- mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
-
- if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
- mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
-
- return tegra_dc_set_mode(dc, &mode);
-}
-EXPORT_SYMBOL(tegra_dc_set_fb_mode);
-
void
tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
{
@@ -1841,6 +813,28 @@ crc_error:
return crc;
}
+static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
+{
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+ u32 val;
+
+ val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
+ if (val & (WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ))
+ return true;
+#endif
+ return false;
+}
+
+static inline void enable_dc_irq(unsigned int irq)
+{
+#ifndef CONFIG_TEGRA_FPGA_PLATFORM
+ enable_irq(irq);
+#else
+ /* Always disable DC interrupts on FPGA. */
+ disable_irq(irq);
+#endif
+}
+
static void tegra_dc_vblank(struct work_struct *work)
{
struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work);
@@ -1987,50 +981,6 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
}
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
-static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
-{
-#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
- u32 val;
-
- val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
- if (val & (WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ))
- return true;
-#endif
- return false;
-}
-
-static void tegra_dc_trigger_windows(struct tegra_dc *dc)
-{
- u32 val, i;
- u32 completed = 0;
- u32 dirty = 0;
-
- val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
- for (i = 0; i < DC_N_WINDOWS; i++) {
-#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
- /* FIXME: this is not needed when the simulator
- clears WIN_x_UPDATE bits as in HW */
- dc->windows[i].dirty = 0;
- completed = 1;
-#else
- if (!(val & (WIN_A_ACT_REQ << i))) {
- dc->windows[i].dirty = 0;
- completed = 1;
- } else {
- dirty = 1;
- }
-#endif
- }
-
- if (!dirty) {
- if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE))
- tegra_dc_mask_interrupt(dc, FRAME_END_INT);
- }
-
- if (completed)
- wake_up(&dc->wq);
-}
-
static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
{
if (status & V_BLANK_INT) {
@@ -2285,7 +1235,7 @@ static int tegra_dc_init(struct tegra_dc *dc)
nvhost_syncpt_read_ext(dc->ndev, syncpt);
}
- print_mode(dc, &dc->mode, __func__);
+ print_mode_info(dc, dc->mode);
if (dc->mode.pclk)
if (tegra_dc_program_mode(dc, &dc->mode))
@@ -2586,7 +1536,8 @@ static void tegra_dc_reset_worker(struct work_struct *work)
mutex_lock(&shared_lock);
- dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
+ dev_warn(&dc->ndev->dev,
+ "overlay stuck in underflow state. resetting.\n");
tegra_dc_ext_disable(dc->ext);
@@ -2698,7 +1649,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev,
goto err_free;
}
- base_res = request_mem_region(res->start, resource_size(res), ndev->name);
+ base_res = request_mem_region(res->start, resource_size(res),
+ ndev->name);
if (!base_res) {
dev_err(&ndev->dev, "request_mem_region failed\n");
ret = -EBUSY;