summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinyu Chen <xinyu.chen@freescale.com>2012-04-20 13:02:04 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-04-20 13:02:04 +0800
commitb0cf397cecdecc102b82fc844b7a9e098d841187 (patch)
tree681e410089711d7e8d13cd819004e698fa6fec14
parenteb1da050c08bb961a1e45dd51f97821d3eeb2ae9 (diff)
parenta7fbbad7276b41e8b338afafcaedf8c005de5c48 (diff)
Merge remote branch 'fsl-linux-sdk/imx_3.0.15_12.04.01' into imx_3.0.15_android
Conflicts: arch/arm/kernel/traps.c arch/arm/mach-mx6/board-mx6q_sabresd.c arch/arm/mach-mx6/cpu.c arch/arm/mach-mx6/system.c
-rwxr-xr-xarch/arm/mach-mx5/clock.c12
-rw-r--r--arch/arm/mach-mx6/Kconfig2
-rw-r--r--arch/arm/mach-mx6/Makefile4
-rw-r--r--arch/arm/mach-mx6/board-mx6q_arm2.c29
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabreauto.c53
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabreauto.h8
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabrelite.c1
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabresd.c62
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabresd.h19
-rw-r--r--arch/arm/mach-mx6/board-mx6solo_sabreauto.h5
-rw-r--r--arch/arm/mach-mx6/bus_freq.c223
-rw-r--r--arch/arm/mach-mx6/clock.c71
-rw-r--r--arch/arm/mach-mx6/cpu.c5
-rw-r--r--arch/arm/mach-mx6/devices-imx6q.h6
-rw-r--r--arch/arm/mach-mx6/mx6_ddr_freq.S873
-rw-r--r--arch/arm/mach-mx6/mx6_mmdc.c313
-rw-r--r--arch/arm/mach-mx6/pcie.c410
-rw-r--r--arch/arm/mach-mx6/system.c19
-rwxr-xr-xarch/arm/plat-mxc/clock.c13
-rwxr-xr-xarch/arm/plat-mxc/cpufreq.c9
-rwxr-xr-xarch/arm/plat-mxc/devices/Kconfig3
-rwxr-xr-xarch/arm/plat-mxc/devices/Makefile1
-rwxr-xr-xarch/arm/plat-mxc/devices/platform-imx-dma.c4
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-pcie.c61
-rwxr-xr-xarch/arm/plat-mxc/include/mach/devices-common.h12
-rw-r--r--arch/arm/plat-mxc/include/mach/pcie.h39
-rw-r--r--arch/arm/plat-mxc/include/mach/sdma.h2
-rw-r--r--drivers/dma/imx-sdma.c6
-rw-r--r--drivers/dma/mxs-dma.c2
-rw-r--r--drivers/media/radio/Kconfig13
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/si4763-i2c.c933
-rw-r--r--drivers/media/radio/si4763-i2c.h249
-rw-r--r--drivers/media/video/mxc/output/mxc_vout.c263
-rw-r--r--drivers/mfd/mxc-hdmi-core.c29
-rw-r--r--drivers/mtd/nand/Kconfig2
-rw-r--r--drivers/mtd/nand/gpmi-nand/bch-regs.h2
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c334
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c70
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h3
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-regs.h209
-rw-r--r--drivers/mxc/ipu3/ipu_device.c5
-rw-r--r--drivers/mxc/ipu3/vdoa.c2
-rw-r--r--drivers/rtc/rtc-snvs.c3
-rw-r--r--drivers/spi/spi_imx.c11
-rw-r--r--drivers/tty/serial/imx.c4
-rwxr-xr-xdrivers/usb/gadget/arcotg_udc.c6
-rwxr-xr-xdrivers/usb/gadget/arcotg_udc.h6
-rw-r--r--drivers/video/mxc/mxc_epdc_fb.c26
-rw-r--r--drivers/video/mxc_hdmi.c4
-rw-r--r--firmware/imx/sdma/sdma-imx6q-to1.bin.ihex187
-rw-r--r--include/linux/ipu.h2
-rw-r--r--include/linux/mfd/mxc-hdmi-core.h1
-rw-r--r--include/linux/mtd/gpmi-nand.h1
-rw-r--r--include/media/radio-si4763.h20
-rw-r--r--include/media/si4763.h48
-rw-r--r--kernel/futex.c87
-rw-r--r--kernel/futex_compat.c36
-rw-r--r--sound/soc/codecs/cs42888.c14
-rw-r--r--sound/soc/codecs/wm8962.c3
-rw-r--r--sound/soc/imx/imx-esai.c22
-rw-r--r--sound/soc/imx/imx-hdmi-dma.c35
-rw-r--r--sound/soc/imx/imx-ssi.c6
-rw-r--r--sound/soc/imx/imx-wm8962.c4
64 files changed, 4488 insertions, 420 deletions
diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c
index d34a8c944fe4..bf60ffa6ef8f 100755
--- a/arch/arm/mach-mx5/clock.c
+++ b/arch/arm/mach-mx5/clock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -148,11 +148,6 @@ static int _clk_enable(struct clk *clk)
reg |= MXC_CCM_CCGRx_CG_MASK << clk->enable_shift;
__raw_writel(reg, clk->enable_reg);
- if (clk->flags & AHB_HIGH_SET_POINT)
- lp_high_freq++;
- else if (clk->flags & AHB_MED_SET_POINT)
- lp_med_freq++;
-
return 0;
}
@@ -173,11 +168,6 @@ static void _clk_disable(struct clk *clk)
reg = __raw_readl(clk->enable_reg);
reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
__raw_writel(reg, clk->enable_reg);
-
- if (clk->flags & AHB_HIGH_SET_POINT)
- lp_high_freq--;
- else if (clk->flags & AHB_MED_SET_POINT)
- lp_med_freq--;
}
static void _clk_disable_inwait(struct clk *clk)
diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig
index 1df24213195b..1db924a0975e 100644
--- a/arch/arm/mach-mx6/Kconfig
+++ b/arch/arm/mach-mx6/Kconfig
@@ -60,6 +60,7 @@ config MACH_MX6Q_ARM2
select IMX_HAVE_PLATFORM_MXC_MLB
select IMX_HAVE_PLATFORM_IMX_EPDC
select IMX_HAVE_PLATFORM_IMX_PXP
+ select IMX_HAVE_PLATFORM_IMX_PCIE
help
Include support for i.MX 6Quad Armadillo2 platform. This includes specific
configurations for the board and its peripherals.
@@ -124,6 +125,7 @@ config MACH_MX6Q_SABRESD
select IMX_HAVE_PLATFORM_MXC_HDMI
select IMX_HAVE_PLATFORM_IMX_ASRC
select IMX_HAVE_PLATFORM_FLEXCAN
+ select IMX_HAVE_PLATFORM_IMX_PCIE
help
Include support for i.MX 6Quad SABRE SD platform. This includes specific
configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile
index 21f776ab598c..e76f438c9194 100644
--- a/arch/arm/mach-mx6/Makefile
+++ b/arch/arm/mach-mx6/Makefile
@@ -3,7 +3,9 @@
#
# Object file lists.
-obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o usb_h3.o pm.o cpu_op-mx6.o mx6_wfi.o mx6_fec.o mx6_anatop_regulator.o cpu_regulator-mx6.o
+obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o usb_h3.o \
+pm.o cpu_op-mx6.o mx6_wfi.o mx6_fec.o mx6_anatop_regulator.o cpu_regulator-mx6.o \
+mx6_mmdc.o mx6_ddr_freq.o
obj-$(CONFIG_ARCH_MX6) += clock.o mx6q_suspend.o
obj-$(CONFIG_MACH_MX6Q_ARM2) += board-mx6q_arm2.o
diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c
index cf6a76076c4f..ca04938126f8 100644
--- a/arch/arm/mach-mx6/board-mx6q_arm2.c
+++ b/arch/arm/mach-mx6/board-mx6q_arm2.c
@@ -150,6 +150,9 @@
#define MX6_ARM2_IO_EXP_GPIO1(x) (MX6_ARM2_MAX7310_1_BASE_ADDR + (x))
#define MX6_ARM2_IO_EXP_GPIO2(x) (MX6_ARM2_MAX7310_2_BASE_ADDR + (x))
+#define MX6_ARM2_PCIE_PWR_EN MX6_ARM2_IO_EXP_GPIO1(2)
+#define MX6_ARM2_PCIE_RESET MX6_ARM2_IO_EXP_GPIO2(2)
+
#define MX6_ARM2_CAN2_STBY MX6_ARM2_IO_EXP_GPIO2(1)
@@ -169,6 +172,7 @@ extern char *gp_reg_id;
extern int epdc_enabled;
extern void mx6_cpu_regulator_init(void);
static int max17135_regulator_init(struct max17135 *max17135);
+extern volatile int num_cpu_idle_lock;
enum sd_pad_mode {
SD_PAD_MODE_LOW_SPEED,
@@ -319,15 +323,24 @@ static int __init gpmi_nand_platform_init(void)
return mxc_iomux_v3_setup_multiple_pads(nand_pads, nand_pads_cnt);
}
-static const struct gpmi_nand_platform_data
-mx6_gpmi_nand_platform_data __initconst = {
+static struct gpmi_nand_platform_data
+mx6_gpmi_nand_platform_data = {
.platform_init = gpmi_nand_platform_init,
.min_prop_delay_in_ns = 5,
.max_prop_delay_in_ns = 9,
.max_chip_count = 1,
.enable_bbt = 1,
+ .enable_ddr = 0,
};
+static int __init board_support_onfi_nand(char *p)
+{
+ mx6_gpmi_nand_platform_data.enable_ddr = 1;
+ return 0;
+}
+
+early_param("onfi_support", board_support_onfi_nand);
+
static const struct anatop_thermal_platform_data
mx6_arm2_anatop_thermal_data __initconst = {
.name = "anatop_thermal",
@@ -1952,6 +1965,13 @@ static struct mxc_spdif_platform_data mxc_spdif_data = {
.spdif_clk = NULL, /* spdif bus clk */
};
+static const struct imx_pcie_platform_data mx6_arm2_pcie_data __initconst = {
+ .pcie_pwr_en = MX6_ARM2_PCIE_PWR_EN,
+ .pcie_rst = MX6_ARM2_PCIE_RESET,
+ .pcie_wake_up = -EINVAL,
+ .pcie_dis = -EINVAL,
+};
+
static int __init early_disable_mipi_dsi(char *p)
{
/*enable on board HDMI*/
@@ -2012,6 +2032,7 @@ static void __init mx6_arm2_init(void)
spdif_pads_cnt = ARRAY_SIZE(mx6dl_arm2_spdif_pads);
flexcan_pads_cnt = ARRAY_SIZE(mx6dl_arm2_can_pads);
i2c3_pads_cnt = ARRAY_SIZE(mx6dl_arm2_i2c3_pads);
+ num_cpu_idle_lock = 0xffff0000;
}
BUG_ON(!common_pads);
@@ -2062,6 +2083,8 @@ static void __init mx6_arm2_init(void)
gp_reg_id = arm2_dvfscore_data.reg_id;
mx6_arm2_init_uart();
+
+
imx6q_add_mipi_csi2(&mipi_csi2_pdata);
imx6q_add_mxc_hdmi_core(&hdmi_core_data);
@@ -2191,6 +2214,8 @@ static void __init mx6_arm2_init(void)
mxc_register_device(&max17135_sensor_device, NULL);
imx6dl_add_imx_epdc(&epdc_data);
}
+ imx6q_add_pcie(&mx6_arm2_pcie_data);
+ imx6q_add_busfreq();
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
index bc32f5674cbf..273a55ab27e6 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
@@ -139,6 +139,8 @@ static struct clk *sata_clk;
static int mipi_sensor;
static int can0_enable;
static int uart3_en;
+static int tuner_en;
+extern volatile int num_cpu_idle_lock;
static int __init uart3_enable(char *p)
{
@@ -147,6 +149,13 @@ static int __init uart3_enable(char *p)
}
early_param("uart3", uart3_enable);
+static int __init tuner_enable(char *p)
+{
+ tuner_en = 1;
+ return 0;
+}
+early_param("tuner", tuner_enable);
+
enum sd_pad_mode {
SD_PAD_MODE_LOW_SPEED,
SD_PAD_MODE_MED_SPEED,
@@ -660,8 +669,29 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
I2C_BOARD_INFO("cs42888", 0x48),
.platform_data = (void *)&cs42888_data,
},
+ {
+ I2C_BOARD_INFO("si4763_i2c", 0x63),
+ },
+
+};
+struct platform_device mxc_si4763_audio_device = {
+ .name = "imx-tuner-si4763",
+ .id = 0,
};
+struct platform_device si4763_codec_device = {
+ .name = "si4763",
+ .id = 0,
+};
+
+static struct imx_ssi_platform_data mx6_sabreauto_ssi1_pdata = {
+ .flags = IMX_SSI_DMA | IMX_SSI_SYN,
+};
+static struct mxc_audio_platform_data si4763_audio_data = {
+ .ssi_num = 1,
+ .src_port = 2,
+ .ext_port = 5,
+};
static void imx6q_sabreauto_usbotg_vbus(bool on)
{
if (on)
@@ -1272,23 +1302,27 @@ static void __init mx6_board_init(void)
iomux_v3_cfg_t *can1_pads = NULL;
iomux_v3_cfg_t *mipi_sensor_pads = NULL;
iomux_v3_cfg_t *i2c3_pads = NULL;
+ iomux_v3_cfg_t *tuner_pads = NULL;
int common_pads_cnt;
int can0_pads_cnt;
int can1_pads_cnt;
int mipi_sensor_pads_cnt;
int i2c3_pads_cnt;
+ int tuner_pads_cnt;
if (cpu_is_mx6q()) {
common_pads = mx6q_sabreauto_pads;
can0_pads = mx6q_sabreauto_can0_pads;
can1_pads = mx6q_sabreauto_can1_pads;
mipi_sensor_pads = mx6q_sabreauto_mipi_sensor_pads;
+ tuner_pads = mx6q_tuner_pads;
common_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_pads);
can0_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_can0_pads);
can1_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_can1_pads);
mipi_sensor_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_mipi_sensor_pads);
+ tuner_pads_cnt = ARRAY_SIZE(mx6q_tuner_pads);
if (board_is_mx6_reva()) {
i2c3_pads = mx6q_i2c3_pads_rev_a;
i2c3_pads_cnt = ARRAY_SIZE(mx6q_i2c3_pads_rev_a);
@@ -1301,11 +1335,13 @@ static void __init mx6_board_init(void)
can0_pads = mx6dl_sabreauto_can0_pads;
can1_pads = mx6dl_sabreauto_can1_pads;
mipi_sensor_pads = mx6dl_sabreauto_mipi_sensor_pads;
+ tuner_pads = mx6dl_tuner_pads;
common_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_pads);
can0_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_can0_pads);
can1_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_can1_pads);
mipi_sensor_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_mipi_sensor_pads);
+ tuner_pads_cnt = ARRAY_SIZE(mx6dl_tuner_pads);
if (board_is_mx6_reva()) {
i2c3_pads = mx6dl_i2c3_pads_rev_a;
i2c3_pads_cnt = ARRAY_SIZE(mx6dl_i2c3_pads_rev_a);
@@ -1313,6 +1349,7 @@ static void __init mx6_board_init(void)
i2c3_pads = mx6dl_i2c3_pads_rev_b;
i2c3_pads_cnt = ARRAY_SIZE(mx6dl_i2c3_pads_rev_b);
}
+ num_cpu_idle_lock = 0xffff0000;
}
BUG_ON(!common_pads);
@@ -1325,9 +1362,14 @@ static void __init mx6_board_init(void)
mxc_iomux_v3_setup_multiple_pads(can0_pads,
can0_pads_cnt);
}
- BUG_ON(!can1_pads);
- mxc_iomux_v3_setup_multiple_pads(can1_pads, can1_pads_cnt);
+ BUG_ON(!can1_pads);
+ mxc_iomux_v3_setup_multiple_pads(can1_pads, can1_pads_cnt);
+ if (tuner_en) {
+ BUG_ON(!tuner_pads);
+ mxc_iomux_v3_setup_multiple_pads(tuner_pads,
+ tuner_pads_cnt);
+ }
/* assert i2c-rst */
gpio_request(SABREAUTO_I2C_EXP_RST, "i2c-rst");
@@ -1483,6 +1525,13 @@ static void __init mx6_board_init(void)
imx6q_add_hdmi_soc();
imx6q_add_hdmi_soc_dai();
imx6q_add_mlb150(&mx6_sabreauto_mlb150_data);
+
+ /* Tuner audio interface */
+ imx6q_add_imx_ssi(1, &mx6_sabreauto_ssi1_pdata);
+ mxc_register_device(&si4763_codec_device, NULL);
+ mxc_register_device(&mxc_si4763_audio_device, &si4763_audio_data);
+
+ imx6q_add_busfreq();
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.h b/arch/arm/mach-mx6/board-mx6q_sabreauto.h
index d2a097ec5e17..4c74a6aba961 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabreauto.h
+++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.h
@@ -138,6 +138,7 @@ static iomux_v3_cfg_t mx6q_sabreauto_pads[] = {
MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18,
MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19,
MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21,
+
/* LITE_SENS_INT_B */
MX6Q_PAD_DISP0_DAT23__GPIO_5_17,
/*PMIC INT*/
@@ -347,3 +348,10 @@ static iomux_v3_cfg_t mx6q_i2c3_pads_rev_b[] __initdata = {
MX6Q_PAD_EIM_A24__GPIO_5_4,
MX6Q_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT,
};
+static iomux_v3_cfg_t mx6q_tuner_pads[] __initdata = {
+ MX6Q_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC,
+ MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS,
+ MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD,
+
+};
+
diff --git a/arch/arm/mach-mx6/board-mx6q_sabrelite.c b/arch/arm/mach-mx6/board-mx6q_sabrelite.c
index c93da957070e..e00994f6fad8 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabrelite.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabrelite.c
@@ -1210,6 +1210,7 @@ static void __init mx6_sabrelite_board_init(void)
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
+ imx6q_add_busfreq();
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.c b/arch/arm/mach-mx6/board-mx6q_sabresd.c
index 3f81e1526aa5..977ec971af6a 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabresd.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabresd.c
@@ -68,6 +68,7 @@
#include <mach/ipu-v3.h>
#include <mach/mxc_hdmi.h>
#include <mach/mxc_asrc.h>
+#include <mach/mipi_dsi.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -145,7 +146,6 @@
#define SABRESD_DI1_D0_CS IMX_GPIO_NR(6, 31)
#define SABRESD_HEADPHONE_DET IMX_GPIO_NR(7, 8)
-#define SABRESD_USB_HUB_RESET IMX_GPIO_NR(7, 12)
#define SABRESD_PCIE_RST_B_REVB IMX_GPIO_NR(7, 12)
#define SABRESD_PMIC_INT_B IMX_GPIO_NR(7, 13)
#define SABRESD_PFUZE_INT IMX_GPIO_NR(7, 13)
@@ -197,9 +197,12 @@
static struct clk *sata_clk;
static int mma8451_position = 1;
static int mag3110_position = 2;
+static int disable_ldb;
extern char *gp_reg_id;
extern int epdc_enabled;
+extern volatile int num_cpu_idle_lock;
+
static int max17135_regulator_init(struct max17135 *max17135);
static const struct esdhc_platform_data mx6q_sabresd_sd2_data __initconst = {
@@ -1165,6 +1168,28 @@ static struct imx_asrc_platform_data imx_asrc_data = {
.clk_map_ver = 2,
};
+static void mx6_reset_mipi_dsi(void)
+{
+ gpio_set_value(SABRESD_DISP_PWR_EN, 1);
+ gpio_set_value(SABRESD_DISP_RST_B, 1);
+ udelay(10);
+ gpio_set_value(SABRESD_DISP_RST_B, 0);
+ udelay(50);
+ gpio_set_value(SABRESD_DISP_RST_B, 1);
+
+ /*
+ * it needs to delay 120ms minimum for reset complete
+ */
+ msleep(120);
+}
+
+static struct mipi_dsi_platform_data mipi_dsi_pdata = {
+ .ipu_id = 0,
+ .disp_id = 1,
+ .lcd_panel = "TRULY-WVGA",
+ .reset = mx6_reset_mipi_dsi,
+};
+
static struct ipuv3_fb_platform_data sabresd_fb_data[] = {
{ /*fb0*/
.disp_dev = "ldb",
@@ -1481,6 +1506,21 @@ static void mx6_snvs_poweroff(void)
writel(value | 0x60, mx6_snvs_base + SNVS_LPCR);
}
+static const struct imx_pcie_platform_data mx6_sabresd_pcie_data __initconst = {
+ .pcie_pwr_en = SABRESD_PCIE_PWR_EN,
+ .pcie_rst = SABRESD_PCIE_RST_B_REVB,
+ .pcie_wake_up = SABRESD_PCIE_WAKE_B,
+ .pcie_dis = SABRESD_PCIE_DIS_B,
+};
+
+static int __init early_disable_ldb(char *p)
+{
+ /*mipi dsi need pll3_pfd_540M as 540MHz, ldb will change to 454Mhz*/
+ disable_ldb = 1;
+ return 0;
+}
+
+early_param("disable_ldb", early_disable_ldb);
/*!
* Board specific initialization.
*/
@@ -1495,9 +1535,11 @@ static void __init mx6_sabresd_board_init(void)
if (cpu_is_mx6q())
mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads,
ARRAY_SIZE(mx6q_sabresd_pads));
- else if (cpu_is_mx6dl())
+ else if (cpu_is_mx6dl()) {
mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_pads,
ARRAY_SIZE(mx6dl_sabresd_pads));
+ num_cpu_idle_lock = 0xffff0000;
+ }
#ifdef CONFIG_FEC_1588
/* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock
@@ -1529,7 +1571,12 @@ static void __init mx6_sabresd_board_init(void)
*/
if (cpu_is_mx6dl()) {
ldb_data.ipu_id = 0;
- ldb_data.disp_id = 1;
+ ldb_data.disp_id = 0;
+ ldb_data.sec_ipu_id = 0;
+ ldb_data.sec_disp_id = 1;
+ hdmi_core_data.disp_id = 1;
+ mipi_dsi_pdata.ipu_id = 0;
+ mipi_dsi_pdata.disp_id = 1;
}
imx6q_add_mxc_hdmi_core(&hdmi_core_data);
@@ -1540,8 +1587,10 @@ static void __init mx6_sabresd_board_init(void)
imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]);
imx6q_add_vdoa();
+ imx6q_add_mipi_dsi(&mipi_dsi_pdata);
imx6q_add_lcdif(&lcdif_data);
- imx6q_add_ldb(&ldb_data);
+ if (!disable_ldb)
+ imx6q_add_ldb(&ldb_data);
imx6q_add_v4l2_output(0);
imx6q_add_v4l2_capture(0);
imx6q_add_mipi_csi2(&mipi_csi2_pdata);
@@ -1599,9 +1648,6 @@ static void __init mx6_sabresd_board_init(void)
imx_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk");
imx6q_add_asrc(&imx_asrc_data);
- /* release USB Hub reset */
- gpio_set_value(SABRESD_USB_HUB_RESET, 1);
-
imx6q_add_mxc_pwm(0);
imx6q_add_mxc_pwm(1);
imx6q_add_mxc_pwm(2);
@@ -1676,7 +1722,9 @@ static void __init mx6_sabresd_board_init(void)
/* Register charger chips */
platform_device_register(&sabresd_max8903_charger_1);
pm_power_off = mx6_snvs_poweroff;
+ imx6q_add_busfreq();
+ imx6q_add_pcie(&mx6_sabresd_pcie_data);
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.h b/arch/arm/mach-mx6/board-mx6q_sabresd.h
index f4c04d3111b5..8ccb3423424f 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabresd.h
+++ b/arch/arm/mach-mx6/board-mx6q_sabresd.h
@@ -38,9 +38,10 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
MX6Q_PAD_GPIO_3__CCM_CLKO2, /* J5 - Camera MCLK */
/* ECSPI1 */
- MX6Q_PAD_EIM_D17__ECSPI1_MISO,
- MX6Q_PAD_EIM_D18__ECSPI1_MOSI,
-
+ MX6Q_PAD_KEY_COL0__ECSPI1_SCLK,
+ MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI,
+ MX6Q_PAD_KEY_COL1__ECSPI1_MISO,
+ MX6Q_PAD_KEY_ROW1__GPIO_4_9,
/* ENET */
MX6Q_PAD_ENET_MDIO__ENET_MDIO,
MX6Q_PAD_ENET_MDC__ENET_MDC,
@@ -122,9 +123,6 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
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 */
-
/* I2C1, WM8958 */
MX6Q_PAD_CSI0_DAT8__I2C1_SDA,
MX6Q_PAD_CSI0_DAT9__I2C1_SCL,
@@ -250,7 +248,16 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
/*GPS AUX_3V15_EN*/
MX6Q_PAD_NANDF_WP_B__GPIO_6_9,
+ /* PCIE */
MX6Q_PAD_EIM_D19__GPIO_3_19, /* PCIE_PWR_EN */
+
+ MX6Q_PAD_GPIO_17__GPIO_7_12, /* PCIE_RST */
+ MX6Q_PAD_KEY_COL4__GPIO_4_14, /* PCIE_DIS */
+
+ /* DISP_RST_B */
+ MX6Q_PAD_NANDF_CS0__GPIO_6_11,
+ /* DISP_PWR_EN */
+ MX6Q_PAD_NANDF_CS1__GPIO_6_14,
};
static iomux_v3_cfg_t mx6q_sabresd_csi0_sensor_pads[] = {
diff --git a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h
index 3829c7ac38e6..dd113bab749b 100644
--- a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h
+++ b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h
@@ -350,3 +350,8 @@ static iomux_v3_cfg_t mx6dl_i2c3_pads_rev_b[] __initdata = {
MX6DL_PAD_EIM_A24__GPIO_5_4,
MX6DL_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT,
};
+static iomux_v3_cfg_t mx6dl_tuner_pads[] __initdata = {
+ MX6DL_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC,
+ MX6DL_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS,
+ MX6DL_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD,
+};
diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c
index 36308c14c8f2..e4244afe7ae7 100644
--- a/arch/arm/mach-mx6/bus_freq.c
+++ b/arch/arm/mach-mx6/bus_freq.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
@@ -43,58 +43,36 @@
#include <asm/mach-types.h>
#include <asm/cacheflush.h>
#include <asm/tlb.h>
+#include "crm_regs.h"
-#define LP_LOW_VOLTAGE 1050000
-#define LP_NORMAL_VOLTAGE 1250000
-#define LP_APM_CLK 24000000
-#define NAND_LP_APM_CLK 12000000
-#define AXI_A_NORMAL_CLK 166250000
-#define AXI_A_CLK_NORMAL_DIV 4
-#define AXI_B_CLK_NORMAL_DIV 5
-#define AHB_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV
-#define EMI_SLOW_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV
-#define NFC_CLK_NORMAL_DIV 4
-#define SPIN_DELAY 1000000 /* in nanoseconds */
-#define DDR_TYPE_DDR3 0x0
-#define DDR_TYPE_DDR2 0x1
-DEFINE_SPINLOCK(ddr_freq_lock);
-
-unsigned long lp_normal_rate;
-unsigned long lp_med_rate;
-unsigned long ddr_normal_rate;
-unsigned long ddr_med_rate;
-unsigned long ddr_low_rate;
+#define LPAPM_CLK 24000000
+#define DDR_MED_CLK 400000000
+#define DDR3_NORMAL_CLK 528000000
-struct regulator *pll_regulator;
+DEFINE_SPINLOCK(ddr_freq_lock);
-struct regulator *lp_regulator;
int low_bus_freq_mode;
int high_bus_freq_mode;
int med_bus_freq_mode;
int bus_freq_scaling_initialized;
-char *lp_reg_id;
-
static struct device *busfreq_dev;
static int busfreq_suspended;
/* True if bus_frequency is scaled not using DVFS-PER */
int bus_freq_scaling_is_active;
-int cpu_op_nr;
int lp_high_freq;
int lp_med_freq;
-
-struct workqueue_struct *voltage_wq;
-struct completion voltage_change_cmpl;
+unsigned int ddr_low_rate;
+unsigned int ddr_med_rate;
+unsigned int ddr_normal_rate;
int low_freq_bus_used(void);
void set_ddr_freq(int ddr_freq);
extern struct cpu_op *(*get_cpu_op)(int *op);
-extern void __iomem *ccm_base;
-extern void __iomem *databahn_base;
extern int update_ddr_freq(int ddr_rate);
@@ -103,29 +81,140 @@ struct mutex bus_freq_mutex;
struct timeval start_time;
struct timeval end_time;
-int set_low_bus_freq(void)
+static int cpu_op_nr;
+static struct cpu_op *cpu_op_tbl;
+static struct clk *pll2_400;
+static struct clk *cpu_clk;
+static unsigned int org_ldo;
+static struct clk *pll3;
+
+static struct delayed_work low_bus_freq_handler;
+
+static void reduce_bus_freq_handler(struct work_struct *work)
{
- return 0;
+ unsigned long reg;
+
+ if (low_bus_freq_mode || !low_freq_bus_used())
+ return;
+
+ while (!mutex_trylock(&bus_freq_mutex))
+ msleep(1);
+
+ /* PLL3 is used in the DDR freq change process, enable it. */
+
+ if (low_bus_freq_mode || !low_freq_bus_used()) {
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+ clk_enable(pll3);
+
+
+ update_ddr_freq(24000000);
+
+ if (med_bus_freq_mode)
+ clk_disable(pll2_400);
+
+ low_bus_freq_mode = 1;
+ high_bus_freq_mode = 0;
+ med_bus_freq_mode = 0;
+
+ /* Power gate the PU LDO. */
+ org_ldo = reg = __raw_readl(ANADIG_REG_CORE);
+ reg &= ~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET);
+ __raw_writel(reg, ANADIG_REG_CORE);
+
+ mutex_unlock(&bus_freq_mutex);
+ clk_disable(pll3);
+
+
}
-int set_high_bus_freq(int high_bus_freq)
+/* Set the DDR, AHB to 24MHz.
+ * This mode will be activated only when none of the modules that
+ * need a higher DDR or AHB frequency are active.
+ */
+int set_low_bus_freq(void)
{
+ if (busfreq_suspended)
+ return 0;
+
+ if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
+ return 0;
+
+ /* Don't lower the frequency immediately. Instead scheduled a delayed work
+ * and drop the freq if the conditions still remain the same.
+ */
+ schedule_delayed_work(&low_bus_freq_handler, usecs_to_jiffies(3000000));
return 0;
}
-void exit_lpapm_mode_mx6q(int high_bus_freq)
+/* Set the DDR to either 528MHz or 400MHz for MX6q
+ * or 400MHz for MX6DL.
+ */
+int set_high_bus_freq(int high_bus_freq)
{
+ if (busfreq_suspended)
+ return 0;
-}
+ if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
+ return 0;
+ if (high_bus_freq_mode && high_bus_freq)
+ return 0;
-void set_ddr_freq(int ddr_rate)
-{
+ if (med_bus_freq_mode && !high_bus_freq)
+ return 0;
+ while (!mutex_trylock(&bus_freq_mutex))
+ msleep(1);
+
+ if ((high_bus_freq_mode && (high_bus_freq || lp_high_freq)) ||
+ (med_bus_freq_mode && !high_bus_freq && lp_med_freq && !lp_high_freq)) {
+ mutex_unlock(&bus_freq_mutex);
+ return 0;
+ }
+ clk_enable(pll3);
+
+ /* Enable the PU LDO */
+ if (low_bus_freq_mode)
+ __raw_writel(org_ldo, ANADIG_REG_CORE);
+
+ if (high_bus_freq) {
+ update_ddr_freq(ddr_normal_rate);
+ if (med_bus_freq_mode)
+ clk_disable(pll2_400);
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 1;
+ med_bus_freq_mode = 0;
+ } else {
+ clk_enable(pll2_400);
+ update_ddr_freq(ddr_med_rate);
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 0;
+ med_bus_freq_mode = 1;
+ }
+
+ mutex_unlock(&bus_freq_mutex);
+ clk_disable(pll3);
+
+ return 0;
}
+
int low_freq_bus_used(void)
{
+ if (!bus_freq_scaling_initialized)
+ return 0;
+
+ /* We only go the lowest setpoint if ARM is also
+ * at the lowest setpoint.
+ */
+ if ((clk_get_rate(cpu_clk) >
+ cpu_op_tbl[cpu_op_nr - 1].cpu_rate)
+ || (cpu_op_nr == 1)) {
+ return 0;
+ }
+
if ((lp_high_freq == 0)
&& (lp_med_freq == 0))
return 1;
@@ -150,6 +239,14 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
+ if (strncmp(buf, "1", 1) == 0) {
+ bus_freq_scaling_is_active = 1;
+ set_high_bus_freq(0);
+ } else if (strncmp(buf, "0", 1) == 0) {
+ if (bus_freq_scaling_is_active)
+ set_high_bus_freq(1);
+ bus_freq_scaling_is_active = 0;
+ }
return size;
}
@@ -180,6 +277,54 @@ static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show,
*/
static int __devinit busfreq_probe(struct platform_device *pdev)
{
+ u32 err;
+
+ busfreq_dev = &pdev->dev;
+
+ pll2_400 = clk_get(NULL, "pll2_pfd_400M");
+ if (IS_ERR(pll2_400)) {
+ printk(KERN_DEBUG "%s: failed to get axi_clk\n",
+ __func__);
+ return PTR_ERR(pll2_400);
+ }
+
+ cpu_clk = clk_get(NULL, "cpu_clk");
+ if (IS_ERR(cpu_clk)) {
+ printk(KERN_DEBUG "%s: failed to get cpu_clk\n",
+ __func__);
+ return PTR_ERR(cpu_clk);
+ }
+
+ pll3 = clk_get(NULL, "pll3_main_clk");
+
+ err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
+ if (err) {
+ printk(KERN_ERR
+ "Unable to register sysdev entry for BUSFREQ");
+ return err;
+ }
+
+ cpu_op_tbl = get_cpu_op(&cpu_op_nr);
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 1;
+ med_bus_freq_mode = 0;
+ bus_freq_scaling_is_active = 0;
+ bus_freq_scaling_initialized = 1;
+
+ if (cpu_is_mx6q()) {
+ ddr_low_rate = LPAPM_CLK;
+ ddr_med_rate = DDR_MED_CLK;
+ ddr_normal_rate = DDR3_NORMAL_CLK;
+ }
+ if (cpu_is_mx6dl()) {
+ ddr_low_rate = LPAPM_CLK;
+ ddr_normal_rate = ddr_med_rate = DDR_MED_CLK;
+ }
+
+ INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler);
+
+ mutex_init(&bus_freq_mutex);
+
return 0;
}
@@ -218,7 +363,7 @@ static void __exit busfreq_cleanup(void)
bus_freq_scaling_initialized = 0;
}
-module_init(busfreq_init);
+late_initcall(busfreq_init);
module_exit(busfreq_cleanup);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c
index 889447b77076..1f7e4312158d 100644
--- a/arch/arm/mach-mx6/clock.c
+++ b/arch/arm/mach-mx6/clock.c
@@ -29,6 +29,8 @@
#include <mach/common.h>
#include <mach/clock.h>
#include <mach/mxc_dvfs.h>
+#include <mach/mxc_hdmi.h>
+#include <mach/ahci_sata.h>
#include "crm_regs.h"
#include "cpu_op-mx6.h"
#include "regs-anadig.h"
@@ -162,11 +164,6 @@ static int _clk_enable(struct clk *clk)
reg |= MXC_CCM_CCGRx_CG_MASK << clk->enable_shift;
__raw_writel(reg, clk->enable_reg);
- if (clk->flags & AHB_HIGH_SET_POINT)
- lp_high_freq++;
- else if (clk->flags & AHB_MED_SET_POINT)
- lp_med_freq++;
-
return 0;
}
@@ -176,11 +173,6 @@ static void _clk_disable(struct clk *clk)
reg = __raw_readl(clk->enable_reg);
reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
__raw_writel(reg, clk->enable_reg);
-
- if (clk->flags & AHB_HIGH_SET_POINT)
- lp_high_freq--;
- else if (clk->flags & AHB_MED_SET_POINT)
- lp_med_freq--;
}
static void _clk_disable_inwait(struct clk *clk)
@@ -2164,7 +2156,6 @@ static struct clk ipu2_clk = {
static struct clk usdhc_dep_clk = {
.parent = &mmdc_ch0_axi_clk[0],
.secondary = &mx6per1_clk,
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_usdhc_round_rate(struct clk *clk,
@@ -2242,7 +2233,6 @@ static struct clk usdhc1_clk = {
.round_rate = _clk_usdhc_round_rate,
.set_rate = _clk_usdhc1_set_rate,
.get_rate = _clk_usdhc1_get_rate,
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static int _clk_usdhc2_set_parent(struct clk *clk, struct clk *parent)
@@ -2300,7 +2290,6 @@ static struct clk usdhc2_clk = {
.round_rate = _clk_usdhc_round_rate,
.set_rate = _clk_usdhc2_set_rate,
.get_rate = _clk_usdhc2_get_rate,
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static int _clk_usdhc3_set_parent(struct clk *clk, struct clk *parent)
@@ -2359,7 +2348,6 @@ static struct clk usdhc3_clk = {
.round_rate = _clk_usdhc_round_rate,
.set_rate = _clk_usdhc3_set_rate,
.get_rate = _clk_usdhc3_get_rate,
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static int _clk_usdhc4_set_parent(struct clk *clk, struct clk *parent)
@@ -2418,7 +2406,6 @@ static struct clk usdhc4_clk = {
.round_rate = _clk_usdhc_round_rate,
.set_rate = _clk_usdhc4_set_rate,
.get_rate = _clk_usdhc4_get_rate,
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ssi_round_rate(struct clk *clk,
@@ -2703,12 +2690,16 @@ static int _clk_ldb_di0_set_rate(struct clk *clk, unsigned long rate)
static int _clk_ldb_di0_set_parent(struct clk *clk, struct clk *parent)
{
u32 reg, mux;
+ int rev = mx6q_revision();
reg = __raw_readl(MXC_CCM_CS2CDR)
& ~MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK;
mux = _get_mux6(parent, &pll5_video_main_clk,
- &pll2_pfd_352M, &pll2_pfd_400M, &pll3_pfd_540M,
+ &pll2_pfd_352M, &pll2_pfd_400M,
+ (rev == IMX_CHIP_REVISION_1_0) ?
+ &pll3_pfd_540M : /* MX6Q TO1.0 */
+ &mmdc_ch1_axi_clk[0], /* MX6Q TO1.1 and MX6DL */
&pll3_usb_otg_main_clk, NULL);
reg |= (mux << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET);
@@ -2720,7 +2711,7 @@ static int _clk_ldb_di0_set_parent(struct clk *clk, struct clk *parent)
static struct clk ldb_di0_clk = {
__INIT_CLK_DEBUG(ldb_di0_clk)
.id = 0,
- .parent = &pll3_pfd_540M,
+ .parent = &pll2_pfd_352M,
.enable_reg = MXC_CCM_CCGR3,
.enable_shift = MXC_CCM_CCGRx_CG6_OFFSET,
.enable = _clk_enable,
@@ -2770,12 +2761,16 @@ static int _clk_ldb_di1_set_rate(struct clk *clk, unsigned long rate)
static int _clk_ldb_di1_set_parent(struct clk *clk, struct clk *parent)
{
u32 reg, mux;
+ int rev = mx6q_revision();
reg = __raw_readl(MXC_CCM_CS2CDR)
& ~MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK;
mux = _get_mux6(parent, &pll5_video_main_clk,
- &pll2_pfd_352M, &pll2_pfd_400M, &pll3_pfd_540M,
+ &pll2_pfd_352M, &pll2_pfd_400M,
+ (rev == IMX_CHIP_REVISION_1_0) ?
+ &pll3_pfd_540M : /* MX6Q TO1.0 */
+ &mmdc_ch1_axi_clk[0], /* MX6Q TO1.1 and MX6DL */
&pll3_usb_otg_main_clk, NULL);
reg |= (mux << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
@@ -2787,7 +2782,7 @@ static int _clk_ldb_di1_set_parent(struct clk *clk, struct clk *parent)
static struct clk ldb_di1_clk = {
__INIT_CLK_DEBUG(ldb_di1_clk)
.id = 0,
- .parent = &pll3_pfd_540M,
+ .parent = &pll2_pfd_352M,
.enable_reg = MXC_CCM_CCGR3,
.enable_shift = MXC_CCM_CCGRx_CG7_OFFSET,
.enable = _clk_enable,
@@ -5022,7 +5017,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "caam_clk", caam_clk[0]),
_REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk[0]),
_REGISTER_CLOCK(NULL, "asrc_serial_clk", asrc_clk[1]),
- _REGISTER_CLOCK("mxs-dma-apbh", NULL, apbh_dma_clk),
+ _REGISTER_CLOCK(NULL, "mxs-dma-apbh", apbh_dma_clk),
_REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk),
_REGISTER_CLOCK(NULL, "gpu3d_clk", gpu3d_core_clk[0]),
_REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_core_clk[0]),
@@ -5084,7 +5079,7 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
unsigned long ckih1, unsigned long ckih2)
{
__iomem void *base;
- int i;
+ int i, reg;
external_low_reference = ckil;
external_high_reference = ckih1;
@@ -5178,6 +5173,7 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
clk_set_rate(&asrc_clk[1], 7500000);
/* set the GPMI clock to default frequency : 20MHz */
+ clk_set_parent(&enfc_clk, &pll2_pfd_400M);
clk_set_rate(&enfc_clk, enfc_clk.round_rate(&enfc_clk, 20000000));
mx6_cpu_op_init();
@@ -5213,8 +5209,8 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
__raw_writel(0, MXC_CCM_CCGR6);
- /* Lower the ipg_perclk frequency to 8.25MHz. */
- clk_set_rate(&ipg_perclk, 8250000);
+ /* Lower the ipg_perclk frequency to 6MHz. */
+ clk_set_rate(&ipg_perclk, 6000000);
/* Set pll2_pfd_352M frequency to 528M for gpu2d core clock */
clk_set_rate(&pll2_pfd_352M, 528000000);
@@ -5248,6 +5244,35 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
lp_high_freq = 0;
lp_med_freq = 0;
+ /* Turn OFF all unnecessary PHYs. */
+ if (cpu_is_mx6q()) {
+ /* Turn off SATA PHY. */
+ base = ioremap(MX6Q_SATA_BASE_ADDR, SZ_8K);
+ reg = __raw_readl(base + PORT_PHY_CTL);
+ __raw_writel(reg | PORT_PHY_CTL_PDDQ_LOC, base + PORT_PHY_CTL);
+ }
+
+ /* Turn off HDMI PHY. */
+ base = ioremap(MX6Q_HDMI_ARB_BASE_ADDR, SZ_128K);
+ reg = __raw_readb(base + HDMI_PHY_CONF0);
+ __raw_writeb(reg | HDMI_PHY_CONF0_GEN2_PDDQ_MASK, base + HDMI_PHY_CONF0);
+
+ reg = __raw_readb(base + HDMI_MC_PHYRSTZ);
+ __raw_writeb(reg | HDMI_MC_PHYRSTZ_DEASSERT, base + HDMI_MC_PHYRSTZ);
+
+ iounmap(base);
+
+ base = ioremap(MX6Q_IOMUXC_BASE_ADDR, SZ_4K);
+ /* Close PLL inside SATA PHY. */
+ reg = __raw_readl(base + 0x34);
+ __raw_writel(reg | (1 << 1), base + 0x34);
+
+ /* Close PCIE PHY. */
+ reg = __raw_readl(base + 0x04);
+ reg |= (1 << 18);
+ __raw_writel(reg, base + 0x04);
+ iounmap(base);
+
return 0;
}
diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c
index ddb4e0cf9976..6f3765e23523 100644
--- a/arch/arm/mach-mx6/cpu.c
+++ b/arch/arm/mach-mx6/cpu.c
@@ -36,7 +36,7 @@ extern unsigned int num_cpu_idle_lock;
void *mx6_wait_in_iram_base;
void (*mx6_wait_in_iram)(void);
extern void mx6_wait(void);
-
+extern int init_mmdc_settings(void);
struct cpu_op *(*get_cpu_op)(int *op);
bool enable_wait_mode;
@@ -92,8 +92,6 @@ static int __init post_cpu_init(void)
{
unsigned int reg;
void __iomem *base;
- unsigned long iram_paddr, cpaddr;
-
iram_init(MX6Q_IRAM_BASE_ADDR, MX6Q_IRAM_SIZE);
@@ -134,6 +132,7 @@ static int __init post_cpu_init(void)
num_cpu_idle_lock = 0x0;
+ init_mmdc_settings();
return 0;
}
postcore_initcall(post_cpu_init);
diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h
index 02ac1f409799..2c3e0c53ac06 100644
--- a/arch/arm/mach-mx6/devices-imx6q.h
+++ b/arch/arm/mach-mx6/devices-imx6q.h
@@ -210,3 +210,9 @@ extern const struct imx_epdc_data imx6dl_epdc_data __initconst;
imx_add_imx_epdc(&imx6dl_epdc_data, pdata)
extern const struct imx_vdoa_data imx6q_vdoa_data __initconst;
#define imx6q_add_vdoa() imx_add_vdoa(&imx6q_vdoa_data)
+
+extern const struct imx_pcie_data imx6q_pcie_data __initconst;
+#define imx6q_add_pcie(pdata) imx_add_pcie(&imx6q_pcie_data, pdata)
+
+#define imx6q_add_busfreq(pdata) imx_add_busfreq(pdata)
+
diff --git a/arch/arm/mach-mx6/mx6_ddr_freq.S b/arch/arm/mach-mx6/mx6_ddr_freq.S
new file mode 100644
index 000000000000..766d867ee1c4
--- /dev/null
+++ b/arch/arm/mach-mx6/mx6_ddr_freq.S
@@ -0,0 +1,873 @@
+/*
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/linkage.h>
+#include <mach/hardware.h>
+
+ .macro switch_to_528MHz
+
+ /* DDR freq change to 528MHz */
+
+ /* check if periph_clk_sel is already set */
+ ldr r0, [r6, #0x14]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ beq switch_pre_periph_clk_528
+
+ /* Step 1: Change periph_clk to be sourced from pll3_clk. */
+ /* Ensure PLL3 is the source and set the divider to 1. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0x3000
+ str r0, [r6, #0x18]
+
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x38000000
+ str r0, [r6, #0x14]
+
+ /* Now switch periph_clk to pll3_main_clk. */
+ ldr r0, [r6, #0x14]
+ orr r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch3:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch3
+
+switch_pre_periph_clk_528:
+
+ /* Now switch pre_periph_clk to PLL2_528MHz. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0xC0000
+ str r0, [r6, #0x18]
+
+ /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4 (need to maintain GPT divider). */
+ ldr r0, [r6, #0x14]
+ ldr r2, =0x3F1D00
+ bic r0, r0, r2
+ orr r0, r0, #0x10000
+ orr r0, r0, #0xD00
+ str r0, [r6, #0x14]
+
+wait_div_update1:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne wait_div_update1
+
+ /* Now switch periph_clk back. */
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch4:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch4
+
+ /* Change the GPT divider so that its at 6MHz. */
+ ldr r0, [r6, #0x1C]
+ bic r0, r0, #0x3F
+ orr r0, r0, #0xB
+ str r0, [r6, #0x1C]
+
+ .endm
+
+ .macro switch_to_400MHz
+
+ /* check if periph_clk_sel is already set */
+ ldr r0, [r6, #0x14]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ beq switch_pre_periph_clk_400
+
+ /* Step 1: Change periph_clk to be sourced from pll3_clk. */
+ /* Ensure PLL3 is the source and set the divider to 1. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0x3000
+ str r0, [r6, #0x18]
+
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x38000000
+ str r0, [r6, #0x14]
+
+ /* Now switch periph_clk to pll3_main_clk. */
+ ldr r0, [r6, #0x14]
+ orr r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch5:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch5
+
+switch_pre_periph_clk_400:
+
+ /* Now switch pre_periph_clk to PFD_400MHz. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0xC0000
+ orr r0, r0, #0x40000
+ str r0, [r6, #0x18]
+
+ /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=3 (need to maintain GPT divider). */
+ ldr r0, [r6, #0x14]
+ ldr r2, =0x3F1D00
+ bic r0, r0, r2
+ orr r0, r0, #0x10000
+ orr r0, r0, #0x900
+ str r0, [r6, #0x14]
+
+wait_div_update400:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne wait_div_update400
+
+ /* Now switch periph_clk back. */
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch6:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch6
+
+ /* Change the GPT divider so that its at 6MHz. */
+ ldr r0, [r6, #0x1C]
+ bic r0, r0, #0x3F
+ orr r0, r0, #0xB
+ str r0, [r6, #0x1C]
+
+ .endm
+
+ .macro switch_to_50MHz
+
+ /* Set DDR to 50MHz. */
+ /* check if periph_clk_sel is already set */
+ ldr r0, [r6, #0x14]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ beq switch_pre_periph_clk_50
+
+ /* Set the periph_clk to be sourced from PLL2_PFD_200M */
+ /* Step 1: Change periph_clk to be sourced from pll3_clk. */
+ /* Ensure PLL3 is the source and set the divider to 1. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0x3000
+ str r0, [r6, #0x18]
+
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x38000000
+ str r0, [r6, #0x14]
+
+ /* Now switch periph_clk to pll3_main_clk. */
+ ldr r0, [r6, #0x14]
+ orr r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch_50:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch_50
+
+switch_pre_periph_clk_50:
+
+ /* Now switch pre_periph_clk to PFD_200MHz. */
+ ldr r0, [r6, #0x18]
+ orr r0, r0, #0xC0000
+ str r0, [r6, #0x18]
+
+ /* Set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=6 (need to maintain GPT divider). */
+ ldr r0, [r6, #0x14]
+ ldr r2, =0x3F1C00
+ bic r0, r0, r2
+
+ orr r0, r0, #0x180000
+ orr r0, r0, #0x10000
+
+ /* If changing AHB divider remember to change the IPGPER divider too below. */
+ orr r0, r0, #0xC00
+ str r0, [r6, #0x14]
+
+wait_div_update_50:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne wait_div_update_50
+
+ /* Now switch periph_clk back. */
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch2:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch2
+
+ /* Change the GPT divider so that its at 6MHz. */
+ ldr r0, [r6, #0x1C]
+ bic r0, r0, #0x3F
+ orr r0, r0, #0x3
+ str r0, [r6, #0x1C]
+
+ .endm
+
+ .macro switch_to_24MHz
+ /* Change the freq now */
+ /* Try setting DDR to 24MHz. */
+ /* Source it from the periph_clk2 */
+ /* Ensure the periph_clk2 is sourced from 24MHz
+ and the divider is 1. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0x3000
+ orr r0, r0, #0x1000
+ str r0, [r6, #0x18]
+
+ ldr r0, [r6, #0x14]
+ bic r0, r0, #0x38000000
+ str r0, [r6, #0x14]
+
+ /* Now switch periph_clk to 24MHz. */
+ ldr r0, [r6, #0x14]
+ orr r0, r0, #0x2000000
+ str r0, [r6, #0x14]
+
+periph_clk_switch1:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne periph_clk_switch1
+
+ /* Change all the dividers to 1. */
+ ldr r0, [r6, #0x14]
+ ldr r2, =0x3F1C00
+ bic r0, r0, r2
+ str r0, [r6, #0x14]
+
+ /* Wait for the divider to change. */
+wait_div_update:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne wait_div_update
+
+ /* Change the GPT divider so that its at 6MHz. */
+ ldr r0, [r6, #0x1C]
+ bic r0, r0, #0x3F
+ orr r0, r0, #0x1
+ str r0, [r6, #0x1C]
+
+ .endm
+
+/*
+ * mx6_ddr_freq_change
+ *
+ * Idle the processor (eg, wait for interrupt).
+ * Make sure DDR is in self-refresh.
+ * IRQs are already disabled.
+ */
+ENTRY(mx6_ddr_freq_change)
+
+ stmfd sp!, {r4,r5,r6, r7, r8, r9, r10, r11} @ Save registers
+
+ ldr r6, =CCM_BASE_ADDR
+ add r6, r6, #PERIPBASE_VIRT
+ ldr r5, =MMDC_P0_BASE_ADDR
+ add r5, r5, #PERIPBASE_VIRT
+ ldr r7, =MX6Q_IOMUXC_BASE_ADDR
+ add r7, r7, #PERIPBASE_VIRT
+
+ mov r4, r0 @save new freq requested
+ mov r8, r1 @save the ddr settings for the new rate
+ mov r9, r2 @save the mode DDR is currently in (DLL ON/OFF)
+ mov r11, r3 @save iomux offsets
+
+ddr_freq_change:
+ /* Make sure no TLB miss will occur when the DDR is in self refresh. */
+ /* Invalidate TLB single entry to ensure that the address is not
+ * already in the TLB.
+ */
+
+ adr r10, ddr_freq_change @Address in this function.
+
+
+ mcr p15, 0, r10, c8, c7, 1 @//@ Make sure freq code address
+ @// @ is not already in TLB.
+ mcr p15, 0, r6, c8, c7, 1 @//@ Make sure CCM address
+ @//@ is not already in TLB.
+ mcr p15, 0, r5, c8, c7, 1 @//@ make sure MMDC address
+ @//@ is not already in TLB.
+ mcr p15, 0, r7, c8, c7, 1 @//@ make sure IOMUX address
+ @//@ is not already in TLB.
+
+ mrc p15, 0, r0, c10, c0, 0 @//@ Read the TLB lockdown register
+ orr r0, r0, #1 @//@ Set the Preserve bit.
+ mcr p15, 0, r0, c10, c0, 0 @//@ Write to the lockdown register
+
+ ldr r2, [r6] @ TLB will miss,
+ @CCM address will be loaded
+ ldr r2, [r5] @ TLB will miss,
+ @MMDC address will be loaded
+ ldr r2, [r7] @ TLB will miss,
+ @IOMUX will be loaded
+
+ ldr r2, [r8] @ Get the DDR settings.
+
+ ldr r2, [r10] @ TLB will miss
+
+ ldr r2, [r11] @Get the IOMUX settings
+
+ mrc p15, 0, r0, c10, c0, 0 @//@ Read the lockdown register
+ @//@ (victim will be incremented)
+ bic r0, r0, #1 @//@ Clear the preserve bit
+ mcr p15, 0, r0, c10, c0, 0 @//@ Write to the lockdown register
+
+ /* Disable automatic power saving. */
+
+ ldr r0, [r5, #0x404]
+ orr r0, r0, #0x01
+ str r0, [r5, #0x404]
+
+ /* Disable MMDC power down timer. */
+ /*MMDC0_MDPDC disable power down timer */
+ ldr r0, [r5, #0x4]
+ bic r0, r0, #0xff00
+ str r0, [r5, #0x4]
+
+ /* set CON_REG */
+ ldr r0, =0x8000
+ str r0, [r5, #0x1C]
+poll_conreq_set_1:
+ ldr r0, [r5, #0x1C]
+ and r0, r0, #0x4000
+ cmp r0, #0x4000
+ bne poll_conreq_set_1
+
+ /*setmem /32 0x021b001c = 0x00008010 //Precharge all on cs0 */
+ /*setmem /32 0x021b001c = 0x00008018 //Precharge all on cs1 */
+ ldr r0, =0x00008010
+ str r0, [r5, #0x1C]
+ ldr r0, =0x00008018
+ str r0, [r5, #0x1C]
+
+ /* if requested frequency is greater than 300MHz go to DLL on mode */
+ ldr r1, =300000000
+ cmp r4, r1
+ bge dll_on_mode
+
+dll_off_mode:
+
+ /* if DLL is currently on, turn it off
+ cmp r9, #1
+ beq continue_dll_off_1
+
+ /* setmem /32 0x021b001c = 0x00018031 //Rtt_NOM off + set dll off, cs 0 */
+ /* setmem /32 0x021b001c = 0x00018039 //Rtt_NOM off + set dll off, cs 1 */
+ ldr r0, =0x00018031
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x00018039
+ str r0, [r5, #0x1C]
+
+ ldr r1, =10
+delay1a:
+ ldr r2, =0
+cont1a:
+ ldr r0, [r5, r2]
+ add r2, r2, #4
+ cmp r2, #16
+ bne cont1a
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt delay1a
+
+continue_dll_off_1:
+
+ /* set DVFS - enter self refresh mode */
+ ldr r0, [r5, #0x404]
+ orr r0, r0, #0x200000
+ str r0, [r5, #0x404]
+
+ /* de-assert con_req */
+ mov r0, #0x0
+ str r0, [r5, #0x1C]
+
+poll_dvfs_set_1:
+ ldr r0, [r5, #0x404]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ bne poll_dvfs_set_1
+
+ ldr r1, =24000000
+ cmp r4, r1
+ beq switch_freq_24
+
+ switch_to_50MHz
+ b continue_dll_off_2
+
+switch_freq_24:
+ switch_to_24MHz
+
+continue_dll_off_2:
+
+ /* set SBS - block ddr accesses */
+ ldr r0, [r5, #0x410]
+ orr r0, r0, #0x100
+ str r0, [r5, #0x410]
+
+ /* clear DVFS - exit from self refresh mode */
+ ldr r0, [r5, #0x404]
+ bic r0, r0, #0x200000
+ str r0, [r5, #0x404]
+
+poll_dvfs_clear_1:
+ ldr r0, [r5, #0x404]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ beq poll_dvfs_clear_1
+
+ /* if DLL was previously on, continue DLL off routine
+ cmp r9, #1
+ beq continue_dll_off_3
+
+ /* setmem /32 0x021b001c = 0x00018031 //Rtt_NOM off + set dll off, cs 0 */
+ /* setmem /32 0x021b001c = 0x00018039 //Rtt_NOM off + set dll off, cs 1 */
+ ldr r0, =0x00018031
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x00018039
+ str r0, [r5, #0x1C]
+
+ /* setmem /32 0x021b001c = 0x04208030 //write mode reg MR0: CL=6, wr=6 ,cs 0 */
+ /* setmem /32 0x021b001c = 0x04208038 //write mode reg MR0: CL=6, wr=6 ,cs 1 */
+ ldr r0, =0x08208030
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x08208038
+ str r0, [r5, #0x1C]
+
+ /* setmem /32 0x021b001c = 0x02088032 //write mode reg MR2 , CWL=6 ,cs0 */
+ /* setmem /32 0x021b001c = 0x0208803A //write mode reg MR2 , CWL=6 ,cs1 */
+ ldr r0, =0x00088032
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x0008803A
+ str r0, [r5, #0x1C]
+
+ /* double refresh ????
+ ldr r0, =0x00001800
+ str r0, [r5, #0x20]*/
+
+ /* delay for a while. */
+ ldr r1, =4
+delay_1:
+ ldr r2, =0
+cont_1:
+ ldr r0, [r5, r2]
+ add r2, r2, #4
+ cmp r2, #16
+ bne cont_1
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt delay_1
+
+ /* MMDC0_MDCFG0 see spread sheet for timings, CAS=6 */
+ ldr r0, [r5, #0x0C]
+ bic r0, r0, #0xf
+ orr r0, r0, #0x3
+ str r0, [r5, #0x0C]
+
+ /* MMDC0_MDCFG1 see spread sheet for timings, tCWL=6 */
+ ldr r0, [r5, #0x10]
+ bic r0, r0, #0x7
+ orr r0, r0, #0x4
+ str r0, [r5, #0x10]
+
+ /* Enable bank interleaving, Address mirror on, WALAT = 0x1, RALAT = 0x2, DDR2_EN = 0 */
+ /*setmem /32 0x021b0018 = 0x00091680 */
+ ldr r0, =0x00091680
+ str r0, [r5, #0x18]
+
+ /* enable dqs pull down in the IOMUX. */
+ /*
+ setmem /32 0x020e05a8 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 - DSE=110
+ setmem /32 0x020e05b0 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 - DSE=110
+ setmem /32 0x020e0524 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 - DSE=110
+ setmem /32 0x020e051c = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 - DSE=110
+ setmem /32 0x020e0518 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS4 - DSE=110
+ setmem /32 0x020e050c = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS5 - DSE=110
+ setmem /32 0x020e05b8 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS6 - DSE=110
+ setmem /32 0x020e05c0 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS7 - DSE=110
+ */
+ ldr r1, [r11] @size of array
+ add r11, r11, #8 @skip first eight bytes in array
+ ldr r2, =0x3028
+update_iomux:
+ ldr r0, [r11, #0x0] @ offset
+ ldr r3, [r7, r0]
+ bic r3, r3, r2 @ Clear the DSE, PUE and PKE bits
+ orr r3, r3, #0x3000 @ Enable the Pull downs and lower the drive strength.
+ orr r3, r3, #0x28
+ str r3, [r7, r0]
+ add r11, r11, #8
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt update_iomux
+
+ /* ODT disabled */
+ /* setmem /32 0x021b0818 = 0x0 // DDR_PHY_P0_MPODTCTRL */
+ /* setmem /32 0x021b4818 = 0x0 // DDR_PHY_P1_MPODTCTRL */
+ ldr r0, =0x0
+ ldr r2, =0x818
+ str r0, [r5, r2]
+ ldr r2, =0x4818
+ str r0, [r5, r2]
+
+ /* DQS gating disabled */
+ /* setmem /32 0x021b083c = 0x233f033f */
+ ldr r2, =0x83c
+ ldr r0, [r5, r2]
+ orr r0, r0, #0x20000000
+ str r0, [r5, r2]
+
+ ldr r2, =0x483c
+ ldr r0, [r5, r2]
+ orr r0, r0, #0x20000000
+ str r0, [r5, r2]
+
+ /* MMDC0_MAPSR adopt power down enable */
+ /* setmem /32 0x021b0404 = 0x00011006 */
+ ldr r0, [r5, #0x404]
+ bic r0, r0, #0x01
+ str r0, [r5, #0x404]
+
+ /* frc_msr + mu bypass*/
+ ldr r0, =0x00000060
+ str r0, [r5, #0x8b8]
+ ldr r2, =0x48b8
+ str r0, [r5, r2]
+ ldr r0, =0x00000460
+ str r0, [r5, #0x8b8]
+ ldr r2, =0x48b8
+ str r0, [r5, r2]
+ ldr r0, =0x00000c60
+ str r0, [r5, #0x8b8]
+ ldr r2, =0x48b8
+ str r0, [r5, r2]
+
+continue_dll_off_3:
+
+ /* clear SBS - unblock accesses to DDR */
+ ldr r0, [r5, #0x410]
+ bic r0, r0, #0x100
+ str r0, [r5, #0x410]
+
+ mov r0, #0x0
+ str r0, [r5, #0x1C]
+poll_conreq_clear_1:
+ ldr r0, [r5, #0x1C]
+ and r0, r0, #0x4000
+ cmp r0, #0x4000
+ beq poll_conreq_clear_1
+
+ b done
+
+dll_on_mode:
+ /* assert DVFS - enter self refresh mode */
+ ldr r0, [r5, #0x404]
+ orr r0, r0, #0x200000
+ str r0, [r5, #0x404]
+
+ /* de-assert CON_REQ */
+ mov r0, #0x0
+ str r0, [r5, #0x1C]
+
+ /* poll DVFS ack */
+poll_dvfs_set_2:
+ ldr r0, [r5, #0x404]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ bne poll_dvfs_set_2
+
+ ldr r1, =528000000
+ cmp r4, r1
+ beq switch_freq_528
+
+ switch_to_400MHz
+
+ b continue_dll_on
+
+switch_freq_528:
+ switch_to_528MHz
+
+continue_dll_on:
+
+ /* set step-by-step mode */
+ ldr r0, [r5, #0x410]
+ orr r0, r0, #0x100
+ str r0, [r5, #0x410]
+
+ /* clear DVFS - exit self refresh mode */
+ ldr r0, [r5, #0x404]
+ bic r0, r0, #0x200000
+ str r0, [r5, #0x404]
+
+poll_dvfs_clear_2:
+ ldr r0, [r5, #0x404]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ beq poll_dvfs_clear_2
+
+ /* if DLL is currently off, turn it back on */
+ cmp r9, #0
+ beq update_calibration
+
+ ldr r0, =0xa5390003
+ str r0, [r5, #0x800]
+ ldr r2, =0x4800
+ str r0, [r5, r2]
+
+ /* enable DQS gating */
+ ldr r2, =0x83c
+ ldr r0, [r5, r2]
+ bic r0, r0, #0x20000000
+ str r0, [r5, r2]
+
+ ldr r2, =0x483c
+ ldr r0, [r5, r2]
+ bic r0, r0, #0x20000000
+ str r0, [r5, r2]
+
+ /* force measure */
+ ldr r0, =0x00000800
+ str r0, [r5, #0x8b8]
+ ldr r2, =0x48b8
+ str r0, [r5, r2]
+
+ /* delay for while */
+ ldr r1, =4
+delay5:
+ ldr r2, =0
+cont5:
+ ldr r0, [r5, r2]
+ add r2, r2, #4
+ cmp r2, #16
+ bne cont5
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt delay5
+
+ /* Disable dqs pull down in the IOMUX. */
+ /*
+ setmem /32 0x020e05a8 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 - DSE=110
+ setmem /32 0x020e05b0 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 - DSE=110
+ setmem /32 0x020e0524 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 - DSE=110
+ setmem /32 0x020e051c = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 - DSE=110
+ setmem /32 0x020e0518 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS4 - DSE=110
+ setmem /32 0x020e050c = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS5 - DSE=110
+ setmem /32 0x020e05b8 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS6 - DSE=110
+ setmem /32 0x020e05c0 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS7 - DSE=110
+ */
+ ldr r1, [r11] @size of array
+ add r11, r11, #8 @skip first eight bytes in array
+update_iomux1:
+ ldr r0, [r11, #0x0] @ offset
+ ldr r3, [r11, #0x4]
+ str r3, [r7, r0] @Store the original IOMUX value read during boot
+ add r11, r11, #8
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt update_iomux1
+
+ /* config ESDCTL timings to 528MHz:
+ @// setmem /32 0x021b000c = 0x555A7975 @// MMDC0_MDCFG0 see spread sheet for timings
+ @//setmem /32 0x021b0010 = 0xFF538E64 @// MMDC0_MDCFG1 see spread sheet for timings
+ @//setmem /32 0x021b0014 = 0x01ff00db @// MMDC0_MDCFG2 - tRRD - 4ck; tWTR - 4ck; tRTP - 4ck; tDLLK - 512ck
+ @//setmem /32 0x021b0018 = 0x00081740 @// MMDC0_MDMISC, RALAT=0x5 (original value)
+ */
+
+ ldr r0, [r5, #0x0C]
+ bic r0, r0, #0xf
+ orr r0, r0, #0x5
+ str r0, [r5, #0x0C]
+
+ ldr r0, [r5, #0x10]
+ bic r0, r0, #0x7
+ orr r0, r0, #0x4
+ str r0, [r5, #0x10]
+
+ /* update MISC register: WALAT, RALAT */
+ ldr r0, =0x00081740
+ str r0, [r5, #0x18]
+
+ /*configure ddr devices to dll on, odt
+ @//setmem /32 0x021b001c = 0x00428031
+ @//setmem /32 0x021b001c = 0x00428039
+ */
+ ldr r0, =0x00028031
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x00028039
+ str r0, [r5, #0x1C]
+
+ /* delay for while */
+ ldr r1, =4
+delay7:
+ ldr r2, =0
+cont7:
+ ldr r0, [r5, r2]
+ add r2, r2, #4
+ cmp r2, #16
+ bne cont7
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt delay7
+
+ /* reset dll
+ @// setmem /32 0x021b001c = 0x09208030
+ @// setmem /32 0x021b001c = 0x09208038
+ */
+ ldr r0, =0x09208030
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x09208038
+ str r0, [r5, #0x1C]
+
+ /* delay for while */
+ ldr r1, =100
+delay8:
+ ldr r2, =0
+cont8:
+ ldr r0, [r5, r2]
+ add r2, r2, #4
+ cmp r2, #16
+ bne cont8
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt delay8
+
+ /* tcwl=6:
+ @//setmem /32 0x021b001c = 0x04088032
+ @//setmem /32 0x021b001c = 0x0408803a
+ */
+ ldr r0, =0x04088032
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x0408803a
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x00428031
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x00428039
+ str r0, [r5, #0x1C]
+
+ /* tcl=8
+ @// setmem /32 0x021b001c = 0x08408030
+ @// setmem /32 0x021b001c = 0x08408038
+ */
+ ldr r0, =0x08408030
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x08408038
+ str r0, [r5, #0x1C]
+
+ /* issue a zq command
+ @// setmem /32 0x021b001c = 0x04000040
+ @// setmem /32 0x021b001c = 0x04000048
+ */
+ ldr r0, =0x04008040
+ str r0, [r5, #0x1C]
+
+ ldr r0, =0x04008048
+ str r0, [r5, #0x1C]
+
+ /* ESDCTL ODT enable
+ @//setmem /32 0x021b0818 = 0x00022225 @// DDR_PHY_P0_MPODTCTRL
+ @//setmem /32 0x021b4818 = 0x00022225 @// DDR_PHY_P1_MPODTCTRL
+ */
+ ldr r0, =0x00022225
+ str r0, [r5, #0x818]
+ ldr r2, =0x4818
+ str r0, [r5, r2]
+
+ /* delay for while */
+ ldr r1, =40
+delay15:
+ ldr r2, =0
+cont15:
+ ldr r0, [r5, r2]
+ add r2, r2, #4
+ cmp r2, #16
+ bne cont15
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt delay15
+
+ /* MMDC0_MAPSR adopt power down enable */
+ /* setmem /32 0x021b0404 = 0x00011006 */
+ ldr r0, [r5, #0x404]
+ bic r0, r0, #0x01
+ str r0, [r5, #0x404]
+
+ /* Enable MMDC power down timer. */
+ ldr r0, [r5, #0x4]
+ orr r0, r0, #0x5500
+ str r0, [r5, #0x4]
+
+update_calibration:
+ /* Write the new calibration values. */
+ ldr r1, [r8] @size of array
+ add r8, r8, #8 @skip first eight bytes in array
+update_calib:
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
+ sub r1, r1, #1
+ cmp r1, #0
+ bgt update_calib
+
+ /* Perform a force measurement. */
+ ldr r0, =0x800
+ str r0, [r5, #0x8B8]
+ ldr r2, =0x48B8
+ str r0, [r5, r2]
+
+ /* clear SBS - unblock DDR accesses */
+ ldr r0, [r5, #0x410]
+ bic r0, r0, #0x100
+ str r0, [r5, #0x410]
+
+ mov r0, #0x0
+ str r0, [r5, #0x1C]
+poll_conreq_clear_2:
+ ldr r0, [r5, #0x1C]
+ and r0, r0, #0x4000
+ cmp r0, #0x4000
+ beq poll_conreq_clear_2
+
+done:
+
+ /* Restore registers */
+
+ ldmfd sp!, {r4,r5,r6, r7, r8, r9, r10, r11}
+
+ mov pc, lr
+
+ .type mx6_do_ddr_freq_change, #object
+ENTRY(mx6_do_ddr_freq_change)
+ .word mx6_ddr_freq_change
+ .size mx6_ddr_freq_change, . - mx6_ddr_freq_change
diff --git a/arch/arm/mach-mx6/mx6_mmdc.c b/arch/arm/mach-mx6/mx6_mmdc.c
new file mode 100644
index 000000000000..2b5ce842489e
--- /dev/null
+++ b/arch/arm/mach-mx6/mx6_mmdc.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mx6_mmdc.c
+ *
+ * @brief MX6 MMDC specific file.
+ *
+ * @ingroup PM
+ */
+#include <asm/io.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/iram_alloc.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/cpumask.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <mach/hardware.h>
+#include <mach/clock.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/cacheflush.h>
+#include <asm/tlb.h>
+#include <asm/hardware/gic.h>
+#include "crm_regs.h"
+
+
+/* DDR settings */
+unsigned long (*iram_ddr_settings)[2];
+unsigned long (*normal_mmdc_settings)[2];
+unsigned long (*iram_iomux_settings)[2];
+void __iomem *mmdc_base;
+void __iomem *iomux_base;
+void __iomem *gic_dist_base;
+void __iomem *gic_cpu_base;
+
+void (*mx6_change_ddr_freq)(u32 freq, void *ddr_settings, bool dll_mode, void* iomux_offsets) = NULL;
+
+extern unsigned int ddr_low_rate;
+extern unsigned int ddr_med_rate;
+extern unsigned int ddr_normal_rate;
+extern int low_bus_freq_mode;
+extern int mmdc_med_rate;
+extern void __iomem *ccm_base;
+extern void mx6_ddr_freq_change(u32 freq, void *ddr_settings, bool dll_mode, void *iomux_offsets);
+
+static void *ddr_freq_change_iram_base;
+static int ddr_settings_size;
+static int iomux_settings_size;
+static volatile unsigned int cpus_in_wfe;
+static volatile bool wait_for_ddr_freq_update;
+
+
+#define MIN_DLL_ON_FREQ 333000000
+#define MAX_DLL_OFF_FREQ 125000000
+
+unsigned long ddr3_mmdc_regs_offsets[][2] = {
+ {0x83c, 0x0},
+ {0x840, 0x0},
+ {0x483c, 0x0},
+ {0x4840, 0x0},
+ {0x848, 0x0},
+ {0x4848, 0x0},
+ {0x850, 0x0},
+ {0x4850, 0x0},
+};
+
+unsigned long iomux_offsets_mx6q[][2] = {
+ {0x5A8, 0x0},
+ {0x5B0, 0x0},
+ {0x524, 0x0},
+ {0x51C, 0x0},
+ {0x518, 0x0},
+ {0x50C, 0x0},
+ {0x5B8, 0x0},
+ {0x5C0, 0x0},
+};
+unsigned long iomux_offsets_mx6dl[][2] = {
+ {0x4BC, 0x0},
+ {0x4C0, 0x0},
+ {0x4C4, 0x0},
+ {0x4C8, 0x0},
+ {0x4CC, 0x0},
+ {0x4D0, 0x0},
+ {0x4D4, 0x0},
+ {0x4D8, 0x0},
+};
+
+unsigned long ddr3_400[][2] = {
+ {0x83c, 0x42490249},
+ {0x840, 0x02470247},
+ {0x483c, 0x42570257},
+ {0x4840, 0x02400240},
+ {0x848, 0x4039363C},
+ {0x4848, 0x3A39333F},
+ {0x850, 0x38414441},
+ {0x4850, 0x472D4833}
+};
+
+unsigned long *irq_used;
+
+unsigned long irqs_used_mx6q[] = {
+ MXC_INT_INTERRUPT_139_NUM,
+ MX6Q_INT_PERFMON1,
+ MX6Q_INT_PERFMON2,
+ MX6Q_INT_PERFMON3,
+};
+
+unsigned long irqs_used_mx6dl[] = {
+ MXC_INT_INTERRUPT_139_NUM,
+ MX6Q_INT_PERFMON1,
+};
+
+int can_change_ddr_freq(void)
+{
+ return 1;
+}
+
+
+/* Each active core apart from the one changing the DDR frequency will execute
+ * this function. The rest of the cores have to remain in WFE state until the frequency
+ * is changed.
+ */
+irqreturn_t wait_in_wfe_irq(int irq, void *dev_id)
+{
+ u32 me = smp_processor_id();
+
+ *((char *)(&cpus_in_wfe) + (u8)me) = 0xff;
+
+ while (wait_for_ddr_freq_update)
+ wfe();
+
+ *((char *)(&cpus_in_wfe) + (u8)me) = 0;
+ return IRQ_HANDLED;
+}
+
+/* Change the DDR frequency. */
+int update_ddr_freq(int ddr_rate)
+{
+ int i;
+ unsigned int reg;
+ bool dll_off = false;
+ unsigned int online_cpus = 0;
+ int cpu = 0;
+ int me;
+
+ if (!can_change_ddr_freq())
+ return -1;
+
+ if (low_bus_freq_mode)
+ dll_off = true;
+
+ iram_ddr_settings[0][0] = ddr_settings_size;
+ iram_iomux_settings[0][0] = iomux_settings_size;
+ if (ddr_rate == ddr_med_rate) {
+ for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ iram_ddr_settings[i + 1][0] =
+ ddr3_400[i][0];
+ iram_ddr_settings[i + 1][1] =
+ ddr3_400[i][1];
+ }
+ } else if (ddr_rate == ddr_normal_rate) {
+ for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ iram_ddr_settings[i + 1][0] =
+ normal_mmdc_settings[i][0];
+ iram_ddr_settings[i + 1][1] =
+ normal_mmdc_settings[i][1];
+ }
+ }
+
+ /* Ensure that all Cores are in WFE. */
+ local_irq_disable();
+
+ me = smp_processor_id();
+
+ *((char *)(&cpus_in_wfe) + (u8)me) = 0xff;
+ wait_for_ddr_freq_update = true;
+
+ for_each_online_cpu(cpu) {
+ *((char *)(&online_cpus) + (u8)cpu) = 0xff;
+ if (cpu != me) {
+ /* Set the interrupt to be pending in the GIC. */
+ reg = 1 << (irq_used[cpu] % 32);
+ writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + (irq_used[cpu] / 32) * 4);
+ udelay(10);
+ }
+ }
+ while (cpus_in_wfe != online_cpus)
+ udelay(5);
+
+ /* Now we can change the DDR frequency. */
+ mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, dll_off, iram_iomux_settings);
+
+ /* DDR frequency change is done . */
+ wait_for_ddr_freq_update = false;
+
+ /* Wake up all the cores. */
+ sev();
+
+ *((char *)(&cpus_in_wfe) + (u8)me) = 0;
+
+ local_irq_enable();
+
+ return 0;
+}
+
+int init_mmdc_settings(void)
+{
+ unsigned long iram_paddr;
+ int i, err, cpu;
+
+ mmdc_base = ioremap(MMDC_P0_BASE_ADDR, SZ_32K);
+ iomux_base = ioremap(MX6Q_IOMUXC_BASE_ADDR, SZ_16K);
+ gic_dist_base = ioremap(IC_DISTRIBUTOR_BASE_ADDR, SZ_16K);
+ gic_cpu_base = ioremap(IC_INTERFACES_BASE_ADDR, SZ_16K);
+
+ normal_mmdc_settings = ddr3_mmdc_regs_offsets;
+ ddr_settings_size = ARRAY_SIZE(ddr3_mmdc_regs_offsets);
+
+ /* Store the original DDR settings at boot. */
+ for (i = 0; i < ddr_settings_size; i++) {
+ normal_mmdc_settings[i][1] =
+ __raw_readl(mmdc_base
+ + normal_mmdc_settings[i][0]);
+ }
+ /* Store the size of the array in iRAM also,
+ * increase the size by 8 bytes.
+ */
+ iram_ddr_settings = iram_alloc(ddr_settings_size + 8, &iram_paddr);
+ if (iram_ddr_settings == NULL) {
+ printk(KERN_DEBUG
+ "%s: failed to allocate iRAM memory for ddr settings\n",
+ __func__);
+ return ENOMEM;
+ }
+
+ /* Store the size of the iomux settings in iRAM also,
+ * increase the size by 8 bytes.
+ */
+ iram_iomux_settings = iram_alloc(iomux_settings_size + 8, &iram_paddr);
+ if (iram_iomux_settings == NULL) {
+ printk(KERN_DEBUG
+ "%s: failed to allocate iRAM memory for iomuxr settings\n",
+ __func__);
+ return ENOMEM;
+ }
+
+ /* Store the IOMUX settings at boot. */
+ if (cpu_is_mx6q()) {
+ iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q);
+ for (i = 0; i < iomux_settings_size; i++) {
+ iomux_offsets_mx6q[i][1] =
+ __raw_readl(iomux_base
+ + iomux_offsets_mx6q[i][0]);
+ iram_iomux_settings[i+1][0] = iomux_offsets_mx6q[i][0];
+ iram_iomux_settings[i+1][1] = iomux_offsets_mx6q[i][1];
+ }
+ irq_used = irqs_used_mx6q;
+ }
+ if (cpu_is_mx6dl()) {
+ iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6dl);
+ for (i = 0; i < iomux_settings_size; i++) {
+ iomux_offsets_mx6dl[i][1] =
+ __raw_readl(iomux_base
+ + iomux_offsets_mx6dl[i][0]);
+ iram_iomux_settings[i+1][0] = iomux_offsets_mx6dl[i][0];
+ iram_iomux_settings[i+1][1] = iomux_offsets_mx6dl[i][1];
+ }
+ irq_used = irqs_used_mx6dl;
+ }
+
+ /* Allocate IRAM for the DDR freq change code. */
+ iram_alloc(SZ_8K, &iram_paddr);
+ /* Need to remap the area here since we want the memory region
+ to be executable. */
+ ddr_freq_change_iram_base = __arm_ioremap(iram_paddr,
+ SZ_8K, MT_MEMORY_NONCACHED);
+ memcpy(ddr_freq_change_iram_base, mx6_ddr_freq_change, SZ_8K);
+ mx6_change_ddr_freq = (void *)ddr_freq_change_iram_base;
+
+ for_each_online_cpu(cpu) {
+ /* Set up a reserved interrupt to get all the active cores into a WFE state
+ * before changing the DDR frequency.
+ */
+ err = request_irq(irq_used[cpu], wait_in_wfe_irq, IRQF_PERCPU, "mmdc_1",
+ NULL);
+ if (err) {
+ printk(KERN_ERR "MMDC: Unable to attach to %ld,err = %d\n", irq_used[cpu], err);
+ return err;
+ }
+ err = irq_set_affinity(irq_used[cpu], cpumask_of(cpu));
+ if (err) {
+ printk(KERN_ERR "MMDC: unable to set irq affinity irq=%ld,\n", irq_used[cpu]);
+ return err;
+ }
+ }
+ return 0;
+}
diff --git a/arch/arm/mach-mx6/pcie.c b/arch/arm/mach-mx6/pcie.c
index 985e6252a5f9..38e9abcd29cc 100644
--- a/arch/arm/mach-mx6/pcie.c
+++ b/arch/arm/mach-mx6/pcie.c
@@ -29,6 +29,9 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
+#include <linux/platform_device.h>
+
+#include <mach/pcie.h>
#include <asm/sizes.h>
@@ -86,6 +89,75 @@
/* GPR8: iomuxc_gpr8_tx_swing_low(iomuxc_gpr8[31:25]) */
#define iomuxc_gpr8_tx_swing_low (0x7F << 25)
+/* Registers of PHY */
+/* Register PHY_STS_R */
+/* PHY Status Register */
+#define PHY_STS_R (PRT_LOG_R_BaseAddress + 0x110)
+
+/* Register PHY_CTRL_R */
+/* PHY Control Register */
+#define PHY_CTRL_R (PRT_LOG_R_BaseAddress + 0x114)
+
+#define SSP_CR_SUP_DIG_MPLL_OVRD_IN_LO 0x0011
+/* FIELD: RES_ACK_IN_OVRD [15:15]
+// FIELD: RES_ACK_IN [14:14]
+// FIELD: RES_REQ_IN_OVRD [13:13]
+// FIELD: RES_REQ_IN [12:12]
+// FIELD: RTUNE_REQ_OVRD [11:11]
+// FIELD: RTUNE_REQ [10:10]
+// FIELD: MPLL_MULTIPLIER_OVRD [9:9]
+// FIELD: MPLL_MULTIPLIER [8:2]
+// FIELD: MPLL_EN_OVRD [1:1]
+// FIELD: MPLL_EN [0:0]
+*/
+
+#define SSP_CR_SUP_DIG_ATEOVRD 0x0010
+/* FIELD: ateovrd_en [2:2]
+// FIELD: ref_usb2_en [1:1]
+// FIELD: ref_clkdiv2 [0:0]
+*/
+
+#define SSP_CR_LANE0_DIG_RX_OVRD_IN_LO 0x1005
+/* FIELD: RX_LOS_EN_OVRD [13:13]
+// FIELD: RX_LOS_EN [12:12]
+// FIELD: RX_TERM_EN_OVRD [11:11]
+// FIELD: RX_TERM_EN [10:10]
+// FIELD: RX_BIT_SHIFT_OVRD [9:9]
+// FIELD: RX_BIT_SHIFT [8:8]
+// FIELD: RX_ALIGN_EN_OVRD [7:7]
+// FIELD: RX_ALIGN_EN [6:6]
+// FIELD: RX_DATA_EN_OVRD [5:5]
+// FIELD: RX_DATA_EN [4:4]
+// FIELD: RX_PLL_EN_OVRD [3:3]
+// FIELD: RX_PLL_EN [2:2]
+// FIELD: RX_INVERT_OVRD [1:1]
+// FIELD: RX_INVERT [0:0]
+*/
+
+#define SSP_CR_LANE0_DIG_RX_ASIC_OUT 0x100D
+/* FIELD: LOS [2:2]
+// FIELD: PLL_STATE [1:1]
+// FIELD: VALID [0:0]
+*/
+
+/* control bus bit definition */
+#define PCIE_CR_CTL_DATA_LOC 0
+#define PCIE_CR_CTL_CAP_ADR_LOC 16
+#define PCIE_CR_CTL_CAP_DAT_LOC 17
+#define PCIE_CR_CTL_WR_LOC 18
+#define PCIE_CR_CTL_RD_LOC 19
+#define PCIE_CR_STAT_DATA_LOC 0
+#define PCIE_CR_STAT_ACK_LOC 16
+
+#define PCIE_CAP_STRUC_BaseAddress 0x70
+
+/* Register LNK_CAP */
+/* PCIE Link cap */
+#define LNK_CAP (PCIE_CAP_STRUC_BaseAddress + 0xc)
+#define LNK_CAP_RegisterSize 32
+#define LNK_CAP_RegisterResetValue 0x011cc12
+#define LNK_CAP_RegisterResetMask 0xffffffff
+
/* End of Register Definitions */
#define PCIE_DBI_BASE_ADDR (PCIE_ARB_END_ADDR - SZ_16K + 1)
@@ -95,9 +167,6 @@
#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
#define PCIE_CONF_REG(r) ((r) & ~0x3)
-#define MX6_ARM2_PCIE_PWR_EN (IMX_GPIO_NR(8, 0) + 2)
-#define MX6_ARM2_PCIE_RESET (IMX_GPIO_NR(8, 8) + 2)
-
static void __iomem *base;
static void __iomem *dbi_base;
@@ -125,6 +194,10 @@ struct imx_pcie_port {
static struct imx_pcie_port imx_pcie_port[1];
static int num_pcie_ports;
+static int pcie_phy_cr_read(int addr, int *data);
+static int pcie_phy_cr_write(int addr, int data);
+static void change_field(int *in, int start, int end, int val);
+
/* IMX PCIE GPR configure routines */
static inline void imx_pcie_clrset(u32 mask, u32 val, void __iomem *addr)
{
@@ -194,13 +267,39 @@ static int __init imx_pcie_setup(int nr, struct pci_sys_data *sys)
static int imx_pcie_link_up(void __iomem *dbi_base)
{
/* Check the pcie link up or link down */
- u32 rc, iterations = 0x100000;
+ int iterations = 200;
+ u32 rc, ltssm, rx_valid, temp;
do {
/* link is debug bit 36 debug 1 start in bit 32 */
- rc = readl(dbi_base + DB_R1) & (0x1 << (36-32)) ;
+ rc = readl(dbi_base + DB_R1) & (0x1 << (36 - 32)) ;
iterations--;
- if ((iterations % 0x100000) == 0)
+ usleep_range(2000, 3000);
+
+ /* From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
+ * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
+ * If (MAC/LTSSM.state == Recovery.RcvrLock)
+ * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
+ * to gen2 is stuck
+ */
+ pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_ASIC_OUT, &rx_valid);
+ ltssm = readl(dbi_base + DB_R0) & 0x3F;
+ if ((ltssm == 0x0D) && ((rx_valid & 0x01) == 0)) {
+ pr_info("Transition to gen2 is stuck, reset PHY!\n");
+ pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, &temp);
+ change_field(&temp, 3, 3, 0x1);
+ change_field(&temp, 5, 5, 0x1);
+ pcie_phy_cr_write(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO,
+ 0x0028);
+ usleep_range(2000, 3000);
+ pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, &temp);
+ change_field(&temp, 3, 3, 0x0);
+ change_field(&temp, 5, 5, 0x0);
+ pcie_phy_cr_write(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO,
+ 0x0000);
+ }
+
+ if ((iterations < 0))
pr_info("link up failed, DB_R0:0x%08x, DB_R1:0x%08x!\n"
, readl(dbi_base + DB_R0)
, readl(dbi_base + DB_R1));
@@ -351,15 +450,151 @@ static struct hw_pci imx_pci __initdata = {
.map_irq = imx_pcie_map_irq,
};
-static void imx_pcie_enable_controller(void)
+/* PHY CR bus acess routines */
+static int pcie_phy_cr_ack_polling(int max_iterations, int exp_val)
+{
+ u32 temp_rd_data, wait_counter = 0;
+
+ do {
+ temp_rd_data = readl(dbi_base + PHY_STS_R);
+ temp_rd_data = (temp_rd_data >> PCIE_CR_STAT_ACK_LOC) & 0x1;
+ wait_counter++;
+ } while ((wait_counter < max_iterations) && (temp_rd_data != exp_val));
+
+ if (temp_rd_data != exp_val)
+ return 0 ;
+ return 1 ;
+}
+
+static int pcie_phy_cr_cap_addr(int addr)
+{
+ u32 temp_wr_data;
+
+ /* write addr */
+ temp_wr_data = addr << PCIE_CR_CTL_DATA_LOC ;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* capture addr */
+ temp_wr_data |= (0x1 << PCIE_CR_CTL_CAP_ADR_LOC);
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack */
+ if (!pcie_phy_cr_ack_polling(100, 1))
+ return 0;
+
+ /* deassert cap addr */
+ temp_wr_data = addr << PCIE_CR_CTL_DATA_LOC;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack de-assetion */
+ if (!pcie_phy_cr_ack_polling(100, 0))
+ return 0 ;
+
+ return 1 ;
+}
+
+static int pcie_phy_cr_read(int addr , int *data)
+{
+ u32 temp_rd_data, temp_wr_data;
+
+ /* write addr */
+ /* cap addr */
+ if (!pcie_phy_cr_cap_addr(addr))
+ return 0;
+
+ /* assert rd signal */
+ temp_wr_data = 0x1 << PCIE_CR_CTL_RD_LOC;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack */
+ if (!pcie_phy_cr_ack_polling(100, 1))
+ return 0;
+
+ /* after got ack return data */
+ temp_rd_data = readl(dbi_base + PHY_STS_R);
+ *data = (temp_rd_data & (0xffff << PCIE_CR_STAT_DATA_LOC)) ;
+
+ /* deassert rd signal */
+ temp_wr_data = 0x0;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack de-assetion */
+ if (!pcie_phy_cr_ack_polling(100, 0))
+ return 0 ;
+
+ return 1 ;
+
+}
+
+static int pcie_phy_cr_write(int addr, int data)
+{
+ u32 temp_wr_data;
+
+ /* write addr */
+ /* cap addr */
+ if (!pcie_phy_cr_cap_addr(addr))
+ return 0 ;
+
+ temp_wr_data = data << PCIE_CR_CTL_DATA_LOC;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* capture data */
+ temp_wr_data |= (0x1 << PCIE_CR_CTL_CAP_DAT_LOC);
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack */
+ if (!pcie_phy_cr_ack_polling(100, 1))
+ return 0 ;
+
+ /* deassert cap data */
+ temp_wr_data = data << PCIE_CR_CTL_DATA_LOC;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack de-assetion */
+ if (!pcie_phy_cr_ack_polling(100, 0))
+ return 0;
+
+ /* assert wr signal */
+ temp_wr_data = 0x1 << PCIE_CR_CTL_WR_LOC;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack */
+ if (!pcie_phy_cr_ack_polling(100, 1))
+ return 0;
+
+ /* deassert wr signal */
+ temp_wr_data = data << PCIE_CR_CTL_DATA_LOC;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ /* wait for ack de-assetion */
+ if (!pcie_phy_cr_ack_polling(100, 0))
+ return 0;
+
+ temp_wr_data = 0x0 ;
+ writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+ return 1 ;
+}
+
+static void change_field(int *in, int start, int end, int val)
+{
+ int mask;
+
+ mask = ((0xFFFFFFFF << start) ^ (0xFFFFFFFF << (end + 1))) & 0xFFFFFFFF;
+ *in = (*in & ~mask) | (val << start);
+}
+
+static void imx_pcie_enable_controller(struct device *dev)
{
struct clk *pcie_clk;
+ struct imx_pcie_platform_data *pdata = dev->platform_data;
+
+ /* Enable PCIE power */
+ gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
- /* PCIE PWR_EN: EXP_IO2 of MAX7310_1 */
- gpio_request(MX6_ARM2_PCIE_PWR_EN, "PCIE POWER_EN");
+ /* activate PCIE_PWR_EN */
+ gpio_direction_output(pdata->pcie_pwr_en, 1);
- /* activate PCIE_PWR_EN CTRL_2 */
- gpio_direction_output(MX6_ARM2_PCIE_PWR_EN, 1);
imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 0 << 18, IOMUXC_GPR1);
/* enable the clks */
@@ -373,23 +608,28 @@ static void imx_pcie_enable_controller(void)
}
}
-static void card_reset(void)
+static void card_reset(struct device *dev)
{
- /* PCIE RESET: EXP_IO2 of MAX7310_2 */
- gpio_request(MX6_ARM2_PCIE_RESET, "PCIE RESET");
+ struct imx_pcie_platform_data *pdata = dev->platform_data;
+
+ /* PCIE RESET */
+ gpio_request(pdata->pcie_rst, "PCIE RESET");
/* activate PERST_B */
- gpio_direction_output(MX6_ARM2_PCIE_RESET, 0);
+ gpio_direction_output(pdata->pcie_rst, 0);
/* Add one reset to the pcie external device */
msleep(100);
/* deactive PERST_B */
- gpio_direction_output(MX6_ARM2_PCIE_RESET, 1);
+ gpio_direction_output(pdata->pcie_rst, 1);
}
-static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base)
+static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base,
+ struct imx_pcie_platform_data *pdata)
{
+ struct clk *pcie_clk;
+
if (imx_pcie_link_up(dbi_base)) {
struct imx_pcie_port *pp = &imx_pcie_port[num_pcie_ports++];
@@ -401,23 +641,51 @@ static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base)
pp->dbi_base = dbi_base;
spin_lock_init(&pp->conf_lock);
memset(pp->res, 0, sizeof(pp->res));
- } else
+ } else {
pr_info("IMX PCIe port: link down!\n");
+ /* Release the clocks, and disable the power */
+
+ pcie_clk = clk_get(NULL, "pcie_clk");
+ if (IS_ERR(pcie_clk))
+ pr_err("no pcie clock.\n");
+
+ clk_disable(pcie_clk);
+ clk_put(pcie_clk);
+
+ /* Disable PCIE power */
+ gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
+
+ /* activate PCIE_PWR_EN */
+ gpio_direction_output(pdata->pcie_pwr_en, 0);
+
+ imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 1 << 18,
+ IOMUXC_GPR1);
+ }
}
-static int __init imx_pcie_init(void)
+static int __devinit imx_pcie_pltfm_probe(struct platform_device *pdev)
{
+ struct resource *mem;
+ struct device *dev = &pdev->dev;
+ struct imx_pcie_platform_data *pdata = dev->platform_data;
+
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(dev, "no mmio space\n");
+ return -EINVAL;
+ }
+
base = ioremap_nocache(PCIE_ARB_END_ADDR - SZ_1M + 1, SZ_1M - SZ_16K);
if (!base) {
pr_err("error with ioremap in function %s\n", __func__);
return -EIO;
}
- dbi_base = ioremap_nocache(PCIE_DBI_BASE_ADDR, SZ_16K);
+ dbi_base = devm_ioremap(dev, mem->start, resource_size(mem));
if (!dbi_base) {
- pr_err("error with ioremap in function %s\n", __func__);
- iounmap(base);
- return -EIO;
+ dev_err(dev, "can't map %pR\n", mem);
+ return -ENOMEM;
}
/* FIXME the field name should be aligned to RM */
@@ -427,31 +695,103 @@ static int __init imx_pcie_init(void)
imx_pcie_clrset(iomuxc_gpr12_device_type, PCI_EXP_TYPE_ROOT_PORT << 12,
IOMUXC_GPR12);
imx_pcie_clrset(iomuxc_gpr12_los_level, 9 << 4, IOMUXC_GPR12);
- imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen1, 21 << 0, IOMUXC_GPR8);
- imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_3p5db, 21 << 6, IOMUXC_GPR8);
- imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_6db, 32 << 12, IOMUXC_GPR8);
- imx_pcie_clrset(iomuxc_gpr8_tx_swing_full, 115 << 18, IOMUXC_GPR8);
- imx_pcie_clrset(iomuxc_gpr8_tx_swing_low, 115 << 25, IOMUXC_GPR8);
+
+ imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen1, 0 << 0, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_3p5db, 0 << 6, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_6db, 0 << 12, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_swing_full, 127 << 18, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_swing_low, 127 << 25, IOMUXC_GPR8);
/* Enable the pwr, clks and so on */
- imx_pcie_enable_controller();
+ imx_pcie_enable_controller(dev);
imx_pcie_clrset(iomuxc_gpr1_pcie_ref_clk_en, 1 << 16, IOMUXC_GPR1);
/* togle the external card's reset */
- card_reset() ;
+ card_reset(dev) ;
+
+ usleep_range(3000, 4000);
+ imx_pcie_regions_setup(dbi_base);
+ usleep_range(3000, 4000);
+
+ /*
+ * Force to GEN1 because of PCIE2USB storage stress tests
+ * would be failed when GEN2 is enabled
+ */
+ writel(((readl(dbi_base + LNK_CAP) & 0xfffffff0) | 0x1),
+ dbi_base + LNK_CAP);
/* start link up */
imx_pcie_clrset(iomuxc_gpr12_app_ltssm_enable, 1 << 10, IOMUXC_GPR12);
/* add the pcie port */
- add_pcie_port(base, dbi_base);
+ add_pcie_port(base, dbi_base, pdata);
- usleep_range(3000, 4000);
- imx_pcie_regions_setup(dbi_base);
- usleep_range(3000, 4000);
pci_common_init(&imx_pci);
return 0;
}
-device_initcall(imx_pcie_init);
+
+static int __devexit imx_pcie_pltfm_remove(struct platform_device *pdev)
+{
+ struct clk *pcie_clk;
+ struct device *dev = &pdev->dev;
+ struct imx_pcie_platform_data *pdata = dev->platform_data;
+ struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ /* Release clocks, and disable power */
+ pcie_clk = clk_get(NULL, "pcie_clk");
+ if (IS_ERR(pcie_clk))
+ pr_err("no pcie clock.\n");
+
+ if (pcie_clk) {
+ clk_disable(pcie_clk);
+ clk_put(pcie_clk);
+ }
+
+ /* Disable PCIE power */
+ gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
+
+ /* activate PCIE_PWR_EN */
+ gpio_direction_output(pdata->pcie_pwr_en, 0);
+
+ imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 1 << 18, IOMUXC_GPR1);
+
+ iounmap(base);
+ iounmap(dbi_base);
+ release_mem_region(iomem->start, resource_size(iomem));
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver imx_pcie_pltfm_driver = {
+ .driver = {
+ .name = "imx-pcie",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx_pcie_pltfm_probe,
+ .remove = __devexit_p(imx_pcie_pltfm_remove),
+};
+
+/*****************************************************************************\
+ * *
+ * Driver init/exit *
+ * *
+\*****************************************************************************/
+
+static int __init imx_pcie_drv_init(void)
+{
+ return platform_driver_register(&imx_pcie_pltfm_driver);
+}
+
+static void __exit imx_pcie_drv_exit(void)
+{
+ platform_driver_unregister(&imx_pcie_pltfm_driver);
+}
+
+module_init(imx_pcie_drv_init);
+module_exit(imx_pcie_drv_exit);
+
+MODULE_DESCRIPTION("i.MX PCIE platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c
index 8475fba89b0d..9c494b20b878 100644
--- a/arch/arm/mach-mx6/system.c
+++ b/arch/arm/mach-mx6/system.c
@@ -55,8 +55,6 @@ static void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR);
volatile unsigned int num_cpu_idle;
volatile unsigned int num_cpu_idle_lock = 0x0;
-
-extern void (*mx6_wait_in_iram)(void *ccm_base);
extern void mx6_wait(void *num_cpu_idle_lock, void *num_cpu_idle);
extern bool enable_wait_mode;
@@ -167,20 +165,19 @@ extern int tick_broadcast_oneshot_active(void);
void arch_idle(void)
{
if (enable_wait_mode) {
- if (num_online_cpus() == num_present_cpus()) {
#ifdef CONFIG_LOCAL_TIMERS
- int cpu = smp_processor_id();
- if (!tick_broadcast_oneshot_active())
- return;
+ int cpu = smp_processor_id();
+ if (!tick_broadcast_oneshot_active())
+ return;
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
#endif
- mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
- mx6_wait(&num_cpu_idle_lock, &num_cpu_idle);
+ *((char *)(&num_cpu_idle_lock) + smp_processor_id()) = 0x0;
+ mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+ mx6_wait((void *)&num_cpu_idle_lock, (void *)&num_cpu_idle);
#ifdef CONFIG_LOCAL_TIMERS
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
#endif
- }
} else
cpu_do_idle();
}
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 4b9247904b96..f6e14a3cf2f5 100755
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -67,7 +67,7 @@ static void __clk_disable(struct clk *clk)
return;
if (!clk->usecount) {
- WARN(1, "clock enable/disable mismatch!\n");
+ WARN(1, "clock enable/disable mismatch! clk %s\n", clk->name);
return;
}
@@ -111,6 +111,11 @@ int clk_enable(struct clk *clk)
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
+ if (clk->flags & AHB_HIGH_SET_POINT)
+ lp_high_freq++;
+ else if (clk->flags & AHB_MED_SET_POINT)
+ lp_med_freq++;
+
if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
&& (clk_get_usecount(clk) == 0)) {
if (!(clk->flags &
@@ -130,7 +135,6 @@ int clk_enable(struct clk *clk)
set_high_bus_freq(1);
}
}
-
mutex_lock(&clocks_mutex);
ret = __clk_enable(clk);
mutex_unlock(&clocks_mutex);
@@ -156,6 +160,11 @@ void clk_disable(struct clk *clk)
if (clk == NULL || IS_ERR(clk))
return;
+ if (clk->flags & AHB_HIGH_SET_POINT)
+ lp_high_freq--;
+ else if (clk->flags & AHB_MED_SET_POINT)
+ lp_med_freq--;
+
mutex_lock(&clocks_mutex);
__clk_disable(clk);
mutex_unlock(&clocks_mutex);
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index 0774d52b315d..9dfdd39be28c 100755
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -45,6 +45,11 @@ static u32 pre_suspend_rate;
extern struct regulator *cpu_regulator;
extern int dvfs_core_is_active;
extern struct cpu_op *(*get_cpu_op)(int *op);
+extern int low_bus_freq_mode;
+extern int high_bus_freq_mode;
+extern int set_low_bus_freq(void);
+extern int set_high_bus_freq(int high_bus_speed);
+extern int low_freq_bus_used(void);
int set_cpu_freq(int freq)
{
@@ -66,6 +71,8 @@ int set_cpu_freq(int freq)
/*Set the voltage for the GP domain. */
if (freq > org_cpu_rate) {
+ if (low_bus_freq_mode)
+ set_high_bus_freq(0);
ret = regulator_set_voltage(cpu_regulator, gp_volt,
gp_volt);
if (ret < 0) {
@@ -88,6 +95,8 @@ int set_cpu_freq(int freq)
printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
return ret;
}
+ if (low_freq_bus_used() && !low_bus_freq_mode)
+ set_low_bus_freq();
}
return ret;
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index 350845eb64f0..47d19921c6b5 100755
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -172,3 +172,6 @@ config IMX_HAVE_PLATFORM_IMX_MIPI_CSI2
config IMX_HAVE_PLATFORM_IMX_VDOA
bool
+
+config IMX_HAVE_PLATFORM_IMX_PCIE
+ bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index f2741caecfca..be2b0a674825 100755
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_ASRC) += platform-imx-asrc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_DSI) += platform-imx-mipi_dsi.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_CSI2) += platform-imx-mipi_csi2.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_VDOA) += platform-imx-vdoa.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_PCIE) += platform-imx-pcie.o
diff --git a/arch/arm/plat-mxc/devices/platform-imx-dma.c b/arch/arm/plat-mxc/devices/platform-imx-dma.c
index 9f99aa481526..65a71ac8b9e9 100755
--- a/arch/arm/plat-mxc/devices/platform-imx-dma.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-dma.c
@@ -183,13 +183,15 @@ static struct sdma_script_start_addrs addr_imx6q_to1 = {
.ap_2_ap_addr = 642,
.uart_2_mcu_addr = 817,
.mcu_2_app_addr = 747,
- .per_2_per_addr = 6474,
+ .per_2_per_addr = 6331,
.uartsh_2_mcu_addr = 1032,
.mcu_2_shp_addr = 960,
.app_2_mcu_addr = 683,
.shp_2_mcu_addr = 891,
.spdif_2_mcu_addr = 1100,
.mcu_2_spdif_addr = 1134,
+ .mcu_2_ssish_addr = 6242,
+ .ssish_2_mcu_addr = 6678,
};
#endif
diff --git a/arch/arm/plat-mxc/devices/platform-imx-pcie.c b/arch/arm/plat-mxc/devices/platform-imx-pcie.c
new file mode 100644
index 000000000000..cf3609365129
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-imx-pcie.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_pcie_data_entry_single(soc, _id, _hwid, size) \
+ { \
+ .id = _id, \
+ .iobase = soc ## _PCIE ## _hwid ## _BASE_ADDR, \
+ .iosize = size, \
+ .irq = soc ## _INT_PCIE ## _hwid, \
+ }
+
+#define imx_pcie_data_entry(soc, _id, _hwid, _size) \
+ [_id] = imx_pcie_data_entry_single(soc, _id, _hwid, _size)
+
+#ifdef CONFIG_SOC_IMX6Q
+#define MX6Q_PCIE_BASE_ADDR (PCIE_ARB_END_ADDR - SZ_16K + 1)
+#define MX6Q_INT_PCIE MXC_INT_PCIE_3
+const struct imx_pcie_data imx6q_pcie_data __initconst =
+ imx_pcie_data_entry_single(MX6Q, 0, , SZ_16K);
+#endif
+
+struct platform_device *__init imx_add_pcie(
+ const struct imx_pcie_data *data,
+ const struct imx_pcie_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + data->iosize - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ return imx_add_platform_device("imx-pcie", -1,
+ res, ARRAY_SIZE(res),
+ pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 9f87b009f129..6fce8c4b8255 100755
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -642,3 +642,15 @@ struct imx_vdoa_data {
};
struct platform_device *__init imx_add_vdoa(
const struct imx_vdoa_data *data);
+
+#include <mach/pcie.h>
+struct imx_pcie_data {
+ int id;
+ resource_size_t iobase;
+ resource_size_t iosize;
+ resource_size_t irq;
+};
+
+struct platform_device *__init imx_add_pcie(
+ const struct imx_pcie_data *data,
+ const struct imx_pcie_platform_data *pdata);
diff --git a/arch/arm/plat-mxc/include/mach/pcie.h b/arch/arm/plat-mxc/include/mach/pcie.h
new file mode 100644
index 000000000000..775f65107978
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/pcie.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __ASM_ARCH_IMX_PCIE_H
+#define __ASM_ARCH_IMX_PCIE_H
+
+/**
+ * struct imx_pcie_platform_data - optional platform data for pcie on i.MX
+ *
+ * @pcie_pwr_en: used for enable/disable pcie power (-EINVAL if unused)
+ * @pcie_rst: used for reset pcie ep (-EINVAL if unused)
+ * @pcie_wake_up: used for wake up (-EINVAL if unused)
+ * @pcie_dis: used for disable pcie ep (-EINVAL if unused)
+ */
+
+struct imx_pcie_platform_data {
+ unsigned int pcie_pwr_en;
+ unsigned int pcie_rst;
+ unsigned int pcie_wake_up;
+ unsigned int pcie_dis;
+};
+#endif /* __ASM_ARCH_IMX_PCIE_H */
diff --git a/arch/arm/plat-mxc/include/mach/sdma.h b/arch/arm/plat-mxc/include/mach/sdma.h
index 913e0432e40e..a145c56b649d 100644
--- a/arch/arm/plat-mxc/include/mach/sdma.h
+++ b/arch/arm/plat-mxc/include/mach/sdma.h
@@ -43,6 +43,8 @@ struct sdma_script_start_addrs {
s32 dptc_dvfs_addr;
s32 utra_addr;
s32 ram_code_start_addr;
+ s32 mcu_2_ssish_addr;
+ s32 ssish_2_mcu_addr;
};
/**
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 6f168fe568a8..b6c7211ccd52 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -576,6 +576,9 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
emi_2_per = sdma->script_addrs->mcu_2_app_addr;
break;
case IMX_DMATYPE_SSI_SP:
+ per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
+ break;
case IMX_DMATYPE_MMC:
case IMX_DMATYPE_SDHC:
case IMX_DMATYPE_CSPI_SP:
@@ -1125,6 +1128,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
sdmac->watermark_level = dmaengine_cfg->dst_maxburst;
sdmac->word_size = dmaengine_cfg->dst_addr_width;
}
+ sdmac->direction = dmaengine_cfg->direction;
return sdma_config_channel(sdmac);
default:
return -ENOSYS;
@@ -1155,7 +1159,7 @@ static void sdma_issue_pending(struct dma_chan *chan)
*/
}
-#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 37
static void sdma_add_scripts(struct sdma_engine *sdma,
const struct sdma_script_start_addrs *addr)
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 4456b331e1d5..162e6c3eb64d 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -637,7 +637,7 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
goto err_ioremap;
}
- mxs_dma->clk = clk_get(&pdev->dev, NULL);
+ mxs_dma->clk = clk_get(NULL, "mxs-dma-apbh");
if (IS_ERR(mxs_dma->clk)) {
ret = PTR_ERR(mxs_dma->clk);
goto err_clk;
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 52798a111e16..4aefb00cc6cf 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -355,6 +355,19 @@ config RADIO_SI470X
bool "Silicon Labs Si470x FM Radio Receiver support"
depends on VIDEO_V4L2
+config I2C_SI4763
+ tristate "Silicon Labs Si4763 AMFM Radio Transmitter support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ Say Y here if you want support to Si4763 AMFM Radio Transmitter.
+ This device can transmit audio through AM or FM.
+ This module is the v4l2 radio
+ interface for the i2c driver of this device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-si4763.
+
+
source "drivers/media/radio/si470x/Kconfig"
config USB_MR800
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index f484a6e04eb2..07cd9ef0e19a 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
+obj-$(CONFIG_I2C_SI4763) += si4763-i2c.o
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
diff --git a/drivers/media/radio/si4763-i2c.c b/drivers/media/radio/si4763-i2c.c
new file mode 100644
index 000000000000..c4990a3eee5d
--- /dev/null
+++ b/drivers/media/radio/si4763-i2c.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2010-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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+
+#include "si4763-i2c.h"
+
+#define DEBUG 1
+/* module parameters */
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0 - 2)");
+
+MODULE_DESCRIPTION("I2C driver for Si4763 FM Radio Transmitter");
+
+/* Radio Nr */
+static int radio_nr = -1;
+
+
+/* radio_si4713_fops - file operations interface */
+static const struct v4l2_file_operations radio_si4763_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = video_ioctl2,
+};
+
+
+#define DEFAULT_RDS_PI 0x00
+#define DEFAULT_RDS_PTY 0x00
+#define DEFAULT_RDS_PS_NAME ""
+#define DEFAULT_RDS_RADIO_TEXT DEFAULT_RDS_PS_NAME
+#define DEFAULT_RDS_DEVIATION 0x00C8
+#define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003
+#define DEFAULT_LIMITER_RTIME 0x1392
+#define DEFAULT_LIMITER_DEV 0x102CA
+#define DEFAULT_PILOT_FREQUENCY 0x4A38
+#define DEFAULT_PILOT_DEVIATION 0x1A5E
+#define DEFAULT_ACOMP_ATIME 0x0000
+#define DEFAULT_ACOMP_RTIME 0xF4240L
+#define DEFAULT_ACOMP_GAIN 0x0F
+#define DEFAULT_ACOMP_THRESHOLD (-0x28)
+#define DEFAULT_MUTE 0x01
+#define DEFAULT_POWER_LEVEL 88
+#define DEFAULT_FREQUENCY 8800
+#define DEFAULT_PREEMPHASIS FMPE_EU
+#define DEFAULT_TUNE_RNL 0xFF
+
+#define to_si4763_device(sd) container_of(sd, struct si4763_device, sd)
+
+/* frequency domain transformation (using times 10 to avoid floats) */
+#define FREQ_RANGE_LOW 8750
+#define FREQ_RANGE_HIGH 10800
+
+#define MAX_ARGS 7
+
+#define RDS_BLOCK 8
+#define RDS_BLOCK_CLEAR 0x03
+#define RDS_BLOCK_LOAD 0x04
+#define RDS_RADIOTEXT_2A 0x20
+#define RDS_RADIOTEXT_BLK_SIZE 4
+#define RDS_RADIOTEXT_INDEX_MAX 0x0F
+#define RDS_CARRIAGE_RETURN 0x0D
+
+#define rds_ps_nblocks(len) ((len / RDS_BLOCK) + (len % RDS_BLOCK ? 1 : 0))
+
+#define get_status_bit(p, b, m) (((p) & (m)) >> (b))
+#define set_bits(p, v, b, m) (((p) & ~(m)) | ((v) << (b)))
+
+#define ATTACK_TIME_UNIT 500
+
+#define POWER_OFF 0x00
+#define POWER_ON 0x01
+
+#define msb(x) ((u8)((u16) x >> 8))
+#define lsb(x) ((u8)((u16) x & 0x00FF))
+#define compose_u16(msb, lsb) (((u16)msb << 8) | lsb)
+#define compose_u32(msb, lsb) (((u32)msb << 16) | lsb)
+#define check_command_failed(status) (!(status & SI4713_CTS) || \
+ (status & SI4713_ERR))
+/* mute definition */
+#define set_mute(p) ((p & 1) | ((p & 1) << 1));
+#define get_mute(p) (p & 0x01)
+
+#ifdef DEBUG
+#define DBG_BUFFER(device, message, buffer, size) \
+ { \
+ int i; \
+ char str[(size)*5]; \
+ for (i = 0; i < size; i++) \
+ sprintf(str + i * 5, " 0x%02x", buffer[i]); \
+ v4l2_dbg(2, debug, device, "%s:%s\n", message, str); \
+ }
+#else
+#define DBG_BUFFER(device, message, buffer, size)
+#endif
+
+
+/*
+ * si4713_send_command - sends a command to si4713 and waits its response
+ * @sdev: si4713_device structure for the device we are communicating
+ * @command: command id
+ * @args: command arguments we are sending (up to 7)
+ * @argn: actual size of @args
+ * @response: buffer to place the expected response from the device (up to 15)
+ * @respn: actual size of @response
+ * @usecs: amount of time to wait before reading the response (in usecs)
+ */
+static int si4713_send_command(struct si4763_device *sdev, const u8 command,
+ const u8 args[], const int argn,
+ u8 response[], const int respn, const int usecs)
+{
+ struct i2c_client *client = sdev->client;
+ u8 data1[MAX_ARGS + 1];
+ int err;
+ int i;
+ if (!client->adapter)
+ return -ENODEV;
+
+ /* First send the command and its arguments */
+ data1[0] = command;
+ memcpy(data1 + 1, args, argn);
+ DBG_BUFFER(&sdev->sd, "Parameters", data1, argn + 1);
+
+ err = i2c_master_send(client, data1, argn + 1);
+ if (err != argn + 1) {
+ v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n",
+ command);
+ return (err > 0) ? -EIO : err;
+ }
+
+ /* Wait response from interrupt */
+/*
+ if (!wait_for_completion_timeout(&sdev->work,
+ usecs_to_jiffies(usecs) + 1))
+ v4l2_warn(&sdev->sd,
+ "(%s) Device took too much time to answer.\n",
+ __func__);
+
+*/
+
+
+ /* Then get the response */
+ i = 0;
+ err = i2c_master_recv(client, response, respn);
+ while (i++ < usecs && ((response[0] & 0x80) != 0x80)) {
+ err = i2c_master_recv(client, response, respn);
+ udelay(1);
+ }
+
+
+ if (err != respn) {
+ v4l2_err(&sdev->sd,
+ "Error while reading response for command 0x%02x\n",
+ command);
+ return (err > 0) ? -EIO : err;
+ }
+
+ DBG_BUFFER(&sdev->sd, "Response", response, respn);
+ if (check_command_failed(response[0]))
+ return -EBUSY;
+
+ return 0;
+}
+
+
+/*
+ * si4713_write_property - modifies a si4713 property
+ * @sdev: si4713_device structure for the device we are communicating
+ * @prop: property identification number
+ * @val: new value for that property
+ */
+static int si4713_write_property(struct si4763_device *sdev, u16 prop, u16 val)
+{
+ int rval;
+ u8 resp[SI4713_SET_PROP_NRESP];
+ /*
+ * .First byte = 0
+ * .Second byte = property's MSB
+ * .Third byte = property's LSB
+ * .Fourth byte = value's MSB
+ * .Fifth byte = value's LSB
+ */
+ const u8 args[SI4713_SET_PROP_NARGS] = {
+ 0x00,
+ msb(prop),
+ lsb(prop),
+ msb(val),
+ lsb(val),
+ };
+
+ rval = si4713_send_command(sdev, SI4713_CMD_SET_PROPERTY,
+ args, ARRAY_SIZE(args),
+ resp, ARRAY_SIZE(resp),
+ DEFAULT_TIMEOUT);
+
+ if (rval < 0)
+ return rval;
+
+ v4l2_dbg(1, debug, &sdev->sd,
+ "%s: property=0x%02x value=0x%02x status=0x%02x\n",
+ __func__, prop, val, resp[0]);
+
+ /*
+ * As there is no command response for SET_PROPERTY,
+ * wait Tcomp time to finish before proceed, in order
+ * to have property properly set.
+ */
+ msleep(TIMEOUT_SET_PROPERTY);
+
+ return rval;
+}
+
+static int si4713_enable_digitalout(struct si4763_device *sdev)
+{
+ int rval;
+ u8 resp[SI4713_SET_PROP_NRESP];
+ /*
+ * .First byte = 0
+ * .Second byte = property's MSB
+ * .Third byte = property's LSB
+ * .Fourth byte = value's MSB
+ * .Fifth byte = value's LSB
+ */
+ const u8 args[SI4713_EN_DIGITALOUT_NARGS] = {
+ 10,
+ 10,
+ 12,
+ 0,
+ };
+
+ rval = si4713_send_command(sdev, SI4713_CMD_EN_DIGITALOUT,
+ args, ARRAY_SIZE(args),
+ resp, ARRAY_SIZE(resp),
+ DEFAULT_TIMEOUT);
+
+ if (rval < 0)
+ return rval;
+
+
+ /*
+ * As there is no command response for SET_PROPERTY,
+ * wait Tcomp time to finish before proceed, in order
+ * to have property properly set.
+ */
+ msleep(TIMEOUT_SET_PROPERTY);
+
+ return rval;
+}
+
+static int si4713_get_digitalout(struct si4763_device *sdev, u32 *response)
+{
+ int rval;
+ u8 resp[5];
+ u16 temp1, temp2;
+
+ /*
+ * .First byte = 0
+ * .Second byte = property's MSB
+ * .Third byte = property's LSB
+ * .Fourth byte = value's MSB
+ * .Fifth byte = value's LSB
+ */
+ const u8 args[SI4713_EN_DIGITALOUT_NARGS] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ };
+
+ rval = si4713_send_command(sdev, SI4713_CMD_EN_DIGITALOUT,
+ args, ARRAY_SIZE(args),
+ resp, ARRAY_SIZE(resp),
+ DEFAULT_TIMEOUT);
+
+ if (rval < 0)
+ return rval;
+
+ temp1 = compose_u16(resp[1], resp[2]);
+ temp2 = compose_u16(resp[3], resp[4]);
+ *response = compose_u32(temp1, temp2);
+ /*
+ * As there is no command response for SET_PROPERTY,
+ * wait Tcomp time to finish before proceed, in order
+ * to have property properly set.
+ */
+ msleep(TIMEOUT_SET_PROPERTY);
+
+ return rval;
+}
+
+
+/*
+ * si4713_powerup - Powers the device up
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_powerup(struct si4763_device *sdev)
+{
+ int err;
+ u8 resp[SI4760_PWUP_NRESP];
+ const u8 args[SI4760_PWUP_NARGS] = {
+ SI4760_PWUP_ARG1,
+ SI4760_PWUP_ARG2,
+ SI4760_PWUP_ARG3,
+ SI4760_PWUP_ARG4,
+ SI4760_PWUP_ARG5,
+ };
+
+
+ if (sdev->power_state)
+ return 0;
+ err = si4713_send_command(sdev, SI4760_CMD_POWER_UP,
+ args, ARRAY_SIZE(args),
+ resp, ARRAY_SIZE(resp),
+ TIMEOUT_POWER_UP);
+
+ if (!err) {
+ v4l2_dbg(1, debug, &sdev->sd, "Powerup response: 0x%02x\n",
+ resp[0]);
+ v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n");
+ sdev->power_state = POWER_ON;
+
+ } else {
+ /* if (gpio_is_valid(sdev->gpio_reset))
+ gpio_set_value(sdev->gpio_reset, 0);
+ err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ */ if (err)
+ v4l2_err(&sdev->sd,
+ "Failed to disable supplies: %d\n", err);
+ }
+
+ return err;
+}
+
+/*
+ * si4713_powerdown - Powers the device down
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_powerdown(struct si4763_device *sdev)
+{
+ int err;
+ u8 resp[SI4760_PWDN_NRESP];
+
+
+ err = si4713_send_command(sdev, SI4760_CMD_POWER_DOWN,
+ NULL, 0,
+ resp, ARRAY_SIZE(resp),
+ DEFAULT_TIMEOUT);
+
+ if (!err) {
+ v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
+ resp[0]);
+ v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
+ if (err)
+ v4l2_err(&sdev->sd,
+ "Failed to disable supplies: %d\n", err);
+ sdev->power_state = POWER_OFF;
+ }
+
+ return err;
+}
+
+/*
+ * si4713_checkrev - Checks if we are treating a device with the correct rev.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_checkrev(struct si4763_device *sdev)
+{
+ struct i2c_client *client = sdev->client;
+ int rval;
+ u8 resp[SI4760_GETREV_NRESP];
+
+ mutex_lock(&sdev->mutex);
+
+ rval = si4713_send_command(sdev, SI4760_CMD_GET_REV,
+ NULL, 0,
+ resp, ARRAY_SIZE(resp),
+ DEFAULT_TIMEOUT);
+
+ if (rval < 0)
+ goto unlock;
+
+ if (resp[1] == SI4760_PRODUCT_NUMBER) {
+ v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+ } else {
+ v4l2_err(&sdev->sd, "Invalid product number\n");
+ rval = -EINVAL;
+ }
+
+unlock:
+ mutex_unlock(&sdev->mutex);
+ return rval;
+}
+
+/*
+ * si4713_wait_stc - Waits STC interrupt and clears status bits. Usefull
+ * for TX_TUNE_POWER, TX_TUNE_FREQ and TX_TUNE_MEAS
+ * @sdev: si4713_device structure for the device we are communicating
+ * @usecs: timeout to wait for STC interrupt signal
+ */
+static int si4713_wait_stc(struct si4763_device *sdev, const int usecs)
+{
+ int err;
+ u8 resp[SI4713_GET_STATUS_NRESP];
+
+ /* Wait response from STC interrupt */
+ if (!wait_for_completion_timeout(&sdev->work,
+ usecs_to_jiffies(usecs) + 1))
+ v4l2_warn(&sdev->sd,
+ "%s: device took too much time to answer (%d usec).\n",
+ __func__, usecs);
+
+ /* Clear status bits */
+ err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
+ NULL, 0,
+ resp, ARRAY_SIZE(resp),
+ DEFAULT_TIMEOUT);
+
+ if (err < 0)
+ goto exit;
+
+ v4l2_dbg(1, debug, &sdev->sd,
+ "%s: status bits: 0x%02x\n", __func__, resp[0]);
+
+ if (!(resp[0] & SI4713_STC_INT))
+ err = -EIO;
+
+exit:
+ return err;
+}
+
+/*
+ * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning
+ * frequency between 76 and 108 MHz in 10 kHz units and
+ * steps of 50 kHz.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
+ */
+static int si4713_tx_tune_freq(struct si4763_device *sdev, u16 frequency)
+{
+ int err;
+ u8 val[SI4713_TXFREQ_NRESP];
+ /*
+ * .First byte = 0
+ * .Second byte = frequency's MSB
+ * .Third byte = frequency's LSB
+ */
+ const u8 args[SI4713_TXFREQ_NARGS] = {
+ 0x00,
+ msb(frequency),
+ lsb(frequency),
+ 0x00,
+ 0x00,
+ };
+
+ err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_FREQ,
+ args, ARRAY_SIZE(args), val,
+ ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+
+/*
+ * si4713_tx_tune_measure - Enters receive mode and measures the received noise
+ * level in units of dBuV on the selected frequency.
+ * The Frequency must be between 76 and 108 MHz in 10 kHz
+ * units and steps of 50 kHz. The command also sets the
+ * antenna tuning capacitance. A value of 0 means
+ * autotuning, and a value of 1 to 191 indicates manual
+ * override.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
+ * @antcap: value of antenna tuning capacitor (0 - 191)
+ */
+static int si4713_tx_tune_measure(struct si4763_device *sdev, u16 frequency,
+ u8 antcap)
+{
+ int err;
+ u8 val[SI4713_TXMEA_NRESP];
+ /*
+ * .First byte = 0
+ * .Second byte = frequency's MSB
+ * .Third byte = frequency's LSB
+ * .Fourth byte = antcap
+ */
+ const u8 args[SI4713_TXMEA_NARGS] = {
+ 0x00,
+ msb(frequency),
+ lsb(frequency),
+ antcap,
+ };
+
+ sdev->tune_rnl = DEFAULT_TUNE_RNL;
+
+ if (antcap > SI4713_MAX_ANTCAP)
+ return -EDOM;
+
+ err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_MEASURE,
+ args, ARRAY_SIZE(args), val,
+ ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+ if (err < 0)
+ return err;
+
+ v4l2_dbg(1, debug, &sdev->sd,
+ "%s: frequency=0x%02x antcap=0x%02x status=0x%02x\n",
+ __func__, frequency, antcap, val[0]);
+
+ return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE);
+}
+
+static int si4763_fm_rsq_status(struct si4763_device *sdev,
+ u16 *frequency)
+{
+ int err;
+ u8 val[SI4763_FM_RSQ_STATUS_NRESP];
+ /*
+ * .First byte = intack bit
+ */
+ const u8 args[SI4763_FM_RSQ_STATUS_NARGS] = {
+ 0x00,
+ };
+
+ err = si4713_send_command(sdev, SI4763_CMD_FM_RSQ_STATUS,
+ args, ARRAY_SIZE(args), val,
+ ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+ *frequency = compose_u16(val[3], val[4]);
+ return err;
+}
+
+
+static int si4713_set_power_state(struct si4763_device *sdev, u8 value)
+{
+ int rval;
+
+ mutex_lock(&sdev->mutex);
+
+ if (value)
+ rval = si4713_powerup(sdev);
+ else
+ rval = si4713_powerdown(sdev);
+
+ mutex_unlock(&sdev->mutex);
+ return rval;
+}
+
+
+/*
+ * si4713_initialize - Sets the device up with default configuration.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_initialize(struct si4763_device *sdev)
+{
+ int rval;
+
+ rval = si4713_set_power_state(sdev, POWER_OFF);
+ if (rval < 0)
+ goto exit;
+
+ rval = si4713_set_power_state(sdev, POWER_ON);
+ if (rval < 0)
+ goto exit;
+
+ rval = si4713_checkrev(sdev);
+ if (rval < 0)
+ goto exit;
+ rval = si4713_set_power_state(sdev, POWER_OFF);
+ if (rval < 0)
+ goto exit;
+
+exit:
+ return rval;
+}
+
+static int si4763_setup(struct si4763_device *sdev)
+{
+ int rval;
+ u32 temp;
+ rval = si4713_write_property(sdev, 0x0202, 0xBB80);
+ if (rval < 0)
+ goto exit;
+
+ rval = si4713_write_property(sdev, 0x0203, 0x0400);
+ if (rval < 0)
+ goto exit;
+ rval = si4713_tx_tune_freq(sdev, FREQ_RANGE_LOW);
+ if (rval < 0)
+ goto exit;
+
+ rval = si4713_enable_digitalout(sdev);
+ if (rval < 0)
+ goto exit;
+
+ rval = si4713_get_digitalout(sdev, &temp);
+ if (rval < 0)
+ goto exit;
+
+exit:
+ return rval;
+}
+
+/*
+ * Video4Linux Subdev Interface
+ */
+
+/* si4713_ioctl - deal with private ioctls (only rnl for now) */
+long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct si4763_device *sdev = to_si4763_device(sd);
+ struct si4713_rnl *rnl = arg;
+ int frequency = 0;
+ int rval = 0;
+
+ if (!arg)
+ return -EINVAL;
+
+ mutex_lock(&sdev->mutex);
+ switch (cmd) {
+ case SI4713_IOC_MEASURE_RNL:
+
+ if (sdev->power_state) {
+ /* Set desired measurement frequency */
+ rval = si4713_tx_tune_measure(sdev, frequency, 0);
+ if (rval < 0)
+ goto unlock;
+ /* get results from tune status */
+ }
+ rnl->rnl = sdev->tune_rnl;
+ break;
+
+ default:
+ /* nothing */
+ rval = -ENOIOCTLCMD;
+ }
+
+unlock:
+ mutex_unlock(&sdev->mutex);
+ return rval;
+}
+
+
+/* si4763_g_frequency - get tuner or modulator radio frequency */
+static int si4763_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+
+ struct si4763_device *sdev = video_drvdata(file);
+ int rval = 0;
+
+ f->type = V4L2_TUNER_RADIO;
+
+ mutex_lock(&sdev->mutex);
+
+ if (sdev->power_state) {
+ u16 freq;
+
+ rval = si4763_fm_rsq_status(sdev, &freq);
+ if (rval < 0)
+ goto unlock;
+
+ sdev->frequency = freq;
+ }
+
+ f->frequency = sdev->frequency;
+
+unlock:
+ mutex_unlock(&sdev->mutex);
+ return rval;
+}
+
+/* si4713_s_frequency - set tuner or modulator radio frequency */
+static int si4763_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+
+{
+ struct si4763_device *sdev = video_drvdata(file);
+ int rval = 0;
+ u16 frequency = f->frequency;
+
+ /* Check frequency range */
+ if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH)
+ return -EDOM;
+
+ mutex_lock(&sdev->mutex);
+
+ if (sdev->power_state) {
+ rval = si4713_tx_tune_freq(sdev, frequency);
+ if (rval < 0)
+ goto unlock;
+ frequency = rval;
+ rval = 0;
+ }
+ sdev->frequency = frequency;
+ f->frequency = frequency;
+
+unlock:
+ mutex_unlock(&sdev->mutex);
+ return rval;
+}
+
+
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si4763_fops_open - file open
+ */
+int si4763_fops_open(struct file *file)
+{
+ struct si4763_device *radio = video_drvdata(file);
+ int retval = 0;
+
+ if (radio->users != 0)
+ return -ENODEV;
+ /* start radio */
+ si4713_set_power_state(radio, POWER_ON);
+ si4763_setup(radio);
+ radio->users = 1;
+
+ return retval;
+}
+
+
+/*
+ * si470x_fops_release - file release
+ */
+int si4763_fops_release(struct file *file)
+{
+ struct si4763_device *radio = video_drvdata(file);
+ int retval = 0;
+
+ /* safety check */
+ if (!radio)
+ return -ENODEV;
+
+
+ /* stop radio */
+ si4713_set_power_state(radio, POWER_OFF);
+ radio->users = 0;
+ return retval;
+}
+
+
+/*
+ * si4763_fops - file operations interface
+ * video_ioctl2 is part of the v4l2 implementations. Change this pointer to the
+ * ioctl function you want to implement, in case you don't want to be part of
+ * v4l2.
+ */
+static const struct v4l2_file_operations si4763_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = video_ioctl2,
+ .open = si4763_fops_open,
+ .release = si4763_fops_release,
+};
+
+
+/*
+ * si4763_ioctl_ops - video device ioctl operations
+ */
+static const struct v4l2_ioctl_ops si4763_ioctl_ops = {
+ .vidioc_g_frequency = si4763_g_frequency,
+ .vidioc_s_frequency = si4763_s_frequency,
+};
+
+
+/*
+ * si4763_viddev_template - video device interface
+ */
+struct video_device si4763_viddev_template = {
+ .fops = &si4763_fops,
+ .name = "si4763_i2c",
+ .release = video_device_release,
+ .ioctl_ops = &si4763_ioctl_ops,
+};
+
+
+/*
+ * I2C driver interface
+ */
+/* si4713_probe - probe for the device */
+static int si4713_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct si4763_device *sdev;
+ int rval;
+
+ sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+ if (!sdev) {
+ dev_err(&client->dev, "Failed to alloc video device.\n");
+ rval = -ENOMEM;
+ goto exit;
+ }
+ sdev->client = client;
+ sdev->users = 0;
+ /* video device allocation and initialization */
+ sdev->videodev = video_device_alloc();
+ if (!sdev->videodev) {
+ rval = -ENOMEM;
+ goto free_video;
+ }
+
+
+ mutex_init(&sdev->mutex);
+ memcpy(sdev->videodev, &si4763_viddev_template,
+ sizeof(si4763_viddev_template));
+ video_set_drvdata(sdev->videodev, sdev);
+/*
+ if (client->irq) {
+ rval = request_irq(client->irq,
+ si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+ client->name, sdev);
+ if (rval < 0) {
+ v4l2_err(&sdev->sd, "Could not request IRQ\n");
+ goto put_reg;
+ }
+ v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n");
+ } else {
+ v4l2_warn(&sdev->sd, "IRQ not configured. Using timeouts.\n");
+ }
+*/
+
+ rval = si4713_initialize(sdev);
+ if (rval < 0) {
+ v4l2_err(&sdev->sd, "Failed to probe device information.\n");
+ goto free_sdev;
+ }
+
+ /* register video device */
+ rval = video_register_device(sdev->videodev, VFL_TYPE_RADIO,
+ radio_nr);
+ if (rval) {
+ dev_warn(&client->dev, "Could not register video device\n");
+ goto free_video;
+ }
+ i2c_set_clientdata(client, sdev);
+ return 0;
+
+free_video:
+ video_device_release(sdev->videodev);
+
+free_sdev:
+ kfree(sdev);
+exit:
+ return rval;
+}
+
+/* si4713_remove - remove the device */
+static int si4713_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct si4763_device *sdev = to_si4763_device(sd);
+
+ if (sdev->power_state)
+ si4713_set_power_state(sdev, POWER_DOWN);
+
+ if (client->irq > 0)
+ free_irq(client->irq, sdev);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sdev);
+
+ return 0;
+}
+
+/* si4713_i2c_driver - i2c driver interface */
+static const struct i2c_device_id si4713_id[] = {
+ { "si4763_i2c" , 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, si4713_id);
+
+static struct i2c_driver si4713_i2c_driver = {
+ .driver = {
+ .name = "si4763_i2c",
+ },
+ .probe = si4713_probe,
+ .remove = si4713_remove,
+ .id_table = si4713_id,
+};
+
+/* Module Interface */
+static int __init si4713_module_init(void)
+{
+ return i2c_add_driver(&si4713_i2c_driver);
+}
+
+static void __exit si4713_module_exit(void)
+{
+ i2c_del_driver(&si4713_i2c_driver);
+}
+
+module_init(si4713_module_init);
+module_exit(si4713_module_exit);
+
+/* Module information */
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("I2C si4763");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/radio/si4763-i2c.h b/drivers/media/radio/si4763-i2c.h
new file mode 100644
index 000000000000..d97eb35863da
--- /dev/null
+++ b/drivers/media/radio/si4763-i2c.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+#ifndef SI4763_I2C_H
+#define SI4763_I2C_H
+
+#include <media/v4l2-subdev.h>
+#include <media/si4763.h>
+
+#define SI4760_PRODUCT_NUMBER 0x05
+
+/* Command Timeouts */
+#define DEFAULT_TIMEOUT 500
+#define TIMEOUT_SET_PROPERTY 20
+#define TIMEOUT_TX_TUNE_POWER 30000
+#define TIMEOUT_TX_TUNE 110000
+#define TIMEOUT_POWER_UP 200000
+
+/*
+ * Command and its arguments definitions
+ */
+#define SI4713_PWUP_CTSIEN (1<<7)
+#define SI4713_PWUP_GPO2OEN (1<<6)
+#define SI4713_PWUP_PATCH (1<<5)
+#define SI4713_PWUP_XOSCEN (1<<4)
+#define SI4713_PWUP_FUNC_TX 0x02
+#define SI4713_PWUP_FUNC_PATCH 0x0F
+#define SI4713_PWUP_OPMOD_ANALOG 0x50
+#define SI4713_PWUP_OPMOD_DIGITAL 0x0F
+#define SI4760_PWUP_NARGS 5
+#define SI4760_PWUP_NRESP 1
+#define SI4760_PWDOWN_NARGS 1
+
+#define SI4760_CMD_POWER_UP 0x01
+
+#define SI4760_PWUP_ARG1 0xF7
+#define SI4760_PWUP_ARG2 0x28
+#define SI4760_PWUP_ARG3 0x07
+#define SI4760_PWUP_ARG4 0x11
+#define SI4760_PWUP_ARG5 0x11
+
+#define SI4713_CMD_EN_DIGITALOUT 0x18
+#define SI4713_EN_DIGITALOUT_NARGS 4
+
+
+#define SI4760_GETREV_NRESP 9
+#define SI4760_CMD_GET_REV 0x02
+
+#define SI4760_PWDN_NRESP 1
+#define SI4760_CMD_POWER_DOWN 0x11
+
+#define SI4763_CMD_FM_RSQ_STATUS 0x32
+#define SI4763_FM_RSQ_STATUS_NARGS 1
+#define SI4763_FM_RSQ_STATUS_NRESP 5
+
+#define SI4713_SET_PROP_NARGS 5
+#define SI4713_SET_PROP_NRESP 1
+#define SI4713_CMD_SET_PROPERTY 0x13
+
+#define SI4713_GET_PROP_NARGS 3
+#define SI4713_GET_PROP_NRESP 4
+#define SI4713_CMD_GET_PROPERTY 0x13
+
+#define SI4713_GET_STATUS_NRESP 1
+#define SI4713_CMD_GET_INT_STATUS 0x14
+
+#define SI4713_CMD_PATCH_ARGS 0x15
+#define SI4713_CMD_PATCH_DATA 0x16
+
+#define SI4713_MAX_FREQ 10800
+#define SI4713_MIN_FREQ 7600
+#define SI4713_TXFREQ_NARGS 5
+#define SI4713_TXFREQ_NRESP 1
+#define SI4713_CMD_TX_TUNE_FREQ 0x30
+
+#define SI4713_MAX_POWER 120
+#define SI4713_MIN_POWER 88
+#define SI4713_MAX_ANTCAP 191
+#define SI4713_MIN_ANTCAP 0
+#define SI4713_TXPWR_NARGS 4
+#define SI4713_TXPWR_NRESP 1
+#define SI4713_CMD_TX_TUNE_POWER 0x31
+
+#define SI4713_TXMEA_NARGS 4
+#define SI4713_TXMEA_NRESP 1
+#define SI4713_CMD_TX_TUNE_MEASURE 0x32
+
+#define SI4713_INTACK_MASK 0x01
+#define SI4713_TXSTATUS_NARGS 1
+#define SI4713_TXSTATUS_NRESP 8
+#define SI4713_CMD_TX_TUNE_STATUS 0x33
+
+#define SI4713_OVERMOD_BIT (1 << 2)
+#define SI4713_IALH_BIT (1 << 1)
+#define SI4713_IALL_BIT (1 << 0)
+#define SI4713_ASQSTATUS_NARGS 1
+#define SI4713_ASQSTATUS_NRESP 5
+#define SI4713_CMD_TX_ASQ_STATUS 0x34
+
+#define SI4713_RDSBUFF_MODE_MASK 0x87
+#define SI4713_RDSBUFF_NARGS 7
+#define SI4713_RDSBUFF_NRESP 6
+#define SI4713_CMD_TX_RDS_BUFF 0x35
+
+#define SI4713_RDSPS_PSID_MASK 0x1F
+#define SI4713_RDSPS_NARGS 5
+#define SI4713_RDSPS_NRESP 1
+#define SI4713_CMD_TX_RDS_PS 0x36
+
+#define SI4713_CMD_GPO_CTL 0x80
+#define SI4713_CMD_GPO_SET 0x81
+
+/*
+ * Bits from status response
+ */
+#define SI4713_CTS (1<<7)
+#define SI4713_ERR (1<<6)
+#define SI4713_RDS_INT (1<<2)
+#define SI4713_ASQ_INT (1<<1)
+#define SI4713_STC_INT (1<<0)
+
+/*
+ * Property definitions
+ */
+#define SI4713_GPO_IEN 0x0001
+#define SI4713_DIG_INPUT_FORMAT 0x0101
+#define SI4713_DIG_INPUT_SAMPLE_RATE 0x0103
+#define SI4713_REFCLK_FREQ 0x0201
+#define SI4713_REFCLK_PRESCALE 0x0202
+#define SI4713_TX_COMPONENT_ENABLE 0x2100
+#define SI4713_TX_AUDIO_DEVIATION 0x2101
+#define SI4713_TX_PILOT_DEVIATION 0x2102
+#define SI4713_TX_RDS_DEVIATION 0x2103
+#define SI4713_TX_LINE_INPUT_LEVEL 0x2104
+#define SI4713_TX_LINE_INPUT_MUTE 0x2105
+#define SI4713_TX_PREEMPHASIS 0x2106
+#define SI4713_TX_PILOT_FREQUENCY 0x2107
+#define SI4713_TX_ACOMP_ENABLE 0x2200
+#define SI4713_TX_ACOMP_THRESHOLD 0x2201
+#define SI4713_TX_ACOMP_ATTACK_TIME 0x2202
+#define SI4713_TX_ACOMP_RELEASE_TIME 0x2203
+#define SI4713_TX_ACOMP_GAIN 0x2204
+#define SI4713_TX_LIMITER_RELEASE_TIME 0x2205
+#define SI4713_TX_ASQ_INTERRUPT_SOURCE 0x2300
+#define SI4713_TX_ASQ_LEVEL_LOW 0x2301
+#define SI4713_TX_ASQ_DURATION_LOW 0x2302
+#define SI4713_TX_ASQ_LEVEL_HIGH 0x2303
+#define SI4713_TX_ASQ_DURATION_HIGH 0x2304
+#define SI4713_TX_RDS_INTERRUPT_SOURCE 0x2C00
+#define SI4713_TX_RDS_PI 0x2C01
+#define SI4713_TX_RDS_PS_MIX 0x2C02
+#define SI4713_TX_RDS_PS_MISC 0x2C03
+#define SI4713_TX_RDS_PS_REPEAT_COUNT 0x2C04
+#define SI4713_TX_RDS_PS_MESSAGE_COUNT 0x2C05
+#define SI4713_TX_RDS_PS_AF 0x2C06
+#define SI4713_TX_RDS_FIFO_SIZE 0x2C07
+
+#define PREEMPHASIS_USA 75
+#define PREEMPHASIS_EU 50
+#define PREEMPHASIS_DISABLED 0
+#define FMPE_USA 0x00
+#define FMPE_EU 0x01
+#define FMPE_DISABLED 0x02
+
+#define POWER_UP 0x01
+#define POWER_DOWN 0x00
+
+struct rds_info {
+ u32 pi;
+#define MAX_RDS_PTY 31
+ u32 pty;
+#define MAX_RDS_DEVIATION 90000
+ u32 deviation;
+/*
+ * PSNAME is known to be defined as 8 character sized (RDS Spec).
+ * However, there is receivers which scroll PSNAME 8xN sized.
+ */
+#define MAX_RDS_PS_NAME 96
+ u8 ps_name[MAX_RDS_PS_NAME + 1];
+/*
+ * MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group)
+ * character sized (RDS Spec).
+ * However, there is receivers which scroll them as well.
+ */
+#define MAX_RDS_RADIO_TEXT 384
+ u8 radio_text[MAX_RDS_RADIO_TEXT + 1];
+ u32 enabled;
+};
+
+struct limiter_info {
+#define MAX_LIMITER_RELEASE_TIME 102390
+ u32 release_time;
+#define MAX_LIMITER_DEVIATION 90000
+ u32 deviation;
+ u32 enabled;
+};
+
+struct pilot_info {
+#define MAX_PILOT_DEVIATION 90000
+ u32 deviation;
+#define MAX_PILOT_FREQUENCY 19000
+ u32 frequency;
+ u32 enabled;
+};
+
+struct acomp_info {
+#define MAX_ACOMP_RELEASE_TIME 1000000
+ u32 release_time;
+#define MAX_ACOMP_ATTACK_TIME 5000
+ u32 attack_time;
+#define MAX_ACOMP_THRESHOLD 0
+#define MIN_ACOMP_THRESHOLD (-40)
+ s32 threshold;
+#define MAX_ACOMP_GAIN 20
+ u32 gain;
+ u32 enabled;
+};
+
+#define SI4763_NUM_SUPPLIES 2
+
+/*
+ * si4763_device - private data
+ */
+struct si4763_device {
+ /* v4l2_subdev and i2c reference (v4l2_subdev priv data) */
+ struct v4l2_subdev sd;
+ /* private data structures */
+ struct mutex mutex;
+ struct completion work;
+ struct rds_info rds_info;
+ struct limiter_info limiter_info;
+ struct pilot_info pilot_info;
+ struct acomp_info acomp_info;
+ struct regulator_bulk_data supplies[SI4763_NUM_SUPPLIES];
+ int gpio_reset;
+ u32 frequency;
+ u32 preemphasis;
+ u32 mute;
+ u32 power_level;
+ u32 power_state;
+ u32 antenna_capacitor;
+ u32 stereo;
+ u32 tune_rnl;
+ u8 users;
+ struct i2c_client *client;
+ struct video_device *videodev;
+};
+#endif /* ifndef SI4763_I2C_H */
diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c
index 43b53678d5ca..7542ca5f2062 100644
--- a/drivers/media/video/mxc/output/mxc_vout.c
+++ b/drivers/media/video/mxc/output/mxc_vout.c
@@ -30,6 +30,22 @@
#define MAX_FB_NUM 6
#define FB_BUFS 3
+#define VALID_HEIGHT_1080P (1080)
+#define FRAME_HEIGHT_1080P (1088)
+#define FRAME_WIDTH_1080P (1920)
+#define MAX_INTERLACED_WIDTH (1024)
+#define CHECK_TILED_1080P_DISPLAY(vout) \
+ (((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) && \
+ ((vout)->task.input.width == FRAME_WIDTH_1080P) && \
+ ((vout)->task.output.crop.w == FRAME_WIDTH_1080P) && \
+ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \
+ ((vout)->task.output.crop.h == VALID_HEIGHT_1080P))
+#define CHECK_TILED_1080P_STREAM(vout) \
+ (((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) && \
+ ((vout)->task.input.width == FRAME_WIDTH_1080P) && \
+ ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \
+ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \
+ ((vout)->task.input.crop.h == FRAME_HEIGHT_1080P))
struct mxc_vout_fb {
char *name;
@@ -62,7 +78,14 @@ struct mxc_vout_output {
bool fmt_init;
bool bypass_pp;
+ bool is_vdoaipu_task;
struct ipu_task task;
+ struct ipu_task vdoa_task;
+ struct vdoa_mem {
+ void *vaddr;
+ dma_addr_t paddr;
+ size_t size;
+ } vdoa_dma;
bool timer_stop;
struct timer_list timer;
@@ -97,7 +120,7 @@ static int video_nr = 16;
/* Module parameters */
module_param(video_nr, int, S_IRUGO);
MODULE_PARM_DESC(video_nr, "video device numbers");
-module_param(debug, bool, S_IRUGO);
+module_param(debug, int, 0600);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
const static struct v4l2_fmtdesc mxc_formats[] = {
@@ -145,6 +168,14 @@ const static struct v4l2_fmtdesc mxc_formats[] = {
.description = "YUV420",
.pixelformat = V4L2_PIX_FMT_YUV420,
},
+ {
+ .description = "TILED NV12P",
+ .pixelformat = IPU_PIX_FMT_TILED_NV12,
+ },
+ {
+ .description = "TILED NV12F",
+ .pixelformat = IPU_PIX_FMT_TILED_NV12F,
+ },
};
#define NUM_MXC_VOUT_FORMATS (ARRAY_SIZE(mxc_formats))
@@ -158,6 +189,24 @@ static struct mxc_vout_fb g_fb_setting[MAX_FB_NUM];
static int config_disp_output(struct mxc_vout_output *vout);
static void release_disp_output(struct mxc_vout_output *vout);
+static unsigned int get_frame_size(struct mxc_vout_output *vout)
+{
+ unsigned int size;
+
+ if (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)
+ size = TILED_NV12_FRAME_SIZE(vout->task.input.width,
+ vout->task.input.height);
+ else if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) {
+ size = TILED_NV12_FRAME_SIZE(vout->task.input.width,
+ vout->task.input.height/2);
+ size *= 2;
+ } else
+ size = vout->task.input.width * vout->task.input.height *
+ fmt_to_bpp(vout->task.input.format)/8;
+
+ return size;
+}
+
static ipu_channel_t get_ipu_channel(struct fb_info *fbi)
{
ipu_channel_t ipu_ch = CHAN_NONE;
@@ -315,6 +364,9 @@ static bool deinterlace_3_field(struct mxc_vout_output *vout)
static bool is_pp_bypass(struct mxc_vout_output *vout)
{
+ if ((IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format))
+ return false;
if ((vout->task.input.width == vout->task.output.width) &&
(vout->task.input.height == vout->task.output.height) &&
(vout->task.input.crop.w == vout->task.output.crop.w) &&
@@ -374,6 +426,8 @@ static int show_buf(struct mxc_vout_output *vout, int idx,
struct fb_info *fbi = vout->fbi;
struct fb_var_screeninfo var;
int ret;
+ u32 is_1080p;
+ u32 yres = 0;
memcpy(&var, &fbi->var, sizeof(var));
@@ -390,9 +444,17 @@ static int show_buf(struct mxc_vout_output *vout, int idx,
ret = fb_pan_display(fbi, &var);
console_unlock();
} else {
- var.yoffset = idx * fbi->var.yres;
console_lock();
+ is_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+ if (is_1080p) {
+ yres = fbi->var.yres;
+ fbi->var.yres = FRAME_HEIGHT_1080P;
+ }
+
+ var.yoffset = idx * fbi->var.yres;
ret = fb_pan_display(fbi, &var);
+ if (is_1080p)
+ fbi->var.yres = yres;
console_unlock();
}
@@ -408,6 +470,8 @@ static void disp_work_func(struct work_struct *work)
unsigned long flags = 0;
struct ipu_pos ipos;
int ret = 0;
+ u32 is_1080p;
+ u32 ocrop_h = 0;
v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work begin one frame\n");
@@ -458,11 +522,31 @@ static void disp_work_func(struct work_struct *work)
}
vout->task.output.paddr =
vout->disp_bufs[vout->frame_count % FB_BUFS];
+
+ is_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+ if (is_1080p) {
+ vout->task.input.crop.h = FRAME_HEIGHT_1080P;
+ vout->task.output.height = FRAME_HEIGHT_1080P;
+ ocrop_h = vout->task.output.crop.h;
+ vout->task.output.crop.h = FRAME_HEIGHT_1080P;
+ }
+ if (vout->is_vdoaipu_task) {
+ vout->vdoa_task.input.paddr = vout->task.input.paddr;
+ vout->vdoa_task.output.paddr = vout->vdoa_dma.paddr;
+ ret = ipu_queue_task(&vout->vdoa_task);
+ if (ret < 0) {
+ mutex_unlock(&vout->task_lock);
+ goto err;
+ }
+ vout->task.input.paddr = vout->vdoa_task.output.paddr;
+ }
ret = ipu_queue_task(&vout->task);
if (ret < 0) {
mutex_unlock(&vout->task_lock);
goto err;
}
+ if (is_1080p)
+ vout->task.output.crop.h = ocrop_h;
}
mutex_unlock(&vout->task_lock);
@@ -569,6 +653,7 @@ static int mxc_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
unsigned int *size)
{
struct mxc_vout_output *vout = q->priv_data;
+ unsigned int frame_size;
if (!vout)
return -EINVAL;
@@ -576,8 +661,8 @@ static int mxc_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
return -EINVAL;
- *size = PAGE_ALIGN(vout->task.input.width * vout->task.input.height *
- fmt_to_bpp(vout->task.input.format)/8);
+ frame_size = get_frame_size(vout);
+ *size = PAGE_ALIGN(frame_size);
return 0;
}
@@ -758,8 +843,7 @@ static int mxc_vidioc_g_fmt_vid_out(struct file *file, void *fh,
f->fmt.pix.width = vout->task.input.width;
f->fmt.pix.height = vout->task.input.height;
f->fmt.pix.pixelformat = vout->task.input.format;
- f->fmt.pix.sizeimage = vout->task.input.width * vout->task.input.height *
- fmt_to_bpp(vout->task.input.format)/8;
+ f->fmt.pix.sizeimage = get_frame_size(vout);
if (f->fmt.pix.priv) {
rect = (struct v4l2_rect *)f->fmt.pix.priv;
@@ -768,6 +852,10 @@ static int mxc_vidioc_g_fmt_vid_out(struct file *file, void *fh,
rect->width = vout->task.input.crop.w;
rect->height = vout->task.input.crop.h;
}
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "frame_size:0x%x, pix_fmt:0x%x\n",
+ f->fmt.pix.sizeimage,
+ vout->task.input.format);
return 0;
}
@@ -813,33 +901,128 @@ again:
return ret;
}
+static inline int vdoaipu_try_task(struct mxc_vout_output *vout)
+{
+ int ret;
+ u32 icrop_h = 0, icrop_w = 0;
+ int is_1080p_stream;
+ size_t size;
+ struct ipu_task *ipu_task = &vout->task;
+ struct ipu_task *vdoa_task = &vout->vdoa_task;
+
+ is_1080p_stream = CHECK_TILED_1080P_STREAM(vout);
+ if (is_1080p_stream)
+ ipu_task->input.crop.h = VALID_HEIGHT_1080P;
+
+ if (ipu_task->input.crop.h % IPU_PIX_FMT_TILED_NV12_MBALIGN) {
+ icrop_h = ipu_task->input.crop.h;
+ ipu_task->input.crop.h = ALIGN(ipu_task->input.crop.h,
+ IPU_PIX_FMT_TILED_NV12_MBALIGN);
+ }
+ if (ipu_task->input.crop.w % IPU_PIX_FMT_TILED_NV12_MBALIGN) {
+ icrop_w = ipu_task->input.crop.w;
+ ipu_task->input.crop.w = ALIGN(ipu_task->input.crop.w,
+ IPU_PIX_FMT_TILED_NV12_MBALIGN);
+ }
+
+ memset(vdoa_task, 0, sizeof(*vdoa_task));
+ memcpy(&vdoa_task->input, &ipu_task->input, sizeof(ipu_task->input));
+ vdoa_task->output.format = IPU_PIX_FMT_NV12;
+ vdoa_task->output.width = ipu_task->input.crop.w;
+ vdoa_task->output.height = ipu_task->input.crop.h;
+ vdoa_task->output.crop.w = ipu_task->input.crop.w;
+ vdoa_task->output.crop.h = ipu_task->input.crop.h;
+
+ size = PAGE_ALIGN(ipu_task->input.crop.w *
+ ipu_task->input.crop.h *
+ fmt_to_bpp(vdoa_task->output.format)/8);
+ if (size > vout->vdoa_dma.size) {
+ if (vout->vdoa_dma.vaddr) {
+ dma_free_coherent(vout->vbq.dev, vout->vdoa_dma.size,
+ vout->vdoa_dma.vaddr, vout->vdoa_dma.paddr);
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "free vdoa_dma.size:0x%x, paddr:0x%x\n",
+ vout->vdoa_dma.size,
+ vout->vdoa_dma.paddr);
+ memset(&vout->vdoa_dma, 0, sizeof(vout->vdoa_dma));
+ }
+ vout->vdoa_dma.size = size;
+ vout->vdoa_dma.vaddr = dma_alloc_coherent(vout->vbq.dev,
+ vout->vdoa_dma.size,
+ &vout->vdoa_dma.paddr,
+ GFP_DMA | GFP_KERNEL);
+ if (!vout->vdoa_dma.vaddr)
+ return -ENOMEM;
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "alloc vdoa_dma.size:0x%x, paddr:0x%x\n",
+ vout->vdoa_dma.size,
+ vout->vdoa_dma.paddr);
+ }
+ ret = ipu_check_task(vdoa_task);
+ if (ret != IPU_CHECK_OK)
+ return -EINVAL;
+
+ ipu_task->input.format = vdoa_task->output.format;
+ if (icrop_h) {
+ ipu_task->input.height = vdoa_task->output.height;
+ ipu_task->input.crop.h = icrop_h;
+ }
+ if (icrop_w) {
+ ipu_task->input.width = vdoa_task->output.width;
+ ipu_task->input.crop.w = icrop_w;
+ }
+ ret = ipu_try_task(vout);
+
+ return ret;
+}
+
static int mxc_vout_try_task(struct mxc_vout_output *vout)
{
int ret = 0;
+ struct ipu_output *output = &vout->task.output;
+ struct ipu_input *input = &vout->task.input;
- vout->task.input.crop.w -= vout->task.input.crop.w%8;
- vout->task.input.crop.h -= vout->task.input.crop.h%8;
-
+ input->crop.w -= input->crop.w%8;
+ input->crop.h -= input->crop.h%8;
/* assume task.output already set by S_CROP */
if (is_pp_bypass(vout)) {
v4l2_info(vout->vfd->v4l2_dev, "Bypass IC.\n");
vout->bypass_pp = true;
- vout->task.output.format = vout->task.input.format;
+ output->format = input->format;
} else {
/* if need CSC, choose IPU-DP or IPU_IC do it */
vout->bypass_pp = false;
if (vout->disp_support_csc) {
- if (colorspaceofpixel(vout->task.input.format) == YUV_CS)
- vout->task.output.format = IPU_PIX_FMT_UYVY;
+ if (colorspaceofpixel(input->format) == YUV_CS)
+ output->format = IPU_PIX_FMT_UYVY;
else
- vout->task.output.format = IPU_PIX_FMT_RGB565;
+ output->format = IPU_PIX_FMT_RGB565;
} else {
if (colorspaceofpixel(vout->disp_fmt) == YUV_CS)
- vout->task.output.format = IPU_PIX_FMT_UYVY;
+ output->format = IPU_PIX_FMT_UYVY;
+ else
+ output->format = IPU_PIX_FMT_RGB565;
+ }
+
+ vout->is_vdoaipu_task = 0;
+ if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
+ (IPU_PIX_FMT_TILED_NV12F == input->format)) {
+ /* check resize/rotate/flip, or csc task */
+ if ((IPU_ROTATE_NONE != output->rotate) ||
+ (input->crop.w != output->crop.w) ||
+ (input->crop.h != output->crop.h) ||
+ (!vout->disp_support_csc &&
+ (colorspaceofpixel(vout->disp_fmt) == RGB_CS)))
+ vout->is_vdoaipu_task = 1;
else
- vout->task.output.format = IPU_PIX_FMT_RGB565;
+ /* IC bypass */
+ output->format = IPU_PIX_FMT_NV12;
}
- ret = ipu_try_task(vout);
+
+ if (vout->is_vdoaipu_task)
+ ret = vdoaipu_try_task(vout);
+ else
+ ret = ipu_try_task(vout);
}
return ret;
@@ -849,11 +1032,23 @@ static int mxc_vout_try_format(struct mxc_vout_output *vout, struct v4l2_format
{
int ret = 0;
struct v4l2_rect *rect = NULL;
+ u32 o_height = 0;
+ u32 ocrop_h = 0;
+ u32 is_1080p;
vout->task.input.width = f->fmt.pix.width;
vout->task.input.height = f->fmt.pix.height;
vout->task.input.format = f->fmt.pix.pixelformat;
+ if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) {
+ if (vout->task.input.width > MAX_INTERLACED_WIDTH)
+ return -EINVAL;
+ v4l2_info(vout->vfd->v4l2_dev,
+ "tiled fmt enable deinterlace.\n");
+ vout->task.input.deinterlace.enable = true;
+ vout->task.input.deinterlace.field_fmt =
+ IPU_DEINTERLACE_FIELD_TOP;
+ }
switch (f->fmt.pix.field) {
/* Images are in progressive format, not interlaced */
case V4L2_FIELD_NONE:
@@ -893,6 +1088,15 @@ static int mxc_vout_try_format(struct mxc_vout_output *vout, struct v4l2_format
vout->task.input.crop.h = f->fmt.pix.height;
}
+ is_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+ if (is_1080p) {
+ vout->task.input.crop.h = FRAME_HEIGHT_1080P;
+ o_height = vout->task.output.height;
+ ocrop_h = vout->task.output.crop.h;
+ vout->task.output.height = FRAME_HEIGHT_1080P;
+ vout->task.output.crop.h = FRAME_HEIGHT_1080P;
+ }
+
ret = mxc_vout_try_task(vout);
if (!ret) {
if (rect) {
@@ -904,6 +1108,11 @@ static int mxc_vout_try_format(struct mxc_vout_output *vout, struct v4l2_format
}
}
+ if (is_1080p) {
+ vout->task.output.height = o_height;
+ vout->task.output.crop.h = ocrop_h;
+ }
+
return ret;
}
@@ -1311,6 +1520,7 @@ static int config_disp_output(struct mxc_vout_output *vout)
struct fb_info *fbi = vout->fbi;
struct fb_var_screeninfo var;
int i, display_buf_size, fb_num, ret;
+ u32 is_1080p;
memcpy(&var, &fbi->var, sizeof(var));
@@ -1332,7 +1542,11 @@ static int config_disp_output(struct mxc_vout_output *vout)
} else {
fb_num = FB_BUFS;
var.xres_virtual = var.xres;
- var.yres_virtual = fb_num * var.yres;
+ is_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+ if (is_1080p)
+ var.yres_virtual = fb_num * FRAME_HEIGHT_1080P;
+ else
+ var.yres_virtual = fb_num * var.yres;
var.vmode &= ~FB_VMODE_YWRAP;
}
var.bits_per_pixel = fmt_to_bpp(vout->task.output.format);
@@ -1357,7 +1571,11 @@ static int config_disp_output(struct mxc_vout_output *vout)
if (ret < 0)
return ret;
- display_buf_size = fbi->fix.line_length * fbi->var.yres;
+ is_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+ if (is_1080p)
+ display_buf_size = fbi->fix.line_length * FRAME_HEIGHT_1080P;
+ else
+ display_buf_size = fbi->fix.line_length * fbi->var.yres;
for (i = 0; i < fb_num; i++)
vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size;
@@ -1515,6 +1733,15 @@ static void mxc_vout_free_output(struct mxc_vout_dev *dev)
for (i = 0; i < dev->out_num; i++) {
vout = dev->out[i];
vfd = vout->vfd;
+ if (vout->vdoa_dma.vaddr) {
+ dma_free_coherent(vout->vbq.dev, vout->vdoa_dma.size,
+ vout->vdoa_dma.vaddr, vout->vdoa_dma.paddr);
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "free vdoa_dma.size:0x%x, paddr:0x%x\n",
+ vout->vdoa_dma.size,
+ vout->vdoa_dma.paddr);
+ memset(&vout->vdoa_dma, 0, sizeof(vout->vdoa_dma));
+ }
if (vfd) {
if (!video_is_registered(vfd))
video_device_release(vfd);
diff --git a/drivers/mfd/mxc-hdmi-core.c b/drivers/mfd/mxc-hdmi-core.c
index 18fd1a67ba83..92fdf710a5b1 100644
--- a/drivers/mfd/mxc-hdmi-core.c
+++ b/drivers/mfd/mxc-hdmi-core.c
@@ -64,6 +64,7 @@ int mxc_hdmi_ipu_id;
int mxc_hdmi_disp_id;
static struct mxc_edid_cfg hdmi_core_edid_cfg;
static int hdmi_core_init;
+static unsigned int hdmi_dma_running;
u8 hdmi_readb(unsigned int reg)
{
@@ -243,6 +244,12 @@ static void hdmi_set_clock_regenerator_n(unsigned int value)
{
u8 val;
+ if (!hdmi_dma_running) {
+ hdmi_writeb(value & 0xff, HDMI_AUD_N1);
+ hdmi_writeb(0, HDMI_AUD_N2);
+ hdmi_writeb(0, HDMI_AUD_N3);
+ }
+
hdmi_writeb(value & 0xff, HDMI_AUD_N1);
hdmi_writeb((value >> 8) & 0xff, HDMI_AUD_N2);
hdmi_writeb((value >> 16) & 0x0f, HDMI_AUD_N3);
@@ -257,6 +264,12 @@ static void hdmi_set_clock_regenerator_cts(unsigned int cts)
{
u8 val;
+ if (!hdmi_dma_running) {
+ hdmi_writeb(cts & 0xff, HDMI_AUD_CTS1);
+ hdmi_writeb(0, HDMI_AUD_CTS2);
+ hdmi_writeb(0, HDMI_AUD_CTS3);
+ }
+
/* Must be set/cleared first */
val = hdmi_readb(HDMI_AUD_CTS3);
val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
@@ -433,18 +446,12 @@ static void hdmi_set_clk_regenerator(void)
return;
}
- clk_enable(isfr_clk);
- clk_enable(iahb_clk);
-
pr_debug("%s: samplerate=%d ratio=%d pixelclk=%d N=%d cts=%d\n",
__func__, sample_rate, hdmi_ratio, (int)pixel_clk_rate,
clk_n, clk_cts);
- hdmi_set_clock_regenerator_n(clk_n);
hdmi_set_clock_regenerator_cts(clk_cts);
-
- clk_disable(iahb_clk);
- clk_disable(isfr_clk);
+ hdmi_set_clock_regenerator_n(clk_n);
}
/* Need to run this before phy is enabled the first time to prevent
@@ -464,10 +471,15 @@ void hdmi_clk_regenerator_update_pixel_clock(void)
hdmi_set_clk_regenerator();
}
+void hdmi_set_dma_mode(unsigned int dma_running)
+{
+ hdmi_dma_running = dma_running;
+ hdmi_set_clk_regenerator();
+}
+
void hdmi_set_sample_rate(unsigned int rate)
{
sample_rate = rate;
- hdmi_set_clk_regenerator();
}
void hdmi_set_edid_cfg(struct mxc_edid_cfg *cfg)
@@ -511,6 +523,7 @@ static int mxc_hdmi_core_probe(struct platform_device *pdev)
#endif
hdmi_core_init = 0;
+ hdmi_dma_running = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index d6f72f8c69a3..beb289133744 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -452,6 +452,8 @@ config MTD_NAND_GPMI_NAND
depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q)
select MTD_PARTITIONS
select MTD_CMDLINE_PARTS
+ select MTC_CHAR
+ select MXS_DMA
help
Enables NAND Flash support for IMX23 or IMX28.
The GPMI controller is very powerful, with the help of BCH
diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h
index 04acf6413b16..e1478d4de587 100644
--- a/drivers/mtd/nand/gpmi-nand/bch-regs.h
+++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h
@@ -71,6 +71,7 @@
? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \
: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \
)
+#define BM_BCH_FLASH0LAYOUT0_GF13_0_GF14_1 0x00000400
#define HW_BCH_FLASH0LAYOUT1 0x00000090
@@ -103,4 +104,5 @@
? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
)
+#define BM_BCH_FLASH0LAYOUT1_GF13_0_GF14_1 0x00000400
#endif
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 698535773ff4..1c273e4eb2b4 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -22,11 +22,15 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <mach/mxs.h>
+#include <mach/clock.h>
#include "gpmi-nand.h"
#include "gpmi-regs.h"
#include "bch-regs.h"
+#define FEATURE_SIZE 4 /* p1, p2, p3, p4 */
+#define NAND_CMD_SET_FEATURE 0xef
+
struct timing_threshod timing_default_threshold = {
.max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
BP_GPMI_TIMING0_DATA_SETUP),
@@ -37,6 +41,281 @@ struct timing_threshod timing_default_threshold = {
.max_dll_delay_in_ns = 16,
};
+static struct clk *mxs_dma_clk;
+
+static void setup_ddr_timing_onfi(struct gpmi_nand_data *this)
+{
+ uint32_t value;
+ struct resources *resources = &this->resources;
+
+ /* set timing 2 register */
+ value = BF_GPMI_TIMING2_DATA_PAUSE(0x6)
+ | BF_GPMI_TIMING2_CMDADD_PAUSE(0x4)
+ | BF_GPMI_TIMING2_POSTAMBLE_DELAY(0x2)
+ | BF_GPMI_TIMING2_PREAMBLE_DELAY(0x4)
+ | BF_GPMI_TIMING2_CE_DELAY(0x2)
+ | BF_GPMI_TIMING2_READ_LATENCY(0x2);
+
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_TIMING2);
+
+ /* set timing 1 register */
+ __raw_writel(BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(0x500),
+ resources->gpmi_regs + HW_GPMI_TIMING1);
+
+ /* Put GPMI in NAND mode, disable device reset, and make certain
+ IRQRDY polarity is active high. */
+ value = BV_GPMI_CTRL1_GPMI_MODE__NAND
+ | BM_GPMI_CTRL1_GANGED_RDYBUSY
+ | BF_GPMI_CTRL1_WRN_DLY_SEL(0x3)
+ | (BV_GPMI_CTRL1_DEV_RESET__DISABLED << 3)
+ | (BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH << 2);
+
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+}
+
+/* This must be called in the context of enabling necessary clocks */
+static void common_ddr_init(struct resources *resources)
+{
+ uint32_t value;
+
+ /* [6] enable both write & read DDR DLLs */
+ value = BM_GPMI_READ_DDR_DLL_CTRL_REFCLK_ON |
+ BM_GPMI_READ_DDR_DLL_CTRL_ENABLE |
+ BF_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT(0x2) |
+ BF_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET(0x7);
+
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+
+ /* [7] reset read */
+ __raw_writel(value | BM_GPMI_READ_DDR_DLL_CTRL_RESET,
+ resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+ value = value & ~BM_GPMI_READ_DDR_DLL_CTRL_RESET;
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+
+ value = BM_GPMI_WRITE_DDR_DLL_CTRL_REFCLK_ON |
+ BM_GPMI_WRITE_DDR_DLL_CTRL_ENABLE |
+ BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT(0x2) |
+ BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET(0x7) ,
+
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+
+ /* [8] reset write */
+ __raw_writel(value | BM_GPMI_WRITE_DDR_DLL_CTRL_RESET,
+ resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+
+ /* [9] wait for locks for read and write */
+ do {
+ uint32_t read_status, write_status;
+ uint32_t r_mask, w_mask;
+
+ read_status = __raw_readl(resources->gpmi_regs
+ + HW_GPMI_READ_DDR_DLL_STS);
+ write_status = __raw_readl(resources->gpmi_regs
+ + HW_GPMI_WRITE_DDR_DLL_STS);
+
+ r_mask = (BM_GPMI_READ_DDR_DLL_STS_REF_LOCK |
+ BM_GPMI_READ_DDR_DLL_STS_SLV_LOCK);
+ w_mask = (BM_GPMI_WRITE_DDR_DLL_STS_REF_LOCK |
+ BM_GPMI_WRITE_DDR_DLL_STS_SLV_LOCK);
+
+ if (((read_status & r_mask) == r_mask)
+ && ((write_status & w_mask) == w_mask))
+ break;
+ } while (1);
+
+ /* [10] force update of read/write */
+ value = __raw_readl(resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+ __raw_writel(value | BM_GPMI_READ_DDR_DLL_CTRL_SLV_FORCE_UPD,
+ resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+
+ value = __raw_readl(resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+ __raw_writel(value | BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_FORCE_UPD,
+ resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+
+ /* [11] set gate update */
+ value = __raw_readl(resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+ value |= BM_GPMI_READ_DDR_DLL_CTRL_GATE_UPDATE;
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_READ_DDR_DLL_CTRL);
+
+ value = __raw_readl(resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+ value |= BM_GPMI_WRITE_DDR_DLL_CTRL_GATE_UPDATE;
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_WRITE_DDR_DLL_CTRL);
+}
+
+static int enable_ddr_onfi(struct gpmi_nand_data *this)
+{
+ struct resources *resources = &this->resources;
+ struct nand_chip *nand = &this->nand;
+ struct mtd_info *mtd = &this->mtd;
+ int saved_chip_number = 0;
+ uint8_t device_feature[FEATURE_SIZE];
+ int mode = 0;/* there is 5 mode available, default is 0 */
+
+ saved_chip_number = this->current_chip;
+ nand->select_chip(mtd, 0);
+
+ /* [0] set proper timing */
+ __raw_writel(BF_GPMI_TIMING0_ADDRESS_SETUP(0x1)
+ | BF_GPMI_TIMING0_DATA_HOLD(0x3)
+ | BF_GPMI_TIMING0_DATA_SETUP(0x3),
+ resources->gpmi_regs + HW_GPMI_TIMING0);
+
+ /* [1] send SET FEATURE commond to NAND */
+ memset(device_feature, 0, sizeof(device_feature));
+ device_feature[0] = (0x1 << 4) | (mode & 0x7);
+
+ nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ nand->cmdfunc(mtd, NAND_CMD_SET_FEATURE, 1, -1);
+ nand->write_buf(mtd, device_feature, FEATURE_SIZE);
+
+ /* [2] set clk divider */
+ __raw_writel(BM_GPMI_CTRL1_GPMI_CLK_DIV2_EN,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* [3] about the clock, pay attention! */
+ nand->select_chip(mtd, saved_chip_number);
+ {
+ struct clk *pll1;
+ pll1 = clk_get(NULL, "pll1_main_clk");
+ if (IS_ERR(pll1)) {
+ printk(KERN_INFO "No PLL1 clock\n");
+ return -EINVAL;
+ }
+ clk_set_parent(resources->clock, pll1);
+ clk_set_rate(resources->clock, 20000000);
+ }
+ nand->select_chip(mtd, 0);
+
+ /* [4] setup timing */
+ setup_ddr_timing_onfi(this);
+
+ /* [5] set to SYNC mode */
+ __raw_writel(BM_GPMI_CTRL1_TOGGLE_MODE,
+ resources->gpmi_regs + HW_GPMI_CTRL1_CLR);
+ __raw_writel(BM_GPMI_CTRL1_SSYNCMODE | BM_GPMI_CTRL1_GANGED_RDYBUSY,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* common DDR initialization */
+ common_ddr_init(resources);
+
+ nand->select_chip(mtd, saved_chip_number);
+
+ printk(KERN_INFO "Micron ONFI NAND enters synchronous mode %d\n", mode);
+ return 0;
+}
+
+static void setup_ddr_timing_toggle(struct gpmi_nand_data *this)
+{
+ uint32_t value;
+ struct resources *resources = &this->resources;
+
+ /* set timing 2 register */
+ value = BF_GPMI_TIMING2_DATA_PAUSE(0x6)
+ | BF_GPMI_TIMING2_CMDADD_PAUSE(0x4)
+ | BF_GPMI_TIMING2_POSTAMBLE_DELAY(0x3)
+ | BF_GPMI_TIMING2_PREAMBLE_DELAY(0x2)
+ | BF_GPMI_TIMING2_CE_DELAY(0x2)
+ | BF_GPMI_TIMING2_READ_LATENCY(0x2);
+
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_TIMING2);
+
+ /* set timing 1 register */
+ __raw_writel(BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(0x500),
+ resources->gpmi_regs + HW_GPMI_TIMING1);
+
+ /* Put GPMI in NAND mode, disable device reset, and make certain
+ IRQRDY polarity is active high. */
+ value = BV_GPMI_CTRL1_GPMI_MODE__NAND
+ | BM_GPMI_CTRL1_GANGED_RDYBUSY
+ | (BV_GPMI_CTRL1_DEV_RESET__DISABLED << 3)
+ | (BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH << 2);
+
+ __raw_writel(value, resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+}
+
+static int enable_ddr_toggle(struct gpmi_nand_data *this)
+{
+ struct resources *resources = &this->resources;
+ struct nand_chip *nand = &this->nand;
+ struct mtd_info *mtd = &this->mtd;
+ int saved_chip_number = this->current_chip;
+
+ nand->select_chip(mtd, 0);
+
+ /* [0] set proper timing */
+ __raw_writel(BF_GPMI_TIMING0_ADDRESS_SETUP(0x5)
+ | BF_GPMI_TIMING0_DATA_HOLD(0xa)
+ | BF_GPMI_TIMING0_DATA_SETUP(0xa),
+ resources->gpmi_regs + HW_GPMI_TIMING0);
+
+ /* [2] set clk divider */
+ __raw_writel(BM_GPMI_CTRL1_GPMI_CLK_DIV2_EN,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* [3] about the clock, pay attention! */
+ nand->select_chip(mtd, saved_chip_number);
+ {
+ struct clk *pll1;
+ unsigned long rate;
+
+ pll1 = clk_get(NULL, "pll1_main_clk");
+ if (IS_ERR(pll1)) {
+ printk(KERN_INFO "No PLL1 clock\n");
+ return -EINVAL;
+ }
+
+ /* toggle nand : 133/66 MHz */
+ rate = 33000000;
+ clk_set_parent(resources->clock, pll1);
+ clk_set_rate(resources->clock, rate);
+ }
+ nand->select_chip(mtd, 0);
+
+ /* [4] setup timing */
+ setup_ddr_timing_toggle(this);
+
+ /* [5] set to TOGGLE mode */
+ __raw_writel(BM_GPMI_CTRL1_SSYNCMODE,
+ resources->gpmi_regs + HW_GPMI_CTRL1_CLR);
+ __raw_writel(BM_GPMI_CTRL1_TOGGLE_MODE | BM_GPMI_CTRL1_GANGED_RDYBUSY,
+ resources->gpmi_regs + HW_GPMI_CTRL1_SET);
+
+ /* common DDR initialization */
+ common_ddr_init(resources);
+
+ nand->select_chip(mtd, saved_chip_number);
+
+ printk(KERN_INFO "-- Sumsung TOGGLE NAND is enabled now. --\n");
+ return 0;
+}
+
+inline bool is_board_support_ddr(struct gpmi_nand_data *this)
+{
+ /* Only arm2 lpddr2pop board supports the DDR, */
+ /* the common arm2 board does not. */
+ return this->pdata->enable_ddr;
+}
+
+inline bool is_ddr_nand(struct gpmi_nand_data *this)
+{
+ return this->nand.onfi_version;
+}
+
+/* To check if we need to initialize something else*/
+int extra_init(struct gpmi_nand_data *this)
+{
+ if (is_board_support_ddr(this)) {
+ if (1)
+ return enable_ddr_onfi(this);
+ if (0)
+ return enable_ddr_toggle(this);
+ }
+ return 0;
+}
+
/*
* Clear the bit and poll it cleared. This is usually called with
* a reset address and mask being either SFTRST(bit 31) or CLKGATE
@@ -128,6 +407,12 @@ int gpmi_init(struct gpmi_nand_data *this)
struct resources *r = &this->resources;
int ret;
+ mxs_dma_clk = clk_get(NULL, "mxs-dma-apbh");
+ if (IS_ERR(mxs_dma_clk)) {
+ pr_err("can not get the dma clock\n");
+ ret = -ENOENT;
+ goto err_out;
+ }
ret = clk_prepare_enable(r->clock);
if (ret)
goto err_out;
@@ -224,11 +509,15 @@ int bch_set_geometry(struct gpmi_nand_data *this)
writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
+ | (is_ddr_nand(this) && is_board_support_ddr(this) ? \
+ BM_BCH_FLASH0LAYOUT0_GF13_0_GF14_1 : 0)
| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
r->bch_regs + HW_BCH_FLASH0LAYOUT0);
writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
+ | (is_ddr_nand(this) && is_board_support_ddr(this) ? \
+ BM_BCH_FLASH0LAYOUT1_GF13_0_GF14_1 : 0)
| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
r->bch_regs + HW_BCH_FLASH0LAYOUT1);
@@ -719,6 +1008,13 @@ void gpmi_begin(struct gpmi_nand_data *this)
pr_err("We failed in enable the clk\n");
goto err_out;
}
+ if (!clk_get_usecount(mxs_dma_clk)) {
+ ret = clk_prepare_enable(mxs_dma_clk);
+ if (ret) {
+ pr_err("We failed in enable the dma clk\n");
+ goto err_out;
+ }
+ }
/* set ready/busy timeout */
writel(0x500 << BP_GPMI_TIMING1_BUSY_TIMEOUT,
@@ -784,6 +1080,8 @@ void gpmi_end(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
clk_disable_unprepare(r->clock);
+ if (clk_get_usecount(mxs_dma_clk))
+ clk_disable_unprepare(mxs_dma_clk);
}
/* Clears a BCH interrupt. */
@@ -951,11 +1249,22 @@ int gpmi_send_page(struct gpmi_nand_data *this,
uint32_t address;
uint32_t ecc_command;
uint32_t buffer_mask;
+ uint32_t busw;
+ uint32_t page_size;
struct dma_async_tx_descriptor *desc;
struct dma_chan *channel = get_dma_chan(this);
int chip = this->current_chip;
u32 pio[6];
+ /* DDR use the 16-bit for DATA transmission! */
+ if (is_board_support_ddr(this) && is_ddr_nand(this)) {
+ busw = BV_GPMI_CTRL0_WORD_LENGTH__16_BIT;
+ page_size = geo->page_size >> 1;
+ } else {
+ busw = BM_GPMI_CTRL0_WORD_LENGTH;
+ page_size = geo->page_size;
+ }
+
/* A DMA descriptor that does an ECC page read. */
command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE;
address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
@@ -964,7 +1273,7 @@ int gpmi_send_page(struct gpmi_nand_data *this,
BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
+ | busw
| BF_GPMI_CTRL0_CS(chip, this)
| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
| BF_GPMI_CTRL0_ADDRESS(address)
@@ -973,7 +1282,7 @@ int gpmi_send_page(struct gpmi_nand_data *this,
pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
- pio[3] = geo->page_size;
+ pio[3] = page_size;
pio[4] = payload;
pio[5] = auxiliary;
@@ -997,18 +1306,29 @@ int gpmi_read_page(struct gpmi_nand_data *this,
uint32_t address;
uint32_t ecc_command;
uint32_t buffer_mask;
+ uint32_t page_size;
+ uint32_t busw;
struct dma_async_tx_descriptor *desc;
struct dma_chan *channel = get_dma_chan(this);
int chip = this->current_chip;
unsigned long flags;
u32 pio[6];
+ /* DDR use the 16-bit for DATA transmission! */
+ if (is_board_support_ddr(this) && is_ddr_nand(this)) {
+ busw = BV_GPMI_CTRL0_WORD_LENGTH__16_BIT;
+ page_size = geo->page_size >> 1;
+ } else {
+ busw = BM_GPMI_CTRL0_WORD_LENGTH;
+ page_size = geo->page_size;
+ }
+
/* [1] Wait for the chip to report ready. */
command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
+ | busw
| BF_GPMI_CTRL0_CS(chip, this)
| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
| BF_GPMI_CTRL0_ADDRESS(address)
@@ -1030,7 +1350,7 @@ int gpmi_read_page(struct gpmi_nand_data *this,
| BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY;
pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
+ | busw
| BF_GPMI_CTRL0_CS(chip, this)
| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
| BF_GPMI_CTRL0_ADDRESS(address)
@@ -1040,7 +1360,7 @@ int gpmi_read_page(struct gpmi_nand_data *this,
pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC
| BF_GPMI_ECCCTRL_ECC_CMD(ecc_command)
| BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask);
- pio[3] = geo->page_size;
+ pio[3] = page_size;
pio[4] = payload;
pio[5] = auxiliary;
@@ -1061,11 +1381,11 @@ int gpmi_read_page(struct gpmi_nand_data *this,
address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA;
pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode)
- | BM_GPMI_CTRL0_WORD_LENGTH
+ | busw
| BF_GPMI_CTRL0_CS(chip, this)
| BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this)
| BF_GPMI_CTRL0_ADDRESS(address)
- | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
+ | BF_GPMI_CTRL0_XFER_COUNT(page_size);
pio[1] = 0;
pio[2] = 0; /* set GPMI_HW_GPMI_ECCCTRL, disable the BCH */
desc = channel->device->device_prep_slave_sg(channel,
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index ea3ce22ff9d5..f25b7c27b101 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -41,7 +41,30 @@ static struct nand_ecclayout gpmi_hw_ecclayout = {
.eccpos = { 0, },
.oobfree = { {.offset = 0, .length = 0} }
};
+#if 0
+void gpmi_show_regs(struct gpmi_nand_data *this)
+{
+ struct resources *r = &this->resources;
+ u32 reg, bch;
+ int i;
+ int n;
+
+ n = 0xc0 / 0x10 + 1;
+ pr_info("-------------- Show GPMI registers ----------\n");
+ for (i = 0; i <= n; i++) {
+ reg = __raw_readl(r->gpmi_regs + i * 0x10);
+ pr_info("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+ }
+ pr_info("-------------- Show GPMI registers end ----------\n");
+ pr_info("-------------- Show BCH registers ----------\n");
+ for (i = 0; i <= n; i++) {
+ reg = __raw_readl(r->bch_regs + i * 0x10);
+ pr_info("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+ }
+ pr_info("-------------- Show BCH registers end ----------\n");
+}
+#endif
static irqreturn_t bch_irq(int irq, void *cookie)
{
struct gpmi_nand_data *this = cookie;
@@ -99,9 +122,14 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
/* The default for the length of Galois Field. */
geo->gf_len = 13;
+ if (is_ddr_nand(this) && is_board_support_ddr(this))
+ geo->gf_len = 14;
/* The default for chunk size. There is no oobsize greater then 512. */
geo->ecc_chunk_size = 512;
+ if (is_ddr_nand(this) && is_board_support_ddr(this))
+ geo->ecc_chunk_size = 1024;
+
while (geo->ecc_chunk_size < mtd->oobsize)
geo->ecc_chunk_size *= 2; /* keep C >= O */
@@ -115,6 +143,10 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
}
geo->page_size = mtd->writesize + mtd->oobsize;
+ if (is_ddr_nand(this) && is_board_support_ddr(this))
+ geo->page_size = mtd->writesize + geo->metadata_size
+ + (geo->ecc_strength * geo->gf_len * 8
+ / geo->ecc_chunk_count);
geo->payload_size = mtd->writesize;
/*
@@ -1001,6 +1033,19 @@ exit_auxiliary:
}
}
+#define MAX_PAGESIZE 8192
+static uint8_t verify_buf[MAX_PAGESIZE];
+
+static int gpmi_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len)
+{
+ struct nand_chip *nand = mtd->priv;
+
+ gpmi_ecc_read_page(mtd, nand, verify_buf, len);
+ if (memcmp(buf, verify_buf, len))
+ return -EFAULT;
+ return 0;
+}
+
/*
* There are several places in this driver where we have to handle the OOB and
* block marks. This is the function where things are the most complicated, so
@@ -1401,6 +1446,25 @@ static int __devinit nand_boot_init(struct gpmi_nand_data *this)
return 0;
}
+#if 0
+static void show_nfc_geometry(struct bch_geometry *geo)
+{
+ pr_info("---------------------------------------\n");
+ pr_info(" NFC Geometry (used by BCH)\n");
+ pr_info("---------------------------------------\n");
+ pr_info("ECC Strength : %u\n", geo->ecc_strength);
+ pr_info("Page Size in Bytes : %u\n", geo->page_size);
+ pr_info("Metadata Size in Bytes : %u\n", geo->metadata_size);
+ pr_info("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size);
+ pr_info("ECC Chunk Count : %u\n", geo->ecc_chunk_count);
+ pr_info("Payload Size in Bytes : %u\n", geo->payload_size);
+ pr_info("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size);
+ pr_info("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset);
+ pr_info("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset);
+ pr_info("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset);
+}
+#endif
+
static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this)
{
int ret;
@@ -1434,6 +1498,11 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
if (ret)
return ret;
+ /* extra init */
+ ret = extra_init(this);
+ if (ret != 0)
+ return ret;
+
/* NAND boot init, depends on the gpmi_set_geometry(). */
return nand_boot_init(this);
}
@@ -1482,6 +1551,7 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
chip->read_byte = gpmi_read_byte;
chip->read_buf = gpmi_read_buf;
chip->write_buf = gpmi_write_buf;
+ chip->verify_buf = gpmi_verify_buf;
chip->ecc.read_page = gpmi_ecc_read_page;
chip->ecc.write_page = gpmi_ecc_write_page;
chip->ecc.read_oob = gpmi_ecc_read_oob;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index 06a072bf85a1..229b2c5e1b12 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -235,6 +235,8 @@ struct timing_threshod {
};
/* Common Services */
+extern bool is_ddr_nand(struct gpmi_nand_data *);
+extern bool is_board_support_ddr(struct gpmi_nand_data *);
extern int common_nfc_set_geometry(struct gpmi_nand_data *);
extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
extern void prepare_data_dma(struct gpmi_nand_data *,
@@ -245,6 +247,7 @@ extern int start_dma_with_bch_irq(struct gpmi_nand_data *,
struct dma_async_tx_descriptor *);
/* GPMI-NAND helper function library */
+extern int extra_init(struct gpmi_nand_data *);
extern int gpmi_init(struct gpmi_nand_data *);
extern void gpmi_clear_bch(struct gpmi_nand_data *);
extern void gpmi_dump_info(struct gpmi_nand_data *);
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
index 83431240e2f2..a281716dc61a 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h
@@ -1,7 +1,7 @@
/*
* Freescale GPMI NAND Flash Driver
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
* Copyright 2008 Embedded Alley Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -108,32 +108,50 @@
#define HW_GPMI_CTRL1_CLR 0x00000068
#define HW_GPMI_CTRL1_TOG 0x0000006c
-#define BM_GPMI_CTRL1_BCH_MODE (1 << 18)
-
-#define BP_GPMI_CTRL1_DLL_ENABLE 17
-#define BM_GPMI_CTRL1_DLL_ENABLE (1 << BP_GPMI_CTRL1_DLL_ENABLE)
-
-#define BP_GPMI_CTRL1_HALF_PERIOD 16
-#define BM_GPMI_CTRL1_HALF_PERIOD (1 << BP_GPMI_CTRL1_HALF_PERIOD)
-
-#define BP_GPMI_CTRL1_RDN_DELAY 12
-#define BM_GPMI_CTRL1_RDN_DELAY (0xf << BP_GPMI_CTRL1_RDN_DELAY)
-#define BF_GPMI_CTRL1_RDN_DELAY(v) \
- (((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY)
-
-#define BM_GPMI_CTRL1_DEV_RESET (1 << 3)
-#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0
-#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1
-
-#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY (1 << 2)
-#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0
-#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1
-
-#define BM_GPMI_CTRL1_CAMERA_MODE (1 << 1)
-#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
-#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
-
-#define BM_GPMI_CTRL1_GPMI_MODE (1 << 0)
+#define BM_GPMI_CTRL1_DEV_CLK_STOP 0x80000000
+#define BM_GPMI_CTRL1_SSYNC_CLK_STOP 0x40000000
+#define BM_GPMI_CTRL1_WRITE_CLK_STOP 0x20000000
+#define BM_GPMI_CTRL1_TOGGLE_MODE 0x10000000
+#define BM_GPMI_CTRL1_GPMI_CLK_DIV2_EN 0x08000000
+#define BM_GPMI_CTRL1_UPDATE_CS 0x04000000
+#define BM_GPMI_CTRL1_SSYNCMODE 0x02000000
+#define BV_GPMI_CTRL1_SSYNCMODE__ASYNC 0x0
+#define BV_GPMI_CTRL1_SSYNCMODE__SSYNC 0x1
+#define BM_GPMI_CTRL1_DECOUPLE_CS 0x01000000
+#define BP_GPMI_CTRL1_WRN_DLY_SEL 22
+#define BM_GPMI_CTRL1_WRN_DLY_SEL 0x00C00000
+#define BF_GPMI_CTRL1_WRN_DLY_SEL(v) \
+ (((v) << 22) & BM_GPMI_CTRL1_WRN_DLY_SEL)
+#define BM_GPMI_CTRL1_RSVD1 0x00200000
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ_EN 0x00100000
+#define BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000
+#define BM_GPMI_CTRL1_BCH_MODE 0x00040000
+#define BM_GPMI_CTRL1_DLL_ENABLE 0x00020000
+#define BP_GPMI_CTRL1_HALF_PERIOD 16
+#define BM_GPMI_CTRL1_HALF_PERIOD 0x00010000
+#define BP_GPMI_CTRL1_RDN_DELAY 12
+#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
+#define BF_GPMI_CTRL1_RDN_DELAY(v) \
+ (((v) << 12) & BM_GPMI_CTRL1_RDN_DELAY)
+#define BM_GPMI_CTRL1_DMA2ECC_MODE 0x00000800
+#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
+#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
+#define BM_GPMI_CTRL1_BURST_EN 0x00000100
+#define BM_GPMI_CTRL1_ABORT_WAIT_REQUEST 0x00000080
+#define BP_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL 4
+#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL 0x00000070
+#define BF_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL(v) \
+ (((v) << 4) & BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY_CHANNEL)
+#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
+#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0
+#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1
+#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0
+#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1
+#define BM_GPMI_CTRL1_CAMERA_MODE 0x00000002
+#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001
+#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0
+#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1
#define HW_GPMI_TIMING0 0x00000070
@@ -154,8 +172,45 @@
#define HW_GPMI_TIMING1 0x00000080
#define BP_GPMI_TIMING1_BUSY_TIMEOUT 16
+#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
+#define BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(v) \
+ (((v) << 16) & BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT)
#define HW_GPMI_TIMING2 0x00000090
+
+#define BP_GPMI_TIMING2_RSVD1 27
+#define BM_GPMI_TIMING2_RSVD1 0xF8000000
+#define BF_GPMI_TIMING2_RSVD1(v) \
+ (((v) << 27) & BM_GPMI_TIMING2_RSVD1)
+#define BP_GPMI_TIMING2_READ_LATENCY 24
+#define BM_GPMI_TIMING2_READ_LATENCY 0x07000000
+#define BF_GPMI_TIMING2_READ_LATENCY(v) \
+ (((v) << 24) & BM_GPMI_TIMING2_READ_LATENCY)
+#define BP_GPMI_TIMING2_RSVD0 21
+#define BM_GPMI_TIMING2_RSVD0 0x00E00000
+#define BF_GPMI_TIMING2_RSVD0(v) \
+ (((v) << 21) & BM_GPMI_TIMING2_RSVD0)
+#define BP_GPMI_TIMING2_CE_DELAY 16
+#define BM_GPMI_TIMING2_CE_DELAY 0x001F0000
+#define BF_GPMI_TIMING2_CE_DELAY(v) \
+ (((v) << 16) & BM_GPMI_TIMING2_CE_DELAY)
+#define BP_GPMI_TIMING2_PREAMBLE_DELAY 12
+#define BM_GPMI_TIMING2_PREAMBLE_DELAY 0x0000F000
+#define BF_GPMI_TIMING2_PREAMBLE_DELAY(v) \
+ (((v) << 12) & BM_GPMI_TIMING2_PREAMBLE_DELAY)
+#define BP_GPMI_TIMING2_POSTAMBLE_DELAY 8
+#define BM_GPMI_TIMING2_POSTAMBLE_DELAY 0x00000F00
+#define BF_GPMI_TIMING2_POSTAMBLE_DELAY(v) \
+ (((v) << 8) & BM_GPMI_TIMING2_POSTAMBLE_DELAY)
+#define BP_GPMI_TIMING2_CMDADD_PAUSE 4
+#define BM_GPMI_TIMING2_CMDADD_PAUSE 0x000000F0
+#define BF_GPMI_TIMING2_CMDADD_PAUSE(v) \
+ (((v) << 4) & BM_GPMI_TIMING2_CMDADD_PAUSE)
+#define BP_GPMI_TIMING2_DATA_PAUSE 0
+#define BM_GPMI_TIMING2_DATA_PAUSE 0x0000000F
+#define BF_GPMI_TIMING2_DATA_PAUSE(v) \
+ (((v) << 0) & BM_GPMI_TIMING2_DATA_PAUSE)
+
#define HW_GPMI_DATA 0x000000a0
/* MX28 uses this to detect READY. */
@@ -169,4 +224,104 @@
#define HW_GPMI_DEBUG 0x000000c0
#define MX23_BP_GPMI_DEBUG_READY0 28
#define MX23_BM_GPMI_DEBUG_READY0 (1 << MX23_BP_GPMI_DEBUG_READY0)
+
+#define HW_GPMI_READ_DDR_DLL_CTRL (0x00000100)
+
+#define BP_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT 28
+#define BM_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT 0xF0000000
+#define BF_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT(v) \
+ (((v) << 28) & BM_GPMI_READ_DDR_DLL_CTRL_REF_UPDATE_INT)
+#define BP_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT 20
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT 0x0FF00000
+#define BF_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT(v) \
+ (((v) << 20) & BM_GPMI_READ_DDR_DLL_CTRL_SLV_UPDATE_INT)
+#define BP_GPMI_READ_DDR_DLL_CTRL_RSVD1 18
+#define BM_GPMI_READ_DDR_DLL_CTRL_RSVD1 0x000C0000
+#define BF_GPMI_READ_DDR_DLL_CTRL_RSVD1(v) \
+ (((v) << 18) & BM_GPMI_READ_DDR_DLL_CTRL_RSVD1)
+#define BP_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 10
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 0x0003FC00
+#define BF_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL(v) \
+ (((v) << 10) & BM_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE_VAL)
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_OVERRIDE 0x00000200
+#define BM_GPMI_READ_DDR_DLL_CTRL_REFCLK_ON 0x00000100
+#define BM_GPMI_READ_DDR_DLL_CTRL_GATE_UPDATE 0x00000080
+#define BP_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET 3
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET 0x00000078
+#define BF_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET(v) \
+ (((v) << 3) & BM_GPMI_READ_DDR_DLL_CTRL_SLV_DLY_TARGET)
+#define BM_GPMI_READ_DDR_DLL_CTRL_SLV_FORCE_UPD 0x00000004
+#define BM_GPMI_READ_DDR_DLL_CTRL_RESET 0x00000002
+#define BM_GPMI_READ_DDR_DLL_CTRL_ENABLE 0x00000001
+
+#define HW_GPMI_WRITE_DDR_DLL_CTRL (0x00000110)
+
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT 28
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT 0xF0000000
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT(v) \
+ (((v) << 28) & BM_GPMI_WRITE_DDR_DLL_CTRL_REF_UPDATE_INT)
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT 20
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT 0x0FF00000
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT(v) \
+ (((v) << 20) & BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_UPDATE_INT)
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_RSVD1 18
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_RSVD1 0x000C0000
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_RSVD1(v) \
+ (((v) << 18) & BM_GPMI_WRITE_DDR_DLL_CTRL_RSVD1)
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 10
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL 0x0003FC00
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL(v) \
+ (((v) << 10) & BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE_VAL)
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_OVERRIDE 0x00000200
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_REFCLK_ON 0x00000100
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_GATE_UPDATE 0x00000080
+#define BP_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET 3
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET 0x00000078
+#define BF_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET(v) \
+ (((v) << 3) & BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_DLY_TARGET)
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_SLV_FORCE_UPD 0x00000004
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_RESET 0x00000002
+#define BM_GPMI_WRITE_DDR_DLL_CTRL_ENABLE 0x00000001
+
+#define HW_GPMI_READ_DDR_DLL_STS (0x00000120)
+
+#define BP_GPMI_READ_DDR_DLL_STS_RSVD1 25
+#define BM_GPMI_READ_DDR_DLL_STS_RSVD1 0xFE000000
+#define BF_GPMI_READ_DDR_DLL_STS_RSVD1(v) \
+ (((v) << 25) & BM_GPMI_READ_DDR_DLL_STS_RSVD1)
+#define BP_GPMI_READ_DDR_DLL_STS_REF_SEL 17
+#define BM_GPMI_READ_DDR_DLL_STS_REF_SEL 0x01FE0000
+#define BF_GPMI_READ_DDR_DLL_STS_REF_SEL(v) \
+ (((v) << 17) & BM_GPMI_READ_DDR_DLL_STS_REF_SEL)
+#define BM_GPMI_READ_DDR_DLL_STS_REF_LOCK 0x00010000
+#define BP_GPMI_READ_DDR_DLL_STS_RSVD0 9
+#define BM_GPMI_READ_DDR_DLL_STS_RSVD0 0x0000FE00
+#define BF_GPMI_READ_DDR_DLL_STS_RSVD0(v) \
+ (((v) << 9) & BM_GPMI_READ_DDR_DLL_STS_RSVD0)
+#define BP_GPMI_READ_DDR_DLL_STS_SLV_SEL 1
+#define BM_GPMI_READ_DDR_DLL_STS_SLV_SEL 0x000001FE
+#define BF_GPMI_READ_DDR_DLL_STS_SLV_SEL(v) \
+ (((v) << 1) & BM_GPMI_READ_DDR_DLL_STS_SLV_SEL)
+#define BM_GPMI_READ_DDR_DLL_STS_SLV_LOCK 0x00000001
+
+#define HW_GPMI_WRITE_DDR_DLL_STS (0x00000130)
+
+#define BP_GPMI_WRITE_DDR_DLL_STS_RSVD1 25
+#define BM_GPMI_WRITE_DDR_DLL_STS_RSVD1 0xFE000000
+#define BF_GPMI_WRITE_DDR_DLL_STS_RSVD1(v) \
+ (((v) << 25) & BM_GPMI_WRITE_DDR_DLL_STS_RSVD1)
+#define BP_GPMI_WRITE_DDR_DLL_STS_REF_SEL 17
+#define BM_GPMI_WRITE_DDR_DLL_STS_REF_SEL 0x01FE0000
+#define BF_GPMI_WRITE_DDR_DLL_STS_REF_SEL(v) \
+ (((v) << 17) & BM_GPMI_WRITE_DDR_DLL_STS_REF_SEL)
+#define BM_GPMI_WRITE_DDR_DLL_STS_REF_LOCK 0x00010000
+#define BP_GPMI_WRITE_DDR_DLL_STS_RSVD0 9
+#define BM_GPMI_WRITE_DDR_DLL_STS_RSVD0 0x0000FE00
+#define BF_GPMI_WRITE_DDR_DLL_STS_RSVD0(v) \
+ (((v) << 9) & BM_GPMI_WRITE_DDR_DLL_STS_RSVD0)
+#define BP_GPMI_WRITE_DDR_DLL_STS_SLV_SEL 1
+#define BM_GPMI_WRITE_DDR_DLL_STS_SLV_SEL 0x000001FE
+#define BF_GPMI_WRITE_DDR_DLL_STS_SLV_SEL(v) \
+ (((v) << 1) & BM_GPMI_WRITE_DDR_DLL_STS_SLV_SEL)
+#define BM_GPMI_WRITE_DDR_DLL_STS_SLV_LOCK 0x00000001
#endif
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
index c7d37df019ed..46a9645fcf25 100644
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -371,13 +371,10 @@ static bool deinterlace_3_field(struct ipu_task_entry *t)
static u32 tiled_filed_size(struct ipu_task_entry *t)
{
- u32 y_size;
u32 field_size;
/* note: page_align is required by VPU hw ouput buffer */
- y_size = t->input.width * t->input.height/2;
- field_size = ALIGN(y_size, SZ_4K) + ALIGN(y_size/2, SZ_4K);
-
+ field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2);
return field_size;
}
diff --git a/drivers/mxc/ipu3/vdoa.c b/drivers/mxc/ipu3/vdoa.c
index 1a5266d7d7a8..2d3aaef16622 100644
--- a/drivers/mxc/ipu3/vdoa.c
+++ b/drivers/mxc/ipu3/vdoa.c
@@ -308,6 +308,7 @@ int vdoa_start(vdoa_handle_t handle, int timeout_ms)
CHECK_NULL_PTR(vdoa);
CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
+ vdoa->state = VDOA_START;
init_completion(&vdoa->comp);
vdoa_write_register(vdoa, VDOAIST,
VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
@@ -318,7 +319,6 @@ int vdoa_start(vdoa_handle_t handle, int timeout_ms)
vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
dump_registers(vdoa);
- vdoa->state = VDOA_START;
ret = wait_for_completion_timeout(&vdoa->comp,
msecs_to_jiffies(timeout_ms));
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index 2051e8691a64..41470e954938 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -609,6 +609,9 @@ static int snvs_rtc_probe(struct platform_device *pdev)
tv.tv_nsec = 0;
tv.tv_sec = rtc_read_lp_counter(ioaddr + SNVS_LPSRTCMR);
+ /* Remove can_wakeup flag to add common power wakeup interface */
+ pdev->dev.power.can_wakeup = 0;
+
/* By default, devices should wakeup if they can */
/* So snvs is set as "should wakeup" as it can */
device_init_wakeup(&pdev->dev, 1);
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index eba760095956..be58e17dc526 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007, 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2007, 2012 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2008 Juergen Beisert
*
* This program is free software; you can redistribute it and/or
@@ -652,6 +652,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
struct spi_imx_config config;
+ clk_enable(spi_imx->clk);
config.bpw = t ? t->bits_per_word : spi->bits_per_word;
config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
config.mode = spi->mode;
@@ -678,7 +679,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
BUG();
spi_imx->devtype_data.config(spi_imx, &config);
-
+ clk_disable(spi_imx->clk);
return 0;
}
@@ -687,6 +688,7 @@ static int spi_imx_transfer(struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+ clk_enable(spi_imx->clk);
spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf;
spi_imx->count = transfer->len;
@@ -699,6 +701,7 @@ static int spi_imx_transfer(struct spi_device *spi,
spi_imx->devtype_data.intctrl(spi_imx, MXC_INT_TE);
wait_for_completion(&spi_imx->xfer_done);
+ clk_disable(spi_imx->clk);
return transfer->len;
}
@@ -863,12 +866,12 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data.reset(spi_imx);
spi_imx->devtype_data.intctrl(spi_imx, 0);
-
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
+ clk_disable(spi_imx->clk);
dev_info(&pdev->dev, "probed\n");
@@ -902,7 +905,7 @@ static int __devexit spi_imx_remove(struct platform_device *pdev)
int i;
spi_bitbang_stop(&spi_imx->bitbang);
-
+ clk_enable(spi_imx->clk);
writel(0, spi_imx->base + MXC_CSPICTRL);
clk_disable(spi_imx->clk);
clk_put(spi_imx->clk);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index f8cd9bd076ce..d65c589cef60 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -881,7 +881,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
goto err;
}
- slave_config.direction = DMA_FROM_DEVICE;
+ slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_addr = sport->port.mapbase + URXD0;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
slave_config.src_maxburst = RXTL; /* fix me */
@@ -908,7 +908,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
goto err;
}
- slave_config.direction = DMA_TO_DEVICE;
+ slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = sport->port.mapbase + URTX0;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
slave_config.dst_maxburst = TXTL; /* fix me */
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 5a1aab94b405..ea81802a3ca6 100755
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -3458,7 +3458,11 @@ end:
dr_clk_gate(false);
}
- --udc_controller->suspended;
+
+ if (!(--udc_controller->suspended) && !udc_controller->stopped) {
+ dr_clk_gate(true);
+ dr_phy_low_power_mode(udc_controller, false);
+ }
enable_irq(udc_controller->irq);
mutex_unlock(&udc_resume_mutex);
printk(KERN_DEBUG "USB Gadget resume ends\n");
diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h
index 00c8e8a8cdd7..8f4b88ebc283 100755
--- a/drivers/usb/gadget/arcotg_udc.h
+++ b/drivers/usb/gadget/arcotg_udc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-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
@@ -46,11 +46,7 @@
#define NEED_IRAM(ep) ((g_iram_size) && \
((ep)->desc->bmAttributes == USB_ENDPOINT_XFER_BULK))
-#ifdef CONFIG_ARCH_MX5
#define POSTPONE_FREE_LAST_DTD
-#else
-#undef POSTPONE_FREE_LAST_DTD
-#endif
/* ### define USB registers here
*/
diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c
index 5bc048d216be..da77373e03a6 100644
--- a/drivers/video/mxc/mxc_epdc_fb.c
+++ b/drivers/video/mxc/mxc_epdc_fb.c
@@ -4726,9 +4726,15 @@ out_copybuffer:
fb_data->phys_addr_copybuf);
out_upd_buffers:
for (i = 0; i < fb_data->max_num_buffers; i++)
- dma_free_writecombine(&pdev->dev, fb_data->max_pix_size,
- fb_data->virt_addr_updbuf[i],
- fb_data->phys_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf[i] != NULL)
+ dma_free_writecombine(&pdev->dev,
+ fb_data->max_pix_size,
+ fb_data->virt_addr_updbuf[i],
+ fb_data->phys_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf != NULL)
+ kfree(fb_data->virt_addr_updbuf);
+ if (fb_data->phys_addr_updbuf != NULL)
+ kfree(fb_data->phys_addr_updbuf);
out_upd_lists:
list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
list) {
@@ -4753,6 +4759,7 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev)
{
struct update_data_list *plist, *temp_list;
struct mxc_epdc_fb_data *fb_data = platform_get_drvdata(pdev);
+ int i;
mxc_epdc_fb_blank(FB_BLANK_POWERDOWN, &fb_data->info);
@@ -4766,6 +4773,16 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev)
unregister_framebuffer(&fb_data->info);
free_irq(fb_data->epdc_irq, fb_data);
+ for (i = 0; i < fb_data->max_num_buffers; i++)
+ if (fb_data->virt_addr_updbuf[i] != NULL)
+ dma_free_writecombine(&pdev->dev, fb_data->max_pix_size,
+ fb_data->virt_addr_updbuf[i],
+ fb_data->phys_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf != NULL)
+ kfree(fb_data->virt_addr_updbuf);
+ if (fb_data->phys_addr_updbuf != NULL)
+ kfree(fb_data->phys_addr_updbuf);
+
dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
fb_data->working_buffer_virt,
fb_data->working_buffer_phys);
@@ -4780,9 +4797,6 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev)
list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
list) {
list_del(&plist->list);
- dma_free_writecombine(&pdev->dev, fb_data->max_pix_size,
- plist->virt_addr,
- plist->phys_addr);
kfree(plist);
}
#ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c
index 19d15df0d901..64a92316f974 100644
--- a/drivers/video/mxc_hdmi.c
+++ b/drivers/video/mxc_hdmi.c
@@ -570,6 +570,10 @@ static void hdmi_video_packetize(struct mxc_hdmi *hdmi)
} else
return;
+ if (!hdmi->edid_cfg.vsd_dc_48bit && !hdmi->edid_cfg.vsd_dc_36bit &&
+ !hdmi->edid_cfg.vsd_dc_30bit && !hdmi->edid_cfg.vsd_dc_y444)
+ color_depth = 0;
+
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
diff --git a/firmware/imx/sdma/sdma-imx6q-to1.bin.ihex b/firmware/imx/sdma/sdma-imx6q-to1.bin.ihex
index f9ef5944601f..b96992873ace 100644
--- a/firmware/imx/sdma/sdma-imx6q-to1.bin.ihex
+++ b/firmware/imx/sdma/sdma-imx6q-to1.bin.ihex
@@ -1,99 +1,100 @@
:1000000053444D4101000000010000001C000000AD
-:1000100023000000A8000000780500008202000014
+:1000100025000000B000000078050000820200000A
:10002000FFFFFFFF00000000FFFFFFFFFFFFFFFFDC
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
-:10004000FFFFFFFFB61800006A1A00004B04000013
-:10005000EB0200004A190000FF180000080400002D
-:1000600095040000C0030000C105000070050000F9
-:1000700009040000AB020000E30400007B03000061
+:10004000FFFFFFFFFFFFFFFF6A1A0000FFFFFFFF38
+:10005000EB020000BB180000FFFFFFFF08040000D8
+:10006000FFFFFFFFC0030000FFFFFFFFFFFFFFFFD9
+:10007000FFFFFFFFAB020000FFFFFFFF7B0300005D
:10008000FFFFFFFFFFFFFFFF4C0400006E040000B6
:10009000FFFFFFFF00180000FFFFFFFFFFFFFFFF54
-:1000A0000000000000180000E3C1DB57E35FE357E6
-:1000B000F352016A8F00D500017D8D00A005EB5D34
-:1000C0007804037D79042C7D367C79041F7CEE5600
-:1000D000000F6006057D0965437E0A62417E209817
-:1000E0000A623E7E09653C7E12051205AD0260077C
-:1000F000037DFB55D36D2B98FB55041DD36DC86A4A
-:100100002F7F011F03200048E47C5398FB55D76DD7
-:10011000150005780962C86A0962C86AD76D5298E5
-:10012000FB55D76D1500150005780A62C86A0A628A
-:10013000C86AD76D5298FB55D76D1500150015008C
-:1001400005780B62C86A0B62C86AD76D097CDF6DDF
-:10015000077F0000EB55004D077DFAC1E357069875
-:100160000700CC680C6813C20AC20398D9C1E3C166
-:10017000DB57E35FE357F352216A8F00D500017D1F
-:100180008D00A005EB5DFB567804037D79042A7D84
-:10019000317C7904207C700B1103EB53000F60035A
-:1001A000057D0965377E0A62357E86980A62327E51
-:1001B0000965307E12051205AD026007027C065A01
-:1001C0008E98265A277F011F03200048E87C700B79
-:1001D00011031353AF98150004780962065A096297
-:1001E000265AAE981500150004780A62065A0A626B
-:1001F000265AAE9815001500150004780B62065AB1
-:100200000B62265A077C0000EB55004D067DFAC1B3
-:10021000E357699807000C6813C20AC26698700B0E
-:10022000110313536C07017CD9C1FB5E8A066B076F
-:10023000017CD9C1F35EDB59D3588F0110010F390E
-:100240008B003CC12B7DC05AC85B4EC1277C880304
-:100250008906E35CFF0D1105FF1DBC053E07004D3F
-:10026000187D700811007E07097D7D07027D2852E8
-:10027000E698F852DB54BC02CC02097C7C07027D74
-:100280002852EF98F852D354BC02CC02097D0004E6
-:10029000DD988B00C052C85359C1D67D0002CD985D
-:1002A000FF08BF007F07157D8804D500017D8D0004
-:1002B000A005EB5D8F0212021202FF3ADA05027C02
-:1002C0003E071899A402DD02027D3E0718995E07D9
-:1002D0001899EB559805EB5DF352FB546A07267DA0
-:1002E0006C07017D55996B07577C6907047D68078A
-:1002F000027D010E2F999358D600017D8E009355F3
-:10030000A005935DA00602780255045D1D7C004E99
-:10031000087C6907037D0255177E3C99045D147FB4
-:10032000890693500048017D2799A0991500067809
-:100330000255045D4F070255245D2F07017CA099EB
-:1003400017006F07017C012093559D000700A7D976
-:10035000F598D36C6907047D6807027D010E6499E6
-:100360009358D600017D8E009355A005935DA0069D
-:1003700002780255C86D0F7C004E087C6907037D2A
-:100380000255097E7199C86D067F89069350004811
-:10039000017D5C99A0999A99C36A6907047D6807F1
-:1003A000027D010E87999358D600017D8E009355EA
-:1003B000A005935DA0060278C865045D0F7C004E21
-:1003C000087C6907037DC865097E9499045D067FF2
-:1003D000890693500048017D7F99A09993559D000F
-:1003E0000700FF6CA7D9F5980000E354EB55004DCA
-:1003F000017CF598DD98E354EB55FF0A1102FF1AD2
-:100400007F07027CA005B4999D008C05BA05A00564
-:100410001002BA04AD0454040600E3C1DB57FB52DA
-:10042000C36AF352056A8F00D500017D8D00A005D7
-:10043000EB5D7804037D79042B7D1E7C7904337C8D
-:10044000EE56000FFB556007027DC36DD599041D64
-:10045000C36DC8623B7E6006027D10021202096A0B
-:10046000357F1202096A327F1202096A2F7F011F4B
-:1004700003200048E77C099AFB55C76D150015005D
-:1004800015000578C8620B6AC8620B6AC76D089AC6
-:10049000FB55C76D150015000578C8620A6AC86269
-:1004A0000A6AC76D089AFB55C76D15000578C862C2
-:1004B000096AC862096AC76D097C286A077F00005B
-:1004C000EB55004D057DFAC1DB57BF9977C2540447
-:1004D0000AC2BA99D9C1E3C1DB57F352056A8F004A
-:1004E000D500017D8D00A005FB567804037D7904BD
-:1004F000297D1F7C79042E7CE35D700D1105ED557F
-:10050000000F6007027D0652329A2652337E600544
-:10051000027D10021202096A2D7F1202096A2A7FE7
-:100520001202096A277F011F03200048EA7CE35575
-:100530005D9A150015001500047806520B6A2652C4
-:100540000B6A5C9A15001500047806520A6A265256
-:100550000A6A5C9A150004780652096A2652096AEA
-:10056000097C286A077F0000DB57004D057DFAC132
-:10057000DB571B9A77C254040AC2189AE3C1DB57AF
-:10058000F352056AFB568E02941AC36AC862690266
-:10059000247D941EC36ED36EC8624802C86A942636
-:1005A000981EC36ED36EC8624C02C86A9826C36E8A
-:1005B000981EC36EC8629826C36E6002097CC8622A
-:1005C0006E02247D096A1E7F0125004D257D849AD7
-:1005D000286A187F04627AC2B89AE36E8F00D80541
-:1005E000017D8D00A005C8626E02107D096A0A7F38
-:1005F0000120F97C286A067F0000004D0D7DFAC1BC
-:10060000DB576E9A070004620C6AB59A286AFA7F73
-:1006100004627AC258045404286AF47F0AC26B9AAE
+:1000A000000000000018000062180000161A00008E
+:1000B000E3C1DB57E35FE357F352016A8F00D500DA
+:1000C000017D8D00A005EB5D7804037D79042C7D16
+:1000D000367C79041F7CEE56000F6006057D0965AD
+:1000E000437E0A62417E20980A623E7E09653C7E1C
+:1000F00012051205AD026007037DFB55D36D2B98E9
+:10010000FB55041DD36DC86A2F7F011F03200048D3
+:10011000E47C5398FB55D76D150005780962C86AD1
+:100120000962C86AD76D5298FB55D76D1500150046
+:1001300005780A62C86A0A62C86AD76D5298FB5588
+:10014000D76D15001500150005780B62C86A0B62A3
+:10015000C86AD76D097CDF6D077F0000EB55004D45
+:10016000077DFAC1E35706980700CC680C6813C2F4
+:100170000AC20398D9C1E3C1DB57E35FE357F352E7
+:10018000216A8F00D500017D8D00A005EB5DFB5637
+:100190007804037D79042A7D317C7904207C700BFE
+:1001A0001103EB53000F6003057D0965377E0A627A
+:1001B000357E86980A62327E0965307E1205120508
+:1001C000AD026007027C065A8E98265A277F011FCF
+:1001D00003200048E87C700B11031353AF981500FF
+:1001E00004780962065A0962265AAE98150015006D
+:1001F00004780A62065A0A62265AAE98150015005B
+:10020000150004780B62065A0B62265A077C000020
+:10021000EB55004D067DFAC1E357699807000C685D
+:1002200013C20AC26698700B110313536C07017C4A
+:10023000D9C1FB5E8A066B07017CD9C1F35EDB592D
+:10024000D3588F0110010F398B003CC12B7DC05A50
+:10025000C85B4EC1277C88038906E35CFF0D11054E
+:10026000FF1DBC053E07004D187D700811007E077C
+:10027000097D7D07027D2852E698F852DB54BC02C6
+:10028000CC02097C7C07027D2852EF98F852D354A7
+:10029000BC02CC02097D0004DD988B00C052C8531B
+:1002A00059C1D67D0002CD98FF08BF007F07157D9C
+:1002B0008804D500017D8D00A005EB5D8F02120240
+:1002C0001202FF3ADA05027C3E071899A402DD0209
+:1002D000027D3E0718995E071899EB559805EB5D6E
+:1002E000F352FB546A07267D6C07017D55996B0715
+:1002F000577C6907047D6807027D010E2F9993588A
+:10030000D600017D8E009355A005935DA00602786E
+:100310000255045D1D7C004E087C6907037D025573
+:10032000177E3C99045D147F890693500048017D37
+:100330002799A099150006780255045D4F070255CC
+:10034000245D2F07017CA09917006F07017C012015
+:1003500093559D000700A7D9F598D36C6907047DD4
+:100360006807027D010E64999358D600017D8E00C6
+:100370009355A005935DA00602780255C86D0F7CC9
+:10038000004E087C6907037D0255097E7199C86D8E
+:10039000067F890693500048017D5C99A0999A993F
+:1003A000C36A6907047D6807027D010E8799935827
+:1003B000D600017D8E009355A005935DA0060278BE
+:1003C000C865045D0F7C004E087C6907037DC86525
+:1003D000097E9499045D067F890693500048017D4B
+:1003E0007F99A09993559D000700FF6CA7D9F598B8
+:1003F0000000E354EB55004D017CF598DD98E35483
+:10040000EB55FF0A1102FF1A7F07027CA005B49981
+:100410009D008C05BA05A0051002BA04AD04540471
+:100420000600E3C1DB57FB52C36AF352056A8F0033
+:10043000D500017D8D00A005EB5D7804037D790476
+:100440002B7D1E7C7904337CEE56000FFB55600734
+:10045000027DC36DD599041DC36DC8623B7E6006E5
+:10046000027D10021202096A357F1202096A327F88
+:100470001202096A2F7F011F03200048E77C099AB6
+:10048000FB55C76D1500150015000578C8620B6A8D
+:10049000C8620B6AC76D089AFB55C76D1500150039
+:1004A0000578C8620A6AC8620A6AC76D089AFB556D
+:1004B000C76D15000578C862096AC862096AC76D08
+:1004C000097C286A077F0000EB55004D057DFAC1C5
+:1004D000DB57BF9977C254040AC2BA99D9C1E3C1A4
+:1004E000DB57F352056A8F00D500017D8D00A00512
+:1004F000FB567804037D7904297D1F7C79042E7CCA
+:10050000E35D700D1105ED55000F6007027D065289
+:10051000329A2652337E6005027D10021202096A69
+:100520002D7F1202096A2A7F1202096A277F011FA2
+:1005300003200048EA7CE3555D9A1500150015007C
+:10054000047806520B6A26520B6A5C9A1500150055
+:10055000047806520A6A26520A6A5C9A15000478E0
+:100560000652096A2652096A097C286A077F000038
+:10057000DB57004D057DFAC1DB571B9A77C2540447
+:100580000AC2189AE3C1DB57F352056AFB568E0282
+:10059000941AC36AC8626902247D941EC36ED36E26
+:1005A000C8624802C86A9426981EC36ED36EC86299
+:1005B0004C02C86A9826C36E981EC36EC8629826FD
+:1005C000C36E6002097CC8626E02247D096A1E7FC8
+:1005D0000125004D257D849A286A187F04627AC21D
+:1005E000B89AE36E8F00D805017D8D00A005C86222
+:1005F0006E02107D096A0A7F0120F97C286A067F55
+:100600000000004D0D7DFAC1DB576E9A07000462B1
+:100610000C6AB59A286AFA7F04627AC258045404B4
+:08062000286AF47F0AC26B9AFC
:00000001FF
diff --git a/include/linux/ipu.h b/include/linux/ipu.h
index 973cfe9b45a5..e0c9e90c2804 100644
--- a/include/linux/ipu.h
+++ b/include/linux/ipu.h
@@ -141,6 +141,8 @@ typedef enum {
#define IPU_PIX_FMT_YUV422P fourcc('4', '2', '2', 'P') /*!< 16 YUV 4:2:2 */
/*! @} */
#define IPU_PIX_FMT_TILED_NV12_MBALIGN (16)
+#define TILED_NV12_FRAME_SIZE(w, h) \
+ (ALIGN((w) * (h), SZ_4K) + ALIGN((w) * (h) / 2, SZ_4K))
/* IPU device */
typedef enum {
RGB_CS,
diff --git a/include/linux/mfd/mxc-hdmi-core.h b/include/linux/mfd/mxc-hdmi-core.h
index 0b241838f1b9..8681053d231f 100644
--- a/include/linux/mfd/mxc-hdmi-core.h
+++ b/include/linux/mfd/mxc-hdmi-core.h
@@ -37,6 +37,7 @@ void hdmi_irq_enable(int irq);
unsigned int hdmi_irq_disable(int irq);
void hdmi_set_sample_rate(unsigned int rate);
+void hdmi_set_dma_mode(unsigned int dma_running);
void hdmi_init_clk_regenerator(void);
void hdmi_clk_regenerator_update_pixel_clock(void);
diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h
index 6659446591ec..e4b52f281df5 100644
--- a/include/linux/mtd/gpmi-nand.h
+++ b/include/linux/mtd/gpmi-nand.h
@@ -66,5 +66,6 @@ struct gpmi_nand_platform_data {
struct mtd_partition *partitions;
unsigned partition_count;
unsigned int enable_bbt:1;
+ unsigned int enable_ddr:1;
};
#endif
diff --git a/include/media/radio-si4763.h b/include/media/radio-si4763.h
new file mode 100644
index 000000000000..e7abac285c14
--- /dev/null
+++ b/include/media/radio-si4763.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+#ifndef RADIO_SI4763_H
+#define RADIO_SI4763_H
+
+#include <linux/i2c.h>
+
+#define SI4763_NAME "radio-si4763"
+
+/*
+ * Platform dependent definition
+ */
+struct radio_si4763_platform_data {
+ int i2c_bus;
+ struct i2c_board_info *subdev_board_info;
+};
+
+#endif /* ifndef RADIO_SI4763_H*/
diff --git a/include/media/si4763.h b/include/media/si4763.h
new file mode 100644
index 000000000000..494542e15c36
--- /dev/null
+++ b/include/media/si4763.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef SI4713_H
+#define SI4713_H
+
+/* The SI4713 I2C sensor chip has a fixed slave address of 0xc6 or 0x22. */
+#define SI4713_I2C_ADDR_BUSEN_HIGH 0x63
+#define SI4713_I2C_ADDR_BUSEN_LOW 0x11
+
+/*
+ * Platform dependent definition
+ */
+struct si4713_platform_data {
+ /* Set power state, zero is off, non-zero is on. */
+ int (*set_power)(int power);
+};
+
+/*
+ * Structure to query for Received Noise Level (RNL).
+ */
+struct si4713_rnl {
+ __u32 index; /* modulator index */
+ __u32 frequency; /* frequency to peform rnl measurement */
+ __s32 rnl; /* result of measurement in dBuV */
+ __u32 reserved[4]; /* drivers and apps must init this to 0 */
+};
+
+/*
+ * This is the ioctl number to query for rnl. Users must pass a
+ * struct si4713_rnl pointer specifying desired frequency in 'frequency' field
+ * following driver capabilities (i.e V4L2_TUNER_CAP_LOW).
+ * Driver must return measured value in the same struture, filling 'rnl' field.
+ */
+#define SI4713_IOC_MEASURE_RNL _IOWR('V', BASE_VIDIOC_PRIVATE + 0, \
+ struct si4713_rnl)
+
+#endif /* ifndef SI4713_H*/
diff --git a/kernel/futex.c b/kernel/futex.c
index e250f004c6e3..5e3a534754d7 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -59,6 +59,7 @@
#include <linux/magic.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
+#include <linux/ptrace.h>
#include <asm/futex.h>
@@ -2443,40 +2444,29 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
{
struct robust_list_head __user *head;
unsigned long ret;
- const struct cred *cred = current_cred(), *pcred;
+ struct task_struct *p;
if (!futex_cmpxchg_enabled)
return -ENOSYS;
+ rcu_read_lock();
+
+ ret = -ESRCH;
if (!pid)
- head = current->robust_list;
+ p = current;
else {
- struct task_struct *p;
-
- ret = -ESRCH;
- rcu_read_lock();
p = find_task_by_vpid(pid);
if (!p)
goto err_unlock;
- ret = -EPERM;
- pcred = __task_cred(p);
- /* If victim is in different user_ns, then uids are not
- comparable, so we must have CAP_SYS_PTRACE */
- if (cred->user->user_ns != pcred->user->user_ns) {
- if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
- goto err_unlock;
- goto ok;
- }
- /* If victim is in same user_ns, then uids are comparable */
- if (cred->euid != pcred->euid &&
- cred->euid != pcred->uid &&
- !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
- goto err_unlock;
-ok:
- head = p->robust_list;
- rcu_read_unlock();
}
+ ret = -EPERM;
+ if (!ptrace_may_access(p, PTRACE_MODE_READ))
+ goto err_unlock;
+
+ head = p->robust_list;
+ rcu_read_unlock();
+
if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(head, head_ptr);
@@ -2628,7 +2618,7 @@ void exit_robust_list(struct task_struct *curr)
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3)
{
- int ret = -ENOSYS, cmd = op & FUTEX_CMD_MASK;
+ int cmd = op & FUTEX_CMD_MASK;
unsigned int flags = 0;
if (!(op & FUTEX_PRIVATE_FLAG))
@@ -2641,49 +2631,44 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
}
switch (cmd) {
+ case FUTEX_LOCK_PI:
+ case FUTEX_UNLOCK_PI:
+ case FUTEX_TRYLOCK_PI:
+ case FUTEX_WAIT_REQUEUE_PI:
+ case FUTEX_CMP_REQUEUE_PI:
+ if (!futex_cmpxchg_enabled)
+ return -ENOSYS;
+ }
+
+ switch (cmd) {
case FUTEX_WAIT:
val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAIT_BITSET:
- ret = futex_wait(uaddr, flags, val, timeout, val3);
- break;
+ return futex_wait(uaddr, flags, val, timeout, val3);
case FUTEX_WAKE:
val3 = FUTEX_BITSET_MATCH_ANY;
case FUTEX_WAKE_BITSET:
- ret = futex_wake(uaddr, flags, val, val3);
- break;
+ return futex_wake(uaddr, flags, val, val3);
case FUTEX_REQUEUE:
- ret = futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
- break;
+ return futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
case FUTEX_CMP_REQUEUE:
- ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
- break;
+ return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
case FUTEX_WAKE_OP:
- ret = futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
- break;
+ return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
case FUTEX_LOCK_PI:
- if (futex_cmpxchg_enabled)
- ret = futex_lock_pi(uaddr, flags, val, timeout, 0);
- break;
+ return futex_lock_pi(uaddr, flags, val, timeout, 0);
case FUTEX_UNLOCK_PI:
- if (futex_cmpxchg_enabled)
- ret = futex_unlock_pi(uaddr, flags);
- break;
+ return futex_unlock_pi(uaddr, flags);
case FUTEX_TRYLOCK_PI:
- if (futex_cmpxchg_enabled)
- ret = futex_lock_pi(uaddr, flags, 0, timeout, 1);
- break;
+ return futex_lock_pi(uaddr, flags, 0, timeout, 1);
case FUTEX_WAIT_REQUEUE_PI:
val3 = FUTEX_BITSET_MATCH_ANY;
- ret = futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
- uaddr2);
- break;
+ return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
+ uaddr2);
case FUTEX_CMP_REQUEUE_PI:
- ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
- break;
- default:
- ret = -ENOSYS;
+ return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
}
- return ret;
+ return -ENOSYS;
}
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 5f9e689dc8f0..a9642d528630 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -10,6 +10,7 @@
#include <linux/compat.h>
#include <linux/nsproxy.h>
#include <linux/futex.h>
+#include <linux/ptrace.h>
#include <asm/uaccess.h>
@@ -136,40 +137,29 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
{
struct compat_robust_list_head __user *head;
unsigned long ret;
- const struct cred *cred = current_cred(), *pcred;
+ struct task_struct *p;
if (!futex_cmpxchg_enabled)
return -ENOSYS;
+ rcu_read_lock();
+
+ ret = -ESRCH;
if (!pid)
- head = current->compat_robust_list;
+ p = current;
else {
- struct task_struct *p;
-
- ret = -ESRCH;
- rcu_read_lock();
p = find_task_by_vpid(pid);
if (!p)
goto err_unlock;
- ret = -EPERM;
- pcred = __task_cred(p);
- /* If victim is in different user_ns, then uids are not
- comparable, so we must have CAP_SYS_PTRACE */
- if (cred->user->user_ns != pcred->user->user_ns) {
- if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
- goto err_unlock;
- goto ok;
- }
- /* If victim is in same user_ns, then uids are comparable */
- if (cred->euid != pcred->euid &&
- cred->euid != pcred->uid &&
- !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
- goto err_unlock;
-ok:
- head = p->compat_robust_list;
- rcu_read_unlock();
}
+ ret = -EPERM;
+ if (!ptrace_may_access(p, PTRACE_MODE_READ))
+ goto err_unlock;
+
+ head = p->compat_robust_list;
+ rcu_read_unlock();
+
if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(ptr_to_compat(head), head_ptr);
diff --git a/sound/soc/codecs/cs42888.c b/sound/soc/codecs/cs42888.c
index 86feec2676df..63d244a8d00a 100644
--- a/sound/soc/codecs/cs42888.c
+++ b/sound/soc/codecs/cs42888.c
@@ -478,11 +478,17 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "AOUT4R", NULL, "PWR" },
/* Capture */
- { "ADC1", NULL, "AIN1L" },
- { "ADC1", NULL, "AIN1R" },
+ { "PWR", NULL, "AIN1L" },
+ { "PWR", NULL, "AIN1R" },
- { "ADC2", NULL, "AIN2L" },
- { "ADC2", NULL, "AIN2R" },
+ { "PWR", NULL, "AIN2L" },
+ { "PWR", NULL, "AIN2R" },
+
+ { "ADC1", NULL, "PWR" },
+ { "ADC1", NULL, "PWR" },
+
+ { "ADC2", NULL, "PWR" },
+ { "ADC2", NULL, "PWR" },
};
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index b8be06b3344a..824a6fa8f487 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3520,7 +3520,8 @@ static int wm8962_mute(struct snd_soc_dai *dai, int mute)
WM8962_DAC_MUTE, val);
}
-#define WM8962_RATES SNDRV_PCM_RATE_8000_96000
+#define WM8962_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/imx/imx-esai.c b/sound/soc/imx/imx-esai.c
index f6361716c20c..5f95ecce842e 100644
--- a/sound/soc/imx/imx-esai.c
+++ b/sound/soc/imx/imx-esai.c
@@ -284,12 +284,10 @@ static int imx_esai_startup(struct snd_pcm_substream *substream,
writel(ESAI_GPIO_ESAI, esai->base + ESAI_PCRC);
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
local_esai->imx_esai_txrx_state |= IMX_DAI_ESAI_TX;
- } else {
+ else
local_esai->imx_esai_txrx_state |= IMX_DAI_ESAI_RX;
- writel(ESAI_RCR_RPR, esai->base + ESAI_RCR);
- }
ESAI_DUMP();
return 0;
@@ -375,6 +373,14 @@ static int imx_esai_hw_rx_params(struct snd_pcm_substream *substream,
rfcr |= ESAI_WORD_LEN_16;
rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL16;
break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ rfcr |= ESAI_WORD_LEN_20;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ rfcr |= ESAI_WORD_LEN_24;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL24;
+ break;
}
channels = params_channels(params);
@@ -438,7 +444,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct imx_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
u32 reg, tfcr = 0, rfcr = 0;
- u32 temp;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tfcr = readl(esai->base + ESAI_TFCR);
@@ -457,12 +462,8 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
reg |= ESAI_TCR_TE(substream->runtime->channels);
writel(reg, esai->base + ESAI_TCR);
} else {
- temp = readl(esai->base + ESAI_TCR);
- temp &= ~ESAI_TCR_TPR;
- writel(temp, esai->base + ESAI_TCR);
rfcr |= ESAI_RFCR_RFEN;
writel(rfcr, esai->base + ESAI_RFCR);
- reg &= ~ESAI_RCR_RPR;
reg |= ESAI_RCR_RE(substream->runtime->channels);
writel(reg, esai->base + ESAI_RCR);
}
@@ -473,7 +474,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg &= ~ESAI_TCR_TE(substream->runtime->channels);
writel(reg, esai->base + ESAI_TCR);
- writel(reg, esai->base + ESAI_TCR);
tfcr |= ESAI_TFCR_TFR;
tfcr &= ~ESAI_TFCR_TFEN;
writel(tfcr, esai->base + ESAI_TFCR);
@@ -482,8 +482,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
} else {
reg &= ~ESAI_RCR_RE(substream->runtime->channels);
writel(reg, esai->base + ESAI_RCR);
- reg |= ESAI_RCR_RPR;
- writel(reg, esai->base + ESAI_RCR);
rfcr |= ESAI_RFCR_RFR;
rfcr &= ~ESAI_RFCR_RFEN;
writel(rfcr, esai->base + ESAI_RFCR);
diff --git a/sound/soc/imx/imx-hdmi-dma.c b/sound/soc/imx/imx-hdmi-dma.c
index c8e88ff79e3b..1bd36ca1ea57 100644
--- a/sound/soc/imx/imx-hdmi-dma.c
+++ b/sound/soc/imx/imx-hdmi-dma.c
@@ -35,6 +35,11 @@
#include <mach/mxc_hdmi.h>
#include "imx-hdmi.h"
+#define HDMI_DMA_BURST_UNSPECIFIED_LEGNTH 0
+#define HDMI_DMA_BURST_INCR4 1
+#define HDMI_DMA_BURST_INCR8 2
+#define HDMI_DMA_BURST_INCR16 3
+
struct imx_hdmi_dma_runtime_data {
struct snd_pcm_substream *tx_substream;
@@ -315,16 +320,16 @@ static void hdmi_dma_set_incr_type(int incr_type)
HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK);
switch (incr_type) {
- case 1:
+ case HDMI_DMA_BURST_UNSPECIFIED_LEGNTH:
break;
- case 4:
+ case HDMI_DMA_BURST_INCR4:
value |= HDMI_AHB_DMA_CONF0_BURST_MODE;
break;
- case 8:
+ case HDMI_DMA_BURST_INCR8:
value |= HDMI_AHB_DMA_CONF0_BURST_MODE |
HDMI_AHB_DMA_CONF0_INCR8;
break;
- case 16:
+ case HDMI_DMA_BURST_INCR16:
value |= HDMI_AHB_DMA_CONF0_BURST_MODE |
HDMI_AHB_DMA_CONF0_INCR16;
break;
@@ -359,11 +364,27 @@ static void hdmi_dma_enable_channels(int channels)
}
}
+static void hdmi_dma_set_thrsld(void)
+{
+ int rev = hdmi_readb(HDMI_REVISION_ID);
+
+ switch (rev) {
+ case 0x0a:
+ hdmi_writeb(126, HDMI_AHB_DMA_THRSLD);
+ break;
+ default:
+ hdmi_writeb(64, HDMI_AHB_DMA_THRSLD);
+ break;
+ }
+
+ pr_debug("HDMI_AHB_DMA_THRSLD 0x%02x\n", hdmi_readb(HDMI_AHB_DMA_THRSLD));
+}
+
static void hdmi_dma_configure_dma(int channels)
{
hdmi_dma_enable_hlock(1);
- hdmi_dma_set_incr_type(4);
- hdmi_writeb(64, HDMI_AHB_DMA_THRSLD);
+ hdmi_dma_set_incr_type(HDMI_DMA_BURST_UNSPECIFIED_LEGNTH);
+ hdmi_dma_set_thrsld();
hdmi_dma_enable_channels(channels);
}
@@ -548,6 +569,7 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd)
hdmi_dma_irq_mask(0);
hdmi_dma_priv->tx_active = true;
hdmi_dma_start();
+ hdmi_set_dma_mode(1);
break;
case SNDRV_PCM_TRIGGER_STOP:
@@ -555,6 +577,7 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
hdmi_dma_priv->tx_active = false;
hdmi_dma_stop();
+ hdmi_set_dma_mode(0);
hdmi_dma_irq_mask(1);
break;
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index be2717587c59..a37c98b925ac 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -157,7 +157,13 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
if (ssi->flags & IMX_SSI_SYN)
scr |= SSI_SCR_SYN;
+ /* Dual-FIFO support */
+ strcr |= SSI_STCR_TFEN1;
+ scr |= SSI_SCR_TCH_EN;
+
writel(strcr, ssi->base + SSI_STCR);
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS)
+ strcr &= ~(SSI_STCR_TFDIR | SSI_STCR_TXDIR);
writel(strcr, ssi->base + SSI_SRCR);
writel(scr, ssi->base + SSI_SCR);
diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c
index 2885d3a47889..74950ad79861 100644
--- a/sound/soc/imx/imx-wm8962.c
+++ b/sound/soc/imx/imx-wm8962.c
@@ -326,9 +326,9 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
/* if amic is inserted, disable DMIC */
if (priv->amic_status != plat->mic_active_low)
- snd_soc_dapm_nc_pin(&gcodec->dapm, "DMIC");
+ snd_soc_dapm_nc_pin(&codec->dapm, "DMIC");
else
- snd_soc_dapm_enable_pin(&gcodec->dapm, "DMIC");
+ snd_soc_dapm_enable_pin(&codec->dapm, "DMIC");
}
return 0;