Merge branch linux-tegra-2.6.36 into android-tegra-2.6.36

Change-Id: I0d4216b0a407e50c029a6c0869d727b188f7da04
This commit is contained in:
Erik Gilling 2010-10-26 18:22:24 -07:00
commit 588ff569ea
10 changed files with 324 additions and 96 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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