mirror of
https://github.com/torvalds/linux.git
synced 2026-06-10 15:42:19 +02:00
Merge branch linux-tegra-2.6.36 into android-tegra-2.6.36
Change-Id: I0d4216b0a407e50c029a6c0869d727b188f7da04
This commit is contained in:
commit
588ff569ea
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,31 +15,181 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#define DEBUG
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef _LINUX_TEGRAFB_H_
|
||||
#define _LINUX_TEGRAFB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/ioctl.h>
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user