Merge branch 'android-tegra' into android-tegra-moto

This commit is contained in:
Erik Gilling 2011-02-24 17:18:22 -08:00
commit 5257d707de
22 changed files with 1736 additions and 134 deletions

View File

@ -1129,6 +1129,16 @@ config ARM_ERRATA_743622
visible impact on the overall performance or power consumption of the
processor.
config ARM_ERRATA_720791
bool "ARM errata: Dynamic high-level clock gating corrupts the Jazelle instruction stream"
depends on CPU_V7
help
This option enables the workaround for the 720791 Cortex-A9
(r1p0..r1p2) erratum. The Jazelle instruction stream may be
corrupted when dynamic high-level clock gating is enabled.
This workaround disables gating the Core clock when the Instruction
side is waiting for a Page Table Walk answer or linefill completion.
endmenu
source "arch/arm/common/Kconfig"

View File

@ -54,6 +54,7 @@
#define L2X0_LINE_TAG 0xF30
#define L2X0_DEBUG_CTRL 0xF40
#define L2X0_PREFETCH_OFFSET 0xF60
#define L2X0_PWR_CTRL 0xF80
#ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);

View File

@ -1,4 +1,5 @@
obj-y += common.o
obj-y += apbio.o
obj-y += io.o
obj-y += irq.o legacy_irq.o
obj-y += syncpt.o
@ -12,6 +13,7 @@ obj-y += delay.o
obj-y += powergate.o
obj-y += suspend.o
obj-y += fuse.o
obj-y += kfuse.o
obj-y += tegra_i2s_audio.o
obj-y += tegra_spdif_audio.o
obj-y += mc.o

151
arch/arm/mach-tegra/apbio.c Normal file
View File

