diff options
-rw-r--r-- | arch/arm/mach-tegra/board.h | 17 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common.c | 182 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/audio.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/dc.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/i2s.h | 49 | ||||
-rw-r--r-- | arch/arm/mach-tegra/suspend.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra_i2s_audio.c | 333 | ||||
-rw-r--r-- | arch/arm/mm/init.c | 135 | ||||
-rw-r--r-- | arch/arm/mm/mmu.c | 43 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 6 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 5 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap.c | 8 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_handle.c | 2 | ||||
-rw-r--r-- | mm/memblock.c | 4 |
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) |