mirror of
https://github.com/torvalds/linux.git
synced 2026-06-10 23:53:52 +02:00
Merge branch 'android-tegra' into android-tegra-moto
This commit is contained in:
commit
5257d707de
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
151
arch/arm/mach-tegra/apbio.c
Normal 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
|
||||
}
|
||||
20
arch/arm/mach-tegra/apbio.h
Normal file
20
arch/arm/mach-tegra/apbio.h
Normal 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);
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
20
arch/arm/mach-tegra/include/mach/kfuse.h
Normal file
20
arch/arm/mach-tegra/include/mach/kfuse.h
Normal 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);
|
||||
88
arch/arm/mach-tegra/kfuse.c
Normal file
88
arch/arm/mach-tegra/kfuse.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
1230
drivers/video/tegra/dc/nvhdcp.c
Normal file
1230
drivers/video/tegra/dc/nvhdcp.c
Normal file
File diff suppressed because it is too large
Load Diff
29
drivers/video/tegra/dc/nvhdcp.h
Normal file
29
drivers/video/tegra/dc/nvhdcp.h
Normal 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
91
include/video/nvhdcp.h
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user