@ -0,0 +1,151 @@
/*
* arch/arm/mach-tegra/apbio.c
*
* Copyright (C) 2010 NVIDIA Corporation.
* Copyright (C) 2010 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <mach/dma.h>
#include <mach/iomap.h>
#include "apbio.h"
static DEFINE_MUTEX(tegra_apb_dma_lock);
#ifdef CONFIG_TEGRA_SYSTEM_DMA
static struct tegra_dma_channel *tegra_apb_dma;
static u32 *tegra_apb_bb;
static dma_addr_t tegra_apb_bb_phys;
static DECLARE_COMPLETION(tegra_apb_wait);
static void apb_dma_complete(struct tegra_dma_req *req)
{
complete(&tegra_apb_wait);
}
static inline u32 apb_readl(unsigned long offset)
{
struct tegra_dma_req req;
int ret;
if (!tegra_apb_dma)
return readl(IO_TO_VIRT(offset));
mutex_lock(&tegra_apb_dma_lock);
req.complete = apb_dma_complete;
req.to_memory = 1;
req.dest_addr = tegra_apb_bb_phys;
req.dest_bus_width = 32;
req.dest_wrap = 1;
req.source_addr = offset;
req.source_bus_width = 32;
req.source_wrap = 4;
req.req_sel = 0;
req.size = 4;
INIT_COMPLETION(tegra_apb_wait);
tegra_dma_enqueue_req(tegra_apb_dma, &req);
ret = wait_for_completion_timeout(&tegra_apb_wait,
msecs_to_jiffies(50));
if (WARN(ret == 0, "apb read dma timed out"))
*(u32 *)tegra_apb_bb = 0;
mutex_unlock(&tegra_apb_dma_lock);
return *((u32 *)tegra_apb_bb);
}
static inline void apb_writel(u32 value, unsigned long offset)
{
struct tegra_dma_req req;
int ret;
if (!tegra_apb_dma) {
writel(value, IO_TO_VIRT(offset));
return;
}
mutex_lock(&tegra_apb_dma_lock);
*((u32 *)tegra_apb_bb) = value;
req.complete = apb_dma_complete;
req.to_memory = 0;
req.dest_addr = offset;
req.dest_wrap = 4;
req.dest_bus_width = 32;
req.source_addr = tegra_apb_bb_phys;
req.source_bus_width = 32;
req.source_wrap = 1;
req.req_sel = 0;
req.size = 4;
INIT_COMPLETION(tegra_apb_wait);
tegra_dma_enqueue_req(tegra_apb_dma, &req);
ret = wait_for_completion_timeout(&tegra_apb_wait,
msecs_to_jiffies(50));
mutex_unlock(&tegra_apb_dma_lock);
}
#else
static inline u32 apb_readl(unsigned long offset)
{
return readl(IO_TO_VIRT(offset));
}
static inline void apb_writel(u32 value, unsigned long offset)
{
writel(value, IO_TO_VIRT(offset));
}
#endif
u32 tegra_apb_readl(unsigned long offset)
{
return apb_readl(offset);
}
void tegra_apb_writel(u32 value, unsigned long offset)
{
apb_writel(value, offset);
}
void tegra_init_apb_dma(void)
{
#ifdef CONFIG_TEGRA_SYSTEM_DMA
tegra_apb_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
TEGRA_DMA_SHARED);
if (!tegra_apb_dma) {
pr_err("%s: can not allocate dma channel\n", __func__);
return;
}
tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
&tegra_apb_bb_phys, GFP_KERNEL);
if (!tegra_apb_bb) {
pr_err("%s: can not allocate bounce buffer\n", __func__);
tegra_dma_free_channel(tegra_apb_dma);
tegra_apb_dma = NULL;
return;
}
#endif
}

View File

@ -0,0 +1,20 @@
/*
* arch/arm/mach-tegra/apbio.h
*
* Copyright (C) 2010 NVIDIA Corporation.
* Copyright (C) 2010 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
u32 tegra_apb_readl(unsigned long offset);
void tegra_apb_writel(u32 value, unsigned long offset);
void tegra_init_apb_dma(void);

View File

@ -33,6 +33,7 @@
#include <mach/powergate.h>
#include <mach/system.h>
#include "apbio.h"
#include "board.h"
#include "clock.h"
#include "fuse.h"
@ -70,6 +71,7 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ "emc", NULL, 0, true },
{ "csite", NULL, 0, true },
{ "timer", NULL, 0, true },
{ "kfuse", NULL, 0, true },
{ "rtc", NULL, 0, true },
/* set frequencies of some device clocks */
@ -89,6 +91,7 @@ void __init tegra_init_cache(void)
writel(0x331, p + L2X0_TAG_LATENCY_CTRL);
writel(0x441, p + L2X0_DATA_LATENCY_CTRL);
writel(7, p + L2X0_PREFETCH_OFFSET);
writel(2, p + L2X0_PWR_CTRL);
l2x0_init(p, 0x7C480001, 0x8200c3fe);
#endif
@ -141,7 +144,7 @@ void __init tegra_common_init(void)
tegra_init_power();
tegra_init_cache();
tegra_dma_init();
tegra_init_fuse_dma();
tegra_init_apb_dma();
}
static int __init tegra_bootloader_fb_arg(char *options)

View File

