summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/board.h17
-rw-r--r--arch/arm/mach-tegra/common.c182
-rw-r--r--arch/arm/mach-tegra/include/mach/audio.h6
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/i2s.h49
-rw-r--r--arch/arm/mach-tegra/suspend.c50
-rw-r--r--arch/arm/mach-tegra/tegra_i2s_audio.c333
-rw-r--r--arch/arm/mm/init.c135
-rw-r--r--arch/arm/mm/mmu.c43
-rw-r--r--drivers/i2c/busses/i2c-tegra.c6
-rw-r--r--drivers/mmc/host/sdhci.c2
-rw-r--r--drivers/video/tegra/dc/dc.c2
-rw-r--r--drivers/video/tegra/fb.c5
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c8
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c2
-rw-r--r--mm/memblock.c4
16 files changed, 624 insertions, 224 deletions
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 3d06354136f2..c47a21f71260 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -27,6 +27,23 @@ void __init tegra_common_init(void);
void __init tegra_map_common_io(void);
void __init tegra_init_irq(void);
void __init tegra_init_clock(void);
+void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
+ unsigned long fb2_size);
+void __init tegra_protected_aperture_init(unsigned long aperture);
+void tegra_move_framebuffer(unsigned long to, unsigned long from,
+ unsigned long size);
+
+extern unsigned long tegra_bootloader_fb_start;
+extern unsigned long tegra_bootloader_fb_size;
+extern unsigned long tegra_fb_start;
+extern unsigned long tegra_fb_size;
+extern unsigned long tegra_fb2_start;
+extern unsigned long tegra_fb2_size;
+extern unsigned long tegra_carveout_start;
+extern unsigned long tegra_carveout_size;
+extern unsigned long tegra_lp0_vec_start;
+extern unsigned long tegra_lp0_vec_size;
+extern unsigned long tegra_grhost_aperture;
extern struct sys_timer tegra_timer;
#endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 99eb45eb30c3..09fdecfc2456 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -21,6 +21,8 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
#include <asm/hardware/cache-l2x0.h>
@@ -33,6 +35,20 @@
#include "clock.h"
#include "fuse.h"
+#define MC_SECURITY_CFG2 0x7c
+
+unsigned long tegra_bootloader_fb_start;
+unsigned long tegra_bootloader_fb_size;
+unsigned long tegra_fb_start;
+unsigned long tegra_fb_size;
+unsigned long tegra_fb2_start;
+unsigned long tegra_fb2_size;
+unsigned long tegra_carveout_start;
+unsigned long tegra_carveout_size;
+unsigned long tegra_lp0_vec_start;
+unsigned long tegra_lp0_vec_size;
+unsigned long tegra_grhost_aperture;
+
void (*tegra_reset)(char mode, const char *cmd);
static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
@@ -84,3 +100,169 @@ void __init tegra_common_init(void)
tegra_dma_init();
#endif
}
+
+static int __init tegra_bootloader_fb_arg(char *options)
+{
+ char *p = options;
+
+ tegra_bootloader_fb_size = memparse(p, &p);
+ if (*p == '@')
+ tegra_bootloader_fb_start = memparse(p+1, &p);
+
+ pr_info("Found tegra_fbmem: %08lx@%08lx\n",
+ tegra_bootloader_fb_size, tegra_bootloader_fb_start);
+
+ return 0;
+}
+early_param("tegra_fbmem", tegra_bootloader_fb_arg);
+
+static int __init tegra_lp0_vec_arg(char *options)
+{
+ char *p = options;
+
+ tegra_lp0_vec_size = memparse(p, &p);
+ if (*p == '@')
+ tegra_lp0_vec_start = memparse(p+1, &p);
+
+ return 0;
+}
+early_param("lp0_vec", tegra_lp0_vec_arg);
+
+/*
+ * Tegra has a protected aperture that prevents access by most non-CPU
+ * memory masters to addresses above the aperture value. Enabling it
+ * secures the CPU's memory from the GPU, except through the GART.
+ */
+void __init tegra_protected_aperture_init(unsigned long aperture)
+{
+#ifndef CONFIG_NVMAP_ALLOW_SYSMEM
+ void __iomem *mc_base = IO_ADDRESS(TEGRA_MC_BASE);
+ pr_info("Enabling Tegra protected aperture at 0x%08lx\n", aperture);
+ writel(aperture, mc_base + MC_SECURITY_CFG2);
+#else
+ pr_err("Tegra protected aperture disabled because nvmap is using "
+ "system memory\n");
+#endif
+}
+
+/*
+ * Due to conflicting restrictions on the placement of the framebuffer,
+ * the bootloader is likely to leave the framebuffer pointed at a location
+ * in memory that is outside the grhost aperture. This function will move
+ * the framebuffer contents from a physical address that is anywher (lowmem,
+ * highmem, or outside the memory map) to a physical address that is outside
+ * the memory map.
+ */
+void tegra_move_framebuffer(unsigned long to, unsigned long from,
+ unsigned long size)
+{
+ struct page *page;
+ void __iomem *to_io;
+ void *from_virt;
+ unsigned long i;
+
+ BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to);
+ BUG_ON(PAGE_ALIGN(from) != from);
+ BUG_ON(PAGE_ALIGN(size) != size);
+
+ to_io = ioremap(to, size);
+ if (!to_io) {
+ pr_err("%s: Failed to map target framebuffer\n", __func__);
+ return;
+ }
+
+ pr_info("%s: %08lx %08lx %08lx %p", __func__, to, from, size, to_io);
+
+ if (pfn_valid(page_to_pfn(phys_to_page(from)))) {
+ for (i = 0 ; i < size; i += PAGE_SIZE) {
+ page = phys_to_page(from + i);
+ from_virt = kmap(page);
+ memcpy_toio(to_io + i, from_virt, PAGE_SIZE);
+ kunmap(page);
+ }
+ } else {
+ void __iomem *from_io = ioremap(from, size);
+ if (!from_io) {
+ pr_err("%s: Failed to map source framebuffer\n",
+ __func__);
+ goto out;
+ }
+
+ for (i = 0; i < size; i+= 4)
+ writel(readl(from_io + i), to_io + i);
+
+ iounmap(from_io);
+ }
+out:
+ iounmap(to_io);
+}
+
+void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
+ unsigned long fb2_size)
+{
+ if (tegra_lp0_vec_size)
+ if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size))
+ pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
+ tegra_lp0_vec_size, tegra_lp0_vec_start);
+
+
+ tegra_carveout_start = memblock_end_of_DRAM() - carveout_size;
+ if (memblock_remove(tegra_carveout_start, carveout_size))
+ pr_err("Failed to remove carveout %08lx@%08lx from memory "
+ "map\n",
+ tegra_carveout_start, carveout_size);
+ else
+ tegra_carveout_size = carveout_size;
+
+ tegra_fb2_start = memblock_end_of_DRAM() - fb2_size;
+ if (memblock_remove(tegra_fb2_start, fb2_size))
+ pr_err("Failed to remove second framebuffer %08lx@%08lx from "
+ "memory map\n",
+ tegra_fb2_start, fb2_size);
+ else
+ tegra_fb2_size = fb2_size;
+
+ tegra_fb_start = memblock_end_of_DRAM() - fb_size;
+ if (memblock_remove(tegra_fb_start, fb_size))
+ pr_err("Failed to remove framebuffer %08lx@%08lx from memory "
+ "map\n",
+ tegra_fb_start, fb_size);
+ else
+ tegra_fb_size = fb_size;
+
+ if (tegra_fb_size)
+ tegra_grhost_aperture = tegra_fb_start;
+
+ if (tegra_fb2_size && tegra_fb2_start < tegra_grhost_aperture)
+ tegra_grhost_aperture = tegra_fb2_start;
+
+ if (tegra_carveout_size && tegra_carveout_start < tegra_grhost_aperture)
+ tegra_grhost_aperture = tegra_carveout_start;
+
+ /*
+ * TODO: We should copy the bootloader's framebuffer to the framebuffer
+ * allocated above, and then free this one.
+ */
+ if (tegra_bootloader_fb_size)
+ if (memblock_reserve(tegra_bootloader_fb_start,
+ tegra_bootloader_fb_size))
+ pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
+ tegra_lp0_vec_size, tegra_lp0_vec_start);
+
+ pr_info("Tegra reserved memory:\n"
+ "LP0: %08lx - %08lx\n"
+ "Bootloader framebuffer: %08lx - %08lx\n"
+ "Framebuffer: %08lx - %08lx\n"
+ "2nd Framebuffer: %08lx - %08lx\n"
+ "Carveout: %08lx - %08lx\n",
+ tegra_lp0_vec_start,
+ tegra_lp0_vec_start + tegra_lp0_vec_size - 1,
+ tegra_bootloader_fb_start,
+ tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1,
+ tegra_fb_start,
+ tegra_fb_start + tegra_fb_size - 1,
+ tegra_fb2_start,
+ tegra_fb2_start + tegra_fb2_size - 1,
+ tegra_carveout_start,
+ tegra_carveout_start + tegra_carveout_size - 1);
+}
diff --git a/arch/arm/mach-tegra/include/mach/audio.h b/arch/arm/mach-tegra/include/mach/audio.h
index 6a6b5d08833d..80f8b2c2d8cd 100644
--- a/arch/arm/mach-tegra/include/mach/audio.h
+++ b/arch/arm/mach-tegra/include/mach/audio.h
@@ -31,6 +31,9 @@
#define I2S_FIFO_TX FIFO1
#define I2S_FIFO_RX FIFO2
+#define TEGRA_AUDIO_ENABLE_TX 1
+#define TEGRA_AUDIO_ENABLE_RX 2
+
struct tegra_audio_platform_data {
bool master;
bool dma_on;
@@ -43,7 +46,8 @@ struct tegra_audio_platform_data {
int bit_size;
int i2s_bus_width; /* 32-bit for 16-bit packed I2S */
int dsp_bus_width; /* 16-bit for DSP data format */
-
+ int mask; /* enable tx and rx? */
+ bool stereo_capture; /* True if hardware supports stereo */
void *driver_data;
};
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index f33c724ed864..78a303e12634 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -143,8 +143,12 @@ struct tegra_fb_data {
int xres;
int yres;
int bits_per_pixel;
+
+ unsigned long flags;
};
+#define TEGRA_FB_FLIP_ON_PROBE (1 << 0)
+
struct tegra_dc_platform_data {
unsigned long flags;
struct tegra_dc_out *default_out;
diff --git a/arch/arm/mach-tegra/include/mach/i2s.h b/arch/arm/mach-tegra/include/mach/i2s.h
index ed8bc14c4ca4..42cce885cdac 100644
--- a/arch/arm/mach-tegra/include/mach/i2s.h
+++ b/arch/arm/mach-tegra/include/mach/i2s.h
@@ -263,5 +263,54 @@
#define I2S_I2S_PCM_CTRL_RCV_MODE (1<<0)
+/*
+ * I2S_I2S_NW_CTRL_0
+ */
+
+#define I2S_TRM_TLPHY_SLOT_SEL_SLOT1 0
+#define I2S_TRM_TLPHY_SLOT_SEL_SLOT2 1
+#define I2S_TRM_TLPHY_SLOT_SEL_SLOT3 2
+#define I2S_TRM_TLPHY_SLOT_SEL_SLOT4 3
+#define I2S_I2S_NW_TRM_TLPHY_SLOT_SEL_SHIFT 4
+
+#define I2S_I2S_NW_TRM_TLPHY_SLOT_SEL_MASK \
+ (3 << I2S_TRM_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_TRM_TLPHY_SLOT_SEL_SLOT1 \
+ (I2S_TRM_TLPHY_SLOT_SEL_SLOT1 \
+ << I2S_I2S_NW_TRM_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_TRM_TLPHY_SLOT_SEL_SLOT2 \
+ (I2S_TRM_TLPHY_SLOT_SEL_SLOT2 \
+ << I2S_I2S_NW_TRM_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_TRM_TLPHY_SLOT_SEL_SLOT3 \
+ (I2S_TRM_TLPHY_SLOT_SEL_SLOT3 \
+ << I2S_I2S_NW_TRM_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_TRM_TLPHY_SLOT_SEL_SLOT4 \
+ (I2S_TRM_TLPHY_SLOT_SEL_SLOT4 \
+ << I2S_I2S_NW_TRM_TLPHY_SLOT_SEL_SHIFT)
+
+#define I2S_I2S_NW_CTRL_TRM_TLPHY_MODE (1<<3)
+
+#define I2S_RCV_TLPHY_SLOT_SEL_SLOT1 0
+#define I2S_RCV_TLPHY_SLOT_SEL_SLOT2 1
+#define I2S_RCV_TLPHY_SLOT_SEL_SLOT3 2
+#define I2S_RCV_TLPHY_SLOT_SEL_SLOT4 3
+#define I2S_I2S_NW_RCV_TLPHY_SLOT_SEL_SHIFT 1
+
+#define I2S_I2S_NW_RCV_TLPHY_SLOT_SEL_MASK \
+ (3 << I2S_RCV_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_RCV_TLPHY_SLOT_SEL_SLOT1 \
+ (I2S_RCV_TLPHY_SLOT_SEL_SLOT1 \
+ << I2S_I2S_NW_RCV_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_RCV_TLPHY_SLOT_SEL_SLOT2 \
+ (I2S_RCV_TLPHY_SLOT_SEL_SLOT2 \
+ << I2S_I2S_NW_RCV_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_RCV_TLPHY_SLOT_SEL_SLOT3 \
+ (I2S_RCV_TLPHY_SLOT_SEL_SLOT3 \
+ << I2S_I2S_NW_RCV_TLPHY_SLOT_SEL_SHIFT)
+#define I2S_I2S_RCV_TLPHY_SLOT_SEL_SLOT4 \
+ (I2S_RCV_TLPHY_SLOT_SEL_SLOT4 \
+ << I2S_I2S_NW_RCV_TLPHY_SLOT_SEL_SHIFT)
+
+#define I2S_I2S_NW_CTRL_RCV_TLPHY_MODE (1<<0)
#endif /* __ARCH_ARM_MACH_TEGRA_I2S_H */
diff --git a/arch/arm/mach-tegra/suspend.c b/arch/arm/mach-tegra/suspend.c
index b46d1bfff9b5..3b64aa56b063 100644
--- a/arch/arm/mach-tegra/suspend.c
+++ b/arch/arm/mach-tegra/suspend.c
@@ -49,6 +49,7 @@
#include <mach/legacy_irq.h>
#include <mach/suspend.h>
+#include "board.h"
#include "power.h"
/* NOTE: only add elements to the end of this structure, since the assembly
@@ -460,13 +461,14 @@ static void tegra_debug_uart_resume(void)
#define MC_SECURITY_START 0x6c
#define MC_SECURITY_SIZE 0x70
+#define MC_SECURITY_CFG2 0x7c
static int tegra_suspend_enter(suspend_state_t state)
{
struct irq_desc *desc;
void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
unsigned long flags;
- u32 mc_data[2];
+ u32 mc_data[3] = {0, 0, 0};
int irq;
bool do_lp0 = (current_suspend_mode == TEGRA_SUSPEND_LP0);
bool do_lp2 = (current_suspend_mode == TEGRA_SUSPEND_LP2);
@@ -493,6 +495,7 @@ static int tegra_suspend_enter(suspend_state_t state)
mc_data[0] = readl(mc + MC_SECURITY_START);
mc_data[1] = readl(mc + MC_SECURITY_SIZE);
+ mc_data[2] = readl(mc + MC_SECURITY_CFG2);
}
for_each_irq_desc(irq, desc) {
@@ -520,6 +523,7 @@ static int tegra_suspend_enter(suspend_state_t state)
if (do_lp0) {
writel(mc_data[0], mc + MC_SECURITY_START);
writel(mc_data[1], mc + MC_SECURITY_SIZE);
+ writel(mc_data[2], mc + MC_SECURITY_CFG2);
tegra_clk_resume();
tegra_gpio_resume();
@@ -543,21 +547,6 @@ static struct platform_suspend_ops tegra_suspend_ops = {
};
#endif
-static unsigned long lp0_vec_orig_start = 0;
-static unsigned long lp0_vec_orig_size = 0;
-
-static int __init tegra_lp0_vec_arg(char *options)
-{
- char *p = options;
-
- lp0_vec_orig_size = memparse(p, &p);
- if (*p == '@')
- lp0_vec_orig_start = memparse(p+1, &p);
-
- return 0;
-}
-__setup("lp0_vec=", tegra_lp0_vec_arg);
-
void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
{
u32 reg, mode;
@@ -568,32 +557,9 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
(void)reg;
(void)mode;
- if (plat->suspend_mode == TEGRA_SUSPEND_LP0 &&
- lp0_vec_orig_size && lp0_vec_orig_start) {
- unsigned char *reloc_lp0;
- unsigned long tmp;
- void __iomem *orig;
- reloc_lp0 = kmalloc(lp0_vec_orig_size+L1_CACHE_BYTES-1,
- GFP_KERNEL);
- WARN_ON(!reloc_lp0);
- if (!reloc_lp0)
- goto out;
-
- orig = ioremap(lp0_vec_orig_start, lp0_vec_orig_size);
- WARN_ON(!orig);
- if (!orig) {
- kfree(reloc_lp0);
- goto out;
- }
- tmp = (unsigned long) reloc_lp0;
- tmp = (tmp + L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES-1);
- reloc_lp0 = (unsigned char *)tmp;
- memcpy(reloc_lp0, orig, lp0_vec_orig_size);
- iounmap(orig);
- wb0_restore = virt_to_phys(reloc_lp0);
- }
-out:
- if (plat->suspend_mode == TEGRA_SUSPEND_LP0 && !wb0_restore) {
+ if (plat->suspend_mode == TEGRA_SUSPEND_LP0 && tegra_lp0_vec_size) {
+ wb0_restore = tegra_lp0_vec_start;
+ } else {
pr_warning("Suspend mode LP0 requested, but missing lp0_vec\n");
pr_warning("Disabling LP0\n");
plat->suspend_mode = TEGRA_SUSPEND_LP1;
diff --git a/arch/arm/mach-tegra/tegra_i2s_audio.c b/arch/arm/mach-tegra/tegra_i2s_audio.c
index 03ef3c3551b8..277532c22700 100644
--- a/arch/arm/mach-tegra/tegra_i2s_audio.c
+++ b/arch/arm/mach-tegra/tegra_i2s_audio.c
@@ -60,6 +60,11 @@
#define PCM_IN_BUFFER_PADDING (1<<6) /* bytes */
+#define TEGRA_AUDIO_DSP_NONE 0
+#define TEGRA_AUDIO_DSP_PCM 1
+#define TEGRA_AUDIO_DSP_NETWORK 2
+#define TEGRA_AUDIO_DSP_TDM 3
+
/* per stream (input/output) */
struct audio_stream {
int opened;
@@ -370,6 +375,51 @@ static void i2s_set_master(unsigned long base, int master)
i2s_writel(base, val, I2S_I2S_CTRL_0);
}
+static int i2s_set_dsp_mode(unsigned long base, unsigned int mode)
+{
+ u32 val;
+ if (mode > TEGRA_AUDIO_DSP_TDM) {
+ pr_err("%s: invalid mode %d.\n", __func__, mode);
+ return -EINVAL;
+ }
+ if (mode == TEGRA_AUDIO_DSP_TDM) {
+ pr_err("TEGRA_AUDIO_DSP_TDM not implemented.\n");
+ return -EINVAL;
+ }
+
+ /* Disable unused modes */
+ if (mode != TEGRA_AUDIO_DSP_PCM) {
+ /* Disable PCM mode */
+ val = i2s_readl(base, I2S_I2S_PCM_CTRL_0);
+ val &= ~(I2S_I2S_PCM_CTRL_TRM_MODE|I2S_I2S_PCM_CTRL_RCV_MODE);
+ i2s_writel(base, val, I2S_I2S_PCM_CTRL_0);
+ }
+ if (mode != TEGRA_AUDIO_DSP_NETWORK) {
+ /* Disable Network mode */
+ val = i2s_readl(base, I2S_I2S_NW_CTRL_0);
+ val &= ~(I2S_I2S_NW_CTRL_TRM_TLPHY_MODE|I2S_I2S_NW_CTRL_RCV_TLPHY_MODE);
+ i2s_writel(base, val, I2S_I2S_NW_CTRL_0);
+ }
+
+ /* Enable the selected mode. */
+ switch (mode) {
+ case TEGRA_AUDIO_DSP_NETWORK:
+ /* Set DSP Network (Telephony) Mode */
+ val = i2s_readl(base, I2S_I2S_NW_CTRL_0);
+ val |= I2S_I2S_NW_CTRL_TRM_TLPHY_MODE|I2S_I2S_NW_CTRL_RCV_TLPHY_MODE;
+ i2s_writel(base, val, I2S_I2S_NW_CTRL_0);
+ break;
+ case TEGRA_AUDIO_DSP_PCM:
+ /* Set DSP PCM Mode */
+ val = i2s_readl(base, I2S_I2S_PCM_CTRL_0);
+ val |= I2S_I2S_PCM_CTRL_TRM_MODE|I2S_I2S_PCM_CTRL_RCV_MODE;
+ i2s_writel(base, val, I2S_I2S_PCM_CTRL_0);
+ break;
+ }
+
+ return 0;
+}
+
static int i2s_set_bit_format(unsigned long base, unsigned fmt)
{
u32 val;
@@ -383,12 +433,12 @@ static int i2s_set_bit_format(unsigned long base, unsigned fmt)
val &= ~I2S_I2S_CTRL_BIT_FORMAT_MASK;
val |= fmt << I2S_BIT_FORMAT_SHIFT;
i2s_writel(base, val, I2S_I2S_CTRL_0);
-
- if (fmt == I2S_BIT_FORMAT_DSP) {
- val = i2s_readl(base, I2S_I2S_PCM_CTRL_0);
- val |= I2S_I2S_PCM_CTRL_TRM_MODE|I2S_I2S_PCM_CTRL_RCV_MODE;
- i2s_writel(base, val, I2S_I2S_PCM_CTRL_0);
- }
+ /* For DSP format, select DSP PCM mode. */
+ /* PCM mode and Network Mode slot 0 are effectively identical. */
+ if (fmt == I2S_BIT_FORMAT_DSP)
+ i2s_set_dsp_mode(base, TEGRA_AUDIO_DSP_PCM);
+ else
+ i2s_set_dsp_mode(base, TEGRA_AUDIO_DSP_NONE);
return 0;
}
@@ -673,46 +723,58 @@ static int setup_dma(struct audio_driver_state *ads)
int rc;
pr_info("%s\n", __func__);
- /* setup audio playback */
- ads->out.buf_phys = dma_map_single(&ads->pdev->dev, ads->out.buffer,
- 1 << PCM_BUFFER_MAX_SIZE_ORDER, DMA_TO_DEVICE);
- BUG_ON(!ads->out.buf_phys);
- setup_dma_tx_request(&ads->out.dma_req, &ads->out);
- ads->out.dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
- if (!ads->out.dma_chan) {
- pr_err("%s: could not allocate output I2S DMA channel: %ld\n",
- __func__, PTR_ERR(ads->out.dma_chan));
- rc = -ENODEV;
- goto fail_tx;
- }
-
- /* setup audio recording */
- ads->in.buf_phys = dma_map_single(&ads->pdev->dev, ads->in.buffer,
- 1 << PCM_BUFFER_MAX_SIZE_ORDER,
- DMA_FROM_DEVICE);
- BUG_ON(!ads->in.buf_phys);
- setup_dma_rx_request(&ads->in.dma_req, &ads->in);
- ads->in.dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
- if (!ads->in.dma_chan) {
- pr_err("%s: could not allocate input I2S DMA channel: %ld\n",
- __func__, PTR_ERR(ads->in.dma_chan));
- rc = -ENODEV;
- goto fail_rx;
+ if ((ads->pdata->mask & TEGRA_AUDIO_ENABLE_TX)) {
+ /* setup audio playback */
+ ads->out.buf_phys = dma_map_single(&ads->pdev->dev,
+ ads->out.buffer,
+ 1 << PCM_BUFFER_MAX_SIZE_ORDER,
+ DMA_TO_DEVICE);
+ BUG_ON(!ads->out.buf_phys);
+ setup_dma_tx_request(&ads->out.dma_req, &ads->out);
+ ads->out.dma_chan =
+ tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
+ if (!ads->out.dma_chan) {
+ pr_err("%s: error allocating output DMA channel: %ld\n",
+ __func__, PTR_ERR(ads->out.dma_chan));
+ rc = -ENODEV;
+ goto fail_tx;
+ }
+ }
+
+ if ((ads->pdata->mask & TEGRA_AUDIO_ENABLE_RX)) {
+ /* setup audio recording */
+ ads->in.buf_phys = dma_map_single(&ads->pdev->dev,
+ ads->in.buffer,
+ 1 << PCM_BUFFER_MAX_SIZE_ORDER,
+ DMA_FROM_DEVICE);
+ BUG_ON(!ads->in.buf_phys);
+ setup_dma_rx_request(&ads->in.dma_req, &ads->in);
+ ads->in.dma_chan =
+ tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
+ if (!ads->in.dma_chan) {
+ pr_err("%s: error allocating input DMA channel: %ld\n",
+ __func__, PTR_ERR(ads->in.dma_chan));
+ rc = -ENODEV;
+ goto fail_rx;
+ }
}
return 0;
fail_rx:
- dma_unmap_single(&ads->pdev->dev, ads->in.buf_phys,
+ if ((ads->pdata->mask & TEGRA_AUDIO_ENABLE_RX)) {
+ dma_unmap_single(&ads->pdev->dev, ads->in.buf_phys,
1 << PCM_BUFFER_MAX_SIZE_ORDER, DMA_FROM_DEVICE);
- tegra_dma_free_channel(ads->in.dma_chan);
- ads->in.dma_chan = 0;
-
+ tegra_dma_free_channel(ads->in.dma_chan);
+ ads->in.dma_chan = 0;
+ }
fail_tx:
- dma_unmap_single(&ads->pdev->dev, ads->out.buf_phys,
+ if ((ads->pdata->mask & TEGRA_AUDIO_ENABLE_TX)) {
+ dma_unmap_single(&ads->pdev->dev, ads->out.buf_phys,
1 << PCM_BUFFER_MAX_SIZE_ORDER, DMA_TO_DEVICE);
- tegra_dma_free_channel(ads->out.dma_chan);
- ads->out.dma_chan = 0;
+ tegra_dma_free_channel(ads->out.dma_chan);
+ ads->out.dma_chan = 0;
+ }
return rc;
}
@@ -1474,6 +1536,7 @@ static long tegra_audio_in_ioctl(struct file *file,
break;
}
+#ifdef SAMPLE_RATE_CONVERTER_IN_DRIVER
switch (cfg.rate) {
case 8000:
ads->in_divs = divs_8000;
@@ -1501,7 +1564,12 @@ static long tegra_audio_in_ioctl(struct file *file,
rc = -EINVAL;
break;
}
-
+#endif
+ if(cfg.stereo && !ads->pdata->stereo_capture) {
+ pr_err("%s: not capable of stereo capture.",
+ __func__);
+ rc = -EINVAL;
+ }
if (!rc) {
pr_info("%s: setting input sampling rate to %d, %s\n",
__func__, cfg.rate,
@@ -1553,6 +1621,23 @@ static long tegra_audio_in_ioctl(struct file *file,
return rc;
}
+static ssize_t __i2s_copy_to_user(struct audio_driver_state *ads,
+ void __user *dst, int dst_size,
+ void *src, int src_size,
+ int *num_consumed)
+{
+ int bytes_written = dst_size < src_size ? dst_size : src_size;
+ *num_consumed = bytes_written;
+ if (copy_to_user(dst, src, bytes_written)) {
+ pr_err("%s: error copying %d bytes to user\n", __func__,
+ bytes_written);
+ return -EFAULT;
+ }
+ return bytes_written;
+}
+
+#ifdef SAMPLE_RATE_CONVERTER_IN_DRIVER
+
/* downsample a 16-bit 44.1kHz PCM stereo stream to stereo or mono 16-bit PCM
* stream.
*/
@@ -1563,6 +1648,7 @@ static int downsample(const s16 *in, int in_len,
const int *divs, int divs_len,
bool out_stereo)
{
+ /* Todo: Handle mono source streams */
int i, j;
int lsum, rsum;
int di, div;
@@ -1625,6 +1711,7 @@ static ssize_t __downsample_to_user(struct audio_driver_state *ads,
return bytes_ds;
}
+#endif /*SAMPLE_RATE_CONVERTER_IN_DRIVER*/
static ssize_t downsample_to_user(struct audio_driver_state *ads,
void __user *buf,
@@ -1661,7 +1748,12 @@ static ssize_t downsample_to_user(struct audio_driver_state *ads,
BUG_ON(!sgl[i].length);
again:
- ds_now = __downsample_to_user(ads,
+#ifdef SAMPLE_RATE_CONVERTER_IN_DRIVER
+ ds_now = __downsample_to_user(
+#else
+ ds_now = __i2s_copy_to_user(
+#endif
+ ads,
buf, size,
sg_virt(&sgl[i]), sgl[i].length,
&bc_now);
@@ -2213,6 +2305,12 @@ static int tegra_audio_probe(struct platform_device *pdev)
state->pdata->driver_data = state;
BUG_ON(!state->pdata);
+ if (!(state->pdata->mask &
+ (TEGRA_AUDIO_ENABLE_TX | TEGRA_AUDIO_ENABLE_RX))) {
+ dev_err(&pdev->dev, "neither tx nor rx is enabled!\n");
+ return -EIO;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no mem resource!\n");
@@ -2232,9 +2330,6 @@ static int tegra_audio_probe(struct platform_device *pdev)
return -EIO;
}
- state->out.i2s_fifo_atn_level = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
- state->in.i2s_fifo_atn_level = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
-
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no dma resource!\n");
@@ -2282,107 +2377,113 @@ static int tegra_audio_probe(struct platform_device *pdev)
}
clk_enable(audio_sync_clk);
+ i2s_enable_fifos(state->i2s_base, 0);
/* disable interrupts from I2S */
i2s_fifo_clear(state->i2s_base, I2S_FIFO_TX);
i2s_fifo_clear(state->i2s_base, I2S_FIFO_RX);
- i2s_enable_fifos(state->i2s_base, 0);
-
i2s_set_left_right_control_polarity(state->i2s_base, 0); /* default */
-
if (state->pdata->master)
i2s_set_channel_bit_count(state->i2s_base, 44100,
clk_get_rate(i2s_clk));
i2s_set_master(state->i2s_base, state->pdata->master);
-
i2s_set_fifo_mode(state->i2s_base, I2S_FIFO_TX, 1);
i2s_set_fifo_mode(state->i2s_base, I2S_FIFO_RX, 0);
-
i2s_set_bit_format(state->i2s_base, state->pdata->mode);
i2s_set_bit_size(state->i2s_base, state->pdata->bit_size);
i2s_set_fifo_format(state->i2s_base, state->pdata->fifo_fmt);
- state->out.opened = 0;
- state->out.active = false;
- mutex_init(&state->out.lock);
- init_completion(&state->out.fifo_completion);
- init_completion(&state->out.stop_completion);
- spin_lock_init(&state->out.dma_req_lock);
- state->out.buf_phys = 0;
- state->out.dma_chan = NULL;
- state->out.dma_has_it = false;
-
- state->in.opened = 0;
- state->in.active = false;
- mutex_init(&state->in.lock);
- init_completion(&state->in.fifo_completion);
- init_completion(&state->in.stop_completion);
- spin_lock_init(&state->in.dma_req_lock);
- state->in.buf_phys = 0;
- state->in.dma_chan = NULL;
- state->in.dma_has_it = false;
-
- state->out.buffer = 0;
- state->out.buf_config.size = PCM_BUFFER_MAX_SIZE_ORDER;
- state->out.buf_config.threshold = PCM_BUFFER_THRESHOLD_ORDER;
- state->out.buf_config.chunk = PCM_BUFFER_DMA_CHUNK_SIZE_ORDER;
- rc = init_stream_buffer(&state->out, &state->out.buf_config, 0);
- if (rc < 0)
- return rc;
-
- state->in.buffer = 0;
- state->in.buf_config.size = PCM_BUFFER_MAX_SIZE_ORDER;
- state->in.buf_config.threshold = PCM_BUFFER_THRESHOLD_ORDER;
- state->in.buf_config.chunk = PCM_BUFFER_DMA_CHUNK_SIZE_ORDER;
- rc = init_stream_buffer(&state->in, &state->in.buf_config,
- PCM_IN_BUFFER_PADDING);
- if (rc < 0)
- return rc;
+ if ((state->pdata->mask & TEGRA_AUDIO_ENABLE_TX)) {
+ state->out.opened = 0;
+ state->out.active = false;
+ mutex_init(&state->out.lock);
+ init_completion(&state->out.fifo_completion);
+ init_completion(&state->out.stop_completion);
+ spin_lock_init(&state->out.dma_req_lock);
+ state->out.buf_phys = 0;
+ state->out.dma_chan = NULL;
+ state->out.dma_has_it = false;
+
+ state->out.i2s_fifo_atn_level = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
+ state->out.buffer = 0;
+ state->out.buf_config.size = PCM_BUFFER_MAX_SIZE_ORDER;
+ state->out.buf_config.threshold = PCM_BUFFER_THRESHOLD_ORDER;
+ state->out.buf_config.chunk = PCM_BUFFER_DMA_CHUNK_SIZE_ORDER;
+ rc = init_stream_buffer(&state->out, &state->out.buf_config, 0);
+ if (rc < 0)
+ return rc;
- pm_qos_add_request(&state->in.pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
- pm_qos_add_request(&state->out.pm_qos, PM_QOS_CPU_DMA_LATENCY,
+ pm_qos_add_request(&state->out.pm_qos, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
- snprintf(state->in.wake_lock_name, sizeof(state->in.wake_lock_name),
- "i2s.%d-audio-in", state->pdev->id);
- wake_lock_init(&state->in.wake_lock, WAKE_LOCK_SUSPEND,
- state->in.wake_lock_name);
- snprintf(state->out.wake_lock_name, sizeof(state->out.wake_lock_name),
- "i2s.%d-audio-out", state->pdev->id);
- wake_lock_init(&state->out.wake_lock, WAKE_LOCK_SUSPEND,
+ snprintf(state->out.wake_lock_name,
+ sizeof(state->out.wake_lock_name),
+ "i2s.%d-audio-out", state->pdev->id);
+ wake_lock_init(&state->out.wake_lock, WAKE_LOCK_SUSPEND,
state->out.wake_lock_name);
- if (request_irq(state->irq, i2s_interrupt,
- IRQF_DISABLED, state->pdev->name, state) < 0) {
- dev_err(&pdev->dev,
- "%s: could not register handler for irq %d\n",
- __func__, state->irq);
- return -EIO;
- }
-
- rc = setup_misc_device(&state->misc_out,
+ rc = setup_misc_device(&state->misc_out,
&tegra_audio_out_fops,
"audio%d_out", state->pdev->id);
- if (rc < 0)
- return rc;
+ if (rc < 0)
+ return rc;
- rc = setup_misc_device(&state->misc_out_ctl,
- &tegra_audio_out_ctl_fops,
- "audio%d_out_ctl", state->pdev->id);
- if (rc < 0)
- return rc;
+ rc = setup_misc_device(&state->misc_out_ctl,
+ &tegra_audio_out_ctl_fops,
+ "audio%d_out_ctl", state->pdev->id);
+ if (rc < 0)
+ return rc;
+ }
+
+ if ((state->pdata->mask & TEGRA_AUDIO_ENABLE_RX)) {
+ state->in.opened = 0;
+ state->in.active = false;
+ mutex_init(&state->in.lock);
+ init_completion(&state->in.fifo_completion);
+ init_completion(&state->in.stop_completion);
+ spin_lock_init(&state->in.dma_req_lock);
+ state->in.buf_phys = 0;
+ state->in.dma_chan = NULL;
+ state->in.dma_has_it = false;
+
+ state->in.i2s_fifo_atn_level = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
+ state->in.buffer = 0;
+ state->in.buf_config.size = PCM_BUFFER_MAX_SIZE_ORDER;
+ state->in.buf_config.threshold = PCM_BUFFER_THRESHOLD_ORDER;
+ state->in.buf_config.chunk = PCM_BUFFER_DMA_CHUNK_SIZE_ORDER;
+ rc = init_stream_buffer(&state->in, &state->in.buf_config,
+ PCM_IN_BUFFER_PADDING);
+ if (rc < 0)
+ return rc;
- rc = setup_misc_device(&state->misc_in,
+ pm_qos_add_request(&state->in.pm_qos, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ snprintf(state->in.wake_lock_name,
+ sizeof(state->in.wake_lock_name),
+ "i2s.%d-audio-in", state->pdev->id);
+ wake_lock_init(&state->in.wake_lock, WAKE_LOCK_SUSPEND,
+ state->in.wake_lock_name);
+
+ rc = setup_misc_device(&state->misc_in,
&tegra_audio_in_fops,
"audio%d_in", state->pdev->id);
- if (rc < 0)
- return rc;
+ if (rc < 0)
+ return rc;
- rc = setup_misc_device(&state->misc_in_ctl,
+ rc = setup_misc_device(&state->misc_in_ctl,
&tegra_audio_in_ctl_fops,
"audio%d_in_ctl", state->pdev->id);
- if (rc < 0)
- return rc;
+ if (rc < 0)
+ return rc;
+ }
+
+ if (request_irq(state->irq, i2s_interrupt,
+ IRQF_DISABLED, state->pdev->name, state) < 0) {
+ dev_err(&pdev->dev,
+ "%s: could not register handler for irq %d\n",
+ __func__, state->irq);
+ return -EIO;
+ }
rc = setup_misc_device(&state->misc_ctl,
&tegra_audio_ctl_fops,
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 7185b00650fe..de77de72e277 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -147,8 +147,8 @@ static void __init find_limits(struct meminfo *mi,
}
}
-static void __init arm_bootmem_init(struct meminfo *mi,
- unsigned long start_pfn, unsigned long end_pfn)
+static void __init arm_bootmem_init(unsigned long start_pfn,
+ unsigned long end_pfn)
{
unsigned int boot_pages;
phys_addr_t bitmap;
@@ -171,27 +171,35 @@ static void __init arm_bootmem_init(struct meminfo *mi,
pgdat = NODE_DATA(0);
init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn);
- for_each_bank(i, mi) {
- struct membank *bank = &mi->bank[i];
- if (!bank->highmem)
- free_bootmem(bank_phys_start(bank), bank_phys_size(bank));
+ /* Free the lowmem regions from memblock into bootmem. */
+ for (i = 0; i < memblock.memory.cnt; i++) {
+ unsigned long start = memblock_start_pfn(&memblock.memory, i);
+ unsigned long end = memblock_end_pfn(&memblock.memory, i);
+
+ if (end >= end_pfn)
+ end = end_pfn;
+ if (start >= end)
+ break;
+
+ free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT);
}
- /*
- * Reserve the memblock reserved regions in bootmem.
- */
+ /* Reserve the lowmem memblock reserved regions in bootmem. */
for (i = 0; i < memblock.reserved.cnt; i++) {
- phys_addr_t start = memblock_start_pfn(&memblock.reserved, i);
- if (start >= start_pfn &&
- memblock_end_pfn(&memblock.reserved, i) <= end_pfn)
- reserve_bootmem_node(pgdat, __pfn_to_phys(start),
- memblock_size_bytes(&memblock.reserved, i),
- BOOTMEM_DEFAULT);
+ unsigned long start = memblock_start_pfn(&memblock.reserved, i);
+ unsigned long size = memblock_size_bytes(&memblock.reserved, i);
+
+ if (start >= end_pfn)
+ break;
+ if (start + PFN_UP(size) > end_pfn)
+ size = (end_pfn - start) << PAGE_SHIFT;
+
+ reserve_bootmem(__pfn_to_phys(start), size, BOOTMEM_DEFAULT);
}
}
-static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min,
- unsigned long max_low, unsigned long max_high)
+static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
+ unsigned long max_high)
{
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
int i;
@@ -216,13 +224,23 @@ static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min,
* holes = node_size - sum(bank_sizes)
*/
memcpy(zhole_size, zone_size, sizeof(zhole_size));
- for_each_bank(i, mi) {
- int idx = 0;
+ for (i = 0; i < memblock.memory.cnt; i++) {
+ unsigned long start = memblock_start_pfn(&memblock.memory, i);
+ unsigned long end = memblock_end_pfn(&memblock.memory, i);
+
+ if (start < max_low) {
+ unsigned long low_end = min(end, max_low);
+
+ zhole_size[0] -= low_end - start;
+ }
+
#ifdef CONFIG_HIGHMEM
- if (mi->bank[i].highmem)
- idx = ZONE_HIGHMEM;
+ if (end > max_low) {
+ unsigned long high_start = max(start, max_low);
+
+ zhole_size[ZONE_HIGHMEM] -= end - high_start;
+ }
#endif
- zhole_size[idx] -= bank_pfn_size(&mi->bank[i]);
}
/*
@@ -310,7 +328,7 @@ void __init bootmem_init(void)
find_limits(mi, &min, &max_low, &max_high);
- arm_bootmem_init(mi, min, max_low);
+ arm_bootmem_init(min, max_low);
/*
* Sparsemem tries to allocate bootmem in memory_present(),
@@ -328,7 +346,7 @@ void __init bootmem_init(void)
* the sparse mem_map arrays initialized by sparse_init()
* for memmap_init_zone(), otherwise all PFNs are invalid.
*/
- arm_bootmem_free(mi, min, max_low, max_high);
+ arm_bootmem_free(min, max_low, max_high);
high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1;
@@ -422,6 +440,57 @@ static void __init free_unused_memmap(struct meminfo *mi)
}
}
+static void __init free_highpages(void)
+{
+#ifdef CONFIG_HIGHMEM
+ unsigned long max_low = max_low_pfn + PHYS_PFN_OFFSET;
+ int i, j;
+
+ /* set highmem page free */
+ for (i = j = 0; i < memblock.memory.cnt; i++) {
+ unsigned long start = memblock_start_pfn(&memblock.memory, i);
+ unsigned long end = memblock_end_pfn(&memblock.memory, i);
+
+ /* Ignore complete lowmem entries */
+ if (end <= max_low)
+ continue;
+
+ /* Truncate partial highmem entries */
+ if (start < max_low)
+ start = max_low;
+
+ /* Find and exclude any reserved regions */
+ for (; j < memblock.reserved.cnt; j++) {
+ unsigned long res_start;
+ unsigned long res_end;
+
+ res_start = memblock_start_pfn(&memblock.reserved, j);
+ res_end = res_start + PFN_UP(memblock_size_bytes(&memblock.reserved, j));
+
+ if (res_end < start)
+ continue;
+ if (res_start < start)
+ res_start = start;
+ if (res_start > end)
+ res_start = end;
+ if (res_end > end)
+ res_end = end;
+ if (res_start != start)
+ totalhigh_pages += free_area(start, res_start,
+ NULL);
+ start = res_end;
+ if (start == end)
+ break;
+ }
+
+ /* And now free anything which remains */
+ if (start < end)
+ totalhigh_pages += free_area(start, end, NULL);
+ }
+ totalram_pages += totalhigh_pages;
+#endif
+}
+
/*
* mem_init() marks the free areas in the mem_map and tells us how much
* memory is free. This is done after various parts of the system have
@@ -450,16 +519,7 @@ void __init mem_init(void)
__phys_to_pfn(__pa(swapper_pg_dir)), NULL);
#endif
-#ifdef CONFIG_HIGHMEM
- /* set highmem page free */
- for_each_bank (i, &meminfo) {
- unsigned long start = bank_pfn_start(&meminfo.bank[i]);
- unsigned long end = bank_pfn_end(&meminfo.bank[i]);
- if (start >= max_low_pfn + PHYS_PFN_OFFSET)
- totalhigh_pages += free_area(start, end, NULL);
- }
- totalram_pages += totalhigh_pages;
-#endif
+ free_highpages();
reserved_pages = free_pages = 0;
@@ -489,9 +549,10 @@ void __init mem_init(void)
*/
printk(KERN_INFO "Memory:");
num_physpages = 0;
- for (i = 0; i < meminfo.nr_banks; i++) {
- num_physpages += bank_pfn_size(&meminfo.bank[i]);
- printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20);
+ for (i = 0; i < memblock.memory.cnt; i++) {
+ unsigned long pages = memblock_size_pages(&memblock.memory, i);
+ num_physpages += pages;
+ printk(" %luMB", pages >> (20 - PAGE_SHIFT));
}
printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e8ed9dc461fe..3825b4f0f871 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -856,6 +856,7 @@ static void __init sanity_check_meminfo(void)
static inline void prepare_page_table(void)
{
unsigned long addr;
+ phys_addr_t end;
/*
* Clear out all the mappings below the kernel image.
@@ -871,10 +872,18 @@ static inline void prepare_page_table(void)
pmd_clear(pmd_off_k(addr));
/*
+ * Find the end of the first block of lowmem. This is complicated
+ * when we use memblock.
+ */
+ end = memblock.memory.region[0].base + memblock.memory.region[0].size;
+ if (end >= lowmem_end_addr)
+ end = lowmem_end_addr;
+
+ /*
* Clear out all the kernel space mappings, except for the first
* memory bank, up to the end of the vmalloc region.
*/
- for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0]));
+ for (addr = __phys_to_virt(end);
addr < VMALLOC_END; addr += PGDIR_SIZE)
pmd_clear(pmd_off_k(addr));
}
@@ -991,29 +1000,27 @@ static void __init kmap_init(void)
#endif
}
-static inline void map_memory_bank(struct membank *bank)
-{
- struct map_desc map;
-
- map.pfn = bank_pfn_start(bank);
- map.virtual = __phys_to_virt(bank_phys_start(bank));
- map.length = bank_phys_size(bank);
- map.type = MT_MEMORY;
-
- create_mapping(&map);
-}
-
static void __init map_lowmem(void)
{
- struct meminfo *mi = &meminfo;
int i;
/* Map all the lowmem memory banks. */
- for (i = 0; i < mi->nr_banks; i++) {
- struct membank *bank = &mi->bank[i];
+ for (i = 0; i < memblock.memory.cnt; i++) {
+ phys_addr_t start = memblock.memory.region[i].base;
+ phys_addr_t end = start + memblock.memory.region[i].size;
+ struct map_desc map;
+
+ if (end >= lowmem_end_addr)
+ end = lowmem_end_addr;
+ if (start >= end)
+ break;
+
+ map.pfn = __phys_to_pfn(start);
+ map.virtual = __phys_to_virt(start);
+ map.length = end - start;
+ map.type = MT_MEMORY;
- if (!bank->highmem)
- map_memory_bank(bank);
+ create_mapping(&map);
}
}
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 7e201501a84c..999ae2d30e30 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -741,7 +741,11 @@ static int __init tegra_i2c_init_driver(void)
{
return platform_driver_register(&tegra_i2c_driver);
}
-module_init(tegra_i2c_init_driver);
+/*
+ * Some drivers (hdmi) depend on i2c busses already being present,
+ * so init at subsys time.
+ */
+subsys_initcall(tegra_i2c_init_driver);
static void __exit tegra_i2c_exit_driver(void)
{
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6709cfb5d4e8..61670e1534b0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1871,6 +1871,8 @@ int sdhci_add_host(struct sdhci_host *host)
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
mmc->caps |= MMC_CAP_NEEDS_POLL;
+ mmc->caps |= MMC_CAP_ERASE;
+
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index ee9c9d9a8b92..bea8080b7d15 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1121,4 +1121,4 @@ static void __exit tegra_dc_module_exit(void)
}
module_exit(tegra_dc_module_exit);
-late_initcall(tegra_dc_module_init);
+module_init(tegra_dc_module_init);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 8e0964841cdb..6d826d03aef9 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -703,6 +703,11 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
dev_info(&ndev->dev, "probed\n");
+ if (fb_data->flags & TEGRA_FB_FLIP_ON_PROBE) {
+ tegra_dc_update_windows(&tegra_fb->win, 1);
+ tegra_dc_sync_windows(&tegra_fb->win, 1);
+ }
+
return tegra_fb;
err_iounmap_fb:
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index 865681f2e221..3cf3935e53fb 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -543,14 +543,6 @@ unsigned long nvmap_pin(struct nvmap_client *client,
atomic_inc(&ref->pin);
-#ifdef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
- /* if IOVMM reclaiming is enabled, IOVMM-backed allocations should
- * only be pinned through the nvmap_pin_array mechanism, since that
- * interface guarantees that handles are unpinned when the pinning
- * command buffers have completed. */
- WARN_ON(h->heap_pgalloc && !h->pgalloc.contig);
-#endif
-
if (WARN_ON(mutex_lock_interruptible(&client->share->pin_lock))) {
ret = -EINTR;
} else {
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 725a132ff6fd..2f50c0a1b8d3 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -149,8 +149,10 @@ static int handle_page_alloc(struct nvmap_client *client,
prot = nvmap_pgprot(h, pgprot_kernel);
+#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
if (nr_page == 1)
contiguous = true;
+#endif
h->pgalloc.area = NULL;
if (contiguous) {
diff --git a/mm/memblock.c b/mm/memblock.c
index 43840b305ecb..aa6919112842 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -196,6 +196,10 @@ static long memblock_add_region(struct memblock_region *rgn, u64 base, u64 size)
long memblock_add(u64 base, u64 size)
{
struct memblock_region *_rgn = &memblock.memory;
+ u64 end = base + size;
+
+ base = PAGE_ALIGN(base);
+ size = (end & PAGE_MASK) - base;
/* On pSeries LPAR systems, the first MEMBLOCK is our RMO region. */
if (base == 0)