diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index b2f2b0fb681e..ffba4441a99b 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -101,8 +101,6 @@ #define TEGRA_SYSTEM_DMA_CH_MAX \ (TEGRA_SYSTEM_DMA_CH_NR - TEGRA_SYSTEM_DMA_AVP_CH_NUM - 1) -#define NV_DMA_MAX_TRASFER_SIZE 0x10000 - const unsigned int ahb_addr_wrap_table[8] = { 0, 32, 64, 128, 256, 512, 1024, 2048 }; @@ -326,7 +324,7 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, unsigned long irq_flags; int start_dma = 0; - if (req->size > NV_DMA_MAX_TRASFER_SIZE || + if (req->size > TEGRA_DMA_MAX_TRANSFER_SIZE || req->source_addr & 0x3 || req->dest_addr & 0x3) { pr_err("Invalid DMA request for channel %d\n", ch->id); return -EINVAL; @@ -365,7 +363,8 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode) channel = find_first_zero_bit(channel_usage, ARRAY_SIZE(dma_channels)); if (channel >= ARRAY_SIZE(dma_channels)) { - pr_err("%s: failed to allocate a DMA channel",__func__); + pr_err("%s: failed to allocate a DMA channel", + __func__); goto out; } } @@ -574,18 +573,20 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch) if (req) { if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) { bool is_dma_ping_complete; - is_dma_ping_complete = (readl(ch->addr + APB_DMA_CHAN_STA) - & STA_PING_PONG) ? true : false; - if( req->to_memory ) + is_dma_ping_complete = + !!(readl(ch->addr + APB_DMA_CHAN_STA) & + STA_PING_PONG); + if (req->to_memory) is_dma_ping_complete = !is_dma_ping_complete; /* Out of sync - Release current buffer */ - if( !is_dma_ping_complete ) { + if (!is_dma_ping_complete) { int bytes_transferred; bytes_transferred = ch->req_transfer_count; bytes_transferred += 1; bytes_transferred <<= 3; - req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL; + req->buffer_status = + TEGRA_DMA_REQ_BUF_STATUS_FULL; req->bytes_transferred = bytes_transferred; req->status = TEGRA_DMA_REQ_SUCCESS; tegra_dma_stop(ch); @@ -598,13 +599,14 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch) list_del(&req->node); - /* DMA lock is NOT held when callbak is called */ + /* DMA lock is NOT held when callbak is + * called. */ spin_unlock_irqrestore(&ch->lock, irq_flags); req->complete(req); return; } - /* Load the next request into the hardware, if available - * */ + /* Load the next request into the hardware, if + * available. */ if (!list_is_last(&req->node, &ch->list)) { next_req = list_entry(req->node.next, typeof(*next_req), node); @@ -637,8 +639,10 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch) /* It may be possible that req came after * half dma complete so it need to start * immediately */ - next_req = list_entry(req->node.next, typeof(*next_req), node); - if (next_req->status != TEGRA_DMA_REQ_INFLIGHT) { + next_req = list_entry(req->node.next, + typeof(*next_req), node); + if (next_req->status != + TEGRA_DMA_REQ_INFLIGHT) { tegra_dma_stop(ch); tegra_dma_update_hw(ch, next_req); } diff --git a/arch/arm/mach-tegra/headsmp-t2.S b/arch/arm/mach-tegra/headsmp-t2.S index e25a3597f7fc..9da0ed68e63d 100644 --- a/arch/arm/mach-tegra/headsmp-t2.S +++ b/arch/arm/mach-tegra/headsmp-t2.S @@ -41,6 +41,13 @@ #define PMC_SCRATCH39 0x138 #define RST_DEVICES_U 0xc +#define CLK_RESET_PLLX_BASE 0xe0 +#define CLK_RESET_PLLX_MISC 0xe4 +#define CLK_RESET_PLLP_BASE 0xa0 +#define CLK_RESET_PLLP_OUTA 0xa4 +#define CLK_RESET_PLLP_OUTB 0xa8 +#define CLK_RESET_PLLP_MISC 0xac + /* .section ".cpuinit.text", "ax"*/ .macro poke_ev, val, tmp @@ -66,26 +73,38 @@ ENDPROC(tegra_secondary_startup) #endif /* - * __restart_pllx + * __restart_plls * - * Loads the saved PLLX parameters from tegra_sctx into PLLX, to - * allow it to stabilize while the rest of the CPU state is restored. + * Loads the saved PLLX and PLLP parameters into the PLLs, to + * allow them to stabilize while the rest of the CPU state is restored. * Should be called after the MMU is enabled. Jumps directly * to __cortex_a9_restore */ .align L1_CACHE_SHIFT -__restart_pllx: +__restart_plls: mov32 r0, tegra_sctx - ldr r1, [r0, #0x8] @ pllx_base - ldr r2, [r0, #0xC] @ pllx_misc mov32 r3, (TEGRA_CLK_RESET_BASE-IO_PPSB_PHYS+IO_PPSB_VIRT) mov32 r4, (TEGRA_TMRUS_BASE-IO_PPSB_PHYS+IO_PPSB_VIRT) - str r2, [r3, #0xe4] @ pllx_misc - str r1, [r3, #0xe0] @ pllx_base - /* record the time that PLLX will be stable */ + + ldr r1, [r0, #0x0] @ pllx_misc + ldr r2, [r0, #0x4] @ pllx_base + str r1, [r3, #CLK_RESET_PLLX_MISC] + str r2, [r3, #CLK_RESET_PLLX_BASE] + + ldr r1, [r0, #0x8] @ pllp_misc + ldr r2, [r0, #0xc] @ pllp_base + str r1, [r3, #CLK_RESET_PLLP_MISC] + str r2, [r3, #CLK_RESET_PLLP_BASE] + + ldr r1, [r0, #0x10] @ pllp_outa + ldr r2, [r0, #0x14] @ pllp_outb + str r1, [r3, #CLK_RESET_PLLP_OUTA] + str r2, [r3, #CLK_RESET_PLLP_OUTB] + + /* record the time that PLLX and PLLP will be stable */ ldr r1, [r4] add r1, r1, #300 - str r1, [r0, #0x10] + str r1, [r0, #0x18] @ pll_timeout /* FIXME: need to record actual power transition here */ mov r0, #0 b __cortex_a9_l2x0_restart @@ -156,7 +175,7 @@ ENDPROC(tegra_lp2_startup) __tegra_lp2_data: .long . .long tegra_pgd_phys - .long __restart_pllx + .long __restart_plls .size __tegra_lp2_data, . - __tegra_lp2_data #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h index 81e62782bac7..243050693eec 100644 --- a/arch/arm/mach-tegra/include/mach/dma.h +++ b/arch/arm/mach-tegra/include/mach/dma.h @@ -56,6 +56,8 @@ struct tegra_dma_channel; #define TEGRA_DMA_REQ_SEL_OWR 25 #define TEGRA_DMA_REQ_SEL_INVALID 31 +#define TEGRA_DMA_MAX_TRANSFER_SIZE 0x10000 + enum tegra_dma_mode { TEGRA_DMA_SHARED = 1, TEGRA_DMA_MODE_CONTINUOUS = 2, diff --git a/arch/arm/mach-tegra/suspend.c b/arch/arm/mach-tegra/suspend.c index 06bafa1c45c6..aef50319852c 100644 --- a/arch/arm/mach-tegra/suspend.c +++ b/arch/arm/mach-tegra/suspend.c @@ -53,15 +53,21 @@ #include "board.h" #include "power.h" -/* NOTE: only add elements to the end of this structure, since the assembly - * code uses hard-coded offsets */ -struct suspend_context -{ +struct suspend_context { + /* + * The next 7 values are referenced by offset in __restart_plls + * in headsmp-t2.S, and should not be moved + */ + u32 pllx_misc; + u32 pllx_base; + u32 pllp_misc; + u32 pllp_base; + u32 pllp_outa; + u32 pllp_outb; + u32 pll_timeout; + u32 cpu_burst; u32 clk_csite_src; - u32 pllx_base; - u32 pllx_misc; - u32 pllx_timeout; u32 twd_ctrl; u32 twd_load; u32 cclk_divider; @@ -101,6 +107,11 @@ static void __iomem *tmrus = IO_ADDRESS(TEGRA_TMRUS_BASE); #define CLK_RESET_PLLM_BASE 0x90 #define CLK_RESET_PLLX_BASE 0xe0 #define CLK_RESET_PLLX_MISC 0xe4 +#define CLK_RESET_PLLP_BASE 0xa0 +#define CLK_RESET_PLLP_OUTA 0xa4 +#define CLK_RESET_PLLP_OUTB 0xa8 +#define CLK_RESET_PLLP_MISC 0xac + #define CLK_RESET_SOURCE_CSITE 0x1d4 @@ -256,7 +267,7 @@ static noinline void restore_cpu_complex(void) BUG_ON(readl(clk_rst + CLK_RESET_PLLX_BASE) != tegra_sctx.pllx_base); if (tegra_sctx.pllx_base & (1<<30)) { - while (readl(tmrus)-tegra_sctx.pllx_timeout >= 0x80000000UL) + while (readl(tmrus)-tegra_sctx.pll_timeout >= 0x80000000UL) cpu_relax(); } writel(tegra_sctx.cclk_divider, clk_rst + CLK_RESET_CCLK_DIVIDER); @@ -295,6 +306,10 @@ static noinline void suspend_cpu_complex(void) tegra_sctx.cpu_burst = readl(clk_rst + CLK_RESET_CCLK_BURST); tegra_sctx.pllx_base = readl(clk_rst + CLK_RESET_PLLX_BASE); tegra_sctx.pllx_misc = readl(clk_rst + CLK_RESET_PLLX_MISC); + tegra_sctx.pllp_base = readl(clk_rst + CLK_RESET_PLLP_BASE); + tegra_sctx.pllp_outa = readl(clk_rst + CLK_RESET_PLLP_OUTA); + tegra_sctx.pllp_outb = readl(clk_rst + CLK_RESET_PLLP_OUTB); + tegra_sctx.pllp_misc = readl(clk_rst + CLK_RESET_PLLP_MISC); tegra_sctx.cclk_divider = readl(clk_rst + CLK_RESET_CCLK_DIVIDER); #ifdef CONFIG_HAVE_ARM_TWD diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 4a9e3e0b7f2e..253de093a8ef 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -2053,7 +2053,7 @@ void __init tegra2_init_clocks(void) #ifdef CONFIG_PM static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM + - PERIPH_CLK_SOURCE_NUM + 19]; + PERIPH_CLK_SOURCE_NUM + 15]; void tegra_clk_suspend(void) { @@ -2061,16 +2061,12 @@ void tegra_clk_suspend(void) u32 *ctx = clk_rst_suspend; *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK; - *ctx++ = clk_readl(tegra_pll_p.reg + PLL_BASE); - *ctx++ = clk_readl(tegra_pll_p.reg + PLL_MISC(&tegra_pll_p)); *ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE); *ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c)); *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE); *ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a)); *ctx++ = clk_readl(tegra_pll_m_out1.reg); - *ctx++ = clk_readl(tegra_pll_p_out1.reg); - *ctx++ = clk_readl(tegra_pll_p_out3.reg); *ctx++ = clk_readl(tegra_pll_a_out0.reg); *ctx++ = clk_readl(tegra_pll_c_out1.reg); @@ -2110,8 +2106,6 @@ void tegra_clk_resume(void) val |= *ctx++; clk_writel(val, OSC_CTRL); - clk_writel(*ctx++, tegra_pll_p.reg + PLL_BASE); - clk_writel(*ctx++, tegra_pll_p.reg + PLL_MISC(&tegra_pll_p)); clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE); clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c)); clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE); @@ -2119,8 +2113,6 @@ void tegra_clk_resume(void) udelay(300); clk_writel(*ctx++, tegra_pll_m_out1.reg); - clk_writel(*ctx++, tegra_pll_p_out1.reg); - clk_writel(*ctx++, tegra_pll_p_out3.reg); clk_writel(*ctx++, tegra_pll_a_out0.reg); clk_writel(*ctx++, tegra_pll_c_out1.reg); diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c index 0b0b1a760a4e..812a0087a96d 100644 --- a/drivers/video/tegra/dc/edid.c +++ b/drivers/video/tegra/dc/edid.c @@ -15,31 +15,181 @@ * */ -#include +#define DEBUG + +#include #include +#include +#include +#include #include "edid.h" +struct tegra_edid { + struct i2c_client *client; + struct i2c_board_info info; + int bus; + + u8 *data; + unsigned len; +}; + +#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) +static int tegra_edid_show(struct seq_file *s, void *unused) +{ + struct tegra_edid *edid = s->private; + int i; + + for (i = 0; i < edid->len; i++) { + if (i % 16 == 0) + seq_printf(s, "edid[%03x] =", i); + + seq_printf(s, " %02x", edid->data[i]); + + if (i % 16 == 15) + seq_printf(s, "\n"); + } + + return 0; +} +#endif + +#ifdef CONFIG_DEBUG_FS +static int tegra_edid_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, tegra_edid_show, inode->i_private); +} + +static const struct file_operations tegra_edid_debug_fops = { + .open = tegra_edid_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void tegra_edid_debug_add(struct tegra_edid *edid) +{ + char name[] = "edidX"; + + snprintf(name, sizeof(name), "edid%1d", edid->bus); + debugfs_create_file(name, S_IRUGO, NULL, edid, &tegra_edid_debug_fops); +} +#else +void tegra_edid_debug_add(struct tegra_edid *edid) +{ +} +#endif + +#ifdef DEBUG +static char tegra_edid_dump_buff[16 * 1024]; + +static void tegra_edid_dump(struct tegra_edid *edid) +{ + struct seq_file s; + int i; + char c; + + memset(&s, 0x0, sizeof(s)); + + s.buf = tegra_edid_dump_buff; + s.size = sizeof(tegra_edid_dump_buff); + s.private = edid; + + tegra_edid_show(&s, NULL); + + i = 0; + while (i < s.count ) { + if ((s.count - i) > 256) { + c = s.buf[i + 256]; + s.buf[i + 256] = 0; + printk("%s", s.buf + i); + s.buf[i + 256] = c; + } else { + printk("%s", s.buf + i); + } + i += 256; + } +} +#else +static void tegra_edid_dump(struct tegra_edid *edid) +{ +} +#endif + +int tegra_edid_read_block(struct tegra_edid *edid, int block, u8 *data) +{ + u8 block_buf[] = {block >> 1}; + u8 cmd_buf[] = {(block & 0x1) * 128}; + int status; + struct i2c_msg msg[] = { + { + .addr = 0x30, + .flags = 0, + .len = 1, + .buf = block_buf, + }, + { + .addr = 0x50, + .flags = 0, + .len = 1, + .buf = cmd_buf, + }, + { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 128, + .buf = data, + }}; + struct i2c_msg *m; + int msg_len; + + if (block > 1) { + msg_len = 3; + m = msg; + } else { + msg_len = 2; + m = &msg[1]; + } + + status = i2c_transfer(edid->client->adapter, m, msg_len); + + if (status < 0) + return status; + + if (status != msg_len) + return -EIO; + + return 0; +} + + int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs) { - u8 data[256]; int i; int ret; + int extension_blocks; - for (i = 0; i < 256; i++) { - ret = i2c_smbus_read_byte_data(edid->client, i); + ret = tegra_edid_read_block(edid, 0, edid->data); + + memset(specs, 0x0, sizeof(struct fb_monspecs)); + fb_edid_to_monspecs(edid->data, specs); + if (specs->modedb == NULL) + return -EINVAL; + + extension_blocks = edid->data[0x7e]; + + for (i = 1; i <= extension_blocks; i++) { + ret = tegra_edid_read_block(edid, i, edid->data + i * 128); if (ret < 0) break; - data[i] = ret; + if (edid->data[i * 128] == 0x2) + fb_edid_add_monspecs(edid->data + i * 128, specs); } - if (i != 128 && i != 256) - return ret; + edid->len = i * 128; - fb_edid_to_monspecs(data, specs); - if (i == 256) - fb_edid_add_monspecs(data + 128, specs); + tegra_edid_dump(edid); return 0; } @@ -48,36 +198,53 @@ struct tegra_edid *tegra_edid_create(int bus) { struct tegra_edid *edid; struct i2c_adapter *adapter; + int err; edid = kzalloc(sizeof(struct tegra_edid), GFP_KERNEL); if (!edid) return ERR_PTR(-ENOMEM); + edid->data = vmalloc(SZ_32K); + if (!edid->data) { + err = -ENOMEM; + goto free_edid; + } strlcpy(edid->info.type, "tegra_edid", sizeof(edid->info.type)); + edid->bus = bus; edid->info.addr = 0x50; edid->info.platform_data = edid; - init_waitqueue_head(&edid->wq); adapter = i2c_get_adapter(bus); if (!adapter) { pr_err("can't get adpater for bus %d\n", bus); - return NULL; + err = -EBUSY; + goto free_edid; } - edid->client = i2c_new_device(adapter, &edid->info); + edid->client = i2c_new_device(adapter, &edid->info); i2c_put_adapter(adapter); if (!edid->client) { pr_err("can't create new device\n"); - return NULL; + err = -EBUSY; + goto free_edid; } + tegra_edid_debug_add(edid); + return edid; + +free_edid: + vfree(edid->data); + kfree(edid); + + return ERR_PTR(err); } void tegra_edid_destroy(struct tegra_edid *edid) { i2c_release_client(edid->client); + vfree(edid->data); kfree(edid); } diff --git a/drivers/video/tegra/dc/edid.h b/drivers/video/tegra/dc/edid.h index eb78abb7e7d8..821da90a8b4f 100644 --- a/drivers/video/tegra/dc/edid.h +++ b/drivers/video/tegra/dc/edid.h @@ -21,13 +21,7 @@ #include #include -struct tegra_edid { - struct i2c_client *client; - struct i2c_board_info info; - - int probed; - wait_queue_head_t wq; -}; +struct tegra_edid; struct tegra_edid *tegra_edid_create(int bus); void tegra_edid_destroy(struct tegra_edid *edid); diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index 58ad135b90cc..acc3b36ea046 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -391,23 +391,26 @@ static void hdmi_dumpregs(struct tegra_dc_hdmi_data *hdmi) static bool tegra_dc_hdmi_mode_equal(const struct fb_videomode *mode1, const struct fb_videomode *mode2) { - int diff = (s64)mode1->pixclock - (s64)mode2->pixclock; - return mode1->xres == mode2->xres && mode1->yres == mode2->yres && - diff < PIXCLOCK_TOLERANCE && - diff > -PIXCLOCK_TOLERANCE && mode1->vmode == mode2->vmode; } static bool tegra_dc_hdmi_mode_filter(struct fb_videomode *mode) { int i; + int clocks; for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_modes); i++) { if (tegra_dc_hdmi_mode_equal(&tegra_dc_hdmi_supported_modes[i], - mode)) + mode)) { + memcpy(mode, &tegra_dc_hdmi_supported_modes[i], sizeof(*mode)); + mode->flag = FB_MODE_IS_DETAILED; + clocks = (mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len) * + (mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len); + mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000) / clocks; return true; + } } return false; diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index ef4e4c3e3708..1d518a561242 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -120,36 +120,35 @@ 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; - /* we only support RGB ordering for now */ - switch (var->bits_per_pixel) { - case 32: - case 24: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.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; + if (var->bits_per_pixel) { + /* we only support RGB ordering for now */ + switch (var->bits_per_pixel) { + case 32: + case 24: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 16; + var->blue.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; - case 0: - break; - - default: - return -EINVAL; + default: + return -EINVAL; + } + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + tegra_fb->win->stride = info->fix.line_length; } - info->fix.line_length = var->xres * var->bits_per_pixel / 8; - tegra_fb->win->stride = info->fix.line_length; if (var->pixclock) { struct tegra_dc_mode mode; @@ -499,6 +498,9 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long { struct tegra_fb_info *tegra_fb = info->par; struct tegra_fb_flip_args flip_args; + struct tegra_fb_modedb modedb; + struct fb_modelist *modelist; + int i; int fd; int ret; @@ -520,6 +522,29 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long return ret; + case FBIO_TEGRA_GET_MODEDB: + if (copy_from_user(&modedb, (void __user *)arg, sizeof(modedb))) + return -EFAULT; + + i = 0; + list_for_each_entry(modelist, &info->modelist, list) { + struct fb_var_screeninfo var; + + if (i >= modedb.modedb_len) + break; + fb_videomode_to_var(&var, &modelist->mode); + + if (copy_to_user((void __user *)&modedb.modedb[i], + &var, sizeof(var))) + return -EFAULT; + i++; + } + modedb.modedb_len = i; + + if (copy_to_user((void __user *)arg, &modedb, sizeof(modedb))) + return -EFAULT; + break; + default: return -ENOTTY; } diff --git a/include/video/tegrafb.h b/include/video/tegrafb.h index 3d7a5a9d66e9..79578c3d7bd4 100644 --- a/include/video/tegrafb.h +++ b/include/video/tegrafb.h @@ -18,6 +18,7 @@ #ifndef _LINUX_TEGRAFB_H_ #define _LINUX_TEGRAFB_H_ +#include #include #include @@ -77,7 +78,13 @@ struct tegra_fb_flip_args { __u32 post_syncpt_val; }; +struct tegra_fb_modedb { + struct fb_var_screeninfo *modedb; + __u32 modedb_len; +}; + #define FBIO_TEGRA_SET_NVMAP_FD _IOW('F', 0x40, __u32) #define FBIO_TEGRA_FLIP _IOW('F', 0x41, struct tegra_fb_flip_args) +#define FBIO_TEGRA_GET_MODEDB _IOWR('F', 0x42, struct tegra_fb_modedb) #endif