@ -536,6 +536,8 @@ ENTRY(__cortex_a9_l2x0_restart)
str r6, [r9, #L2X0_DATA_LATENCY_CTRL]
str r7, [r9, #L2X0_PREFETCH_OFFSET]
str r4, [r9, #L2X0_AUX_CTRL]
mov r4, #0x2 @ L2X0_DYNAMIC_CLK_GATING_EN
str r4, [r9, #L2X0_PWR_CTRL]
cmp r0, #0
beq __reenable_l2x0

View File

@ -19,30 +19,17 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <mach/dma.h>
#include <mach/iomap.h>
#include "fuse.h"
#include "apbio.h"
#define FUSE_UID_LOW 0x108
#define FUSE_UID_HIGH 0x10c
#define FUSE_SKU_INFO 0x110
#define FUSE_SPARE_BIT 0x200
static DEFINE_MUTEX(tegra_fuse_dma_lock);
#ifdef CONFIG_TEGRA_SYSTEM_DMA
static struct tegra_dma_channel *tegra_fuse_dma;
static u32 *tegra_fuse_bb;
static dma_addr_t tegra_fuse_bb_phys;
static DECLARE_COMPLETION(tegra_fuse_wait);
static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_UNKNOWN] = "unknown",
[TEGRA_REVISION_A02] = "A02",
@ -50,102 +37,19 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_A03p] = "A03 prime",
};
static void fuse_dma_complete(struct tegra_dma_req *req)
{
complete(&tegra_fuse_wait);
}
static inline u32 fuse_readl(unsigned long offset)
{
struct tegra_dma_req req;
int ret;
if (!tegra_fuse_dma)
return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
mutex_lock(&tegra_fuse_dma_lock);
req.complete = fuse_dma_complete;
req.to_memory = 1;
req.dest_addr = tegra_fuse_bb_phys;
req.dest_bus_width = 32;
req.dest_wrap = 1;
req.source_addr = TEGRA_FUSE_BASE + offset;
req.source_bus_width = 32;
req.source_wrap = 4;
req.req_sel = 0;
req.size = 4;
INIT_COMPLETION(tegra_fuse_wait);
tegra_dma_enqueue_req(tegra_fuse_dma, &req);
ret = wait_for_completion_timeout(&tegra_fuse_wait,
msecs_to_jiffies(50));
if (WARN(ret == 0, "fuse read dma timed out"))
*(u32 *)tegra_fuse_bb = 0;
mutex_unlock(&tegra_fuse_dma_lock);
return *((u32 *)tegra_fuse_bb);
}
static inline void fuse_writel(u32 value, unsigned long offset)
{
struct tegra_dma_req req;
int ret;
if (!tegra_fuse_dma) {
writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
return;
}
mutex_lock(&tegra_fuse_dma_lock);
*((u32 *)tegra_fuse_bb) = value;
req.complete = fuse_dma_complete;
req.to_memory = 0;
req.dest_addr = TEGRA_FUSE_BASE + offset;
req.dest_wrap = 4;
req.dest_bus_width = 32;
req.source_addr = tegra_fuse_bb_phys;
req.source_bus_width = 32;
req.source_wrap = 1;
req.req_sel = 0;
req.size = 4;
INIT_COMPLETION(tegra_fuse_wait);
tegra_dma_enqueue_req(tegra_fuse_dma, &req);
ret = wait_for_completion_timeout(&tegra_fuse_wait,
msecs_to_jiffies(50));
mutex_unlock(&tegra_fuse_dma_lock);
}
#else
static inline u32 fuse_readl(unsigned long offset)
{
return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
}
static inline void fuse_writel(u32 value, unsigned long offset)
{
writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
}
#endif
u32 tegra_fuse_readl(unsigned long offset)
{
return fuse_readl(offset);
return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
}
void tegra_fuse_writel(u32 value, unsigned long offset)
{
fuse_writel(value, offset);
tegra_apb_writel(value, TEGRA_FUSE_BASE + offset);
}
static inline bool get_spare_fuse(int bit)
{
return fuse_readl(FUSE_SPARE_BIT + bit * 4);
return tegra_apb_readl(FUSE_SPARE_BIT + bit * 4);
}
void tegra_init_fuse(void)
@ -160,40 +64,19 @@ void tegra_init_fuse(void)
tegra_core_process_id());
}
void tegra_init_fuse_dma(void)
{
#ifdef CONFIG_TEGRA_SYSTEM_DMA
tegra_fuse_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
TEGRA_DMA_SHARED);
if (!tegra_fuse_dma) {
pr_err("%s: can not allocate dma channel\n", __func__);
return;
}
tegra_fuse_bb = dma_alloc_coherent(NULL, sizeof(u32),
&tegra_fuse_bb_phys, GFP_KERNEL);
if (!tegra_fuse_bb) {
pr_err("%s: can not allocate bounce buffer\n", __func__);
tegra_dma_free_channel(tegra_fuse_dma);
tegra_fuse_dma = NULL;
return;
}
#endif
}
unsigned long long tegra_chip_uid(void)
{
unsigned long long lo, hi;
lo = fuse_readl(FUSE_UID_LOW);
hi = fuse_readl(FUSE_UID_HIGH);
lo = tegra_fuse_readl(FUSE_UID_LOW);
hi = tegra_fuse_readl(FUSE_UID_HIGH);
return (hi << 32ull) | lo;
}
int tegra_sku_id(void)
{
int sku_id;
u32 reg = fuse_readl(FUSE_SKU_INFO);
u32 reg = tegra_fuse_readl(FUSE_SKU_INFO);
sku_id = reg & 0xFF;
return sku_id;
}
@ -201,7 +84,7 @@ int tegra_sku_id(void)
int tegra_cpu_process_id(void)
{
int cpu_process_id;
u32 reg = fuse_readl(FUSE_SPARE_BIT);
u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
cpu_process_id = (reg >> 6) & 3;
return cpu_process_id;
}
@ -209,7 +92,7 @@ int tegra_cpu_process_id(void)
int tegra_core_process_id(void)
{
int core_process_id;
u32 reg = fuse_readl(FUSE_SPARE_BIT);
u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
core_process_id = (reg >> 12) & 3;
return core_process_id;
}

