diff options
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 6 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_priv.h | 6 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/dev.c | 32 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/hdmi.c | 13 | ||||
-rw-r--r-- | drivers/video/tegra/dc/mode.c | 285 | ||||
-rw-r--r-- | drivers/video/tegra/dc/nvhdcp.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/window.c | 15 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 343 | ||||
-rw-r--r-- | drivers/video/tegra/host/bus_client.c | 3 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_acm.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_syncpt.c | 3 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap.c | 6 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dev.c | 3 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_handle.c | 3 |
15 files changed, 589 insertions, 135 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index bfd916e0e16e..d4c3f8bc9a49 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -1067,9 +1067,11 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status) queue_work(system_freezable_wq, &dc->vblank_work); if (status & FRAME_END_INT) { +#ifndef CONFIG_ANDROID struct timespec tm = CURRENT_TIME; dc->frame_end_timestamp = timespec_to_ns(&tm); wake_up(&dc->timestamp_wq); +#endif /* !CONFIG_ANDROID */ /* Mark the frame_end as complete. */ if (!completion_done(&dc->frame_end_complete)) @@ -1079,6 +1081,7 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status) } } +#ifndef CONFIG_ANDROID /* XXX: Not sure if we limit look ahead to 1 frame */ bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts) { @@ -1094,6 +1097,7 @@ bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts) != div_s64((old_ts - dc->frame_end_timestamp), dc->frametime_ns))); } +#endif /* !CONFIG_ANDROID */ #endif static irqreturn_t tegra_dc_irq(int irq, void *ptr) @@ -1781,7 +1785,9 @@ static int tegra_dc_probe(struct nvhost_device *ndev, mutex_init(&dc->one_shot_lock); init_completion(&dc->frame_end_complete); init_waitqueue_head(&dc->wq); +#ifndef CONFIG_ANDROID init_waitqueue_head(&dc->timestamp_wq); +#endif /* !CONFIG_ANDROID */ #ifdef CONFIG_ARCH_TEGRA_2x_SOC INIT_WORK(&dc->reset_work, tegra_dc_reset_worker); #endif diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h index 75c3a2a29658..e91071f70ddc 100644 --- a/drivers/video/tegra/dc/dc_priv.h +++ b/drivers/video/tegra/dc/dc_priv.h @@ -113,14 +113,18 @@ struct tegra_dc { void *out_data; struct tegra_dc_mode mode; +#ifndef CONFIG_ANDROID s64 frametime_ns; +#endif /* !CONFIG_ANDROID */ struct tegra_dc_win windows[DC_N_WINDOWS]; struct tegra_dc_blend blend; int n_windows; wait_queue_head_t wq; +#ifndef CONFIG_ANDROID wait_queue_head_t timestamp_wq; +#endif /* !CONFIG_ANDROID */ struct mutex lock; struct mutex one_shot_lock; @@ -165,7 +169,9 @@ struct tegra_dc { struct delayed_work underflow_work; u32 one_shot_delay_ms; struct delayed_work one_shot_work; +#ifndef CONFIG_ANDROID s64 frame_end_timestamp; +#endif /* !CONFIG_ANDROID */ }; #define print_mode_info(dc, mode) do { \ diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c index 88273e26c51c..37a6d9bd3f80 100644 --- a/drivers/video/tegra/dc/ext/dev.c +++ b/drivers/video/tegra/dc/ext/dev.c @@ -56,7 +56,9 @@ struct tegra_dc_ext_flip_data { struct tegra_dc_ext *ext; struct work_struct work; struct tegra_dc_ext_flip_win win[DC_N_WINDOWS]; +#ifndef CONFIG_ANDROID struct list_head timestamp_node; +#endif /* !CONFIG_ANDROID */ }; int tegra_dc_ext_get_num_outputs(void) @@ -208,7 +210,9 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, { int err = 0; struct tegra_dc_ext_win *ext_win = &ext->win[win->idx]; +#ifndef CONFIG_ANDROID s64 timestamp_ns; +#endif /* !CONFIG_ANDROID */ if (flip_win->handle[TEGRA_DC_Y] == NULL) { win->flags = 0; @@ -272,6 +276,7 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, msecs_to_jiffies(500), NULL); } +#ifndef CONFIG_ANDROID #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM timestamp_ns = timespec_to_ns(&flip_win->attr.timestamp); @@ -286,9 +291,12 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, } #endif return err; +#else /* !CONFIG_ANDROID */ + return 0; +#endif /* !CONFIG_ANDROID */ } -static void (*flip_callback)(void); +static int (*flip_callback)(void); static spinlock_t flip_callback_lock; static bool init_tegra_dc_flip_callback_called; @@ -301,7 +309,7 @@ static int __init init_tegra_dc_flip_callback(void) pure_initcall(init_tegra_dc_flip_callback); -int tegra_dc_set_flip_callback(void (*callback)(void)) +int tegra_dc_set_flip_callback(int (*callback)(void)) { WARN_ON(!init_tegra_dc_flip_callback_called); @@ -337,11 +345,14 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; - int j = 0, index = flip_win->attr.index; + int index = flip_win->attr.index; struct tegra_dc_win *win; struct tegra_dc_ext_win *ext_win; +#ifndef CONFIG_ANDROID + int j = 0; struct tegra_dc_ext_flip_data *temp = NULL; s64 head_timestamp = 0; +#endif /* !CONFIG_ANDROID */ if (index < 0) continue; @@ -353,6 +364,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR)) skip_flip = true; +#ifndef CONFIG_ANDROID mutex_lock(&ext_win->queue_lock); list_for_each_entry(temp, &ext_win->timestamp_queue, timestamp_node) { @@ -377,6 +389,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) if (!list_empty(&ext_win->timestamp_queue)) list_del(&data->timestamp_node); mutex_unlock(&ext_win->queue_lock); +#endif /* !CONFIG_ANDROID */ if (win->flags & TEGRA_WIN_FLAG_ENABLED) { int j; @@ -409,6 +422,9 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) flip_callback(); spin_unlock(&flip_callback_lock); } +#ifdef CONFIG_ANDROID + } +#endif /* CONFIG_ANDROID */ for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; @@ -420,7 +436,9 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work) tegra_dc_incr_syncpt_min(ext->dc, index, flip_win->syncpt_max); } +#ifndef CONFIG_ANDROID } +#endif /* !CONFIG_ANDROID */ /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { @@ -531,7 +549,9 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, struct tegra_dc_ext_flip_data *data; int work_index = -1; int i, ret = 0; +#ifndef CONFIG_ANDROID bool has_timestamp = false; +#endif /* !CONFIG_ANDROID */ #ifdef CONFIG_ANDROID int index_check[DC_N_WINDOWS] = {0, }; @@ -572,8 +592,10 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, int index = args->win[i].index; memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr)); +#ifndef CONFIG_ANDROID if (timespec_to_ns(&flip_win->attr.timestamp)) has_timestamp = true; +#endif /* !CONFIG_ANDROID */ if (index < 0) continue; @@ -648,11 +670,13 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, ret = -EINVAL; goto unlock; } +#ifndef CONFIG_ANDROID if (has_timestamp) { mutex_lock(&ext->win[work_index].queue_lock); list_add_tail(&data->timestamp_node, &ext->win[work_index].timestamp_queue); mutex_unlock(&ext->win[work_index].queue_lock); } +#endif /* !CONFIG_ANDROID */ queue_work(ext->win[work_index].flip_wq, &data->work); unlock_windows_for_flip(user, args); @@ -993,8 +1017,10 @@ static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext) } mutex_init(&win->lock); +#ifndef CONFIG_ANDROID mutex_init(&win->queue_lock); INIT_LIST_HEAD(&win->timestamp_queue); +#endif /* !CONFIG_ANDROID */ } return 0; diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h index ef7361d1d933..7238e95e59db 100644 --- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h +++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h @@ -59,9 +59,11 @@ struct tegra_dc_ext_win { atomic_t nr_pending_flips; +#ifndef CONFIG_ANDROID struct mutex queue_lock; struct list_head timestamp_queue; +#endif /* !CONFIG_ANDROID */ }; struct tegra_dc_ext { diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index 55d9163d4faf..225d48ab15ee 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -1258,6 +1258,9 @@ static bool tegra_dc_hdmi_valid_asp_ratio(const struct tegra_dc *dc, int m_aspratio = 0; int s_aspratio = 0; + if (!mode->yres) + return false; + /* To check the aspect upto two decimal digits, calculate in % */ m_aspratio = (mode->xres*100 / mode->yres); @@ -1345,7 +1348,8 @@ void tegra_dc_hdmi_detect_config(struct tegra_dc *dc, hdmi->dvi = !(specs->misc & FB_MISC_HDMI); - tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter); + if (dc->fb != NULL) + tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter); #ifdef CONFIG_SWITCH hdmi->hpd_switch.state = 0; switch_set_state(&hdmi->hpd_switch, 1); @@ -1413,11 +1417,18 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc) struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); struct fb_monspecs specs; int err; + int cnt = 0; if (!tegra_dc_hdmi_hpd(dc)) goto fail; err = tegra_edid_get_monspecs(hdmi->edid, &specs); + /* retry, maybe hdmi detect is not debounced or the monitor needs some time */ + while ( (err < 0) && (cnt++ < 4) ) { + dev_err(&dc->ndev->dev, "error reading edid, trying again in 500ms\n"); + msleep(500); + err = tegra_edid_get_monspecs(hdmi->edid, &specs); + } if (err < 0) { if (dc->out->n_modes) tegra_dc_enable(dc); diff --git a/drivers/video/tegra/dc/mode.c b/drivers/video/tegra/dc/mode.c index 3a95f2e7ab0e..f5cd4fb0cdea 100644 --- a/drivers/video/tegra/dc/mode.c +++ b/drivers/video/tegra/dc/mode.c @@ -26,6 +26,179 @@ #include "dc_reg.h" #include "dc_priv.h" +const struct fb_videomode tegra_modes[] = { + /* EDT 5.7" ET070080DH or TouchRevolution Fusion 7" */ + { + .name = "800x480", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = 30807, + .left_margin = 128, + .right_margin = 64, + .upper_margin = 22, + .lower_margin = 20, + .hsync_len = 64, + .vsync_len = 3, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .flag = FB_FLAG_RATIO_16_9, + .vmode = FB_VMODE_NONINTERLACED + }, + /* TouchRevolution Fusion 10" aka Chunghwa Picture Tubes + * CLAA100NC05 10.1 inch 1024x600 single channel LVDS panel + */ + { + .name = "1024x600", + .refresh = 60, + .xres = 1024, + .yres = 600, + .pixclock = KHZ2PICOS(48000), + .left_margin = 104, + .right_margin = 43, + .upper_margin = 24, + .lower_margin = 20, + .hsync_len = 5, + .vsync_len = 5, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .flag = FB_FLAG_RATIO_16_9, + .vmode = FB_VMODE_NONINTERLACED + }, + { + /* 1366x768 */ + .refresh = 60, + .xres = 1366, + .yres = 768, + .pixclock = KHZ2PICOS(72072), + .hsync_len = 58, /* h_sync_width */ + .vsync_len = 4, /* v_sync_width */ + .left_margin = 58, /* h_back_porch */ + .upper_margin = 4, /* v_back_porch */ + .right_margin = 58, /* h_front_porch */ + .lower_margin = 4, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + { + /* 1680x1050p 59.94/60hz */ + .refresh = 60, + .xres = 1680, + .yres = 1050, + .pixclock = KHZ2PICOS(147140), + .hsync_len = 184, /* h_sync_width */ + .vsync_len = 3, /* v_sync_width */ + .left_margin = 288, /* h_back_porch */ + .upper_margin = 33, /* v_back_porch */ + .right_margin = 104, /* h_front_porch */ + .lower_margin = 1, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + { + /* 1920x1080p 59.94/60hz CVT */ + .refresh = 60, + .xres = 1920, + .yres = 1080, + .pixclock = KHZ2PICOS(148500), + .hsync_len = 44, /* h_sync_width */ + .vsync_len = 5, /* v_sync_width */ + .left_margin = 148, /* h_back_porch */ + .upper_margin = 36, /* v_back_porch */ + .right_margin = 88, /* h_front_porch */ + .lower_margin = 4, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, + { + /* 1920x1200p 60hz */ + .refresh = 60, + .xres = 1920, + .yres = 1200, + .pixclock = KHZ2PICOS(154000), + .hsync_len = 32, /* h_sync_width */ + .vsync_len = 6, /* v_sync_width */ + .left_margin = 80, /* h_back_porch */ + .upper_margin = 26, /* v_back_porch */ + .right_margin = 48, /* h_front_porch */ + .lower_margin = 3, /* v_front_porch */ + .vmode = FB_VMODE_NONINTERLACED, + .sync = 0, + }, + /* Portrait modes */ + { + .name = "480x640", + .refresh = 60, + .xres = 480, + .yres = 640, + .pixclock = 55555, + .left_margin = 20, + .right_margin = 8, + .upper_margin = 7, + .lower_margin = 8, + .hsync_len = 4, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "540x960", + .refresh = 60, + .xres = 540, + .yres = 960, + .pixclock = 100000, + .left_margin = 32, + .right_margin = 32, + .upper_margin = 1, + .lower_margin = 2, + .hsync_len = 16, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "720x1280", + .refresh = 60, + .xres = 720, + .yres = 1280, + .pixclock = 16282, + .left_margin = 100, + .right_margin = 4, + .upper_margin = 14, + .lower_margin = 4, + .hsync_len = 4, + .vsync_len = 4, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, +}; + +/* try to find best matching mode using our modes, VESA and CEA modes from + * modedb + */ +int tegra_fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, + const char* option, unsigned int default_bpp) +{ + int out; + + out = fb_find_mode(var, info, option, tegra_modes, + ARRAY_SIZE(tegra_modes), NULL, default_bpp); + + /* Only accept this mode if we found a reasonable match (resolution) */ + if (out == 1 || out == 2) + return out; + + out = fb_find_mode(&info->var, info, option, + cea_modes, CEA_MODEDB_SIZE, NULL, default_bpp); + + /* Check if we found a full match */ + if (out == 1 || out == 2) + return out; + + return fb_find_mode(&info->var, info, option, + vesa_modes, VESA_MODEDB_SIZE, NULL, default_bpp); +} +EXPORT_SYMBOL(tegra_fb_find_mode); + + /* return non-zero if constraint is violated */ static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href) { @@ -137,6 +310,7 @@ static bool check_ref_to_sync(struct tegra_dc_mode *mode) return true; } +#ifndef CONFIG_ANDROID static s64 calc_frametime_ns(const struct tegra_dc_mode *m) { long h_total, v_total; @@ -147,6 +321,7 @@ static s64 calc_frametime_ns(const struct tegra_dc_mode *m) return (!m->pclk) ? 0 : (s64)(div_s64(((s64)h_total * v_total * 1000000000ULL), m->pclk)); } +#endif /* !CONFIG_ANDROID */ /* return in 1000ths of a Hertz */ int tegra_dc_calc_refresh(const struct tegra_dc_mode *m) @@ -270,21 +445,108 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode) { memcpy(&dc->mode, mode, sizeof(dc->mode)); + 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 + ); + if (dc->out->type == TEGRA_DC_OUT_RGB) panel_sync_rate = tegra_dc_calc_refresh(mode); else if (dc->out->type == TEGRA_DC_OUT_DSI) panel_sync_rate = dc->out->dsi->rated_refresh_rate * 1000; print_mode(dc, mode, __func__); +#ifndef CONFIG_ANDROID dc->frametime_ns = calc_frametime_ns(mode); +#endif /* !CONFIG_ANDROID */ return 0; } EXPORT_SYMBOL(tegra_dc_set_mode); +int tegra_dc_var_to_dc_mode(struct tegra_dc *dc, struct fb_var_screeninfo *var, + struct tegra_dc_mode *mode) +{ + bool stereo_mode = false; + int err; + + if (!var->pixclock) + return -EINVAL; + + mode->pclk = PICOS2KHZ(var->pixclock) * 1000; + mode->h_sync_width = var->hsync_len; + mode->v_sync_width = var->vsync_len; + mode->h_back_porch = var->left_margin; + mode->v_back_porch = var->upper_margin; + mode->h_active = var->xres; + mode->v_active = var->yres; + mode->h_front_porch = var->right_margin; + mode->v_front_porch = var->lower_margin; + mode->stereo_mode = stereo_mode; + + /* + * HACK: + * If v_front_porch is only 1, we would violate Constraint 5/6 + * in this case, increase front porch by 1 + */ + if (mode->v_front_porch <= 1) + mode->v_front_porch = 2; + + + 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 { + /* Calculate ref_to_sync signals */ + err = calc_ref_to_sync(mode); + if (err) { + dev_err(&dc->ndev->dev, "display timing ref_to_sync" + "calculation failed with code %d\n", err); + return -EINVAL; + } + dev_info(&dc->ndev->dev, "Calculated sync href=%d vref=%d\n", + mode->h_ref_to_sync, mode->v_ref_to_sync); + } + if (!check_ref_to_sync(mode)) { + dev_err(&dc->ndev->dev, + "display timing doesn't meet restrictions.\n"); + return -EINVAL; + } + +#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 = var->yres * 2 + + var->vsync_len + + var->upper_margin + + var->lower_margin; + } +#endif + + mode->flags = 0; + + if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) + mode->flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC; + + if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) + mode->flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC; + + return 0; +} +EXPORT_SYMBOL(tegra_dc_var_to_dc_mode); + +/* + * This method is only used by sysfs interface + * /sys/devices/tegradc.1/nvdps + */ int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode, bool stereo_mode) { + int err; struct tegra_dc_mode mode; if (!fbmode->pixclock) @@ -305,17 +567,28 @@ int tegra_dc_set_fb_mode(struct tegra_dc *dc, mode.h_ref_to_sync = 1; mode.v_ref_to_sync = 1; } else { - calc_ref_to_sync(&mode); + /* + * HACK: + * If v_front_porch is only 1, we would violate Constraint 5/6 + * in this case, increase front porch by 1 + */ + if (mode.v_front_porch <= 1) + mode.v_front_porch = 2; + + err = calc_ref_to_sync(&mode); + if (err) { + dev_err(&dc->ndev->dev, "display timing ref_to_sync" + "calculation failed with code %d\n", err); + return -EINVAL; + } + dev_info(&dc->ndev->dev, "Calculated sync href=%d vref=%d\n", + mode.h_ref_to_sync, mode.v_ref_to_sync); } if (!check_ref_to_sync(&mode)) { dev_err(&dc->ndev->dev, - "Display timing doesn't meet restrictions.\n"); + "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 diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c index 3566e2bd33b5..8489ebf69719 100644 --- a/drivers/video/tegra/dc/nvhdcp.c +++ b/drivers/video/tegra/dc/nvhdcp.c @@ -760,7 +760,7 @@ static int get_repeater_info(struct tegra_nvhdcp *nvhdcp) { int e, retries; u8 b_caps; - u16 b_status; + u16 b_status = 0; nvhdcp_vdbg("repeater found:fetching repeater info\n"); diff --git a/drivers/video/tegra/dc/window.c b/drivers/video/tegra/dc/window.c index cd91fab428ed..af18564f45b9 100644 --- a/drivers/video/tegra/dc/window.c +++ b/drivers/video/tegra/dc/window.c @@ -24,7 +24,9 @@ #include "dc_priv.h" static int no_vsync; +#ifndef CONFIG_ANDROID static atomic_t frame_end_ref = ATOMIC_INIT(0); +#endif /* !CONFIG_ANDROID */ module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR); @@ -41,6 +43,7 @@ static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[], return true; } +#ifndef CONFIG_ANDROID int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable) { tegra_dc_writel(dc, FRAME_END_INT, DC_CMD_INT_STATUS); @@ -51,6 +54,7 @@ int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable) tegra_dc_mask_interrupt(dc, FRAME_END_INT); return 0; } +#endif /* !CONFIG_ANDROID */ static int get_topmost_window(u32 *depths, unsigned long *wins) { @@ -418,9 +422,14 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); } else { clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); - tegra_dc_mask_interrupt(dc, V_BLANK_INT | ALL_UF_INT); + tegra_dc_mask_interrupt(dc, +#ifndef CONFIG_ANDROID + V_BLANK_INT | ALL_UF_INT); if (!atomic_read(&frame_end_ref)) tegra_dc_mask_interrupt(dc, FRAME_END_INT); +#else /* !CONFIG_ANDROID */ + FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); +#endif /* !CONFIG_ANDROID */ } if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) @@ -470,7 +479,11 @@ void tegra_dc_trigger_windows(struct tegra_dc *dc) if (!dirty) { if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) +#ifndef CONFIG_ANDROID && !atomic_read(&frame_end_ref)) +#else /* !CONFIG_ANDROID */ + ) +#endif /* !CONFIG_ANDROID */ tegra_dc_mask_interrupt(dc, FRAME_END_INT); } diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index f69048f62cc2..b7aa066751fc 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -55,9 +55,6 @@ struct tegra_fb_info { bool valid; struct resource *fb_mem; - - int xres; - int yres; }; /* palette array used by the fbcon */ @@ -75,10 +72,18 @@ static int tegra_fb_check_var(struct fb_var_screeninfo *var, info->screen_size) return -EINVAL; + fb_var_to_videomode(&mode, var); + +#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T20) || \ +defined(CONFIG_MACH_COLIBRI_T30) + /* Hack: avoid 24 Hz mode in X resulting in no display at all */ + if (mode.refresh < 50) + return -EINVAL; +#endif /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T20 | + CONFIG_MACH_COLIBRI_T30 */ + /* Apply mode filter for HDMI only -LVDS supports only fix mode */ if (ops && ops->mode_filter) { - - fb_var_to_videomode(&mode, var); if (!ops->mode_filter(dc, &mode)) return -EINVAL; @@ -87,8 +92,35 @@ static int tegra_fb_check_var(struct fb_var_screeninfo *var, } /* Double yres_virtual to allow double buffering through pan_display */ + var->xres_virtual = var->xres; var->yres_virtual = var->yres * 2; + /* we only support RGB ordering for now */ + switch (var->bits_per_pixel) { + case 32: + case 24: + var->bits_per_pixel = 32; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + case 16: + default: + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + return 0; } @@ -97,103 +129,61 @@ static int tegra_fb_set_par(struct fb_info *info) struct tegra_fb_info *tegra_fb = info->par; struct fb_var_screeninfo *var = &info->var; struct tegra_dc *dc = tegra_fb->win->dc; + int err; - if (var->bits_per_pixel) { - /* we only support RGB ordering for now */ - switch (var->bits_per_pixel) { - case 32: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8; - break; - case 16: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5; - break; - - default: - return -EINVAL; - } - /* if line_length unset, then pad the stride */ - info->fix.line_length = var->xres * var->bits_per_pixel / 8; - info->fix.line_length = round_up(info->fix.line_length, - TEGRA_LINEAR_PITCH_ALIGNMENT); - tegra_fb->win->stride = info->fix.line_length; - tegra_fb->win->stride_uv = 0; - tegra_fb->win->phys_addr_u = 0; - tegra_fb->win->phys_addr_v = 0; - } - - if (var->pixclock) { - bool stereo; - unsigned old_len = 0; - struct fb_videomode m; - struct fb_videomode *old_mode = NULL; - - fb_var_to_videomode(&m, var); + struct tegra_dc_mode mode; - /* Load framebuffer info with new mode details*/ - old_mode = info->mode; - old_len = info->fix.line_length; - - info->mode = (struct fb_videomode *) - fb_find_nearest_mode(&m, &info->modelist); - if (!info->mode) { - dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n"); - info->mode = old_mode; - return -EINVAL; - } + /* This is usually altered to 16/32 by tegra_fb_check_var + * above which is called before this function + */ + switch (var->bits_per_pixel) { + case 32: + tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8; + break; + case 16: + tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5; + break; + default: + return -EINVAL; + break; + } - /* Update fix line_length and window stride as per new mode */ - info->fix.line_length = var->xres * var->bits_per_pixel / 8; - info->fix.line_length = round_up(info->fix.line_length, - TEGRA_LINEAR_PITCH_ALIGNMENT); - tegra_fb->win->stride = info->fix.line_length; + /* if line_length unset, then pad the stride */ + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + info->fix.line_length = round_up(info->fix.line_length, + TEGRA_LINEAR_PITCH_ALIGNMENT); + tegra_fb->win->stride = info->fix.line_length; + tegra_fb->win->stride_uv = 0; + tegra_fb->win->phys_addr_u = 0; + tegra_fb->win->phys_addr_v = 0; + + tegra_fb->win->w.full = dfixed_const(var->xres); + tegra_fb->win->h.full = dfixed_const(var->yres); + tegra_fb->win->out_w = var->xres; + tegra_fb->win->out_h = var->yres; + + dev_info(&tegra_fb->ndev->dev, "switching framebuffer to %dx%d\n", + var->xres, var->yres); + + err = tegra_dc_var_to_dc_mode(dc, var, &mode); + if (err) { + dev_warn(&tegra_fb->ndev->dev, "could not convert var %d\n", err); + return -EINVAL; + } - /* - * only enable stereo if the mode supports it and - * client requests it - */ - stereo = !!(var->vmode & info->mode->vmode & -#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT - FB_VMODE_STEREO_FRAME_PACK); -#else - FB_VMODE_STEREO_LEFT_RIGHT); -#endif + err = tegra_dc_set_mode(dc, &mode); + if (err) { + dev_warn(&tegra_fb->ndev->dev, "could not set dc mode %d\n", err); + return -EINVAL; + } - /* Configure DC with new mode */ - if (tegra_dc_set_fb_mode(dc, info->mode, stereo)) { - /* Error while configuring DC, fallback to old mode */ - dev_warn(&tegra_fb->ndev->dev, "can't configure dc with mode %ux%u\n", - info->mode->xres, info->mode->yres); - info->mode = old_mode; - info->fix.line_length = old_len; - tegra_fb->win->stride = old_len; - return -EINVAL; - } + /* Reflect changes on HW */ + if (dc->enabled) + tegra_dc_disable(dc); + tegra_dc_enable(dc); - /* Reflect mode chnage on DC HW */ - if (dc->enabled) - tegra_dc_disable(dc); - tegra_dc_enable(dc); + return err; - tegra_fb->win->w.full = dfixed_const(info->mode->xres); - tegra_fb->win->h.full = dfixed_const(info->mode->yres); - tegra_fb->win->out_w = info->mode->xres; - tegra_fb->win->out_h = info->mode->yres; - } - return 0; } static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -417,6 +407,9 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long } int tegra_fb_get_mode(struct tegra_dc *dc) { + /* Avoid error when reading sysfs */ + if (dc->fb->info->mode == NULL) + return 0; return dc->fb->info->mode->refresh; } @@ -532,13 +525,11 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, /* Prepare a mode db */ for (i = 0; i < specs->modedb_len; i++) { if (info->fbops->fb_check_var) { - struct fb_videomode m; - /* Call mode filter to check mode */ fb_videomode_to_var(&var, &specs->modedb[i]); if (!(info->fbops->fb_check_var(&var, info))) { - fb_var_to_videomode(&m, &var); - fb_add_videomode(&m, + fb_var_to_videomode(&specs->modedb[i], &var); + fb_add_videomode(&specs->modedb[i], &fb_info->info->modelist); /* EDID stds recommend first detailed mode to be applied as default,but if first mode @@ -584,6 +575,106 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info, mutex_unlock(&fb_info->info->lock); } +struct tegra_dc_out_pin dc_out_pins[4]; + + +static int parse_opt(struct tegra_dc_out *out, char *this_opt) +{ + if (!strncmp(this_opt, "hsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } else if (!strncmp(this_opt, "vsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } else if (!strncmp(this_opt, "outputen:", 9)) { + if (simple_strtoul(this_opt+9, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } else if (!strncmp(this_opt, "pixclockpol:", 12)) { + if (simple_strtoul(this_opt+12, NULL, 0) == 0) { + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = + TEGRA_DC_OUT_PIN_POL_LOW; + } else { + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = + TEGRA_DC_OUT_PIN_POL_HIGH; + } + return 0; + } + + return -1; +} + +static void tegra_dc_copy_pin_modes(struct tegra_dc_out *out) +{ + int i; + struct tegra_dc_out_pin *def = out->out_pins; + int n_out_pins_default = out->n_out_pins; + + /* Allocate memory for dynamic output pin configuration... */ + out->n_out_pins = 4; + out->out_pins = kmalloc(sizeof(struct tegra_dc_out_pin) * out->n_out_pins, + GFP_KERNEL); + + /* ...set fallback values, we use the pin enum as array index... */ + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].name = TEGRA_DC_OUT_PIN_DATA_ENABLE; + out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = TEGRA_DC_OUT_PIN_POL_HIGH; + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].name = TEGRA_DC_OUT_PIN_H_SYNC; + out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = TEGRA_DC_OUT_PIN_POL_LOW; + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].name = TEGRA_DC_OUT_PIN_V_SYNC; + out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = TEGRA_DC_OUT_PIN_POL_LOW; + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK; + out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = TEGRA_DC_OUT_PIN_POL_LOW; + + /* ... and copy the static default config from platform data */ + for (i = 0; i < n_out_pins_default; i++) + out->out_pins[def[i].name].pol = def[i].pol; +} + +static int tegra_parse_options(struct tegra_dc_out *out, struct fb_info *info, + char *option) +{ + char *this_opt; + + /* This off option works perfectly for framebuffer + * device, however the tegra binary driver somehow + * has troubles to handle a missing fb0 + * (then, dc1 gets remapped to fb0, which seems + * to be an issue for the binary driver)... + */ + if (!strcmp(option, "off")) + return -ENODEV; + + while ((this_opt = strsep(&option, ",")) != NULL) { + /* Parse driver specific arguments for RGB output */ + if (out->type == TEGRA_DC_OUT_RGB) { + if (parse_opt(out, this_opt) == 0) + continue; + } + + /* No valid driver specific argument, has to be mode */ + if (!tegra_fb_find_mode(&info->var, info, this_opt, 16)) + return -EINVAL; + } + return 0; +} + struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, struct tegra_dc *dc, struct tegra_fb_data *fb_data, @@ -597,6 +688,9 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, unsigned long fb_phys = 0; int ret = 0; unsigned stride; + char *param_option = NULL; + char *option = NULL; + char driver[10]; win = tegra_dc_get_window(dc, fb_data->win); if (!win) { @@ -615,8 +709,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, tegra_fb->win = win; tegra_fb->ndev = ndev; tegra_fb->fb_mem = fb_mem; - tegra_fb->xres = fb_data->xres; - tegra_fb->yres = fb_data->yres; if (fb_mem) { fb_size = resource_size(fb_mem); @@ -653,6 +745,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, info->var.xres_virtual = fb_data->xres; info->var.yres_virtual = fb_data->yres * 2; info->var.bits_per_pixel = fb_data->bits_per_pixel; + info->var.activate = FB_ACTIVATE_VBL; info->var.height = tegra_dc_get_out_height(dc); info->var.width = tegra_dc_get_out_width(dc); @@ -665,11 +758,11 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, info->var.vsync_len = 0; info->var.vmode = FB_VMODE_NONINTERLACED; + /* window settings */ win->x.full = dfixed_const(0); win->y.full = dfixed_const(0); win->w.full = dfixed_const(fb_data->xres); win->h.full = dfixed_const(fb_data->yres); - /* TODO: set to output res dc */ win->out_x = 0; win->out_y = 0; win->out_w = fb_data->xres; @@ -683,6 +776,32 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, win->stride_uv = 0; win->flags = TEGRA_WIN_FLAG_ENABLED; + /* Set/copy default pin modes, if output is RGB... */ + if (dc->out->type == TEGRA_DC_OUT_RGB) + tegra_dc_copy_pin_modes(dc->out); + + /* try to use kernel cmd line specified mode */ + sprintf(driver, "tegrafb%d", ndev->id); + fb_get_options(driver, ¶m_option); + if (param_option != NULL) { + option = param_option; + dev_info(&ndev->dev, "use cmd options for %s: %s\n", + driver, option); + } else { + option = dc->out->default_mode; + dev_info(&ndev->dev, "use default mode for %s: %s\n", + driver, option); + } + + if (option != NULL) { + ret = tegra_parse_options(dc->out, info, option); + if (ret < 0) + goto err_iounmap_fb; + } + + /* Activate current settings (tegra_fb_find_mode has call + * tegra_fb_check_var already) + */ if (fb_mem) tegra_fb_set_par(info); @@ -701,26 +820,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, tegra_dc_sync_windows(&tegra_fb->win, 1); } - if (dc->mode.pclk > 1000) { - struct tegra_dc_mode *mode = &dc->mode; - struct fb_videomode vmode; - - if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) - info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000); - else - info->var.pixclock = KHZ2PICOS(mode->pclk / 1000); - info->var.left_margin = mode->h_back_porch; - info->var.right_margin = mode->h_front_porch; - info->var.upper_margin = mode->v_back_porch; - info->var.lower_margin = mode->v_front_porch; - info->var.hsync_len = mode->h_sync_width; - info->var.vsync_len = mode->v_sync_width; - - /* Keep info->var consistent with info->modelist. */ - fb_var_to_videomode(&vmode, &info->var); - fb_add_videomode(&vmode, &info->modelist); - } - return tegra_fb; err_iounmap_fb: diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c index 4614689ec37c..2b92a62cc0bc 100644 --- a/drivers/video/tegra/host/bus_client.c +++ b/drivers/video/tegra/host/bus_client.c @@ -611,6 +611,7 @@ fail: nvhost_free_channel(ch); return err; } +EXPORT_SYMBOL(nvhost_client_device_init); int nvhost_client_device_suspend(struct nvhost_device *dev) { @@ -658,6 +659,7 @@ fail: return -ENXIO; } +EXPORT_SYMBOL(nvhost_client_device_get_resources); void nvhost_client_device_put_resources(struct nvhost_device *dev) { @@ -670,3 +672,4 @@ void nvhost_client_device_put_resources(struct nvhost_device *dev) release_mem_region(r->start, resource_size(r)); } +EXPORT_SYMBOL(nvhost_client_device_put_resources); diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c index 5bde55ad2ff5..f22c91ac03f1 100644 --- a/drivers/video/tegra/host/nvhost_acm.c +++ b/drivers/video/tegra/host/nvhost_acm.c @@ -639,8 +639,10 @@ void nvhost_module_busy_ext(struct nvhost_device *dev) { nvhost_module_busy(dev); } +EXPORT_SYMBOL(nvhost_module_busy_ext); void nvhost_module_idle_ext(struct nvhost_device *dev) { nvhost_module_idle(dev); } +EXPORT_SYMBOL(nvhost_module_idle_ext); diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c index 38c28ca116e7..de3e04f65cdd 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.c +++ b/drivers/video/tegra/host/nvhost_syncpt.c @@ -493,12 +493,14 @@ void nvhost_syncpt_cpu_incr_ext(struct nvhost_device *dev, u32 id) struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); nvhost_syncpt_cpu_incr(sp, id); } +EXPORT_SYMBOL(nvhost_syncpt_cpu_incr_ext); u32 nvhost_syncpt_read_ext(struct nvhost_device *dev, u32 id) { struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); return nvhost_syncpt_read(sp, id); } +EXPORT_SYMBOL(nvhost_syncpt_read_ext); int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh, u32 timeout, u32 *value) @@ -506,3 +508,4 @@ int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value); } +EXPORT_SYMBOL(nvhost_syncpt_wait_timeout_ext); diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c index 19b821d41284..e66ca982f2f3 100644 --- a/drivers/video/tegra/nvmap/nvmap.c +++ b/drivers/video/tegra/nvmap/nvmap.c @@ -387,6 +387,7 @@ phys_addr_t nvmap_pin(struct nvmap_client *client, return ret ?: phys; } +EXPORT_SYMBOL(nvmap_pin); phys_addr_t nvmap_handle_address(struct nvmap_client *c, unsigned long id) { @@ -413,6 +414,7 @@ void nvmap_unpin(struct nvmap_client *client, struct nvmap_handle_ref *ref) if (handle_unpin(client, ref->handle, false)) wake_up(&client->share->pin_wait); } +EXPORT_SYMBOL(nvmap_unpin); void nvmap_unpin_handles(struct nvmap_client *client, struct nvmap_handle **h, int nr) @@ -501,6 +503,7 @@ void *nvmap_mmap(struct nvmap_handle_ref *ref) * nvmap_handle_put will be called by unmapping this address */ return p; } +EXPORT_SYMBOL(nvmap_mmap); void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr) { @@ -523,6 +526,7 @@ void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr) } nvmap_handle_put(h); } +EXPORT_SYMBOL(nvmap_munmap); struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size, size_t align, unsigned int flags, @@ -550,6 +554,7 @@ struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size, return r; } +EXPORT_SYMBOL(nvmap_alloc); /* allocates memory with specifed iovm_start address. */ struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client, @@ -605,6 +610,7 @@ void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r) nvmap_free_handle_id(client, nvmap_ref_to_id(r)); } +EXPORT_SYMBOL(nvmap_free); int nvmap_mark_global(struct nvmap_client *client, struct nvmap_handle_ref *r) { diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c index 3b0db14f16ca..3ea7bd2ea797 100644 --- a/drivers/video/tegra/nvmap/nvmap_dev.c +++ b/drivers/video/tegra/nvmap/nvmap_dev.c @@ -87,6 +87,7 @@ struct nvmap_device { }; struct nvmap_device *nvmap_dev; +EXPORT_SYMBOL(nvmap_dev); static struct backing_dev_info nvmap_bdi = { .ra_pages = 0, @@ -670,6 +671,7 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev, spin_unlock(&dev->clients_lock); return client; } +EXPORT_SYMBOL(nvmap_create_client); static void destroy_client(struct nvmap_client *client) { @@ -756,6 +758,7 @@ void nvmap_client_put(struct nvmap_client *client) if (!atomic_dec_return(&client->count)) destroy_client(client); } +EXPORT_SYMBOL(nvmap_client_put); static int nvmap_open(struct inode *inode, struct file *filp) { diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c index 4b7760b22190..c1add8383e83 100644 --- a/drivers/video/tegra/nvmap/nvmap_handle.c +++ b/drivers/video/tegra/nvmap/nvmap_handle.c @@ -572,9 +572,10 @@ static int handle_page_alloc(struct nvmap_client *client, #ifdef CONFIG_NVMAP_PAGE_POOLS struct nvmap_page_pool *pool = NULL; struct nvmap_share *share = nvmap_get_share_from_dev(h->dev); + unsigned long paddr; #endif gfp_t gfp = GFP_NVMAP; - unsigned long kaddr, paddr; + unsigned long kaddr; pte_t **pte = NULL; if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES) { |