summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinyu Chen <xinyu.chen@freescale.com>2012-02-07 11:04:37 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-02-07 11:04:37 +0800
commit468940b0f4a7d24526b8fcb62f03aac789cbfa81 (patch)
treedb213ff6a9b32eb2367066199ce28715e3ddcac1
parentb377e57b416972c57eb946876a60bec666731bf5 (diff)
parent4a77281fc5b763f6e12ac1fd9b12ff68a9d91acc (diff)
Merge remote-tracking branch 'origin/imx_3.0.15' into imx_3.0.15_android
-rw-r--r--arch/arm/mach-mx6/board-mx6q_arm2.c2
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabresd.c28
-rw-r--r--arch/arm/mach-mx6/clock.c35
-rw-r--r--arch/arm/mach-mx6/crm_regs.h4
-rw-r--r--arch/arm/mach-mx6/headsmp.S116
-rw-r--r--arch/arm/mach-mx6/platsmp.c31
-rw-r--r--arch/arm/mach-mx6/pm.c5
-rw-r--r--arch/arm/mach-mx6/system.c32
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-uart.c6
-rwxr-xr-xarch/arm/plat-mxc/include/mach/common.h3
-rw-r--r--arch/arm/plat-mxc/time.c62
-rw-r--r--drivers/mmc/core/core.h1
-rw-r--r--drivers/mmc/core/sd.c34
-rw-r--r--drivers/mmc/core/sd_ops.c43
-rw-r--r--drivers/mmc/core/sd_ops.h1
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c99
-rw-r--r--include/linux/mmc/sd.h3
-rw-r--r--sound/soc/imx/Makefile.rej15
-rw-r--r--sound/soc/imx/imx-hdmi-dma.c209
19 files changed, 486 insertions, 243 deletions
diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c
index bf7a780b0a71..c3b46b7a551f 100644
--- a/arch/arm/mach-mx6/board-mx6q_arm2.c
+++ b/arch/arm/mach-mx6/board-mx6q_arm2.c
@@ -521,7 +521,7 @@ static const struct imxuart_platform_data mx6q_uart1_data __initconst = {
static inline void mx6q_arm2_init_uart(void)
{
- imx6q_add_imx_uart(0, NULL);
+ imx6q_add_imx_uart(3, NULL);
imx6q_add_imx_uart(1, &mx6q_uart1_data);
}
diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.c b/arch/arm/mach-mx6/board-mx6q_sabresd.c
index f17413b95454..764abced9497 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabresd.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabresd.c
@@ -80,7 +80,8 @@
#define MX6Q_SABRESD_SD3_WP IMX_GPIO_NR(2, 1)
#define MX6Q_SABRESD_ECSPI1_CS1 IMX_GPIO_NR(3, 19)
#define MX6Q_SABRESD_USB_OTG_PWR IMX_GPIO_NR(3, 22)
-#define MX6Q_SABRESD_CAP_TCH_INT1 IMX_GPIO_NR(1, 9)
+#define MX6Q_SABRESD_CAP_TCH_INT1 IMX_GPIO_NR(6, 7)
+#define MX6Q_SABRESD_CAP_TCH_INT0 IMX_GPIO_NR(6, 8)
#define MX6Q_SABRESD_USB_HUB_RESET IMX_GPIO_NR(7, 12)
#define MX6Q_SABRESD_CAN1_STBY IMX_GPIO_NR(1, 2)
#define MX6Q_SABRESD_CAN1_EN IMX_GPIO_NR(1, 4)
@@ -89,6 +90,7 @@
#define MX6Q_SABRESD_CSI0_PWN IMX_GPIO_NR(1, 16)
#define MX6Q_SABRESD_MIPICSI_RST IMX_GPIO_NR(1, 20)
#define MX6Q_SABRESD_MIPICSI_PWN IMX_GPIO_NR(1, 19)
+#define MX6Q_SABRESD_AUX_5V_EN IMX_GPIO_NR(6, 10)
void __init early_console_setup(unsigned long base, struct clk *clk);
static struct clk *sata_clk;
@@ -192,6 +194,7 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
/* GPIO6 */
MX6Q_PAD_EIM_A23__GPIO_6_6, /* J12 - Boot Mode Select */
+ MX6Q_PAD_NANDF_RB0__GPIO_6_10, /* AUX_5V Enable */
/* GPIO7 */
MX6Q_PAD_GPIO_17__GPIO_7_12, /* USB Hub Reset */
@@ -205,8 +208,8 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */
/* I2C3 */
- MX6Q_PAD_GPIO_5__I2C3_SCL, /* GPIO1[5] - J7 - Display card */
- MX6Q_PAD_GPIO_16__I2C3_SDA, /* GPIO7[11] - J15 - RGB connector */
+ MX6Q_PAD_GPIO_3__I2C3_SCL, /* GPIO1[3] */
+ MX6Q_PAD_GPIO_16__I2C3_SDA, /* GPIO7[11]*/
/* DISPLAY */
MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK,
@@ -360,7 +363,7 @@ static const struct anatop_thermal_platform_data
static inline void mx6q_sabresd_init_uart(void)
{
imx6q_add_imx_uart(2, NULL);
- imx6q_add_imx_uart(3, NULL);
+ imx6q_add_imx_uart(0, NULL);
}
static int mx6q_sabresd_fec_phy_init(struct phy_device *phydev)
@@ -565,6 +568,10 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
I2C_BOARD_INFO("ov5640_mipi", 0x3c),
.platform_data = (void *)&mipi_csi2_data,
},
+ {
+ I2C_BOARD_INFO("egalax_ts", 0x4),
+ .irq = gpio_to_irq(MX6Q_SABRESD_CAP_TCH_INT0),
+ },
};
static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
@@ -792,11 +799,15 @@ static struct imx_ipuv3_platform_data ipu_data[] = {
static void sabresd_suspend_enter(void)
{
/* suspend preparation */
+ /* Disable AUX 5V */
+ gpio_set_value(MX6Q_SABRESD_AUX_5V_EN, 0);
}
static void sabresd_suspend_exit(void)
{
/* resume restore */
+ /* Enable AUX 5V */
+ gpio_set_value(MX6Q_SABRESD_AUX_5V_EN, 1);
}
static const struct pm_platform_data mx6q_sabresd_pm_data __initconst = {
.name = "imx_pm",
@@ -923,7 +934,7 @@ static int imx6q_init_audio(void)
}
static struct platform_pwm_backlight_data mx6_sabresd_pwm_backlight_data = {
- .pwm_id = 3,
+ .pwm_id = 0,
.max_brightness = 255,
.dft_brightness = 128,
.pwm_period_ns = 50000,
@@ -1044,7 +1055,7 @@ static void __init mx6_sabresd_board_init(void)
imx6q_add_mxc_pwm(1);
imx6q_add_mxc_pwm(2);
imx6q_add_mxc_pwm(3);
- imx6q_add_mxc_pwm_backlight(3, &mx6_sabresd_pwm_backlight_data);
+ imx6q_add_mxc_pwm_backlight(0, &mx6_sabresd_pwm_backlight_data);
imx6q_add_otp();
imx6q_add_viim();
@@ -1076,6 +1087,11 @@ static void __init mx6_sabresd_board_init(void)
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
+
+ /* Enable Aux_5V */
+ gpio_request(MX6Q_SABRESD_AUX_5V_EN, "aux_5v_en");
+ gpio_direction_output(MX6Q_SABRESD_AUX_5V_EN, 1);
+ gpio_set_value(MX6Q_SABRESD_AUX_5V_EN, 1);
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c
index 3e2c00a938c5..403664a62168 100644
--- a/arch/arm/mach-mx6/clock.c
+++ b/arch/arm/mach-mx6/clock.c
@@ -31,6 +31,7 @@
#include <mach/mxc_dvfs.h>
#include "crm_regs.h"
#include "cpu_op-mx6.h"
+#include "regs-anadig.h"
#ifdef CONFIG_CLK_DEBUG
#define __INIT_CLK_DEBUG(n) .name = #n,
@@ -396,6 +397,10 @@ static int _clk_pll_enable(struct clk *clk)
__raw_writel(reg, pllbase);
+ /* It will power on pll3 */
+ if (clk == &pll3_usb_otg_main_clk)
+ __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_CLR);
+
/* Wait for PLL to lock */
if (!WAIT(__raw_readl(pllbase) & ANADIG_PLL_LOCK,
SPIN_DELAY))
@@ -421,6 +426,13 @@ static void _clk_pll_disable(struct clk *clk)
reg &= ~ANADIG_PLL_ENABLE;
__raw_writel(reg, pllbase);
+
+ /*
+ * It will power off PLL3's power, it is the TO1.1 fix
+ * Please see TKT064178 for detail.
+ */
+ if (clk == &pll3_usb_otg_main_clk)
+ __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_SET);
}
static unsigned long _clk_pll1_main_get_rate(struct clk *clk)
@@ -1732,15 +1744,31 @@ static struct clk vdoa_clk = {
.disable = _clk_disable,
};
+static unsigned long _clk_gpt_get_rate(struct clk *clk)
+{
+ u32 reg;
+ unsigned long rate;
+
+ if (mx6q_revision() == IMX_CHIP_REVISION_1_0)
+ return clk_get_rate(clk->parent);
+
+ rate = mx6_timer_rate();
+ if (!rate)
+ return clk_get_rate(clk->parent);
+
+ return rate;
+}
+
static struct clk gpt_clk[] = {
{
__INIT_CLK_DEBUG(gpt_clk)
- .parent = &ipg_perclk,
+ .parent = &osc_clk,
.id = 0,
.enable_reg = MXC_CCM_CCGR1,
.enable_shift = MXC_CCM_CCGRx_CG10_OFFSET,
.enable = _clk_enable,
.disable = _clk_disable,
+ .get_rate = _clk_gpt_get_rate,
.secondary = &gpt_clk[1],
},
{
@@ -5188,6 +5216,11 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
/* S/PDIF */
clk_set_parent(&spdif0_clk[0], &pll3_pfd_454M);
+ if (mx6q_revision() == IMX_CHIP_REVISION_1_0) {
+ gpt_clk[0].parent = &ipg_perclk;
+ gpt_clk[0].get_rate = NULL;
+ }
+
base = ioremap(GPT_BASE_ADDR, SZ_4K);
mxc_timer_init(&gpt_clk[0], base, MXC_INT_GPT);
diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h
index 354d28b3f2e7..0e29ea83f1df 100644
--- a/arch/arm/mach-mx6/crm_regs.h
+++ b/arch/arm/mach-mx6/crm_regs.h
@@ -185,8 +185,8 @@
#define MXC_CCM_CCR_RBC_EN (1 << 27)
#define MXC_CCM_CCR_REG_BYPASS_CNT_MASK (0x3F << 21)
#define MXC_CCM_CCR_REG_BYPASS_CNT_OFFSET (21)
-#define MXC_CCM_CCR_WB_COUNT_MASK (0x7)
-#define MXC_CCM_CCR_WB_COUNT_OFFSET (1 << 16)
+#define MXC_CCM_CCR_WB_COUNT_MASK (0x7 << 16)
+#define MXC_CCM_CCR_WB_COUNT_OFFSET (16)
#define MXC_CCM_CCR_COSC_EN (1 << 12)
#define MXC_CCM_CCR_OSCNT_MASK (0xFF)
#define MXC_CCM_CCR_OSCNT_OFFSET (0)
diff --git a/arch/arm/mach-mx6/headsmp.S b/arch/arm/mach-mx6/headsmp.S
index d9fca6a575a5..9492d8dc1765 100644
--- a/arch/arm/mach-mx6/headsmp.S
+++ b/arch/arm/mach-mx6/headsmp.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,120 +54,26 @@ ENDPROC(v7_invalidate_l1)
__CPUINIT
ENTRY(mx6_secondary_startup)
- /*************************************************************
- The following code include workaround for smp wdog reset issue,
- when system reset, core1~core3 will check its GPR register, if
- it contain a valid pointer, they will continue to run, but
- since when a reset happen, DRAM can't be access before its
- controller initialized, so we must make sure the pointer value
- is in iRAM space, also, ARM recommend that there should not be
- any AXI access pending in the system if we want to reset
- individual CPU, it is better to put CPU in WFI state before
- reset, so now we implement the following flow to make sure
- this scenario:
- _______________________ _______________________
- | CPU0 | ----> | CPU<n> |
- |_______________________| | |_______________________|
- | | |
- | | |
- \|/ | \|/
- _______________________ | _______________________
- | GPR<n*2+2>=parameter | | | Rom jump to boot_entry|
- |_______________________| | |_______________________|
- | | |
- | | |
- \|/ | \|/
- _______________________ | _______________________
- | GPR<n*2+1>=boot_entry | | -- | GPR<n*2+1>=0 |
- |_______________________| | | |_______________________|
- | | | |
- | | | | <----------------
- \|/ | | \|/ |
- _______________________ | | _____________ N _________
- | Reset CPU<n> |____| | ---> /CPU<n*2+2>=0?\ ------->| WFI |
- |_______________________| | | \_____________/ |_________|
- | | | | ^
---------------> | | | | Y |
-| \|/ | | \|/ |
-| N _____________ | | |
--------------/GPR<n*2+1>=0?\ <--------- | |
- \_____________/ | |
- | | |
- Y | | |
- \|/ | |
- _______________________ | |
- | GPR<n*2+2>=0 | ---------- |
- |_______________________| |
- | |
- | |
- \|/ |
- _______________________ |
- | IPI software irq |---------------------------------------------
- |_______________________|
-
-
- This function code is copied to iRAM 0x93f000, since
- there is function call below, such as v7_invalidate_l1 and
- secondary_startup, we have to use absolute address jump,
- to get the physical address of these functions, we need
- the offset of physical and virtual address, the
- offset is passed from GPR parameter, currently we store
- it at r8, future code change should avoid using r8.
-*****************************************************************************/
/* Invalidate L1 I-cache first */
mov r1, #0x0
mcr p15, 0, r1, c7, c5, 0 @ Invalidate I-Cache
- /* count the offset value and store it in r8 */
- ldr r3, =mx6_secondary_startup
- mrc p15, 0, r0, c0, c0, 5
- and r0, r0, #15
- ldr r1, =0x020d8024
- add r1, r0, LSL#3
- ldr r0, [r1]
- sub r8, r3, r0
-
+ /* Invalidate L1 D-cache */
+ bl v7_invalidate_l1
+ /* Set ARM working mode */
msr cpsr_fsxc, #0xd3
- /* must enable gic cpu, then cpu<n> can wakeup when cpu0
- send a software irq*/
- ldr r1, =0xa00100
- mov r0, #0x1
- str r0, [r1]
- mov r0, #0xf0
- str r0, [r1, #0x4]
- mov r0, #0x2
- str r0, [r1, #0x8]
-
- /* read cpu number in order to clear related GPRx */
- mrc p15, 0, r0, c0, c0, 5
+ mrc p15, 0, r0, c0, c0, 5
and r0, r0, #15
- ldr r1, =0x020d8020
+ ldr r1, = 0x020d8020
add r1, r0, LSL#3
- /* clear GPR boot_entry register */
+
+ /*Clear SRC_GPR register */
mov r0, #0
str r0, [r1]
+ str r0, [r1, #0x4]
- /* check whether GPR paremeter register is cleared */
- ldr r0, [r1, #0x4]
- cmp r0, #0x0
- beq 4f
-3:
- wfi
- ldr r0, [r1, #0x4]
- cmp r0, #0x0
- bne 3b
-4:
- /* invalidate l1-cache first */
- ldr r0, =v7_invalidate_l1
- sub r0, r0, r8
- mov lr, pc
- add lr, lr, #0x4
- mov pc, r0
- ldr r0, =secondary_startup
- sub r0, r0, r8
-
- /* jump to secondary_startup */
- mov pc, r0
+ /* Jump to secondary_startup */
+ b secondary_startup
ENDPROC(mx6_secondary_startup)
diff --git a/arch/arm/mach-mx6/platsmp.c b/arch/arm/mach-mx6/platsmp.c
index bf332e6c23da..a21f0231f131 100644
--- a/arch/arm/mach-mx6/platsmp.c
+++ b/arch/arm/mach-mx6/platsmp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,6 +44,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
{
trace_hardirqs_off();
+ spin_lock(&boot_lock);
/*
* if any interrupts are already enabled for the primary
* core (e.g. timer irq), then they will not have been enabled
@@ -54,7 +55,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
/*
* Synchronise with the boot thread.
*/
- spin_lock(&boot_lock);
+
spin_unlock(&boot_lock);
}
@@ -63,7 +64,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long boot_entry;
void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR);
- void *boot_iram_base;
unsigned int val;
/*
@@ -72,15 +72,11 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
spin_lock(&boot_lock);
- /* boot entry is at the last 4K iRAM, from 0x93f000 */
- boot_entry = MX6Q_IRAM_BASE_ADDR + MX6Q_IRAM_SIZE;
- boot_iram_base = (void *)ioremap(boot_entry, SZ_4K);
- memcpy((void *)boot_iram_base, mx6_secondary_startup, SZ_1K);
-
/* set entry point for cpu1-cpu3*/
+ boot_entry = virt_to_phys(mx6_secondary_startup);
+
writel(boot_entry, src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu);
- writel(virt_to_phys(mx6_secondary_startup),
- src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu + 4);
+ writel(0, src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu + 4);
smp_wmb();
dsb();
@@ -92,21 +88,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
val |= 1 << (BP_SRC_SCR_CORES_DBG_RST + cpu);
writel(val, src_base + SRC_SCR_OFFSET);
- val = jiffies;
- /* wait cpu<n> boot up and clear boot_entry, timeout is 500ms */
- while (__raw_readl(src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu) != 0) {
- if (time_after(jiffies, (unsigned long)(val + HZ / 2))) {
- printk(KERN_WARNING "cpu %d: boot up failed!\n", cpu);
- break;
- }
- }
-
- /* let cpu<n> out of loop, call secondary_startup function*/
- writel(0, src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu + 4);
- smp_send_reschedule(cpu);
-
- /* unmap iram base */
- iounmap(boot_iram_base);
/*
* now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
diff --git a/arch/arm/mach-mx6/pm.c b/arch/arm/mach-mx6/pm.c
index 381cc1d7a573..4771193c5478 100644
--- a/arch/arm/mach-mx6/pm.c
+++ b/arch/arm/mach-mx6/pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -164,7 +164,8 @@ static void mx6_suspend_restore(void)
/* Per spec, the count needs to be zeroed and reconfigured on exit from
* low power mode
*/
- __raw_writel(ccm_ccr & ~MXC_CCM_CCR_REG_BYPASS_CNT_MASK, MXC_CCM_CCR);
+ __raw_writel(ccm_ccr & ~MXC_CCM_CCR_REG_BYPASS_CNT_MASK &
+ ~MXC_CCM_CCR_WB_COUNT_MASK, MXC_CCM_CCR);
udelay(50);
__raw_writel(ccm_ccr, MXC_CCM_CCR);
__raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c
index fae41383eaab..efc838e08078 100644
--- a/arch/arm/mach-mx6/system.c
+++ b/arch/arm/mach-mx6/system.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/pmic_external.h>
@@ -27,6 +28,7 @@
#include <asm/proc-fns.h>
#include <asm/system.h>
#include "crm_regs.h"
+#include "regs-anadig.h"
#define SCU_CTRL 0x00
#define SCU_CONFIG 0x04
@@ -38,18 +40,13 @@
#define GPC_PGC_CPU_PDN_OFFSET 0x2a0
#define GPC_PGC_CPU_PUPSCR_OFFSET 0x2a4
#define GPC_PGC_CPU_PDNSCR_OFFSET 0x2a8
-#define ANATOP_REG_2P5_OFFSET 0x130
-#define ANATOP_REG_CORE_OFFSET 0x140
#define MODULE_CLKGATE (1 << 30)
#define MODULE_SFTRST (1 << 31)
-static DEFINE_SPINLOCK(wfi_lock);
extern unsigned int gpc_wake_irq[4];
extern int mx6q_revision(void);
-static unsigned int cpu_idle_mask;
-
static void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR);
extern void (*mx6_wait_in_iram)(void);
@@ -129,10 +126,27 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
__raw_writel(0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET);
__raw_writel(0x1, gpc_base + GPC_CNTR_OFFSET);
/* Enable weak 2P5 linear regulator */
- anatop_val = __raw_readl(anatop_base + ANATOP_REG_2P5_OFFSET);
- anatop_val |= 1 << 18;
- __raw_writel(anatop_val, anatop_base + ANATOP_REG_2P5_OFFSET);
- __raw_writel(__raw_readl(MXC_CCM_CCR) | MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR);
+ anatop_val = __raw_readl(anatop_base +
+ HW_ANADIG_REG_2P5);
+ anatop_val |= BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG;
+ __raw_writel(anatop_val, anatop_base +
+ HW_ANADIG_REG_2P5);
+ if (mx6q_revision() != IMX_CHIP_REVISION_1_0) {
+ /* Enable fet_odrive */
+ anatop_val = __raw_readl(anatop_base +
+ HW_ANADIG_REG_CORE);
+ anatop_val |= BM_ANADIG_REG_CORE_FET_ODRIVE;
+ __raw_writel(anatop_val, anatop_base +
+ HW_ANADIG_REG_CORE);
+ }
+ __raw_writel(__raw_readl(MXC_CCM_CCR) |
+ MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR);
+ /* Make sure we clear WB_COUNT and re-config it */
+ __raw_writel(__raw_readl(MXC_CCM_CCR) &
+ (~MXC_CCM_CCR_WB_COUNT_MASK), MXC_CCM_CCR);
+ udelay(50);
+ __raw_writel(__raw_readl(MXC_CCM_CCR) | (0x1 <<
+ MXC_CCM_CCR_WB_COUNT_OFFSET), MXC_CCM_CCR);
ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM;
}
}
diff --git a/arch/arm/plat-mxc/devices/platform-imx-uart.c b/arch/arm/plat-mxc/devices/platform-imx-uart.c
index f51f69e4295c..ecfadc3060ea 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-uart.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-uart.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 Pengutronix
+ * Copyright (C) 2009-2012 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify it under
@@ -130,10 +130,10 @@ const struct imx_imx_uart_1irq_data imx53_imx_uart_data[] __initconst = {
const struct imx_imx_uart_1irq_data imx6q_imx_uart_data[] __initconst = {
#define imx6q_imx_uart_data_entry(_id, _hwid) \
imx_imx_uart_1irq_data_entry(MX6Q, _id, _hwid, SZ_4K)
- imx6q_imx_uart_data_entry(0, 4),
+ imx6q_imx_uart_data_entry(0, 1),
imx6q_imx_uart_data_entry(1, 2),
imx6q_imx_uart_data_entry(2, 3),
- imx6q_imx_uart_data_entry(3, 1),
+ imx6q_imx_uart_data_entry(3, 4),
};
#endif /* ifdef CONFIG_SOC_IMX6Q */
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 9a340ccf8dac..a8d1982b1b08 100755
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -86,4 +86,5 @@ extern void mx51_efikamx_reset(void);
extern int mx53_revision(void);
extern int mx50_revision(void);
extern int mx53_display_revision(void);
+extern unsigned long mx6_timer_rate(void);
#endif
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
index dd6b74e378c1..437921fdd2c2 100644
--- a/arch/arm/plat-mxc/time.c
+++ b/arch/arm/plat-mxc/time.c
@@ -58,7 +58,13 @@
#define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */
#define V2_TCTL_CLK_IPG (1 << 6)
#define V2_TCTL_CLK_PER (2 << 6)
-#define V2_TCTL_FRR (1 << 9)
+#define V2_TCTL_CLK_OSC_DIV8 (5 << 6)
+#define V2_TCTL_CLK_OSC (7 << 6)
+#define V2_TCTL_FRR (1 << 9)
+#define V2_TCTL_ENABLE24M (1 << 10)
+#define V2_TPRER_PRE24M_DIV8 7
+#define V2_TPRER_PRE24M_MASK 0xF
+#define V2_TPRER_PRE24M_OFFSET 12
#define V2_IR 0x0c
#define V2_TSTAT 0x08
#define V2_TSTAT_OF1 (1 << 0)
@@ -73,6 +79,10 @@ static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
static void __iomem *timer_base;
+#ifdef CONFIG_ARCH_MX6
+extern int mx6q_revision(void);
+#endif
+
static inline void gpt_irq_disable(void)
{
unsigned int tmp;
@@ -289,9 +299,38 @@ static int __init mxc_clockevent_init(struct clk *timer_clk)
return 0;
}
+#ifdef CONFIG_ARCH_MX6
+unsigned long mx6_timer_rate()
+{
+ struct clk *osc_clk = clk_get(NULL, "osc");
+ u32 parent_rate = clk_get_rate(osc_clk);
+
+ u32 reg = __raw_readl(timer_base + MXC_TCTL);
+ u32 div;
+
+ clk_put(osc_clk);
+
+ if ((reg & V2_TCTL_CLK_OSC_DIV8) == V2_TCTL_CLK_OSC_DIV8) {
+ if (cpu_is_mx6q())
+ /* For MX6Q, only options are 24MHz or 24MHz/8*/
+ return parent_rate / 8;
+ else {
+ /* For MX6DLS and MX6Solo, the rate is based on the
+ * divider value set in prescalar register. */
+ div = __raw_readl(timer_base + MXC_TPRER);
+ div = (div >> V2_TPRER_PRE24M_OFFSET) &
+ V2_TPRER_PRE24M_MASK;
+ return parent_rate / (div + 1);
+ }
+ }
+ return 0;
+}
+#endif
+
void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
{
uint32_t tctl_val;
+ u32 reg;
clk_enable(timer_clk);
@@ -304,9 +343,24 @@ void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
__raw_writel(0, timer_base + MXC_TCTL);
__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
- if (timer_is_v2())
- tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
- else
+ if (timer_is_v2()) {
+ if (cpu_is_mx5() ||
+ mx6q_revision() == IMX_CHIP_REVISION_1_0)
+ tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR |
+ V2_TCTL_WAITEN | MXC_TCTL_TEN;
+ else {
+ tctl_val = V2_TCTL_CLK_OSC_DIV8 | V2_TCTL_FRR |
+ V2_TCTL_WAITEN | MXC_TCTL_TEN;
+ if (!cpu_is_mx6q()) {
+ reg = __raw_readl(timer_base + MXC_TPRER);
+ reg |= (V2_TPRER_PRE24M_DIV8 <<
+ V2_TPRER_PRE24M_OFFSET);
+ __raw_writel(reg, timer_base + MXC_TPRER);
+ /* Enable the 24MHz input clock. */
+ tctl_val |= V2_TCTL_ENABLE24M;
+ }
+ }
+ } else
tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
__raw_writel(tctl_val, timer_base + MXC_TCTL);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 14664f1fb16f..84370cad499d 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -33,6 +33,7 @@ void mmc_init_erase(struct mmc_card *card);
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_set_tuning(struct mmc_host *host, unsigned int tuning);
void mmc_gate_clock(struct mmc_host *host);
void mmc_ungate_clock(struct mmc_host *host);
void mmc_set_ungated(struct mmc_host *host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 0635da51a970..5a7d8f5d41e0 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -613,19 +613,45 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
if (err)
goto out;
- /* Set bus speed mode of the card */
- err = sd_set_bus_speed_mode(card, status);
+ /* Set current limit for the card */
+ err = sd_set_current_limit(card, status);
if (err)
goto out;
- /* Set current limit for the card */
- err = sd_set_current_limit(card, status);
+ /* Set bus speed mode of the card */
+ err = sd_set_bus_speed_mode(card, status);
if (err)
goto out;
/* SPI mode doesn't define CMD19 */
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
+ if (!mmc_host_is_spi(card->host)) {
+ int min, max, avg;
+
+ min = card->host->tuning_min;
+ while (min < card->host->tuning_max) {
+ mmc_set_tuning(card->host, min);
+ if (!mmc_send_tuning_cmd(card))
+ break;
+ min += card->host->tuning_step;
+ }
+
+ max = min;
+ while (max < card->host->tuning_max) {
+ mmc_set_tuning(card->host, max);
+ if (!mmc_send_tuning_cmd(card))
+ break;
+ max += card->host->tuning_step;
+ }
+
+ avg = (min + max) / 2;
+ mmc_set_tuning(card->host, avg);
+ mmc_send_tuning_cmd(card);
+ }
+#else
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
err = card->host->ops->execute_tuning(card->host);
+#endif
out:
kfree(status);
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed153804..afafc8c81d01 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -345,6 +345,49 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
return 0;
}
+int mmc_send_tuning_cmd(struct mmc_card *card)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+ char scr[64];
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+ memset(scr, 0, 64);
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = MMC_SEND_TUNING_BLOCK;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 64;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, scr, 64);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ return 0;
+}
+
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
int err;
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index ffc2305d905f..2142da4b611c 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -20,6 +20,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
+int mmc_send_tuning_cmd(struct mmc_card *card);
#endif
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 9362f00623b6..5aec0bfe6fd6 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -39,6 +39,7 @@
#define SDHCI_MIX_CTRL_EXE_TUNE (1 << 22)
#define SDHCI_MIX_CTRL_SMPCLK_SEL (1 << 23)
+#define SDHCI_MIX_CTRL_AUTOTUNE_EN (1 << 24)
#define SDHCI_MIX_CTRL_FBCLK_SEL (1 << 25)
#define SDHCI_VENDOR_SPEC_VSELECT (1 << 1)
@@ -67,6 +68,8 @@
struct pltfm_imx_data {
int flags;
u32 scratchpad;
+ /* uhs mode for sdhc host control2 */
+ unsigned char uhs_mode;
};
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
@@ -99,7 +102,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
val |= SDHCI_CARD_PRESENT;
}
- if (reg == SDHCI_INT_STATUS && cpu_is_mx6q())
+ if (reg == SDHCI_INT_STATUS && cpu_is_mx6q()) {
/*
* on mx6q, there is low possibility that
* DATA END interrupt comes ealier than DMA
@@ -110,6 +113,32 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
if ((val & SDHCI_INT_DATA_END) && \
!(val & SDHCI_INT_DMA_END))
val = readl(host->ioaddr + reg);
+ } else if (reg == SDHCI_CAPABILITIES_1 && cpu_is_mx6q()) {
+ /*
+ * on mx6q, no cap_1 available, fake one.
+ */
+ val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 | \
+ SDHCI_SUPPORT_SDR50;
+ } else if (reg == SDHCI_MAX_CURRENT && cpu_is_mx6q()) {
+ /*
+ * on mx6q, no max current available, fake one.
+ */
+ val = 0;
+ val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT;
+ val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT;
+ val |= 0xFF << SDHCI_MAX_CURRENT_180_SHIFT;
+ }
+
+ if (reg == SDHCI_PRESENT_STATE && cpu_is_mx6q()) {
+ u32 fsl_prss = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+ /* save the least 20 bits */
+ val = fsl_prss & 0x000FFFFF;
+ /* move dat[0-3] line signal bits */
+ val |= (fsl_prss & 0x0F000000) >> 4;
+ /* move cmd line signal bits */
+ val |= (fsl_prss & 0x00800000) << 1;
+ }
+
return val;
}
@@ -174,9 +203,34 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{
+ u16 ret;
+ u32 val;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
if (unlikely(reg == SDHCI_HOST_VERSION))
reg ^= 2;
+ switch (reg) {
+ case SDHCI_HOST_CONTROL2:
+ ret = 0;
+ /* collect bit info from several regs */
+ val = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+ ret |= (val & SDHCI_VENDOR_SPEC_VSELECT)
+ ? SDHCI_CTRL_VDD_180 : 0;
+
+ val = readl(host->ioaddr + SDHCI_MIX_CTRL);
+ ret |= (val & SDHCI_MIX_CTRL_EXE_TUNE)
+ ? SDHCI_CTRL_EXEC_TUNING : 0;
+ ret |= (val & SDHCI_MIX_CTRL_SMPCLK_SEL)
+ ? 0 : SDHCI_CTRL_TUNED_CLK ;
+ ret |= SDHCI_CTRL_UHS_MASK & imx_data->uhs_mode;
+ /* no preset enable available */
+ ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
+ return ret;
+ }
+
return readw(host->ioaddr + reg);
}
@@ -187,6 +241,7 @@ void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
reg = sdhci_readl(host, SDHCI_MIX_CTRL);
reg |= SDHCI_MIX_CTRL_EXE_TUNE | \
SDHCI_MIX_CTRL_SMPCLK_SEL | \
+ SDHCI_MIX_CTRL_AUTOTUNE_EN | \
SDHCI_MIX_CTRL_FBCLK_SEL;
sdhci_writel(host, reg, SDHCI_MIX_CTRL);
sdhci_writel(host, (val << 8), SDHCI_TUNE_CTRL_STATUS);
@@ -197,8 +252,50 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
+ u32 orig_reg;
switch (reg) {
+ case SDHCI_CLOCK_CONTROL:
+ orig_reg = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+ if (val & SDHCI_CLOCK_CARD_EN) {
+ writel(orig_reg | SDHCI_VENDOR_SPEC_FRC_SDCLK_ON, \
+ host->ioaddr + SDHCI_VENDOR_SPEC);
+ } else {
+ writel(orig_reg & ~SDHCI_VENDOR_SPEC_FRC_SDCLK_ON, \
+ host->ioaddr + SDHCI_VENDOR_SPEC);
+ }
+
+ return;
+ case SDHCI_HOST_CONTROL2:
+ orig_reg = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+ if (val & SDHCI_CTRL_VDD_180) {
+ orig_reg |= SDHCI_VENDOR_SPEC_VSELECT;
+ writel(orig_reg, host->ioaddr + SDHCI_VENDOR_SPEC);
+ } else {
+ orig_reg &= ~SDHCI_VENDOR_SPEC_VSELECT;
+ writel(orig_reg, host->ioaddr + SDHCI_VENDOR_SPEC);
+ }
+
+ /*
+ * FSL sdhc controls bus and signal voltage via one bit
+ * VSELECT in VENDOR_SPEC, which has been set in
+ * SDHCI_POWER_CONTROL. So we skip the SDHCI_CTRL_VDD_180
+ * here.
+ *
+ * ignore exec_tuning flag written to SDHCI_HOST_CONTROL2,
+ * tuning will be handled differently for FSL SDHC ip.
+ */
+ orig_reg = readl(host->ioaddr + SDHCI_MIX_CTRL);
+ orig_reg &= ~SDHCI_MIX_CTRL_SMPCLK_SEL;
+
+ orig_reg |= (val & SDHCI_CTRL_TUNED_CLK)
+ ? 0 : SDHCI_MIX_CTRL_SMPCLK_SEL;
+
+ writel(orig_reg, host->ioaddr + SDHCI_MIX_CTRL);
+
+ imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
+
+ return;
case SDHCI_TRANSFER_MODE:
/*
* Postpone this write, we must do it together with a
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
index ae7cf9519b21..e4c46fdd3015 100644
--- a/include/linux/mmc/sd.h
+++ b/include/linux/mmc/sd.h
@@ -91,7 +91,4 @@
#define SD_SWITCH_ACCESS_DEF 0
#define SD_SWITCH_ACCESS_HS 1
-#define SD_VOLTAGE_SWITCH 11
-#define SD_TUNING_CMD 19
-
#endif
diff --git a/sound/soc/imx/Makefile.rej b/sound/soc/imx/Makefile.rej
deleted file mode 100644
index 7ff4796ff0bb..000000000000
--- a/sound/soc/imx/Makefile.rej
+++ /dev/null
@@ -1,15 +0,0 @@
---- sound/soc/imx/Makefile
-+++ sound/soc/imx/Makefile
-@@ -14,10 +14,12 @@
- snd-soc-phycore-ac97-objs := phycore-ac97.o
- snd-soc-wm1133-ev1-objs := wm1133-ev1.o
- snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
-+snd-soc-imx-cs42888-objs := imx-cs42888.o
- snd-soc-imx-spdif-objs := imx-spdif.o
-
- obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
- obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
- obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
- obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
-+obj-$(CONFIG_SND_SOC_IMX_CS42888) += snd-soc-imx-cs42888.o
- obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
diff --git a/sound/soc/imx/imx-hdmi-dma.c b/sound/soc/imx/imx-hdmi-dma.c
index 34a64d6072d6..9ce99efccc1b 100644
--- a/sound/soc/imx/imx-hdmi-dma.c
+++ b/sound/soc/imx/imx-hdmi-dma.c
@@ -39,7 +39,8 @@ struct imx_hdmi_dma_runtime_data {
struct snd_pcm_substream *tx_substream;
unsigned long buffer_bytes;
- void *buf;
+ struct snd_dma_buffer hw_buffer;
+ unsigned long appl_bytes;
int period_time;
int periods;
@@ -147,7 +148,7 @@ static void dumprtd(struct imx_hdmi_dma_runtime_data *rtd)
pr_debug("period_bytes = %d\n", rtd->period_bytes);
pr_debug("dma period_bytes = %d\n", rtd->dma_period_bytes);
pr_debug("buffer_ratio = %d\n", rtd->buffer_ratio);
- pr_debug("dma buf addr = 0x%08x\n", (int)rtd->buf);
+ pr_debug("hw dma buffer = 0x%08x\n", (int)rtd->hw_buffer.addr);
pr_debug("dma buf size = %d\n", (int)rtd->buffer_bytes);
pr_debug("sample_rate = %d\n", (int)rtd->rate);
}
@@ -225,13 +226,86 @@ static void hdmi_dma_irq_mute(int mute)
hdmi_writeb(0x00, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
}
+/* Add frame information for one pcm subframe */
+static u32 hdmi_dma_add_frame_info(struct imx_hdmi_dma_runtime_data *rtd,
+ u32 pcm_data, int subframe_idx)
+{
+ hdmi_audio_dma_data_t subframe;
+ int i;
+
+ subframe.U = 0;
+ iec_header.B.channel = subframe_idx;
+
+ /* fill b (start-of-block) */
+ subframe.B.b = (rtd->frame_idx == 0) ? 1 : 0;
+
+ /* fill c (channel status) */
+ if (rtd->frame_idx < 42)
+ subframe.B.c = (iec_header.U >> rtd->frame_idx) & 0x1;
+ else
+ subframe.B.c = 0;
+
+ /* fill p (parity) */
+ for (i = 0 ; i < rtd->sample_bits ; i++)
+ subframe.B.p ^= (pcm_data >> i) & 0x01;
+ subframe.B.p ^= subframe.B.c;
+ subframe.B.p ^= subframe.B.u;
+ subframe.B.p ^= subframe.B.v;
+
+ /* fill data */
+ if (rtd->sample_bits == 16)
+ subframe.B.data = pcm_data << 8;
+ else
+ subframe.B.data = pcm_data;
+
+ return subframe.U;
+}
+
+/* Increment the frame index. We save frame_idx in case a frame
+ * spans more than one dma period. */
+static void hdmi_dma_incr_frame_idx(struct imx_hdmi_dma_runtime_data *rtd)
+{
+ rtd->frame_idx++;
+ if (rtd->frame_idx == 192)
+ rtd->frame_idx = 0;
+}
+
+static void hdmi_dma_mmap_copy(struct snd_pcm_substream *substream,
+ int offset, int count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct imx_hdmi_dma_runtime_data *rtd = runtime->private_data;
+ u32 *hw_buf, *dma_buf_u32;
+ u16 *dma_buf_u16;
+ int subframe_idx;
+
+ /* dma_buffer is the mmapped buffer we are copying pcm from. */
+ dma_buf_u16 = (u16 *)(runtime->dma_area + offset);
+ dma_buf_u32 = (u32 *)(runtime->dma_area + offset);
+
+ /* hw_buffer is the destination for pcm data plus frame info. */
+ hw_buf = (u32 *)(rtd->hw_buffer.area + (offset * rtd->buffer_ratio));
+
+ while (count > 0) {
+ for (subframe_idx = 1 ; subframe_idx <= rtd->channels ; subframe_idx++) {
+ if (rtd->sample_align == 2)
+ *hw_buf++ = hdmi_dma_add_frame_info(rtd, *dma_buf_u16++, subframe_idx);
+ else
+ *hw_buf++ = hdmi_dma_add_frame_info(rtd, *dma_buf_u32++, subframe_idx);
+
+ count -= rtd->sample_align;
+ }
+ hdmi_dma_incr_frame_idx(rtd);
+ }
+}
+
static irqreturn_t hdmi_dma_isr(int irq, void *dev_id)
{
struct imx_hdmi_dma_runtime_data *rtd = dev_id;
struct snd_pcm_substream *substream = rtd->tx_substream;
- struct snd_dma_buffer *dma_buffer;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long offset, count, space_to_end, appl_bytes;
unsigned int status;
- unsigned int dma_offset;
unsigned long flags;
spin_lock_irqsave(&rtd->irq_lock, flags);
@@ -249,17 +323,28 @@ static irqreturn_t hdmi_dma_isr(int irq, void *dev_id)
rtd->offset += rtd->period_bytes;
rtd->offset %= rtd->period_bytes * rtd->periods;
- dma_offset = rtd->offset * rtd->buffer_ratio;
+ /* For mmap access, need to copy data from dma_buffer to hw_buffer
+ * and add the frame info. */
+ if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
+ appl_bytes = frames_to_bytes(runtime,
+ runtime->control->appl_ptr);
+ count = appl_bytes - rtd->appl_bytes;
+ offset = rtd->appl_bytes % rtd->buffer_bytes;
+ space_to_end = rtd->buffer_bytes - offset;
+
+ if (count <= space_to_end)
+ hdmi_dma_mmap_copy(substream, offset, count);
+ else {
+ hdmi_dma_mmap_copy(substream, offset, space_to_end);
+ hdmi_dma_mmap_copy(substream, 0, count - space_to_end);
+ }
+ rtd->appl_bytes = appl_bytes;
+ }
snd_pcm_period_elapsed(substream);
- pr_debug("HDMI DMA Done interrupt: period_bytes=%d offset=%d\n",
- rtd->period_bytes, (int)rtd->offset);
-
- dma_buffer = &substream->dma_buffer;
-
- hdmi_dma_set_addr(dma_buffer->addr + dma_offset,
- rtd->dma_period_bytes);
+ hdmi_dma_set_addr(rtd->hw_buffer.addr + (rtd->offset * rtd->buffer_ratio),
+ rtd->dma_period_bytes);
hdmi_dma_start();
}
@@ -381,10 +466,18 @@ static int hdmi_dma_update_iec_header(struct snd_pcm_substream *substream)
iec_header.B.sample_freq = 0x02;
iec_header.B.org_sample_freq = 0x0D;
break;
+ case 88200:
+ iec_header.B.sample_freq = 0x08;
+ iec_header.B.org_sample_freq = 0x07;
+ break;
case 96000:
iec_header.B.sample_freq = 0x0A;
iec_header.B.org_sample_freq = 0x05;
break;
+ case 176400:
+ iec_header.B.sample_freq = 0x0C;
+ iec_header.B.org_sample_freq = 0x03;
+ break;
case 192000:
iec_header.B.sample_freq = 0x0E;
iec_header.B.org_sample_freq = 0x01;
@@ -421,59 +514,26 @@ static int hdmi_dma_copy(struct snd_pcm_substream *substream, int channel,
struct imx_hdmi_dma_runtime_data *rtd = runtime->private_data;
unsigned int count = frames_to_bytes(runtime, frames);
unsigned int pos_bytes = frames_to_bytes(runtime, pos);
-
- u8 *addr_start;
- u8 *addr_end;
- u32 *addr_cur;
- int subframe_idx, i;
- hdmi_audio_dma_data_t hdmi_audio_dma_data;
+ u32 *hw_buf;
+ int subframe_idx;
u32 pcm_data;
- addr_start = rtd->buf + (pos_bytes * rtd->buffer_ratio);
- addr_end = addr_start + (frames * rtd->channels * 4);
- addr_cur = (u32 *)addr_start;
+ /* Copy pcm data from userspace and add frame info. Destination is hw_buffer. */
+ hw_buf = (u32 *)(rtd->hw_buffer.area + (pos_bytes * rtd->buffer_ratio));
- while ((count > 0) && ((u32)addr_cur < (u32)addr_end)) {
+ while (count > 0) {
for (subframe_idx = 1 ; subframe_idx <= rtd->channels ; subframe_idx++) {
- pcm_data = 0;
+
if (copy_from_user(&pcm_data, buf, rtd->sample_align))
return -EFAULT;
+
buf += rtd->sample_align;
count -= rtd->sample_align;
- hdmi_audio_dma_data.U = 0;
- iec_header.B.channel = subframe_idx;
-
- /* fill b (start-of-block) */
- hdmi_audio_dma_data.B.b = (rtd->frame_idx == 0) ? 1 : 0;
-
- /* fill c (channel status) */
- if (rtd->frame_idx < 42)
- hdmi_audio_dma_data.B.c =
- (iec_header.U >> rtd->frame_idx) & 0x1;
- else
- hdmi_audio_dma_data.B.c = 0;
-
- /* fill p (parity) */
- for (i = 0 ; i < rtd->sample_bits ; i++)
- hdmi_audio_dma_data.B.p ^= (pcm_data >> i) & 0x01;
- hdmi_audio_dma_data.B.p ^= hdmi_audio_dma_data.B.c;
- hdmi_audio_dma_data.B.p ^= hdmi_audio_dma_data.B.u;
- hdmi_audio_dma_data.B.p ^= hdmi_audio_dma_data.B.v;
-
- /* fill data */
- if (rtd->sample_bits == 16)
- hdmi_audio_dma_data.B.data = pcm_data << 8;
- else
- hdmi_audio_dma_data.B.data = pcm_data;
-
- *addr_cur = hdmi_audio_dma_data.U;
- addr_cur++;
+ /* Save the header info to the audio dma buffer */
+ *hw_buf++ = hdmi_dma_add_frame_info(rtd, pcm_data, subframe_idx);
}
-
- rtd->frame_idx++;
- if (rtd->frame_idx == 192)
- rtd->frame_idx = 0;
+ hdmi_dma_incr_frame_idx(rtd);
}
return 0;
@@ -484,7 +544,6 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_hdmi_dma_runtime_data *rtd = runtime->private_data;
- struct snd_dma_buffer *dma_buffer = &substream->dma_buffer;
rtd->buffer_bytes = params_buffer_bytes(params);
rtd->periods = params_periods(params);
@@ -495,7 +554,6 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream,
rtd->offset = 0;
rtd->period_time = HZ / (params_rate(params) / params_period_size(params));
- rtd->buf = (unsigned int *)dma_buffer->area;
switch (rtd->format) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -520,7 +578,7 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream,
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
hdmi_dma_configure_dma(rtd->channels);
- hdmi_dma_set_addr(dma_buffer->addr, rtd->dma_period_bytes);
+ hdmi_dma_set_addr(rtd->hw_buffer.addr, rtd->dma_period_bytes);
dumprtd(rtd);
@@ -539,6 +597,12 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
rtd->frame_idx = 0;
+ if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
+ rtd->appl_bytes = frames_to_bytes(runtime,
+ runtime->control->appl_ptr);
+
+ hdmi_dma_mmap_copy(substream, 0, rtd->appl_bytes);
+ }
dumpregs();
hdmi_dma_irq_mask(0);
hdmi_dma_start();
@@ -569,6 +633,8 @@ static snd_pcm_uframes_t hdmi_dma_pointer(struct snd_pcm_substream *substream)
static struct snd_pcm_hardware snd_imx_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = MXC_HDMI_FORMATS_PLAYBACK,
@@ -686,9 +752,12 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = HDMI_DMA_BUF_SIZE;
+ struct snd_dma_buffer *hw_buffer = &hdmi_dma_priv->hw_buffer;
- buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ /* The 'dma_buffer' is the buffer alsa knows about.
+ * It contains only raw audio. */
+ buf->area = dma_alloc_writecombine(pcm->card->dev,
+ HDMI_DMA_BUF_SIZE / 2,
&buf->addr, GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
@@ -696,10 +765,19 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
- buf->bytes = size;
+ buf->bytes = HDMI_DMA_BUF_SIZE / 2;
hdmi_dma_priv->tx_substream = substream;
+ /* For mmap access, isr will copy from the dma_buffer to the hw_buffer */
+ hw_buffer->area = dma_alloc_writecombine(pcm->card->dev,
+ HDMI_DMA_BUF_SIZE,
+ &hw_buffer->addr, GFP_KERNEL);
+ if (!hw_buffer->area)
+ return -ENOMEM;
+
+ hw_buffer->bytes = HDMI_DMA_BUF_SIZE;
+
return 0;
}
@@ -730,6 +808,7 @@ static void imx_hdmi_dma_pcm_free(struct snd_pcm *pcm)
struct snd_dma_buffer *buf;
int stream;
+ /* free each dma_buffer */
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
if (!substream)
@@ -743,6 +822,14 @@ static void imx_hdmi_dma_pcm_free(struct snd_pcm *pcm)
buf->area, buf->addr);
buf->area = NULL;
}
+
+ /* free the hw_buffer */
+ buf = &hdmi_dma_priv->hw_buffer;
+ if (buf->area) {
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
}
static struct snd_soc_platform_driver imx_soc_platform_mx2 = {