View File

@ -30,7 +30,6 @@ int tegra_sku_id(void);
int tegra_cpu_process_id(void);
int tegra_core_process_id(void);
void tegra_init_fuse(void);
void tegra_init_fuse_dma(void);
u32 tegra_fuse_readl(unsigned long offset);
void tegra_fuse_writel(u32 value, unsigned long offset);
enum tegra_revision tegra_get_revision(void);

View File

@ -73,9 +73,13 @@ struct tegra_dc_out {
int (*disable)(void);
};
#define TEGRA_DC_OUT_HOTPLUG_HIGH (0 << 1)
#define TEGRA_DC_OUT_HOTPLUG_LOW (1 << 1)
#define TEGRA_DC_OUT_HOTPLUG_MASK (1 << 1)
/* bits for tegra_dc_out.flags */
#define TEGRA_DC_OUT_HOTPLUG_HIGH (0 << 1)
#define TEGRA_DC_OUT_HOTPLUG_LOW (1 << 1)
#define TEGRA_DC_OUT_HOTPLUG_MASK (1 << 1)
#define TEGRA_DC_OUT_NVHDCP_POLICY_ALWAYS_ON (0 << 2)
#define TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND (1 << 2)
#define TEGRA_DC_OUT_NVHDCP_POLICY_MASK (1 << 2)
#define TEGRA_DC_ALIGN_MSB 0
#define TEGRA_DC_ALIGN_LSB 1

View File

@ -0,0 +1,20 @@
/*
* arch/arm/mach-tegra/kfuse.h
*
* Copyright (C) 2010-2011 NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/* there are 144 32-bit values in total */
#define KFUSE_DATA_SZ (144 * 4)
int tegra_kfuse_read(void *dest, size_t len);

View File

@ -0,0 +1,88 @@
/*
* arch/arm/mach-tegra/kfuse.c
*
* Copyright (C) 2010-2011 NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/* The kfuse block stores downstream and upstream HDCP keys for use by HDMI
* module.
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <mach/iomap.h>
#include <mach/kfuse.h>
#include "apbio.h"
/* register definition */
#define KFUSE_STATE 0x80
#define KFUSE_STATE_DONE (1u << 16)
#define KFUSE_STATE_CRCPASS (1u << 17)
#define KFUSE_KEYADDR 0x88
#define KFUSE_KEYADDR_AUTOINC (1u << 16)
#define KFUSE_KEYS 0x8c
static inline u32 tegra_kfuse_readl(unsigned long offset)
{
return tegra_apb_readl(TEGRA_KFUSE_BASE + offset);
}
static inline void tegra_kfuse_writel(u32 value, unsigned long offset)
{
tegra_apb_writel(value, TEGRA_KFUSE_BASE + offset);
}
static int wait_for_done(void)
{
u32 reg;
int retries = 50;
do {
reg = tegra_kfuse_readl(KFUSE_STATE);
if (reg & KFUSE_STATE_DONE);
return 0;
msleep(10);
} while(--retries);
return -ETIMEDOUT;
}
/* read up to KFUSE_DATA_SZ bytes into dest.
* always starts at the first kfuse.
*/
int tegra_kfuse_read(void *dest, size_t len)
{
u32 v;
unsigned cnt;
if (len > KFUSE_DATA_SZ)
return -EINVAL;
tegra_kfuse_writel(KFUSE_KEYADDR_AUTOINC, KFUSE_KEYADDR);
wait_for_done();
if ((tegra_kfuse_readl(KFUSE_STATE) & KFUSE_STATE_CRCPASS) == 0) {
pr_err("kfuse: crc failed\n");
return -EIO;
}
for (cnt = 0; cnt < len; cnt += 4) {
v = tegra_kfuse_readl(KFUSE_KEYS);
memcpy(dest + cnt, &v, sizeof v);
}
return 0;
}

View File

@ -1955,6 +1955,7 @@ static struct clk tegra_clk_emc = {
struct clk tegra_list_clks[] = {
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),

View File

@ -238,6 +238,16 @@ __v7_setup:
2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number
teq r0, r10
bne 3f
cmp r6, #0x10 @ power ctrl reg added r1p0
mrcge p15, 0, r10, c15, c0, 0 @ read power control register
orrge r10, r10, #1 @ enable dynamic clock gating
mcrge p15, 0, r10, c15, c0, 0 @ write power control register
#ifdef CONFIG_ARM_ERRATA_720791
teq r5, #0x00100000 @ only present in r1p*
mrceq p15, 0, r10, c15, c0, 2 @ read "chicken power ctrl" reg
orreq r10, r10, #0x30 @ disable core clk gate on
mcreq p15, 0, r10, c15, c0, 2 @ instr-side waits
#endif
#ifdef CONFIG_ARM_ERRATA_742230
cmp r6, #0x22 @ only present up to r2p2
mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register

View File

@ -1,4 +1,5 @@
obj-y += dc.o
obj-y += rgb.o
obj-y += hdmi.o
obj-y += edid.o
obj-y += nvhdcp.o
obj-y += edid.o

View File

@ -170,6 +170,8 @@ int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs)
int extension_blocks;
ret = tegra_edid_read_block(edid, 0, edid->data);
if (ret)
return ret;
memset(specs, 0x0, sizeof(struct fb_monspecs));
fb_edid_to_monspecs(edid->data, specs);

View File

@ -32,11 +32,14 @@
#include <mach/fb.h>
#include <mach/nvhost.h>
#include <video/tegrafb.h>
#include "dc_reg.h"
#include "dc_priv.h"
#include "hdmi_reg.h"
#include "hdmi.h"
#include "edid.h"
#include "nvhdcp.h"
/* datasheet claims this will always be 216MHz */
#define HDMI_AUDIOCLK_FREQ 216000000
@ -46,6 +49,7 @@
struct tegra_dc_hdmi_data {
struct tegra_dc *dc;
struct tegra_edid *edid;
struct tegra_nvhdcp *nvhdcp;
struct delayed_work work;
struct resource *base_res;
@ -206,13 +210,13 @@ static const struct tegra_hdmi_audio_config
}
static inline unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
unsigned long reg)
{
return readl(hdmi->base + reg * 4);
}
static inline void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
unsigned long val, unsigned long reg)
{
writel(val, hdmi->base + reg * 4);
@ -468,6 +472,7 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc)
fail:
switch_set_state(&hdmi->hpd_switch, 0);
tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
return false;
}
@ -510,6 +515,7 @@ static void tegra_dc_hdmi_suspend(struct tegra_dc *dc)
unsigned long flags;
spin_lock_irqsave(&hdmi->suspend_lock, flags);
tegra_nvhdcp_suspend(hdmi->nvhdcp);
hdmi->suspended = true;
spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
}
@ -605,6 +611,14 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
goto err_free_irq;
}
hdmi->nvhdcp = tegra_nvhdcp_create(hdmi, dc->ndev->id,
dc->out->dcc_bus);
if (IS_ERR_OR_NULL(hdmi->nvhdcp)) {
dev_err(&dc->ndev->dev, "hdmi: can't create nvhdcp\n");
err = PTR_ERR(hdmi->nvhdcp);
goto err_edid_destroy;
}
INIT_DELAYED_WORK(&hdmi->work, tegra_dc_hdmi_detect_worker);
hdmi->dc = dc;
@ -624,8 +638,18 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
tegra_dc_set_outdata(dc, hdmi);
/* boards can select default content protection policy */
if (dc->out->flags & TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND) {
tegra_nvhdcp_set_policy(hdmi->nvhdcp,
TEGRA_NVHDCP_POLICY_ON_DEMAND);
} else {
tegra_nvhdcp_set_policy(hdmi->nvhdcp,
TEGRA_NVHDCP_POLICY_ALWAYS_ON);
}
return 0;
err_edid_destroy:
tegra_edid_destroy(hdmi->edid);
err_free_irq:
free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc);
err_put_clock:
@ -657,6 +681,7 @@ static void tegra_dc_hdmi_destroy(struct tegra_dc *dc)
clk_put(hdmi->disp1_clk);
clk_put(hdmi->disp2_clk);
tegra_edid_destroy(hdmi->edid);
tegra_nvhdcp_destroy(hdmi->nvhdcp);
kfree(hdmi);
@ -1108,15 +1133,21 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
if (!hdmi->dvi)
tegra_nvhdcp_set_plug(hdmi->nvhdcp, 1);
}
static void tegra_dc_hdmi_disable(struct tegra_dc *dc)
{
struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
tegra_periph_reset_assert(hdmi->clk);
clk_disable(hdmi->clk);
}
struct tegra_dc_out_ops tegra_dc_hdmi_ops = {
.init = tegra_dc_hdmi_init,
.destroy = tegra_dc_hdmi_destroy,

View File

@ -180,4 +180,10 @@ struct hdmi_audio_infoframe {
#define HDMI_AUDIO_CXT_HE_AAC_V2 0x2
#define HDMI_AUDIO_CXT_MPEG_SURROUND 0x3
struct tegra_dc_hdmi_data;
unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
unsigned long reg);
void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
unsigned long val, unsigned long reg);
#endif

View File

@ -57,16 +57,29 @@
#define HDMI_NV_PDISP_RG_HDCP_AKSV_MSB 0x08
#define HDMI_NV_PDISP_RG_HDCP_AKSV_LSB 0x09
#define HDMI_NV_PDISP_RG_HDCP_BKSV_MSB 0x0a
#define REPEATER (1 << 31)
#define HDMI_NV_PDISP_RG_HDCP_BKSV_LSB 0x0b
#define HDMI_NV_PDISP_RG_HDCP_CKSV_MSB 0x0c
#define HDMI_NV_PDISP_RG_HDCP_CKSV_LSB 0x0d
#define HDMI_NV_PDISP_RG_HDCP_DKSV_MSB 0x0e
#define HDMI_NV_PDISP_RG_HDCP_DKSV_LSB 0x0f
#define HDMI_NV_PDISP_RG_HDCP_CTRL 0x10
#define HDCP_RUN_YES (1 << 0)
#define CRYPT_ENABLED (1 << 1)
#define ONEONE_ENABLED (1 << 3)
#define AN_VALID (1 << 8)
#define R0_VALID (1 << 9)
#define SPRIME_VALID (1 << 10)
#define MPRIME_VALID (1 << 11)
#define SROM_ERR (1 << 13)
#define HDMI_NV_PDISP_RG_HDCP_CMODE 0x11
#define TMDS0_LINK0 (1 << 4)
#define READ_S (1 << 0)
#define READ_M (2 << 0)
#define HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB 0x12
#define HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB 0x13
#define HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB 0x14
#define STATUS_CS (1 << 6)
#define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2 0x15
#define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1 0x16
#define HDMI_NV_PDISP_RG_HDCP_RI 0x17
@ -417,6 +430,11 @@
#define PE_CURRENT3(x) (((x) & 0xf) << 24)
#define HDMI_NV_PDISP_KEY_CTRL 0x9a
#define LOCAL_KEYS (1 << 0)
#define AUTOINC (1 << 1)
#define WRITE16 (1 << 4)
#define PKEY_REQUEST_RELOAD_TRIGGER (1 << 5)
#define PKEY_LOADED (1 << 6)
#define HDMI_NV_PDISP_KEY_DEBUG0 0x9b
#define HDMI_NV_PDISP_KEY_DEBUG1 0x9c
#define HDMI_NV_PDISP_KEY_DEBUG2 0x9d

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
/*
* drivers/video/tegra/dc/nvhdcp.h
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __DRIVERS_VIDEO_TEGRA_DC_NVHDCP_H
#define __DRIVERS_VIDEO_TEGRA_DC_NVHDCP_H
#include <video/nvhdcp.h>
struct tegra_nvhdcp;
void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd);
int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol);
void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp);
struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi,
int id, int bus);
void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp);
#endif

91
include/video/nvhdcp.h Normal file
View File

@ -0,0 +1,91 @@
/*
* include/video/nvhdcp.h
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _LINUX_NVHDCP_H_
#define _LINUX_NVHDCP_H_
#include <linux/fb.h>
#include <linux/types.h>
#include <asm/ioctl.h>
/* maximum receivers and repeaters connected at a time */
#define TEGRA_NVHDCP_MAX_DEVS 127
/* values for value_flags */
#define TEGRA_NVHDCP_FLAG_AN 0x0001
#define TEGRA_NVHDCP_FLAG_AKSV 0x0002
#define TEGRA_NVHDCP_FLAG_BKSV 0x0004
#define TEGRA_NVHDCP_FLAG_BSTATUS 0x0008 /* repeater status */
#define TEGRA_NVHDCP_FLAG_CN 0x0010 /* c_n */
#define TEGRA_NVHDCP_FLAG_CKSV 0x0020 /* c_ksv */
#define TEGRA_NVHDCP_FLAG_DKSV 0x0040 /* d_ksv */
#define TEGRA_NVHDCP_FLAG_KP 0x0080 /* k_prime */
#define TEGRA_NVHDCP_FLAG_S 0x0100 /* hdcp_status */
#define TEGRA_NVHDCP_FLAG_CS 0x0200 /* connection state */
#define TEGRA_NVHDCP_FLAG_V 0x0400
#define TEGRA_NVHDCP_FLAG_MP 0x0800
#define TEGRA_NVHDCP_FLAG_BKSVLIST 0x1000
/* values for packet_results */
#define TEGRA_NVHDCP_RESULT_SUCCESS 0
#define TEGRA_NVHDCP_RESULT_UNSUCCESSFUL 1
#define TEGRA_NVHDCP_RESULT_PENDING 0x103
#define TEGRA_NVHDCP_RESULT_LINK_FAILED 0xc0000013
/* TODO: replace with -EINVAL */
#define TEGRA_NVHDCP_RESULT_INVALID_PARAMETER 0xc000000d
#define TEGRA_NVHDCP_RESULT_INVALID_PARAMETER_MIX 0xc0000030
/* TODO: replace with -ENOMEM */
#define TEGRA_NVHDCP_RESULT_NO_MEMORY 0xc0000017
struct tegra_nvhdcp_packet {
__u32 value_flags; // (IN/OUT)
__u32 packet_results; // (OUT)
__u64 c_n; // (IN) upstream exchange number
__u64 c_ksv; // (IN)
__u32 b_status; // (OUT) link/repeater status
__u64 hdcp_status; // (OUT) READ_S
__u64 cs; // (OUT) Connection State
__u64 k_prime; // (OUT)
__u64 a_n; // (OUT)
__u64 a_ksv; // (OUT)
__u64 b_ksv; // (OUT)
__u64 d_ksv; // (OUT)
__u8 v_prime[20]; // (OUT) 160-bit
__u64 m_prime; // (OUT)
// (OUT) Valid KSVs in the bKsvList. Maximum is 127 devices
__u32 num_bksv_list;
// (OUT) Up to 127 receivers & repeaters
__u64 bksv_list[TEGRA_NVHDCP_MAX_DEVS];
};
/* parameters to TEGRAIO_NVHDCP_SET_POLICY */
#define TEGRA_NVHDCP_POLICY_ON_DEMAND 0
#define TEGRA_NVHDCP_POLICY_ALWAYS_ON 1
/* ioctls */
#define TEGRAIO_NVHDCP_ON _IO('F', 0x70)
#define TEGRAIO_NVHDCP_OFF _IO('F', 0x71)
#define TEGRAIO_NVHDCP_SET_POLICY _IOW('F', 0x72, __u32)
#define TEGRAIO_NVHDCP_READ_M _IOWR('F', 0x73, struct tegra_nvhdcp_packet)
#define TEGRAIO_NVHDCP_READ_S _IOWR('F', 0x74, struct tegra_nvhdcp_packet)
#define TEGRAIO_NVHDCP_RENEGOTIATE _IO('F', 0x75)
#endif