diff options
76 files changed, 2386 insertions, 893 deletions
diff --git a/arch/arm/configs/imx6s_defconfig b/arch/arm/configs/imx6s_defconfig index 7620cab69c61..1cae0463855e 100644 --- a/arch/arm/configs/imx6s_defconfig +++ b/arch/arm/configs/imx6s_defconfig @@ -1,3 +1,4 @@ + # # Automatically generated make config: don't edit # Linux/arm 3.0.35 Kernel Configuration @@ -316,6 +317,7 @@ CONFIG_MACH_MX6SL_EVK=y # CONFIG_MACH_MX6Q_SABRELITE is not set CONFIG_MACH_MX6Q_SABRESD=y # CONFIG_MACH_MX6Q_SABREAUTO is not set +CONFIG_SDMA_IRAM=y # # MX6 Options: @@ -1818,6 +1820,7 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_AC97_BUS=y CONFIG_SND_IMX_SOC=y CONFIG_SND_MXC_SOC_MX2=y +CONFIG_SND_MXC_SOC_IRAM=y CONFIG_SND_MXC_SOC_SPDIF_DAI=y CONFIG_SND_SOC_IMX_SGTL5000=y CONFIG_SND_SOC_IMX_WM8958=y diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig index df954b40d8e8..005b56551ffb 100644 --- a/arch/arm/mach-mx6/Kconfig +++ b/arch/arm/mach-mx6/Kconfig @@ -288,6 +288,14 @@ config IMX_PCIE bool "PCI Express support" select PCI +config IMX_PCIE_EP_MODE_IN_EP_RC_SYS + bool "PCI Express EP mode in the IMX6 RC/EP interconnection system" + depends on IMX_PCIE + +config IMX_PCIE_RC_MODE_IN_EP_RC_SYS + bool "PCI Express RC mode in the IMX6 RC/EP interconnection system" + depends on IMX_PCIE + config USB_EHCI_ARC_H1 tristate "USB Host 1 support" depends on USB_EHCI_ARC @@ -295,6 +303,11 @@ config USB_EHCI_ARC_H1 config USB_FSL_ARC_OTG tristate "FSL USB OTG support" +config USB_ID_WAKEUP_ENABLE + bool "Enable USB ID Pin As System Wakeup Source" + depends on SOC_IMX6SL + default n + config MX6_INTER_LDO_BYPASS bool "Internal LDO in MX6Q/DL bypass" depends on REGULATOR_PFUZE100 && CPU_FREQ_IMX && ARCH_MX6 @@ -319,11 +332,10 @@ config MACH_IMX_BLUETOOTH_RFKILL ---help--- Say Y to get the standard rfkill interface of Bluetooth -config MX6_ENET_IRQ_TO_GPIO - bool "Route ENET interrupts to GPIO" - default n +config SDMA_IRAM + bool "Use Internal RAM for SDMA data structures" + depends on IMX_SDMA && SOC_IMX6SL help - Enabling this will direct all the ENET interrupts to a board specific GPIO. - This will allow the system to enter WAIT mode when ENET is active. + SDMA buffer or control structures are stored in the IRAM/OCRAM endif diff --git a/arch/arm/mach-mx6/board-mx6dl_arm2.h b/arch/arm/mach-mx6/board-mx6dl_arm2.h index 429febb9813d..f4560e4a0d74 100644 --- a/arch/arm/mach-mx6/board-mx6dl_arm2.h +++ b/arch/arm/mach-mx6/board-mx6dl_arm2.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2012-2013 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 @@ -182,13 +182,7 @@ static iomux_v3_cfg_t mx6dl_arm2_pads[] = { /* USBOTG ID pin */ MX6DL_PAD_GPIO_1__USBOTG_ID, - - /* MLB150 */ - MX6DL_PAD_GPIO_3__MLB_MLBCLK, - MX6DL_PAD_GPIO_6__MLB_MLBSIG, - MX6DL_PAD_GPIO_2__MLB_MLBDAT, - -}; + }; static iomux_v3_cfg_t mx6dl_arm2_epdc_pads[] = { MX6DL_PAD_EIM_A17__GPIO_2_21, diff --git a/arch/arm/mach-mx6/board-mx6dl_sabresd.h b/arch/arm/mach-mx6/board-mx6dl_sabresd.h index fe278e82491f..7cb69246a824 100644 --- a/arch/arm/mach-mx6/board-mx6dl_sabresd.h +++ b/arch/arm/mach-mx6/board-mx6dl_sabresd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2012-2013 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 @@ -66,7 +66,6 @@ static iomux_v3_cfg_t mx6dl_sabresd_pads[] = { /* I2C3 */ MX6DL_PAD_GPIO_3__I2C3_SCL, - MX6DL_PAD_GPIO_6__I2C3_SDA, /* DISPLAY */ MX6DL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, @@ -167,7 +166,7 @@ static iomux_v3_cfg_t mx6dl_sabresd_pads[] = { MX6DL_PAD_SD4_DAT7__USDHC4_DAT7_50MHZ, /* HDMI_CEC_IN*/ - MX6DL_PAD_KEY_ROW2__GPIO_4_11, + MX6DL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, /* CCM - Audio, Camera clock */ MX6DL_PAD_GPIO_0__CCM_CLKO, diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c index 8a2687d04f36..721db5490a6c 100644 --- a/arch/arm/mach-mx6/board-mx6q_arm2.c +++ b/arch/arm/mach-mx6/board-mx6q_arm2.c @@ -156,12 +156,10 @@ #define MX6_ARM2_CAN2_STBY MX6_ARM2_IO_EXP_GPIO2(1) -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO #define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) #define IOMUX_OBSRV_MUX1_OFFSET 0x3c #define OBSRV_MUX1_MASK 0x3f #define OBSRV_MUX1_ENET_IRQ 0x9 -#endif #define BMCR_PDOWN 0x0800 /* PHY Powerdown */ @@ -180,6 +178,7 @@ extern char *gp_reg_id; extern char *soc_reg_id; extern char *pu_reg_id; extern int epdc_enabled; +extern bool enet_to_gpio_6; static int max17135_regulator_init(struct max17135 *max17135); enum sd_pad_mode { @@ -394,9 +393,7 @@ static struct fec_platform_data fec_data __initdata = { .init = mx6_arm2_fec_phy_init, .power_hibernate = mx6_arm2_fec_power_hibernate, .phy = PHY_INTERFACE_MODE_RGMII, -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO .gpio_irq = MX6_ENET_IRQ, -#endif }; static int mx6_arm2_spi_cs[] = { @@ -883,11 +880,7 @@ static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { }, }; -static struct imxi2c_platform_data mx6_arm2_i2c0_data = { - .bitrate = 100000, -}; - -static struct imxi2c_platform_data mx6_arm2_i2c1_data = { +static struct imxi2c_platform_data mx6_arm2_i2c_data = { .bitrate = 100000, }; @@ -2087,6 +2080,18 @@ static void __init mx6_arm2_init(void) spdif_pads_cnt = ARRAY_SIZE(mx6q_arm2_spdif_pads); flexcan_pads_cnt = ARRAY_SIZE(mx6q_arm2_can_pads); i2c3_pads_cnt = ARRAY_SIZE(mx6q_arm2_i2c3_pads); + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + iomux_v3_cfg_t mlb_pads[] = { + MX6Q_PAD_GPIO_3__MLB_MLBCLK, + MX6Q_PAD_GPIO_6__MLB_MLBSIG, + MX6Q_PAD_GPIO_2__MLB_MLBDAT}; + mxc_iomux_v3_setup_multiple_pads(mlb_pads, + ARRAY_SIZE(mlb_pads)); + } } else if (cpu_is_mx6dl()) { common_pads = mx6dl_arm2_pads; esai_rec_pads = mx6dl_arm2_esai_record_pads; @@ -2101,6 +2106,18 @@ static void __init mx6_arm2_init(void) flexcan_pads_cnt = ARRAY_SIZE(mx6dl_arm2_can_pads); i2c3_pads_cnt = ARRAY_SIZE(mx6dl_arm2_i2c3_pads); epdc_pads_cnt = ARRAY_SIZE(mx6dl_arm2_epdc_pads); + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6DL_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + iomux_v3_cfg_t mlb_pads[] = { + MX6DL_PAD_GPIO_3__MLB_MLBCLK, + MX6DL_PAD_GPIO_6__MLB_MLBSIG, + MX6DL_PAD_GPIO_2__MLB_MLBDAT}; + mxc_iomux_v3_setup_multiple_pads(mlb_pads, + ARRAY_SIZE(mlb_pads)); + } } BUG_ON(!common_pads); @@ -2187,8 +2204,8 @@ static void __init mx6_arm2_init(void) imx6q_add_imx_caam(); - imx6q_add_imx_i2c(0, &mx6_arm2_i2c0_data); - imx6q_add_imx_i2c(1, &mx6_arm2_i2c1_data); + imx6q_add_imx_i2c(0, &mx6_arm2_i2c_data); + imx6q_add_imx_i2c(1, &mx6_arm2_i2c_data); i2c_register_board_info(0, mxc_i2c0_board_info, ARRAY_SIZE(mxc_i2c0_board_info)); i2c_register_board_info(1, mxc_i2c1_board_info, @@ -2200,6 +2217,8 @@ static void __init mx6_arm2_init(void) i2c_register_board_info(2, mxc_i2c2_board_info, ARRAY_SIZE(mxc_i2c2_board_info)); } + if (cpu_is_mx6dl()) + imx6q_add_imx_i2c(3, &mx6_arm2_i2c_data); /* SPI */ imx6q_add_ecspi(0, &mx6_arm2_spi_data); @@ -2210,12 +2229,15 @@ static void __init mx6_arm2_init(void) imx6q_add_anatop_thermal_imx(1, &mx6_arm2_anatop_thermal_data); if (!esai_record) { + if (enet_to_gpio_6) + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register( + IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, + OBSRV_MUX1_MASK); + else + fec_data.gpio_irq = -1; imx6_init_fec(fec_data); -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ - mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, - OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); -#endif } imx6q_add_pm_imx(0, &mx6_arm2_pm_data); diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.h b/arch/arm/mach-mx6/board-mx6q_arm2.h index 2a6a2052b3f9..24a894fab905 100644 --- a/arch/arm/mach-mx6/board-mx6q_arm2.h +++ b/arch/arm/mach-mx6/board-mx6q_arm2.h @@ -182,16 +182,7 @@ static iomux_v3_cfg_t mx6q_arm2_pads[] = { /* USBOTG ID pin */ MX6Q_PAD_GPIO_1__USBOTG_ID, - -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, -#else - /* MLB150 */ - MX6Q_PAD_GPIO_3__MLB_MLBCLK, - MX6Q_PAD_GPIO_6__MLB_MLBSIG, - MX6Q_PAD_GPIO_2__MLB_MLBDAT, -#endif -}; + }; static iomux_v3_cfg_t mx6q_arm2_i2c3_pads[] = { MX6Q_PAD_GPIO_5__I2C3_SCL, diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c index 3f7824fbaf62..e5378ba92cf6 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c @@ -115,12 +115,10 @@ #define SABREAUTO_MAX7310_2_BASE_ADDR IMX_GPIO_NR(8, 8) #define SABREAUTO_MAX7310_3_BASE_ADDR IMX_GPIO_NR(8, 16) -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO #define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) #define IOMUX_OBSRV_MUX1_OFFSET 0x3c #define OBSRV_MUX1_MASK 0x3f #define OBSRV_MUX1_ENET_IRQ 0x9 -#endif #define SABREAUTO_IO_EXP_GPIO1(x) (SABREAUTO_MAX7310_1_BASE_ADDR + (x)) #define SABREAUTO_IO_EXP_GPIO2(x) (SABREAUTO_MAX7310_2_BASE_ADDR + (x)) @@ -143,6 +141,7 @@ extern char *gp_reg_id; extern char *soc_reg_id; extern char *pu_reg_id; +extern bool enet_to_gpio_6; static int mma8x5x_position = 7; static int mag3110_position = 7; @@ -417,9 +416,7 @@ static struct fec_platform_data fec_data __initdata = { .init = mx6q_sabreauto_fec_phy_init, .power_hibernate = mx6q_sabreauto_fec_power_hibernate, .phy = PHY_INTERFACE_MODE_RGMII, -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - .gpio_irq = MX6_ENET_IRQ, -#endif + .gpio_irq = MX6_ENET_IRQ, }; static int mx6q_sabreauto_spi_cs[] = { @@ -753,7 +750,7 @@ static struct imxi2c_platform_data mx6q_sabreauto_i2c2_data = { .bitrate = 400000, }; -static struct imxi2c_platform_data mx6q_sabreauto_i2c1_data = { +static struct imxi2c_platform_data mx6q_sabreauto_i2c_data = { .bitrate = 100000, }; @@ -1570,6 +1567,18 @@ static void __init mx6_board_init(void) mxc_iomux_v3_setup_multiple_pads(extra_pads, extra_pads_cnt); } + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + iomux_v3_cfg_t mlb_pads[] = { + MX6Q_PAD_ENET_TXD1__MLB_MLBCLK, + MX6Q_PAD_GPIO_6__MLB_MLBSIG, + MX6Q_PAD_GPIO_2__MLB_MLBDAT}; + mxc_iomux_v3_setup_multiple_pads(mlb_pads, + ARRAY_SIZE(mlb_pads)); + } } else if (cpu_is_mx6dl()) { common_pads = mx6dl_sabreauto_pads; can0_pads = mx6dl_sabreauto_can0_pads; @@ -1602,6 +1611,18 @@ static void __init mx6_board_init(void) mxc_iomux_v3_setup_multiple_pads(extra_pads, extra_pads_cnt); } + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6DL_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + iomux_v3_cfg_t mlb_pads[] = { + MX6DL_PAD_ENET_TXD1__MLB_MLBCLK, + MX6DL_PAD_GPIO_6__MLB_MLBSIG, + MX6DL_PAD_GPIO_2__MLB_MLBDAT}; + mxc_iomux_v3_setup_multiple_pads(mlb_pads, + ARRAY_SIZE(mlb_pads)); + } } BUG_ON(!common_pads); @@ -1715,12 +1736,15 @@ static void __init mx6_board_init(void) if (1 == caam_enabled) imx6q_add_imx_caam(); - imx6q_add_imx_i2c(1, &mx6q_sabreauto_i2c1_data); + imx6q_add_imx_i2c(1, &mx6q_sabreauto_i2c_data); i2c_register_board_info(1, mxc_i2c1_board_info, ARRAY_SIZE(mxc_i2c1_board_info)); imx6q_add_imx_i2c(2, &mx6q_sabreauto_i2c2_data); i2c_register_board_info(2, mxc_i2c2_board_info, ARRAY_SIZE(mxc_i2c2_board_info)); + if (cpu_is_mx6dl()) + imx6q_add_imx_i2c(3, &mx6q_sabreauto_i2c_data); + ret = gpio_request(SABREAUTO_PMIC_INT, "pFUZE-int"); if (ret) { @@ -1743,13 +1767,15 @@ static void __init mx6_board_init(void) imx6q_add_anatop_thermal_imx(1, &mx6q_sabreauto_anatop_thermal_data); if (!can0_enable) { + if (enet_to_gpio_6) + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register( + IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, + OBSRV_MUX1_MASK); + else + fec_data.gpio_irq = -1; imx6_init_fec(fec_data); -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ - mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, - OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); -#endif - } imx6q_add_pm_imx(0, &mx6q_sabreauto_pm_data); diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.h b/arch/arm/mach-mx6/board-mx6q_sabreauto.h index e4d62f1baaa5..436a11d03a31 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabreauto.h +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.h @@ -207,16 +207,7 @@ static iomux_v3_cfg_t mx6q_sabreauto_pads[] = { /* HDMI */ MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE, - -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, -#else - /* MLB150 */ - MX6Q_PAD_ENET_TXD1__MLB_MLBCLK, - MX6Q_PAD_GPIO_6__MLB_MLBSIG, - MX6Q_PAD_GPIO_2__MLB_MLBDAT, -#endif -}; + }; static iomux_v3_cfg_t mx6q_sabreauto_can0_pads[] = { /* CAN1 */ diff --git a/arch/arm/mach-mx6/board-mx6q_sabrelite.c b/arch/arm/mach-mx6/board-mx6q_sabrelite.c index ec77b8646266..636bfa9a65ff 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabrelite.c +++ b/arch/arm/mach-mx6/board-mx6q_sabrelite.c @@ -94,12 +94,10 @@ #define MX6Q_SABRELITE_CSI0_RST IMX_GPIO_NR(1, 8) #define MX6Q_SABRELITE_CSI0_PWN IMX_GPIO_NR(1, 6) -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO #define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) #define IOMUX_OBSRV_MUX1_OFFSET 0x3c #define OBSRV_MUX1_MASK 0x3f #define OBSRV_MUX1_ENET_IRQ 0x9 -#endif #define MX6Q_SABRELITE_SD3_WP_PADCFG (PAD_CTL_PKE | PAD_CTL_PUE | \ PAD_CTL_PUS_22K_UP | PAD_CTL_SPEED_MED | \ @@ -111,6 +109,7 @@ static struct clk *sata_clk; extern char *gp_reg_id; extern char *soc_reg_id; extern char *pu_reg_id; +extern bool enet_to_gpio_6; static int caam_enabled; extern struct regulator *(*get_cpu_regulator)(void); @@ -217,8 +216,8 @@ static iomux_v3_cfg_t mx6q_sabrelite_pads[] = { MX6Q_PAD_EIM_D28__I2C1_SDA, /* GPIO3[28] */ /* I2C2 Camera, MIPI */ - MX6Q_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ - MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ /* I2C3 */ MX6Q_PAD_GPIO_5__I2C3_SCL, /* GPIO1[5] - J7 - Display card */ @@ -329,9 +328,6 @@ static iomux_v3_cfg_t mx6q_sabrelite_csi0_sensor_pads[] = { MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, -#ifndef CONFIG_MX6_ENET_IRQ_TO_GPIO - MX6Q_PAD_GPIO_6__GPIO_1_6, /* J5 - Camera GP */ -#endif MX6Q_PAD_GPIO_8__GPIO_1_8, /* J5 - Camera Reset */ MX6Q_PAD_SD1_DAT0__GPIO_1_16, /* J5 - Camera GP */ MX6Q_PAD_NANDF_D5__GPIO_2_5, /* J16 - MIPI GP */ @@ -477,9 +473,7 @@ static int mx6q_sabrelite_fec_phy_init(struct phy_device *phydev) static struct fec_platform_data fec_data __initdata = { .init = mx6q_sabrelite_fec_phy_init, .phy = PHY_INTERFACE_MODE_RGMII, -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO .gpio_irq = MX6_ENET_IRQ, -#endif }; static int mx6q_sabrelite_spi_cs[] = { @@ -931,6 +925,16 @@ static struct fsl_mxc_capture_platform_data capture_data[] = { }; +struct imx_vout_mem { + resource_size_t res_mbase; + resource_size_t res_msize; +}; + +static struct imx_vout_mem vout_mem __initdata = { + .res_msize = SZ_128M, +}; + + static void sabrelite_suspend_enter(void) { /* suspend preparation */ @@ -1216,10 +1220,22 @@ static void __init mx6_sabrelite_board_init(void) struct clk *clko2; struct clk *new_parent; int rate; + struct platform_device *voutdev; mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_pads, ARRAY_SIZE(mx6q_sabrelite_pads)); + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + /* J5 - Camera GP */ + iomux_v3_cfg_t camera_gpio_pad = + MX6Q_PAD_GPIO_6__GPIO_1_6; + mxc_iomux_v3_setup_pad(camera_gpio_pad); + } + #ifdef CONFIG_FEC_1588 /* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock * For MX6 GPR1 bit21 meaning: @@ -1244,7 +1260,17 @@ static void __init mx6_sabrelite_board_init(void) imx6q_add_vdoa(); imx6q_add_lcdif(&lcdif_data); imx6q_add_ldb(&ldb_data); - imx6q_add_v4l2_output(0); + voutdev = imx6q_add_v4l2_output(0); + if (vout_mem.res_msize && voutdev) { + dma_declare_coherent_memory(&voutdev->dev, + vout_mem.res_mbase, + vout_mem.res_mbase, + vout_mem.res_msize, + (DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE)); + } + + imx6q_add_v4l2_capture(0, &capture_data[0]); imx6q_add_v4l2_capture(1, &capture_data[1]); imx6q_add_mipi_csi2(&mipi_csi2_pdata); @@ -1270,6 +1296,15 @@ static void __init mx6_sabrelite_board_init(void) imx6q_add_mxc_hdmi(&hdmi_data); imx6q_add_anatop_thermal_imx(1, &mx6q_sabrelite_anatop_thermal_data); + if (enet_to_gpio_6) + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register( + IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, + OBSRV_MUX1_MASK); + else + fec_data.gpio_irq = -1; + imx6_init_fec(fec_data); #ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ @@ -1403,6 +1438,13 @@ static void __init mx6q_sabrelite_reserve(void) memblock_remove(phys, sabrelite_fb_data[i].res_size[0]); sabrelite_fb_data[i].res_base[0] = phys; } + if (vout_mem.res_msize) { + phys = memblock_alloc_base(vout_mem.res_msize, + SZ_4K, SZ_1G); + memblock_remove(phys, vout_mem.res_msize); + vout_mem.res_mbase = phys; + } + } /* diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.c b/arch/arm/mach-mx6/board-mx6q_sabresd.c index 8921a995c270..193931e446f3 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabresd.c +++ b/arch/arm/mach-mx6/board-mx6q_sabresd.c @@ -201,12 +201,10 @@ #define SABRESD_ELAN_RST IMX_GPIO_NR(3, 8) #define SABRESD_ELAN_INT IMX_GPIO_NR(3, 28) -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO #define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) #define IOMUX_OBSRV_MUX1_OFFSET 0x3c #define OBSRV_MUX1_MASK 0x3f #define OBSRV_MUX1_ENET_IRQ 0x9 -#endif static struct clk *sata_clk; static struct clk *clko; @@ -220,6 +218,7 @@ extern char *gp_reg_id; extern char *soc_reg_id; extern char *pu_reg_id; extern int epdc_enabled; +extern bool enet_to_gpio_6; static int max17135_regulator_init(struct max17135 *max17135); @@ -310,9 +309,7 @@ static int mx6q_sabresd_fec_phy_init(struct phy_device *phydev) static struct fec_platform_data fec_data __initdata = { .init = mx6q_sabresd_fec_phy_init, .phy = PHY_INTERFACE_MODE_RGMII, -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO .gpio_irq = MX6_ENET_IRQ, -#endif }; static int mx6q_sabresd_spi_cs[] = { @@ -1368,6 +1365,8 @@ static struct fsl_mxc_hdmi_platform_data hdmi_data = { .init = hdmi_init, .enable_pins = hdmi_enable_ddc_pin, .disable_pins = hdmi_disable_ddc_pin, + .phy_reg_vlev = 0x0294, + .phy_reg_cksymtx = 0x800d, }; static struct fsl_mxc_hdmi_core_platform_data hdmi_core_data = { @@ -1474,6 +1473,16 @@ static struct platform_device mxc_bt_rfkill = { static struct imx_bt_rfkill_platform_data mxc_bt_rfkill_data = { .power_change = mx6q_sd_bt_power_change, }; + +struct imx_vout_mem { + resource_size_t res_mbase; + resource_size_t res_msize; +}; + +static struct imx_vout_mem vout_mem __initdata = { + .res_msize = 0, +}; + static void sabresd_suspend_enter(void) { /* suspend preparation */ @@ -1794,6 +1803,11 @@ static const struct imx_pcie_platform_data mx6_sabresd_pcie_data __initconst = { .pcie_rst = SABRESD_PCIE_RST_B_REVB, .pcie_wake_up = SABRESD_PCIE_WAKE_B, .pcie_dis = SABRESD_PCIE_DIS_B, +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS + .type_ep = 1, +#else + .type_ep = 0, +#endif .pcie_power_always_on = 1, }; @@ -1863,15 +1877,36 @@ static void __init mx6_sabresd_board_init(void) struct clk *clko, *clko2; struct clk *new_parent; int rate; + struct platform_device *voutdev; - if (cpu_is_mx6q()) + if (cpu_is_mx6q()) { mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads, ARRAY_SIZE(mx6q_sabresd_pads)); - else if (cpu_is_mx6dl()) { + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + iomux_v3_cfg_t i2c3_pad = + MX6Q_PAD_GPIO_6__I2C3_SDA; + mxc_iomux_v3_setup_pad(i2c3_pad); + } + } else if (cpu_is_mx6dl()) { mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_pads, ARRAY_SIZE(mx6dl_sabresd_pads)); + + if (enet_to_gpio_6) { + iomux_v3_cfg_t enet_gpio_pad = + MX6DL_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6; + mxc_iomux_v3_setup_pad(enet_gpio_pad); + } else { + iomux_v3_cfg_t i2c3_pad = + MX6DL_PAD_GPIO_6__I2C3_SDA; + mxc_iomux_v3_setup_pad(i2c3_pad); + } } + #ifdef CONFIG_FEC_1588 /* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock * For MX6 GPR1 bit21 meaning: @@ -1922,7 +1957,16 @@ static void __init mx6_sabresd_board_init(void) imx6q_add_mipi_dsi(&mipi_dsi_pdata); imx6q_add_lcdif(&lcdif_data); imx6q_add_ldb(&ldb_data); - imx6q_add_v4l2_output(0); + voutdev = imx6q_add_v4l2_output(0); + if (vout_mem.res_msize && voutdev) { + dma_declare_coherent_memory(&voutdev->dev, + vout_mem.res_mbase, + vout_mem.res_mbase, + vout_mem.res_msize, + (DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE)); + } + imx6q_add_v4l2_capture(0, &capture_data[0]); imx6q_add_v4l2_capture(1, &capture_data[1]); imx6q_add_mipi_csi2(&mipi_csi2_pdata); @@ -1943,6 +1987,8 @@ static void __init mx6_sabresd_board_init(void) imx6q_add_imx_i2c(0, &mx6q_sabresd_i2c_data); imx6q_add_imx_i2c(1, &mx6q_sabresd_i2c_data); imx6q_add_imx_i2c(2, &mx6q_sabresd_i2c_data); + if (cpu_is_mx6dl()) + imx6q_add_imx_i2c(3, &mx6q_sabresd_i2c_data); i2c_register_board_info(0, mxc_i2c0_board_info, ARRAY_SIZE(mxc_i2c0_board_info)); i2c_register_board_info(1, mxc_i2c1_board_info, @@ -1964,12 +2010,16 @@ static void __init mx6_sabresd_board_init(void) imx6q_add_mxc_hdmi(&hdmi_data); imx6q_add_anatop_thermal_imx(1, &mx6q_sabresd_anatop_thermal_data); + + if (enet_to_gpio_6) + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register( + IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, + OBSRV_MUX1_MASK); + else + fec_data.gpio_irq = -1; imx6_init_fec(fec_data); -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ - mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, - OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); -#endif imx6q_add_pm_imx(0, &mx6q_sabresd_pm_data); @@ -2192,6 +2242,13 @@ static void __init mx6q_sabresd_reserve(void) imx_ion_data.heaps[0].base = phys; } #endif + + if (vout_mem.res_msize) { + phys = memblock_alloc_base(vout_mem.res_msize, + SZ_4K, SZ_1G); + memblock_remove(phys, vout_mem.res_msize); + vout_mem.res_mbase = phys; + } } /* diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.h b/arch/arm/mach-mx6/board-mx6q_sabresd.h index b2bb8c923f0f..73ee909e50ef 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabresd.h +++ b/arch/arm/mach-mx6/board-mx6q_sabresd.h @@ -132,13 +132,9 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = { MX6Q_PAD_KEY_COL3__I2C2_SCL, MX6Q_PAD_KEY_ROW3__I2C2_SDA, -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, -#else /* I2C3 */ MX6Q_PAD_GPIO_3__I2C3_SCL, /* GPIO1[3] */ MX6Q_PAD_GPIO_6__I2C3_SDA, -#endif /* DISPLAY */ MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, diff --git a/arch/arm/mach-mx6/board-mx6sl_arm2.c b/arch/arm/mach-mx6/board-mx6sl_arm2.c index cd21b37a6885..a29f3bcb9b07 100755 --- a/arch/arm/mach-mx6/board-mx6sl_arm2.c +++ b/arch/arm/mach-mx6/board-mx6sl_arm2.c @@ -484,8 +484,8 @@ static int mxc_wm8962_init(void) clk_set_parent(extern_audio_root, pll4); - rate = clk_round_rate(extern_audio_root, 26000000); - clk_set_rate(extern_audio_root, rate); + rate = 24000000; + clk_set_rate(extern_audio_root, 24000000); wm8962_data.sysclk = rate; @@ -1092,7 +1092,7 @@ static struct platform_pwm_backlight_data mx6_arm2_pwm_backlight_data = { static struct fb_videomode video_modes[] = { { /* 800x480 @ 57 Hz , pixel clk @ 32MHz */ - "SEIKO-WVGA", 60, 800, 480, 29850, 99, 164, 33, 10, 10, 10, + "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10, FB_SYNC_CLK_LAT_FALL, FB_VMODE_NONINTERLACED, 0,}, diff --git a/arch/arm/mach-mx6/board-mx6sl_common.h b/arch/arm/mach-mx6/board-mx6sl_common.h index 2b2dd6b93c9a..897099f2c1ea 100644 --- a/arch/arm/mach-mx6/board-mx6sl_common.h +++ b/arch/arm/mach-mx6/board-mx6sl_common.h @@ -481,7 +481,9 @@ static iomux_v3_cfg_t suspend_enter_pads[] = { MX6SL_PAD_SD3_DAT3__GPIO_5_17, /* USBOTG ID pin */ +#ifndef CONFIG_USB_ID_WAKEUP_ENABLE MX6SL_PAD_EPDC_PWRCOM__GPIO_2_11, +#endif MX6SL_PAD_HSIC_STROBE__GPIO_3_20, MX6SL_PAD_HSIC_DAT__GPIO_3_19, diff --git a/arch/arm/mach-mx6/board-mx6sl_evk.c b/arch/arm/mach-mx6/board-mx6sl_evk.c index 729054c9f015..082845ba22a3 100644 --- a/arch/arm/mach-mx6/board-mx6sl_evk.c +++ b/arch/arm/mach-mx6/board-mx6sl_evk.c @@ -547,8 +547,8 @@ static int mxc_wm8962_init(void) clk_set_parent(extern_audio_root, pll4); - rate = clk_round_rate(extern_audio_root, 26000000); - clk_set_rate(extern_audio_root, rate); + rate = 24000000; + clk_set_rate(extern_audio_root, 24000000); wm8962_data.sysclk = rate; /* set AUDMUX pads to 1.8v */ @@ -1255,6 +1255,14 @@ static void imx6_evk_usbotg_vbus(bool on) gpio_set_value(MX6_BRD_USBOTG1_PWR, 0); } +static void imx6_evk_usbh1_vbus(bool on) +{ + if (on) + gpio_set_value(MX6_BRD_USBOTG2_PWR, 1); + else + gpio_set_value(MX6_BRD_USBOTG2_PWR, 0); +} + static void __init mx6_evk_init_usb(void) { int ret = 0; @@ -1277,9 +1285,10 @@ static void __init mx6_evk_init_usb(void) pr_err("failed to get GPIO MX6_BRD_USBOTG2_PWR:%d\n", ret); return; } - gpio_direction_output(MX6_BRD_USBOTG2_PWR, 1); + gpio_direction_output(MX6_BRD_USBOTG2_PWR, 0); mx6_set_otghost_vbus_func(imx6_evk_usbotg_vbus); + mx6_set_host1_vbus_func(imx6_evk_usbh1_vbus); #ifdef CONFIG_USB_EHCI_ARC_HSIC mx6_usb_h2_init(); @@ -1295,7 +1304,7 @@ static struct platform_pwm_backlight_data mx6_evk_pwm_backlight_data = { static struct fb_videomode wvga_video_modes[] = { { /* 800x480 @ 57 Hz , pixel clk @ 32MHz */ - "SEIKO-WVGA", 60, 800, 480, 29850, 99, 164, 33, 10, 10, 10, + "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10, FB_SYNC_CLK_LAT_FALL, FB_VMODE_NONINTERLACED, 0,}, diff --git a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h index 9d65724cd910..da36cb7187b2 100644 --- a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h +++ b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h @@ -207,12 +207,7 @@ static iomux_v3_cfg_t mx6dl_sabreauto_pads[] = { /* HDMI */ MX6DL_PAD_EIM_A25__HDMI_TX_CEC_LINE, - - /* MLB150 */ - MX6DL_PAD_ENET_TXD1__MLB_MLBCLK, - MX6DL_PAD_GPIO_6__MLB_MLBSIG, - MX6DL_PAD_GPIO_2__MLB_MLBDAT, -}; + }; static iomux_v3_cfg_t mx6dl_sabreauto_can0_pads[] = { /* CAN1 */ diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c index 1f429f9e0656..ba2636785232 100644 --- a/arch/arm/mach-mx6/bus_freq.c +++ b/arch/arm/mach-mx6/bus_freq.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2013 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 @@ -47,7 +47,7 @@ #include <linux/suspend.h> #define LPAPM_CLK 24000000 -#define DDR_AUDIO_CLK 50000000 +#define DDR_AUDIO_CLK 100000000 #define DDR_MED_CLK 400000000 #define DDR3_NORMAL_CLK 528000000 #define GPC_PGC_GPU_PGCR_OFFSET 0x260 @@ -78,7 +78,8 @@ unsigned int ddr_normal_rate; int low_freq_bus_used(void); void set_ddr_freq(int ddr_freq); void *mx6sl_wfi_iram_base; -void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr) = NULL; +void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr,\ + int audio_mode) = NULL; extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr); void *mx6sl_ddr_freq_base; @@ -169,6 +170,10 @@ void reduce_bus_freq(void) /* PLL2 is on in this mode, as DDR is at 50MHz. */ /* Now change DDR freq while running from IRAM. */ + /* Set AHB to 24MHz. */ + clk_set_rate(ahb_clk, + clk_round_rate(ahb_clk, LPAPM_CLK / 3)); + spin_lock_irqsave(&freq_lock, flags); mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK, low_bus_freq_mode); @@ -269,7 +274,7 @@ int set_low_bus_freq(void) if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) return 0; - /* Check to see if we need to got from + /* Check to see if we need to get from * low bus freq mode to audio bus freq mode. * If so, the change needs to be done immediately. */ diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c index 574b142eb758..1bf20d5857c2 100644 --- a/arch/arm/mach-mx6/clock.c +++ b/arch/arm/mach-mx6/clock.c @@ -52,6 +52,7 @@ extern int wait_mode_arm_podf; extern int lp_audio_freq; extern int cur_arm_podf; extern bool enet_is_active; +extern bool enet_to_gpio_6; void __iomem *apll_base; @@ -1025,7 +1026,8 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate) __raw_writel(mfn, pllbase + PLL_NUM_DIV_OFFSET); __raw_writel(mfd, pllbase + PLL_DENOM_DIV_OFFSET); - if (rev >= IMX_CHIP_REVISION_1_1) { + if ((rev >= IMX_CHIP_REVISION_1_1) && + (pllbase == PLL5_VIDEO_BASE_ADDR)) { reg = __raw_readl(ANA_MISC2_BASE_ADDR) & ~ANADIG_ANA_MISC2_CONTROL3_MASK; reg |= control3 << ANADIG_ANA_MISC2_CONTROL3_OFFSET; @@ -1865,6 +1867,8 @@ static int _clk_ipg_perclk_set_rate(struct clk *clk, unsigned long rate) reg = __raw_readl(MXC_CCM_CSCMR1); reg &= ~MXC_CCM_CSCMR1_PERCLK_PODF_MASK; reg |= (div - 1) << MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET; + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -2396,6 +2400,9 @@ static int _clk_usdhc1_set_parent(struct clk *clk, struct clk *parent) if (parent == &pll2_pfd_352M) reg |= (MXC_CCM_CSCMR1_USDHC1_CLK_SEL); + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -2453,6 +2460,9 @@ static int _clk_usdhc2_set_parent(struct clk *clk, struct clk *parent) if (parent == &pll2_pfd_352M) reg |= (MXC_CCM_CSCMR1_USDHC2_CLK_SEL); + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -2510,6 +2520,9 @@ static int _clk_usdhc3_set_parent(struct clk *clk, struct clk *parent) if (parent == &pll2_pfd_352M) reg |= (MXC_CCM_CSCMR1_USDHC3_CLK_SEL); + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -2568,6 +2581,9 @@ static int _clk_usdhc4_set_parent(struct clk *clk, struct clk *parent) if (parent == &pll2_pfd_352M) reg |= (MXC_CCM_CSCMR1_USDHC4_CLK_SEL); + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -2683,6 +2699,8 @@ static int _clk_ssi1_set_parent(struct clk *clk, struct clk *parent) mux = _get_mux6(parent, &pll3_pfd_508M, &pll3_pfd_454M, &pll4_audio_main_clk, NULL, NULL, NULL); reg |= (mux << MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); @@ -2757,6 +2775,8 @@ static int _clk_ssi2_set_parent(struct clk *clk, struct clk *parent) mux = _get_mux6(parent, &pll3_pfd_508M, &pll3_pfd_454M, &pll4_audio_main_clk, NULL, NULL, NULL); reg |= (mux << MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); @@ -2830,6 +2850,8 @@ static int _clk_ssi3_set_parent(struct clk *clk, struct clk *parent) mux = _get_mux6(parent, &pll3_pfd_508M, &pll3_pfd_454M, &pll4_audio_main_clk, NULL, NULL, NULL); reg |= (mux << MXC_CCM_CSCMR1_SSI3_CLK_SEL_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); @@ -3731,9 +3753,9 @@ static unsigned long _clk_enet_get_rate(struct clk *clk) static int _clk_enet_enable(struct clk *clk) { -#ifndef CONFIG_MX6_ENET_IRQ_TO_GPIO - enet_is_active = true; -#endif + if (!enet_to_gpio_6) + enet_is_active = true; + _clk_enable(clk); return 0; } @@ -3741,9 +3763,9 @@ static int _clk_enet_enable(struct clk *clk) static void _clk_enet_disable(struct clk *clk) { _clk_disable(clk); -#ifndef CONFIG_MX6_ENET_IRQ_TO_GPIO - enet_is_active = false; -#endif + + if (!enet_to_gpio_6) + enet_is_active = false; } static struct clk enet_clk[] = { @@ -3848,6 +3870,8 @@ static int _clk_emi_slow_set_parent(struct clk *clk, struct clk *parent) mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk, &pll2_pfd_400M, &pll2_pfd_352M, NULL, NULL); reg |= (mux << MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -3878,6 +3902,8 @@ static int _clk_emi_slow_set_rate(struct clk *clk, unsigned long rate) reg = __raw_readl(MXC_CCM_CSCMR1); reg &= ~MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK; reg |= (div - 1) << MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET; + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -3922,9 +3948,11 @@ static int _clk_emi_set_parent(struct clk *clk, struct clk *parent) int mux; u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_ACLK_EMI_MASK; - mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk, - &pll2_pfd_400M, &pll2_pfd_352M, NULL, NULL); + mux = _get_mux6(parent, &pll2_pfd_400M, &pll3_usb_otg_main_clk, + &axi_clk, &pll2_pfd_352M, NULL, NULL); reg |= (mux << MXC_CCM_CSCMR1_ACLK_EMI_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -3934,6 +3962,7 @@ static unsigned long _clk_emi_get_rate(struct clk *clk) { u32 reg, div; + /* ACLK_EMI_PODF read value matches with real divider value */ reg = __raw_readl(MXC_CCM_CSCMR1); div = ((reg & MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK) >> MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET) + 1; @@ -3952,9 +3981,26 @@ static int _clk_emi_set_rate(struct clk *clk, unsigned long rate) if (((parent_rate / div) != rate) || (div > 8)) return -EINVAL; + /* + * This is a software workaround for ACLK_EMI_PODF SoC + * implementation bug. The write/read/divider values + * have the relationship described by the following table: + * + * write value read value description + * 3b'000 3b'110 divided by 7 + * 3b'001 3b'111 divided by 8 + * 3b'010 3b'100 divided by 5 + * 3b'011 3b'101 divided by 6 + * 3b'100 3b'010 divided by 3 + * 3b'101 3b'011 divided by 4 + * 3b'110 3b'000 divided by 1 + * 3b'111 3b'001 divided by 2(default) + * + * That's why we do the xor operation below. + */ reg = __raw_readl(MXC_CCM_CSCMR1); reg &= ~MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK; - reg |= (div - 1) << MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET; + reg |= ((div - 1)^0x6) << MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET; __raw_writel(reg, MXC_CCM_CSCMR1); return 0; @@ -4793,6 +4839,7 @@ static int _clk_pcie_enable(struct clk *clk) { unsigned int reg; +#ifndef CONFIG_IMX_PCIE_RC_MODE_IN_EP_RC_SYS /* Activate LVDS CLK1 (the MiniPCIe slot clock input) */ reg = __raw_readl(ANADIG_MISC1_REG); reg &= ~ANATOP_LVDS_CLK1_IBEN_MASK; @@ -4805,6 +4852,7 @@ static int _clk_pcie_enable(struct clk *clk) reg = __raw_readl(ANADIG_MISC1_REG); reg |= ANATOP_LVDS_CLK1_OBEN_MASK; __raw_writel(reg, ANADIG_MISC1_REG); +#endif /* Enable PCIE ref clock */ reg = __raw_readl(PLL8_ENET_BASE_ADDR); @@ -4822,9 +4870,10 @@ static void _clk_pcie_disable(struct clk *clk) _clk_disable(clk); +#ifndef CONFIG_IMX_PCIE_RC_MODE_IN_EP_RC_SYS /* De-activate LVDS CLK1 (the MiniPCIe slot clock input) */ reg = __raw_readl(ANADIG_MISC1_REG); - reg &= ~ANATOP_LVDS_CLK1_IBEN_MASK; + reg |= ANATOP_LVDS_CLK1_IBEN_MASK; __raw_writel(reg, ANADIG_MISC1_REG); reg = __raw_readl(ANADIG_MISC1_REG); @@ -4834,6 +4883,7 @@ static void _clk_pcie_disable(struct clk *clk) reg = __raw_readl(ANADIG_MISC1_REG); reg &= ~ANATOP_LVDS_CLK1_OBEN_MASK; __raw_writel(reg, ANADIG_MISC1_REG); +#endif /* Disable PCIE ref clock */ reg = __raw_readl(PLL8_ENET_BASE_ADDR); @@ -4867,6 +4917,53 @@ static struct clk pcie_clk[] = { }, }; +static int _clk_pcie_ep_enable(struct clk *clk) +{ + unsigned int reg; + + /* Enable PCIE ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg |= ANADIG_PLL_ENET_EN_PCIE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + _clk_enable(clk); + + return 0; +} + +static void _clk_pcie_ep_disable(struct clk *clk) +{ + unsigned int reg; + + _clk_disable(clk); + + /* Disable PCIE ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_ENET_EN_PCIE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); +} + +static struct clk pcie_ep_clk[] = { + { + __INIT_CLK_DEBUG(pcie_ep_clk) + .parent = &pcie_axi_clk, + .enable = _clk_pcie_ep_enable, + .disable = _clk_pcie_ep_disable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .secondary = &pcie_ep_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &pll8_enet_main_clk, + .secondary = &pcie_ep_clk[2], + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6fast1_clk, + }, +}; + static struct clk usboh3_clk[] = { { __INIT_CLK_DEBUG(usboh3_clk) @@ -5274,7 +5371,6 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("imx6q-ecspi.1", NULL, ecspi_clk[1]), _REGISTER_CLOCK("imx6q-ecspi.2", NULL, ecspi_clk[2]), _REGISTER_CLOCK("imx6q-ecspi.3", NULL, ecspi_clk[3]), - _REGISTER_CLOCK("imx6q-ecspi.4", NULL, ecspi_clk[4]), _REGISTER_CLOCK(NULL, "emi_slow_clk", emi_slow_clk), _REGISTER_CLOCK(NULL, "emi_clk", emi_clk), _REGISTER_CLOCK(NULL, "enfc_clk", enfc_clk), @@ -5303,6 +5399,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm_clk[2]), _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm_clk[3]), _REGISTER_CLOCK(NULL, "pcie_clk", pcie_clk[0]), + _REGISTER_CLOCK(NULL, "pcie_ep_clk", pcie_ep_clk[0]), _REGISTER_CLOCK("enet.0", NULL, enet_clk[0]), _REGISTER_CLOCK(NULL, "imx_sata_clk", sata_clk[0]), _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk[0]), @@ -5331,6 +5428,11 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "apb_pclk", dummy_clk), }; +static struct +clk_lookup imx6dl_i2c4 = _REGISTER_CLOCK("imx-i2c.3", NULL, ecspi_clk[4]); +static struct +clk_lookup imx6q_ecspi5 = _REGISTER_CLOCK("imx6q-ecspi.4", NULL, ecspi_clk[4]); + static void clk_tree_init(void) { @@ -5368,13 +5470,18 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc, clk_debug_register(lookups[i].clk); } - /* Lower the ipg_perclk frequency to 22MHz. - * I2C needs a minimum of 12.8MHz as its source - * to acheive 400KHz speed. IPG_PERCLK sources - * I2C. 22MHz when divided by the I2C divider gives the - * freq closest to 400KHz. - */ - clk_set_rate(&ipg_perclk, 22000000); + /* + * imx6q have 5 ecspi and 3 i2c + * imx6dl have 4 ecspi and 4 i2c + * imx6dl i2c4 use the imx6q ecspi5 clock source + */ + if (cpu_is_mx6dl()) { + clkdev_add(&imx6dl_i2c4); + clk_debug_register(imx6dl_i2c4.clk); + } else { + clkdev_add(&imx6q_ecspi5); + clk_debug_register(imx6q_ecspi5.clk); + } /* Timer needs to be initialized first as the * the WAIT routines use GPT counter as @@ -5393,6 +5500,15 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc, clk_tree_init(); + /* + * Lower the ipg_perclk frequency to 22MHz. + * I2C needs a minimum of 12.8MHz as its source + * to acheive 400KHz speed. IPG_PERCLK sources + * I2C. 22MHz when divided by the I2C divider gives the + * freq closest to 400KHz. + */ + clk_set_rate(&ipg_perclk, 22000000); + #ifdef CONFIG_MX6_VPU_352M if (cpu_is_mx6q()) { clk_set_rate(&pll2_pfd_400M, 352000000); @@ -5461,8 +5577,11 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc, clk_set_parent(&ipu2_di_clk[1], &pll5_video_main_clk); clk_set_parent(&emi_clk, &pll2_pfd_400M); - clk_set_rate(&emi_clk, 200000000); - +#ifdef CONFIG_MX6_VPU_352M + clk_set_rate(&emi_clk, 176000000); +#else + clk_set_rate(&emi_clk, 198000000); +#endif /* * on mx6dl, 2d core clock sources from 3d shader core clock, * but 3d shader clock multiplexer of mx6dl is different from diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c index c6b08cbce8cb..d8f33877bfe0 100755 --- a/arch/arm/mach-mx6/clock_mx6sl.c +++ b/arch/arm/mach-mx6/clock_mx6sl.c @@ -73,6 +73,7 @@ static struct cpu_op *cpu_op_tbl; static int cpu_op_nr; static bool pll1_enabled; static bool arm_needs_pll2_400; +static bool audio_pll_bypass; DEFINE_SPINLOCK(mx6sl_clk_lock); #define SPIN_DELAY 1200000 /* in nanoseconds */ @@ -429,7 +430,8 @@ static int _clk_pll_enable(struct clk *clk) pllbase = _get_pll_base(clk); reg = __raw_readl(pllbase); - reg &= ~ANADIG_PLL_POWER_DOWN; + if (clk != &pll4_audio_main_clk || !audio_pll_bypass) + reg &= ~ANADIG_PLL_POWER_DOWN; /* The 480MHz PLLs have the opposite definition for power bit. */ if (clk == &pll3_usb_otg_main_clk || clk == &pll7_usb_host_main_clk) @@ -442,14 +444,20 @@ static int _clk_pll_enable(struct clk *clk) __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_CLR); /* Wait for PLL to lock */ - if (!WAIT((__raw_readl(pllbase) & ANADIG_PLL_LOCK), - SPIN_DELAY)) - panic("pll enable failed\n"); - + if (clk != &pll4_audio_main_clk || !audio_pll_bypass) { + if (!WAIT((__raw_readl(pllbase) & ANADIG_PLL_LOCK), + SPIN_DELAY)) + panic("pll enable failed\n"); + } /* Enable the PLL output now*/ reg = __raw_readl(pllbase); - reg &= ~ANADIG_PLL_BYPASS; + + /* If audio PLL is set to 24MHz, leave it in bypass mode. */ + if (clk != &pll4_audio_main_clk || !audio_pll_bypass) + reg &= ~ANADIG_PLL_BYPASS; + reg |= ANADIG_PLL_ENABLE; + __raw_writel(reg, pllbase); return 0; @@ -874,6 +882,9 @@ static unsigned long _clk_audio_video_get_rate(struct clk *clk) pllbase = _get_pll_base(clk); + if (__raw_readl(pllbase) & ANADIG_PLL_BYPASS) + return 24000000; + test_div_sel = (__raw_readl(pllbase) & ANADIG_PLL_AV_TEST_DIV_SEL_MASK) >> ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET; @@ -917,6 +928,16 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate) u32 test_div_sel = 2; u32 control3 = 0; + pllbase = _get_pll_base(clk); + + if (clk == &pll4_audio_main_clk && audio_pll_bypass) { + reg = __raw_readl(pllbase) + & ~ANADIG_PLL_SYS_DIV_SELECT_MASK + & ~ANADIG_PLL_AV_TEST_DIV_SEL_MASK; + __raw_writel(reg, pllbase); + return 0; + } + if (clk == &pll4_audio_main_clk) min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4; else @@ -925,8 +946,6 @@ static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate) if ((rate < min_clk_rate) || (rate > AUDIO_VIDEO_MAX_CLK_FREQ)) return -EINVAL; - pllbase = _get_pll_base(clk); - pre_div_rate = rate; while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) { pre_div_rate *= 2; @@ -986,6 +1005,9 @@ static unsigned long _clk_audio_video_round_rate(struct clk *clk, u32 control3 = 0; unsigned long final_rate; + if (clk == &pll4_audio_main_clk && audio_pll_bypass) + return 24000000; + if (clk == &pll4_audio_main_clk) min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4; else @@ -1681,6 +1703,7 @@ static struct clk mmdc_ch1_axi_clk[] = { .secondary = &tzasc2_clk, }, }; + #if defined(CONFIG_SDMA_IRAM) || defined(CONFIG_SND_MXC_SOC_IRAM) static struct clk ocram_clk = { __INIT_CLK_DEBUG(ocram_clk) @@ -1692,6 +1715,7 @@ static struct clk ocram_clk = { .disable = _clk_disable_inwait, }; #endif + static unsigned long _clk_ipg_perclk_get_rate(struct clk *clk) { u32 reg, div; @@ -2376,14 +2400,23 @@ static int _clk_extern_audio_set_rate(struct clk *clk, unsigned long rate) u32 reg, div, pre, post; u32 parent_rate = clk_get_rate(clk->parent); - div = parent_rate / rate; - if (div == 0) - div++; - if (((parent_rate / div) != rate) || div > 64) - return -EINVAL; + if (rate == 24000000 && clk->parent == &pll4_audio_main_clk) { + /* If the requested rate is 24MHz, + * set the PLL4 to bypass mode. + */ + audio_pll_bypass = 1; + pre = post = 1; + } else { + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 64) + return -EINVAL; - __calc_pre_post_dividers(1 << 3, div, &pre, &post); + audio_pll_bypass = 0; + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + } reg = __raw_readl(MXC_CCM_CS1CDR); reg &= ~(MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK| MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK); @@ -2442,15 +2475,10 @@ static struct clk ssi1_clk[] = { .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, #ifndef CONFIG_SND_MXC_SOC_IRAM .secondary = &mmdc_ch1_axi_clk[0], - }, #else - .secondary = &ssi1_clk[1], - }, - { - .parent = &mmdc_ch1_axi_clk[0], .secondary = &ocram_clk, - }, #endif + }, }; static unsigned long _clk_ssi2_get_rate(struct clk *clk) @@ -2523,15 +2551,10 @@ static struct clk ssi2_clk[] = { .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, #ifndef CONFIG_SND_MXC_SOC_IRAM .secondary = &mmdc_ch1_axi_clk[0], - }, #else - .secondary = &ssi2_clk[1], - }, - { - .parent = &mmdc_ch1_axi_clk[0], .secondary = &ocram_clk, - }, #endif + }, }; static unsigned long _clk_ssi3_get_rate(struct clk *clk) @@ -2603,15 +2626,10 @@ static struct clk ssi3_clk[] = { .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, #ifndef CONFIG_SND_MXC_SOC_IRAM .secondary = &mmdc_ch1_axi_clk[0], - }, #else - .secondary = &ssi3_clk[1], - }, - { - .parent = &mmdc_ch1_axi_clk[0], .secondary = &ocram_clk, - }, #endif + }, }; static unsigned long _clk_epdc_lcdif_pix_round_rate(struct clk *clk, @@ -4118,6 +4136,8 @@ int __init mx6sl_clocks_init(unsigned long ckil, unsigned long osc, /* lcdif pix - PLL5 as parent */ clk_set_parent(&lcdif_pix_clk, &pll5_video_main_clk); + clk_set_parent(&ssi2_clk[0], &pll4_audio_main_clk); + lp_high_freq = 0; lp_med_freq = 0; diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c index eaeae1d3c57c..a65ad81e666d 100644 --- a/arch/arm/mach-mx6/cpu.c +++ b/arch/arm/mach-mx6/cpu.c @@ -37,6 +37,7 @@ bool enable_wait_mode = true; u32 enable_ldo_mode = LDO_MODE_DEFAULT; u32 arm_max_freq = CPU_AT_1_2GHz; bool mem_clk_on_in_wait; +bool enet_to_gpio_6; int chip_rev; void __iomem *gpc_base; @@ -276,5 +277,10 @@ static int __init enable_mem_clk_in_wait(char *p) early_param("mem_clk_on", enable_mem_clk_in_wait); +static int __init set_enet_irq_to_gpio(char *p) +{ + enet_to_gpio_6 = true; + return 0; +} - +early_param("enet_gpio_6", set_enet_irq_to_gpio); diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h index c4e923eeb650..0ae8e41e01a5 100644 --- a/arch/arm/mach-mx6/crm_regs.h +++ b/arch/arm/mach-mx6/crm_regs.h @@ -178,9 +178,9 @@ #define ANADIG_ANA_MISC2_REG1_BO_EN (1 << 13) #define ANADIG_ANA_MISC2_CONTROL3_MASK 0xC0000000 #define ANADIG_ANA_MISC2_CONTROL3_OFFSET 30 -#define ANADIG_ANA_MISC2_REG0_STEP_TIME_MASK 0x30000000 -#define ANADIG_ANA_MISC2_REG1_STEP_TIME_MASK 0xC000000 -#define ANADIG_ANA_MISC2_REG2_STEP_TIME_MASK 0x3000000 +#define ANADIG_ANA_MISC2_REG0_STEP_TIME_MASK 0x03000000 +#define ANADIG_ANA_MISC2_REG1_STEP_TIME_MASK 0x0C000000 +#define ANADIG_ANA_MISC2_REG2_STEP_TIME_MASK 0x30000000 #define MXC_CCM_BASE MX6_IO_ADDRESS(CCM_BASE_ADDR) /* CCM Register Offsets. */ diff --git a/arch/arm/mach-mx6/mx6_ddr_freq.S b/arch/arm/mach-mx6/mx6_ddr_freq.S index 8d649f336085..de20f0c3248a 100644 --- a/arch/arm/mach-mx6/mx6_ddr_freq.S +++ b/arch/arm/mach-mx6/mx6_ddr_freq.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2013 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 @@ -401,20 +401,6 @@ ddr_freq_change: 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, @@ -423,18 +409,33 @@ ddr_freq_change: @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 + /* Make sure all the L1 & L2 buffers are drained, as + * we don't want any writes to the DDR when it is + * in self-refresh. + */ + /* Make sure the L1 buffers are drained. */ + dsb - /* Disable automatic power saving. */ +#ifdef CONFIG_CACHE_L2X0 + /* Make sure the L2 buffers are drained. + * Sync operation on L2 drains the buffers. + */ + ldr r0, =L2_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + mov r1, #0x0 + str r1, [r0, #0x730] +#endif + /* The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + /* Disable automatic power saving. */ ldr r0, [r5, #0x404] orr r0, r0, #0x01 str r0, [r5, #0x404] diff --git a/arch/arm/mach-mx6/mx6sl_ddr.S b/arch/arm/mach-mx6/mx6sl_ddr.S index 3059f3aa3c8c..9e83985ed0f8 100644 --- a/arch/arm/mach-mx6/mx6sl_ddr.S +++ b/arch/arm/mach-mx6/mx6sl_ddr.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2012-2013 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 @@ -116,13 +116,6 @@ mmdc_podf0: .macro ddr_switch_400MHz - /* Check if we are switching between - * 400Mhz <-> 50MHz. If so, we only need to - * update MMDC divider. - */ - cmp r1, #0 - beq change_divider_only - /* Set MMDC divider first, in case PLL3 is at 480MHz. */ ldr r6, [r3, #0x10] and r6, r6, #0x10000 @@ -141,6 +134,13 @@ mmdc_podf: pll3_in_bypass: + /* Check if we are switching between + * 400Mhz <-> 100MHz.If so, we should + * try to source MMDC from PLL2_200M. + */ + cmp r1, #0 + beq not_low_bus_freq + /* Ensure that MMDC is sourced from PLL2 mux first. */ ldr r6, [r2, #0x14] bic r6, r6, #0x4000000 @@ -151,6 +151,7 @@ periph2_clk_switch4: cmp r6, #0 bne periph2_clk_switch4 +not_low_bus_freq: /* Now ensure periph2_clk2_sel mux is set to PLL3 */ ldr r6, [r2, #0x18] bic r6, r6, #0x100000 @@ -166,6 +167,12 @@ periph2_clk_switch5: cmp r6, #0 bne periph2_clk_switch5 + /* Check if PLL2 is already unlocked. + * If so do nothing with PLL2. + */ + cmp r1, #0 + beq pll2_already_on + /* Now power up PLL2 and unbypass it. */ ldr r6, [r3, #0x30] bic r6, r6, #0x1000 @@ -192,27 +199,43 @@ wait_for_pll_lock: bic r6, r6, #0x800000 str r6, [r3, #0x100] +pll2_already_on: /* Now switch MMDC clk back to pll2_mux option. */ /* Ensure pre_periph2_clk2 is set to pll2_pfd_400M */ + /* If switching to audio DDR freq, set the + * pre_periph2_clk2 to PLL2_PFD_200M + */ + ldr r6, =400000000 + cmp r6, r0 + bne use_pll2_pfd_200M + ldr r6, [r2, #0x18] bic r6, r6, #0x600000 orr r6, r6, #0x200000 str r6, [r2, #0x18] + ldr r6, =400000000 + b cont2 - ldr r6, [r2, #0x14] - bic r6, r6, #0x4000000 - str r6, [r2, #0x14] +use_pll2_pfd_200M: + ldr r6, [r2, #0x18] + orr r6, r6, #0x600000 + str r6, [r2, #0x18] + ldr r6, =200000000 + +cont2: + ldr r4, [r2, #0x14] + bic r4, r4, #0x4000000 + str r4, [r2, #0x14] periph2_clk_switch6: - ldr r6, [r2, #0x48] - cmp r6, #0 + ldr r4, [r2, #0x48] + cmp r4, #0 bne periph2_clk_switch6 change_divider_only: /* Calculate the MMDC divider * based on the requested freq. */ - ldr r6, =400000000 ldr r4, =0 Loop2: sub r6, r6, r0 @@ -306,7 +329,7 @@ force_measure1: */ ENTRY(mx6sl_ddr_iram) - push {r4, r5, r6, r7, r8, r9, r10 } + push {r4-r10} mx6sl_ddr_freq_change: ldr r3, =ANATOP_BASE_ADDR @@ -326,6 +349,21 @@ mx6sl_ddr_freq_change: ldr r6, [r3] ldr r6, [r2] + /* Drain all the L1 buffers. */ + dsb + +#ifdef CONFIG_CACHE_L2X0 + /* Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. */ + ldr r7, =L2_BASE_ADDR + add r7, r7, #PERIPBASE_VIRT + mov r6, #0x0 + str r6, [r7, #0x730] +#endif + + /* The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ dsb isb @@ -421,7 +459,7 @@ skip_power_down: bic r6, r6, #0x100 str r6, [r8, #0x410] - pop {r4,r5, r6, r7, r8, r9, r10} + pop {r4-r10} /* Restore registers */ mov pc, lr diff --git a/arch/arm/mach-mx6/mx6sl_wfi.S b/arch/arm/mach-mx6/mx6sl_wfi.S index 4ec97e424237..bd5a00c67828 100644 --- a/arch/arm/mach-mx6/mx6sl_wfi.S +++ b/arch/arm/mach-mx6/mx6sl_wfi.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2012-2013 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 @@ -158,9 +158,11 @@ fifo_reset2_wait: */ ENTRY(mx6sl_wait) - push {r4, r5, r6, r7, r8, r9, r10} + push {r4-r11} mx6sl_lpm_wfi: + mov r11, r2 + /* Get the IRAM data storage address. */ mov r10, r1 mov r9, r1 /* get suspend_iram_base */ @@ -192,7 +194,23 @@ mx6sl_lpm_wfi: ldr r6, [r2] ldr r6, [r1] + /* Drain all the L1 buffers. */ + dsb + +#ifdef CONFIG_CACHE_L2X0 + /* Need to make sure the buffers in L2 are drained. + * Performing a sync operation does this. */ + ldr r7, =L2_BASE_ADDR + add r7, r7, #PERIPBASE_VIRT + mov r6, #0x0 + str r6, [r7, #0x730] +#endif + + /* The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ dsb + isb /* Disable Automatic power savings. */ ldr r6, [r8, #0x404] @@ -215,6 +233,9 @@ poll_dvfs_set_1: orr r6, r6, #0x100 str r6, [r8, #0x410] + cmp r11, #1 + beq audio_mode + /* Now set DDR rate to 1MHz. */ /* DDR is from bypassed PLL2 on periph2_clk2 path. * Set the periph2_clk2_podf to divide by 8. @@ -228,6 +249,15 @@ poll_dvfs_set_1: bic r6, r6, #0x38 orr r6, r6, #0x10 str r6, [r2, #0x14] + b mmdc_podf + +audio_mode: + /* MMDC is from PLL2_200M. + * Set the mmdc_podf to div by 8. + */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x38 + str r6, [r2, #0x14] /* Loop till podf is accepted. */ mmdc_podf: @@ -238,6 +268,9 @@ mmdc_podf: /* Set the DDR IO in LPM state. */ sl_ddr_io_set_lpm + cmp r11, #1 + beq do_audio_arm_clk + /* Check if none of the PLLs are * locked, except PLL1 which will get * bypassed below. @@ -378,6 +411,30 @@ podf_loop: orr r6, r6, #0x1 str r6, [r3, #0x150] + b do_wfi + +do_audio_arm_clk: + /* ARM is from PLL2_PFD2_400M here. + * Switch ARM to bypassed PLL1. + */ + ldr r6, [r2, #0xC] + bic r6, r6, #0x4 + str r6, [r2, #0xC] + + /* Set the ARM_PODF to divide by 2 + * as IPG is at 4MHz, we cannot run + * ARM_CLK above 9.6MHz when + * system enters WAIT mode. + */ + ldr r6, =0x2 + str r6, [r2, #0x10] + + /* Loop till podf is accepted. */ +podf_loop_audio: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne podf_loop_audio + do_wfi: /* Now do WFI. */ wfi @@ -391,6 +448,9 @@ podf_loop1: cmp r6, #0x0 bne podf_loop1 + cmp r11, #1 + beq audio_arm_clk_restore + /* Check if powered down * analog components. */ @@ -473,12 +533,24 @@ ahb_podf1: cmp r6, #0x0 bne podf_loop1 - mov r9, r10 /* get suspend_iram_base */ + b wfi_restore + +audio_arm_clk_restore: + /* Move ARM back to PLL2_PFD2_400M */ + ldr r6, [r2, #0xC] + orr r6, r6, #0x4 + str r6, [r2, #0xC] + +wfi_restore: + mov r9, r10 /* get suspend_iram_base */ add r9, r9, #IRAM_WAIT_SIZE /* 4K */ /* Restore the DDR IO before exiting self-refresh. */ sl_ddr_io_restore + cmp r11, #1 + beq mmdc_audio_restore + /* Set MMDC back to 24MHz. */ /* Set periph2_clk2_podf to divide by 1. */ /* Now set MMDC PODF to divide by 1. */ @@ -486,6 +558,15 @@ ahb_podf1: bic r6, r6, #0x3f str r6, [r2, #0x14] + b mmdc_podf1 + +mmdc_audio_restore: + /* Set MMDC back to 100MHz. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x8 + str r6, [r2, $0x14] + mmdc_podf1: ldr r6, [r2, #0x48] cmp r6, #0x0 @@ -549,7 +630,7 @@ poll_dvfs_clear_1: str r6, [r8, #0x410] - pop {r4,r5, r6, r7, r8, r9, r10} + pop {r4-r11} /* Restore registers */ mov pc, lr diff --git a/arch/arm/mach-mx6/pcie.c b/arch/arm/mach-mx6/pcie.c index e6b77ae9e750..5a6374cbe6ab 100644 --- a/arch/arm/mach-mx6/pcie.c +++ b/arch/arm/mach-mx6/pcie.c @@ -29,7 +29,9 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/slab.h> #include <linux/platform_device.h> +#include <linux/time.h> #include <mach/pcie.h> @@ -160,6 +162,21 @@ #define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8) #define PCIE_CONF_REG(r) ((r) & ~0x3) +/* + * The default values of the RC's reserved ddr memory + * used to verify EP mode. + * BTW, here is the layout of the 1G ddr on SD boards + * 0x1000_0000 ~ 0x4FFF_FFFF + */ +static u32 rc_ddr_test_region = 0x40000000; +static u32 rc_ddr_test_region_size = (SZ_16M - SZ_16K); + +#ifdef EP_SELF_IO_TEST +static void *rc_ddr_test_reg1, *rc_ddr_test_reg2; +static void __iomem *pcie_arb_base_addr; +static struct timeval tv1, tv2, tv3; +static u32 tv_count1, tv_count2; +#endif static void __iomem *base; static void __iomem *dbi_base; @@ -228,7 +245,7 @@ static int __init imx_pcie_setup(int nr, struct pci_sys_data *sys) pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0; pp->res[0].name = pp->io_space_name; if (pp->index == 0) { - pp->res[0].start = PCIE_ARB_BASE_ADDR; + pp->res[0].start = PCIE_ARB_BASE_ADDR + SZ_16M - SZ_2M; pp->res[0].end = pp->res[0].start + SZ_1M - 1; } pp->res[0].flags = IORESOURCE_IO; @@ -244,7 +261,7 @@ static int __init imx_pcie_setup(int nr, struct pci_sys_data *sys) pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0; pp->res[1].name = pp->mem_space_name; if (pp->index == 0) { - pp->res[1].start = PCIE_ARB_BASE_ADDR + SZ_1M; + pp->res[1].start = PCIE_ARB_BASE_ADDR; pp->res[1].end = pp->res[1].start + SZ_16M - SZ_2M - 1; } pp->res[1].flags = IORESOURCE_MEM; @@ -303,10 +320,11 @@ static int imx_pcie_link_up(void __iomem *dbi_base) return 1; } -static void imx_pcie_regions_setup(void __iomem *dbi_base) +static void imx_pcie_regions_setup(struct device *dev, void __iomem *dbi_base) { - unsigned int i; + struct imx_pcie_platform_data *pdata = dev->platform_data; #ifdef CONFIG_PCI_MSI + unsigned int i; void __iomem *p = dbi_base + PCIE_PL_MSIC_INT; #endif @@ -317,9 +335,13 @@ static void imx_pcie_regions_setup(void __iomem *dbi_base) * split and defined into different regions by iATU, * with sizes and offsets as follows: * - * 0x0100_0000 --- 0x010F_FFFF 1MB IORESOURCE_IO - * 0x0110_0000 --- 0x01EF_FFFF 14MB IORESOURCE_MEM + * RC: + * 0x0100_0000 --- 0x01DF_FFFF 14MB IORESOURCE_MEM + * 0x01E0_0000 --- 0x01EF_FFFF 1MB IORESOURCE_IO * 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + MSI + Registers + * + * EP (default value): + * 0x0100_0000 --- 0x01FF_C000 16MB - 16KB IORESOURCE_MEM */ /* CMD reg:I/O space, MEM space, and Bus Master Enable */ @@ -329,23 +351,80 @@ static void imx_pcie_regions_setup(void __iomem *dbi_base) | PCI_COMMAND_MASTER, dbi_base + PCI_COMMAND); - /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ - writel(readl(dbi_base + PCI_CLASS_REVISION) - | (PCI_CLASS_BRIDGE_PCI << 16), - dbi_base + PCI_CLASS_REVISION); + if (pdata->type_ep) { + /* + * configure the class_rev(emaluate one memory ram ep device), + * bar0 and bar1 of ep + */ + writel(0xdeadbeaf, dbi_base + PCI_VENDOR_ID); + writel(readl(dbi_base + PCI_CLASS_REVISION) + | (PCI_CLASS_MEMORY_RAM << 16), + dbi_base + PCI_CLASS_REVISION); + writel(0xdeadbeaf, dbi_base + PCI_SUBSYSTEM_VENDOR_ID); + + /* 32bit none-prefetchable 8M bytes memory on bar0 */ + writel(0x0, dbi_base + PCI_BASE_ADDRESS_0); + writel(SZ_8M - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_0); + + /* None used bar1 */ + writel(0x0, dbi_base + PCI_BASE_ADDRESS_1); + writel(0, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_1); + + /* 4K bytes IO on bar2 */ + writel(0x1, dbi_base + PCI_BASE_ADDRESS_2); + writel(SZ_4K - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_2); + + /* + * 32bit prefetchable 1M bytes memory on bar3 + * FIXME BAR MASK3 is not changable, the size + * is fixed to 256 bytes. + */ + writel(0x8, dbi_base + PCI_BASE_ADDRESS_3); + writel(SZ_1M - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_3); - /* - * region0 outbound used to access target cfg - */ - writel(0, dbi_base + ATU_VIEWPORT_R); - writel(PCIE_ARB_END_ADDR - SZ_1M + 1, dbi_base + ATU_REGION_LOWBASE_R); - writel(PCIE_ARB_END_ADDR - SZ_64K, dbi_base + ATU_REGION_LIMIT_ADDR_R); - writel(0, dbi_base + ATU_REGION_UPBASE_R); + /* + * 64bit prefetchable 1M bytes memory on bar4-5. + * FIXME BAR4,5 are not enabled yet + */ + writel(0xc, dbi_base + PCI_BASE_ADDRESS_4); + writel(SZ_1M - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_4); + writel(0, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_5); - writel(0, dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); - writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R); - writel(CfgRdWr0, dbi_base + ATU_REGION_CTRL1_R); - writel((1<<31), dbi_base + ATU_REGION_CTRL2_R); + /* + * region0 outbound used to access RC's reserved ddr memory + */ + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(PCIE_ARB_BASE_ADDR, dbi_base + ATU_REGION_LOWBASE_R); + writel(0, dbi_base + ATU_REGION_UPBASE_R); + writel(PCIE_ARB_BASE_ADDR + rc_ddr_test_region_size, + dbi_base + ATU_REGION_LIMIT_ADDR_R); + + writel(rc_ddr_test_region, + dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); + writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R); + writel(MemRdWr, dbi_base + ATU_REGION_CTRL1_R); + writel((1<<31), dbi_base + ATU_REGION_CTRL2_R); + } else { + /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ + writel(readl(dbi_base + PCI_CLASS_REVISION) + | (PCI_CLASS_BRIDGE_PCI << 16), + dbi_base + PCI_CLASS_REVISION); + + /* + * region0 outbound used to access target cfg + */ + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(PCIE_ARB_END_ADDR - SZ_1M + 1, + dbi_base + ATU_REGION_LOWBASE_R); + writel(PCIE_ARB_END_ADDR - SZ_64K, + dbi_base + ATU_REGION_LIMIT_ADDR_R); + writel(0, dbi_base + ATU_REGION_UPBASE_R); + + writel(0, dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); + writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R); + writel(CfgRdWr0, dbi_base + ATU_REGION_CTRL1_R); + writel((1<<31), dbi_base + ATU_REGION_CTRL2_R); + } #ifdef CONFIG_PCI_MSI writel(MSI_MATCH_ADDR, dbi_base + PCIE_PL_MSICA); @@ -700,14 +779,26 @@ static void imx_pcie_enable_controller(struct device *dev) imx_pcie_clrset(IOMUXC_GPR1_TEST_POWERDOWN, 0 << 18, IOMUXC_GPR1); + /* enable the clks */ - pcie_clk = clk_get(NULL, "pcie_clk"); - if (IS_ERR(pcie_clk)) - pr_err("no pcie clock.\n"); + if (pdata->type_ep) { + pcie_clk = clk_get(NULL, "pcie_ep_clk"); + if (IS_ERR(pcie_clk)) + pr_err("no pcie_ep clock.\n"); - if (clk_enable(pcie_clk)) { - pr_err("can't enable pcie clock.\n"); - clk_put(pcie_clk); + if (clk_enable(pcie_clk)) { + pr_err("can't enable pcie_ep clock.\n"); + clk_put(pcie_clk); + } + } else { + pcie_clk = clk_get(NULL, "pcie_clk"); + if (IS_ERR(pcie_clk)) + pr_err("no pcie clock.\n"); + + if (clk_enable(pcie_clk)) { + pr_err("can't enable pcie clock.\n"); + clk_put(pcie_clk); + } } imx_pcie_clrset(IOMUXC_GPR1_PCIE_REF_CLK_EN, 1 << 16, IOMUXC_GPR1); } @@ -750,6 +841,7 @@ static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base, pdata->pcie_power_always_on); /* Release the clocks, and disable the power */ + /* 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"); @@ -786,18 +878,107 @@ static int imx6q_pcie_abort_handler(unsigned long addr, return 0; } +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS +static ssize_t imx_pcie_rc_memw_info(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "imx-pcie-rc-memw-info start 0x%08x, size 0x%08x\n", + rc_ddr_test_region, rc_ddr_test_region_size); +} + +static ssize_t +imx_pcie_rc_memw_start(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 memw_start; + + sscanf(buf, "%x\n", &memw_start); + + if (memw_start < 0x10000000) { + dev_err(dev, "Invalid memory start address.\n"); + dev_info(dev, "For example: echo 0x41000000 > /sys/..."); + return -1; + } + + if (rc_ddr_test_region != memw_start) { + rc_ddr_test_region = memw_start; + /* Re-setup the iATU */ + imx_pcie_regions_setup(dev, dbi_base); + } + + return count; +} + +static ssize_t +imx_pcie_rc_memw_size(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 memw_size; + + sscanf(buf, "%x\n", &memw_size); + + if ((memw_size > (SZ_16M - SZ_16K)) || (memw_size < SZ_64K)) { + dev_err(dev, "Invalid, should be [SZ_64K,SZ_16M - SZ_16KB].\n"); + dev_info(dev, "For example: echo 0x800000 > /sys/..."); + return -1; + } + + if (rc_ddr_test_region_size != memw_size) { + rc_ddr_test_region_size = memw_size; + /* Re-setup the iATU */ + imx_pcie_regions_setup(dev, dbi_base); + } + + return count; +} + +static DEVICE_ATTR(rc_memw_info, S_IRUGO, imx_pcie_rc_memw_info, NULL); +static DEVICE_ATTR(rc_memw_start_set, S_IWUGO, NULL, imx_pcie_rc_memw_start); +static DEVICE_ATTR(rc_memw_size_set, S_IWUGO, NULL, imx_pcie_rc_memw_size); + +static struct attribute *imx_pcie_attrs[] = { + /* + * The start address, and the limitation (64KB ~ (16MB - 16KB)) + * of the ddr mem window reserved by RC, and used for EP to access. + * BTW, these attrs are only configured at EP side. + */ + &dev_attr_rc_memw_info.attr, + &dev_attr_rc_memw_start_set.attr, + &dev_attr_rc_memw_size_set.attr, + NULL +}; + +static struct attribute_group imx_pcie_attrgroup = { + .attrs = imx_pcie_attrs, +}; +#endif + static int __devinit imx_pcie_pltfm_probe(struct platform_device *pdev) { +#ifdef EP_SELF_IO_TEST + int i; +#endif + int ret = 0; struct resource *mem; struct device *dev = &pdev->dev; struct imx_pcie_platform_data *pdata = dev->platform_data; + pr_info("iMX6 PCIe %s mode %s entering.\n", + pdata->type_ep ? "PCIe EP" : "PCIe RC", __func__); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(dev, "no mmio space\n"); return -EINVAL; } +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS + /* add attributes for device */ + ret = sysfs_create_group(&pdev->dev.kobj, &imx_pcie_attrgroup); + if (ret) + return -EINVAL; +#endif + /* Added for PCI abort handling */ hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, "imprecise external abort"); @@ -805,21 +986,32 @@ static int __devinit imx_pcie_pltfm_probe(struct platform_device *pdev) 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; + ret = PTR_ERR(base); +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS + sysfs_remove_group(&pdev->dev.kobj, &imx_pcie_attrgroup); +#endif + return ret; } dbi_base = devm_ioremap(dev, mem->start, resource_size(mem)); if (!dbi_base) { dev_err(dev, "can't map %pR\n", mem); - return -ENOMEM; + ret = PTR_ERR(dbi_base); + goto err_base; } /* FIXME the field name should be aligned to RM */ imx_pcie_clrset(IOMUXC_GPR12_APP_LTSSM_ENABLE, 0 << 10, IOMUXC_GPR12); /* configure constant input signal to the pcie ctrl and phy */ - imx_pcie_clrset(IOMUXC_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12, - IOMUXC_GPR12); + if (pdata->type_ep & 1) + /* EP */ + imx_pcie_clrset(IOMUXC_GPR12_DEVICE_TYPE, + PCI_EXP_TYPE_ENDPOINT << 12, IOMUXC_GPR12); + else + /* RC */ + 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, 0 << 0, IOMUXC_GPR8); @@ -830,58 +1022,116 @@ static int __devinit imx_pcie_pltfm_probe(struct platform_device *pdev) /* Enable the pwr, clks and so on */ imx_pcie_enable_controller(dev); + if (!(pdata->type_ep)) { + /*Only RC: togle the external card's reset */ + card_reset(dev) ; - /* togle the external card's reset */ - card_reset(dev) ; - - usleep_range(3000, 4000); - imx_pcie_regions_setup(dbi_base); - usleep_range(3000, 4000); + imx_pcie_regions_setup(dev, dbi_base); + } + pr_info("PCIE: %s start link up.\n", __func__); /* 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, pdata); - + if (pdata->type_ep) { +#ifdef EP_SELF_IO_TEST + /* Prepare the test regions and data */ + rc_ddr_test_reg1 = kzalloc(rc_ddr_test_region_size, GFP_KERNEL); + if (!rc_ddr_test_reg1) + pr_err("PCIe EP: can't alloc the test region1.\n"); + + rc_ddr_test_reg2 = kzalloc(rc_ddr_test_region_size, GFP_KERNEL); + if (!rc_ddr_test_reg2) { + kfree(rc_ddr_test_reg1); + pr_err("PCIe EP: can't alloc the test region2.\n"); + } - pci_common_init(&imx_pci); - return 0; -} + pcie_arb_base_addr = ioremap_cached(PCIE_ARB_BASE_ADDR, + rc_ddr_test_region_size); -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); + if (!pcie_arb_base_addr) { + pr_err("error with ioremap in function %s\n", __func__); + ret = PTR_ERR(pcie_arb_base_addr); + kfree(rc_ddr_test_reg2); + kfree(rc_ddr_test_reg1); + goto err_base; + } - /* Release clocks, and disable power */ - pcie_clk = clk_get(NULL, "pcie_clk"); - if (IS_ERR(pcie_clk)) - pr_err("no pcie clock.\n"); + for (i = 0; i < rc_ddr_test_region_size; i = i + 4) { + writel(0xE6600D00 + i, rc_ddr_test_reg1 + i); + writel(0xDEADBEAF, rc_ddr_test_reg2 + i); + } +#endif - if (pcie_clk) { - clk_disable(pcie_clk); - clk_put(pcie_clk); - } + pr_info("PCIe EP: waiting for link up...\n"); + /* link is debug bit 36 debug 1 start in bit 32 */ + do { + usleep_range(10, 20); + } while ((readl(dbi_base + DB_R1) & 0x10) == 0); + /* Make sure that the PCIe link is up */ + if (imx_pcie_link_up(dbi_base)) { + pr_info("PCIe EP: link up.\n"); + } else { + pr_info("PCIe EP: ERROR link is down, exit!\n"); +#ifdef EP_SELF_IO_TEST + kfree(rc_ddr_test_reg2); + kfree(rc_ddr_test_reg1); + iounmap(pcie_arb_base_addr); +#endif + goto err_link_down; + } - imx_pcie_clrset(IOMUXC_GPR1_PCIE_REF_CLK_EN, 0 << 16, IOMUXC_GPR1); + imx_pcie_regions_setup(dev, dbi_base); +#ifdef EP_SELF_IO_TEST + /* PCIe EP start the data transfer after link up */ + pr_info("PCIe EP: Starting data transfer...\n"); + do_gettimeofday(&tv1); + + memcpy((unsigned long *)pcie_arb_base_addr, + (unsigned long *)rc_ddr_test_reg1, 0xFFC000); + + do_gettimeofday(&tv2); + + memcpy((unsigned long *)rc_ddr_test_reg2, + (unsigned long *)pcie_arb_base_addr, 0xFFC000); + + do_gettimeofday(&tv3); + + if (memcmp(rc_ddr_test_reg2, rc_ddr_test_reg1, 0xFFC000) != 0) { + pr_info("PCIe EP: Data transfer is failed.\n"); + } else { + tv_count1 = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + + tv2.tv_usec - tv1.tv_usec; + tv_count2 = (tv3.tv_sec - tv2.tv_sec) * USEC_PER_SEC + + tv3.tv_usec - tv2.tv_usec; + + pr_info("PCIe EP: Data transfer is successful." + "tv_count1 %dus, tv_count2 %dus.\n", + tv_count1, tv_count2); + pr_info("PCIe EP: Data write speed is %ldMB/s.\n", + ((((0xFFC000/1024) * MSEC_PER_SEC))) + /(tv_count1)); + pr_info("PCIe EP: Data read speed is %ldMB/s.\n", + ((((0xFFC000/1024) * MSEC_PER_SEC))) + /(tv_count2)); + } +#endif - /* Disable PCIE power */ - gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN"); + } else { + /* add the pcie port */ + add_pcie_port(base, dbi_base, pdata); - /* activate PCIE_PWR_EN */ - gpio_direction_output(pdata->pcie_pwr_en, 0); + pci_common_init(&imx_pci); + } + return 0; - imx_pcie_clrset(IOMUXC_GPR1_TEST_POWERDOWN, 1 << 18, IOMUXC_GPR1); +err_link_down: + iounmap(dbi_base); +err_base: iounmap(base); - iounmap(dbi_base); - release_mem_region(iomem->start, resource_size(iomem)); - platform_set_drvdata(pdev, NULL); - return 0; + return ret; } static struct platform_driver imx_pcie_pltfm_driver = { @@ -890,7 +1140,6 @@ static struct platform_driver imx_pcie_pltfm_driver = { .owner = THIS_MODULE, }, .probe = imx_pcie_pltfm_probe, - .remove = __devexit_p(imx_pcie_pltfm_remove), }; /*****************************************************************************\ diff --git a/arch/arm/mach-mx6/pm.c b/arch/arm/mach-mx6/pm.c index 6e306c279d20..d9c04e11bed0 100644 --- a/arch/arm/mach-mx6/pm.c +++ b/arch/arm/mach-mx6/pm.c @@ -176,9 +176,8 @@ static void usb_power_up_handler(void) static void disp_power_down(void) { -#if !defined(CONFIG_FB_MXC_ELCDIF_FB) && \ - !defined(CONFIG_FB_MXC_ELCDIF_FB_MODULE) - if (cpu_is_mx6sl()) { + if (cpu_is_mx6sl() && (mx6sl_revision() >= IMX_CHIP_REVISION_1_2)) { + __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_DISP_PUPSCR_OFFSET); __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_DISP_PDNSCR_OFFSET); @@ -194,14 +193,11 @@ static void disp_power_down(void) ~MXC_CCM_CCGRx_CG1_MASK, MXC_CCM_CCGR3); } -#endif } static void disp_power_up(void) { -#if !defined(CONFIG_FB_MXC_ELCDIF_FB) && \ - !defined(CONFIG_FB_MXC_ELCDIF_FB_MODULE) - if (cpu_is_mx6sl()) { + if (cpu_is_mx6sl() && (mx6sl_revision() >= IMX_CHIP_REVISION_1_2)) { /* * Need to enable EPDC/LCDIF pix clock, and * EPDC/LCDIF/PXP axi clock before power up. @@ -217,7 +213,6 @@ static void disp_power_up(void) __raw_writel(0x20, gpc_base + GPC_CNTR_OFFSET); __raw_writel(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); } -#endif } static void mx6_suspend_store(void) @@ -342,6 +337,14 @@ static int mx6_suspend_enter(suspend_state_t state) return -EINVAL; } + /* + * L2 can exit by 'reset' or Inband beacon (from remote EP) + * toggling phy_powerdown has same effect as 'inband beacon' + * So, toggle bit18 of GPR1, to fix errata + * "PCIe PCIe does not support L2 Power Down" + */ + __raw_writel(__raw_readl(IOMUXC_GPR1) | (1 << 18), IOMUXC_GPR1); + if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY) { local_flush_tlb_all(); @@ -405,6 +408,14 @@ static int mx6_suspend_enter(suspend_state_t state) cpu_do_idle(); } + /* + * L2 can exit by 'reset' or Inband beacon (from remote EP) + * toggling phy_powerdown has same effect as 'inband beacon' + * So, toggle bit18 of GPR1, to fix errata + * "PCIe PCIe does not support L2 Power Down" + */ + __raw_writel(__raw_readl(IOMUXC_GPR1) & (~(1 << 18)), IOMUXC_GPR1); + return 0; } diff --git a/arch/arm/mach-mx6/regs-anadig.h b/arch/arm/mach-mx6/regs-anadig.h index 773a43d1f9ae..b1d164561f8e 100644 --- a/arch/arm/mach-mx6/regs-anadig.h +++ b/arch/arm/mach-mx6/regs-anadig.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2013 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 @@ -622,7 +622,8 @@ #define BF_ANADIG_ANA_MISC0_OSC_I(v) \ (((v) << 14) & BM_ANADIG_ANA_MISC0_OSC_I) #define BM_ANADIG_ANA_MISC0_RTC_RINGOSC_EN 0x00002000 -#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x00001000 +#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG \ + (cpu_is_mx6sl() ? 0x00000800 : 0x00001000) #define BP_ANADIG_ANA_MISC0_RSVD0 10 #define BM_ANADIG_ANA_MISC0_RSVD0 0x00000C00 #define BF_ANADIG_ANA_MISC0_RSVD0(v) \ diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c index 6b30d08cb830..ff1feda30f5b 100644 --- a/arch/arm/mach-mx6/system.c +++ b/arch/arm/mach-mx6/system.c @@ -61,7 +61,8 @@ bool enet_is_active; void arch_idle_with_workaround(int cpu); extern void *mx6sl_wfi_iram_base; -extern void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr); +extern void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr, \ + int audio_mode); extern void mx6_wait(void *num_cpu_idle_lock, void *num_cpu_idle, \ int wait_arm_podf, int cur_arm_podf); extern bool enable_wait_mode; @@ -262,7 +263,7 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) */ reg = __raw_readl(MXC_CCM_CGPR); reg |= MXC_CCM_CGPR_MEM_IPG_STOP_MASK; - if (!cpu_is_mx6sl()) { + if (!cpu_is_mx6sl() && stop_mode >= 2) { /* * For MX6QTO1.2 or later and MX6DLTO1.1 or later, * ensure that the CCM_CGPR bit 17 is cleared before @@ -306,8 +307,8 @@ void arch_idle_single_core(void) if ((mmdc_ch0_axi != NULL)) ddr_usecount = clk_get_usecount(mmdc_ch0_axi); - if (cpu_is_mx6sl() && low_bus_freq_mode - && ddr_usecount == 1) { + if (cpu_is_mx6sl() && (ddr_usecount == 1) && + (low_bus_freq_mode || audio_bus_freq_mode)) { /* In this mode PLL2 i already in bypass, * ARM is sourced from PLL1. The code in IRAM * will set ARM to be sourced from STEP_CLK @@ -320,7 +321,8 @@ void arch_idle_single_core(void) * we can lower DDR freq. */ mx6sl_wfi_iram(org_arm_podf, - (unsigned long)mx6sl_wfi_iram_base); + (unsigned long)mx6sl_wfi_iram_base, + audio_bus_freq_mode); } else { /* Need to set ARM to run at 24MHz since IPG * is at 12MHz. This is valid for audio mode on diff --git a/arch/arm/mach-mx6/usb_dr.c b/arch/arm/mach-mx6/usb_dr.c index 8fb850397c10..e6496bc9cd50 100644 --- a/arch/arm/mach-mx6/usb_dr.c +++ b/arch/arm/mach-mx6/usb_dr.c @@ -37,6 +37,8 @@ static void _dr_discharge_line(bool enable); extern bool usb_icbug_swfix_need(void); static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, \ bool enable); +static u32 wakeup_irq_enable_src; /* only useful at otg mode */ +static u32 low_power_enable_src; /* only useful at otg mode */ /* The usb_phy1_clk do not have enable/disable function at clock.c * and PLL output for usb1's phy should be always enabled. @@ -99,6 +101,16 @@ static int usb_phy_enable(struct fsl_usb2_platform_data *pdata) UOG_USBCMD |= UCMD_RESET; while ((UOG_USBCMD) & (UCMD_RESET)) ; + + /* + * If the controller reset does not put the PHY be out of + * low power mode, do it manually. + */ + if (UOG_PORTSC1 & PORTSC_PHCD) { + UOG_PORTSC1 &= ~PORTSC_PHCD; + mdelay(1); + } + /* Reset USBPHY module */ phy_ctrl = phy_reg + HW_USBPHY_CTRL; tmp = __raw_readl(phy_ctrl); @@ -152,6 +164,8 @@ static int usbotg_init_ext(struct platform_device *pdev) return ret; } if (!otg_used) { + wakeup_irq_enable_src = 0; + low_power_enable_src = 0; usb_phy_enable(pdev->dev.platform_data); enter_phy_lowpower_suspend(pdev->dev.platform_data, false); /*after the phy reset,can not read the readingvalue for id/vbus at @@ -168,10 +182,7 @@ static void usbotg_uninit_ext(struct platform_device *pdev) { otg_used--; if (!otg_used) { - clk_disable(usb_phy1_clk); clk_put(usb_phy1_clk); - - clk_disable(usb_oh3_clk); clk_put(usb_oh3_clk); } } @@ -218,7 +229,6 @@ static void _dr_discharge_line(bool enable) /* Below two macros are used at otg mode to indicate usb mode*/ #define ENABLED_BY_HOST (0x1 << 0) #define ENABLED_BY_DEVICE (0x1 << 1) -static u32 low_power_enable_src; /* only useful at otg mode */ static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) { void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); @@ -251,6 +261,19 @@ static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, boo | BM_USBPHY_PWD_RXPWDDIFF | BM_USBPHY_PWD_RXPWDRX); __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR); + /* + * The PHY works at 32Khz clock when it is at low power mode, + * it needs 10 clocks from 32Khz to normal work state, so + * 500us is the safe value for PHY enters stable status + * according to IC engineer. + * + * Besides, the digital value needs 1ms debounce time to + * wait the value to be stable. We have expected the + * value from OTGSC is correct after calling this API. + * + * So delay 2ms is a save value. + */ + mdelay(2); } pr_debug("DR: %s ends, enable is %d\n", __func__, enable); @@ -289,6 +312,12 @@ static void otg_wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_SET); USB_OTG_CTRL |= UCTRL_OWIE; } else { + __raw_writel(BM_USBPHY_CTRL_ENDPDMCHG_WKUP + | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS + | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD + | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE + | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE + | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_CLR); USB_OTG_CTRL &= ~UCTRL_OWIE; /* The interrupt must be disabled for at least 3 clock * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ @@ -296,7 +325,6 @@ static void otg_wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable } } -static u32 wakeup_irq_enable_src; /* only useful at otg mode */ static void __wakeup_irq_enable(struct fsl_usb2_platform_data *pdata, bool on, int source) { /* otg host and device share the OWIE bit, only when host and device @@ -491,6 +519,7 @@ static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enabl { void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); __wakeup_irq_enable(pdata, enable, ENABLED_BY_HOST); +#ifdef CONFIG_USB_OTG if (enable) { pr_debug("host wakeup enable\n"); USB_OTG_CTRL |= UCTRL_WKUP_ID_EN; @@ -504,6 +533,7 @@ static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enabl udelay(100); } pr_debug("the otgsc is 0x%x, usbsts is 0x%x, portsc is 0x%x, otgctrl: 0x%x\n", UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, USB_OTG_CTRL); +#endif } static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdata) @@ -517,8 +547,6 @@ static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdat /* if ID change sts, it is a host wakeup event */ if (otgsc & OTGSC_IS_USB_ID) { pr_debug("otg host ID wakeup\n"); - /* if host ID wakeup, we must clear the ID change sts */ - otgsc |= OTGSC_IS_USB_ID; return WAKEUP_EVENT_ID; } if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) { diff --git a/arch/arm/mach-mx6/usb_h1.c b/arch/arm/mach-mx6/usb_h1.c index d4b7001a111c..6de99d96142b 100644 --- a/arch/arm/mach-mx6/usb_h1.c +++ b/arch/arm/mach-mx6/usb_h1.c @@ -111,6 +111,16 @@ static int usb_phy_enable(struct fsl_usb2_platform_data *pdata) UH1_USBCMD |= UCMD_RESET; while ((UH1_USBCMD) & (UCMD_RESET)) ; + + /* + * If the controller reset does not put the PHY be out of + * low power mode, do it manually. + */ + if (UH1_PORTSC1 & PORTSC_PHCD) { + UH1_PORTSC1 &= ~PORTSC_PHCD; + mdelay(1); + } + /* Reset USBPHY module */ phy_ctrl = phy_reg + HW_USBPHY_CTRL; tmp = __raw_readl(phy_ctrl); @@ -164,7 +174,6 @@ static void fsl_usb_host_uninit_ext(struct platform_device *pdev) fsl_usb_host_uninit(pdata); - clk_disable(usb_oh3_clk); clk_put(usb_oh3_clk); } @@ -194,9 +203,14 @@ static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_SET); USB_H1_CTRL |= (UCTRL_OWIE); } else { - USB_H1_CTRL &= ~(UCTRL_OWIE); __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP | BM_USBPHY_CTRL_ENVBUSCHG_WKUP - | BM_USBPHY_CTRL_ENDPDMCHG_WKUP, phy_reg + HW_USBPHY_CTRL_CLR); + | BM_USBPHY_CTRL_ENDPDMCHG_WKUP + | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS + | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD + | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE + | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE + | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_CLR); + USB_H1_CTRL &= ~(UCTRL_OWIE); /* The interrupt must be disabled for at least 3 * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ udelay(100); @@ -331,6 +345,13 @@ static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool ena | BM_USBPHY_PWD_RXPWDDIFF | BM_USBPHY_PWD_RXPWDRX); __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR); + /* + * The PHY works at 32Khz clock when it is at low power mode, + * it needs 10 clocks from 32Khz to normal work state, so + * 500us is the safe value for PHY enters stable status + * according to IC engineer. + */ + udelay(500); } } @@ -353,13 +374,16 @@ static void h1_wakeup_handler(struct fsl_usb2_platform_data *pdata) static void usbh1_wakeup_event_clear(void) { - void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR); - u32 wakeup_irq_bits; - - wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ; - if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && wakeup_irq_bits) { - /* clear the wakeup interrupt status */ - __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR); + int wakeup_req = USB_H1_CTRL & UCTRL_OWIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(H1 OTGSC 0x%x)\n", UH1_OTGSC); + /* Disable OWIE to clear OWIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USB_H1_CTRL &= ~UCTRL_OWIE; + udelay(100); + USB_H1_CTRL |= UCTRL_OWIE; } } diff --git a/arch/arm/mach-mx6/usb_h2.c b/arch/arm/mach-mx6/usb_h2.c index be092ab8c97c..6ce99abafa41 100644 --- a/arch/arm/mach-mx6/usb_h2.c +++ b/arch/arm/mach-mx6/usb_h2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2013 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 @@ -89,12 +89,7 @@ static void fsl_usb_host_uninit_ext(struct platform_device *pdev) fsl_usb_host_uninit(pdata); - usbh2_internal_phy_clock_gate(false); - - clk_disable(usb_phy3_clk); clk_put(usb_phy3_clk); - - clk_disable(usb_oh3_clk); clk_put(usb_oh3_clk); } diff --git a/arch/arm/mach-mx6/usb_h3.c b/arch/arm/mach-mx6/usb_h3.c index e25c01621b52..cddf55244098 100644 --- a/arch/arm/mach-mx6/usb_h3.c +++ b/arch/arm/mach-mx6/usb_h3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2013 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 @@ -89,12 +89,7 @@ static void fsl_usb_host_uninit_ext(struct platform_device *pdev) fsl_usb_host_uninit(pdata); - usbh3_internal_phy_clock_gate(false); - - clk_disable(usb_phy4_clk); clk_put(usb_phy4_clk); - - clk_disable(usb_oh3_clk); clk_put(usb_oh3_clk); } diff --git a/arch/arm/plat-mxc/devices/platform-imx-i2c.c b/arch/arm/plat-mxc/devices/platform-imx-i2c.c index d11f52da4ac2..f2780ad46a91 100755 --- a/arch/arm/plat-mxc/devices/platform-imx-i2c.c +++ b/arch/arm/plat-mxc/devices/platform-imx-i2c.c @@ -102,9 +102,12 @@ const struct imx_imx_i2c_data imx53_imx_i2c_data[] __initconst = { const struct imx_imx_i2c_data imx6q_imx_i2c_data[] __initconst = { #define imx6q_imx_i2c_data_entry(_id, _hwid) \ imx_imx_i2c_data_entry(MX6Q, _id, _hwid, SZ_4K) +#define imx6dl_imx_i2c_data_entry(_id, _hwid) \ + imx_imx_i2c_data_entry(MX6DL, _id, _hwid, SZ_4K) imx6q_imx_i2c_data_entry(0, 1), imx6q_imx_i2c_data_entry(1, 2), imx6q_imx_i2c_data_entry(2, 3), + imx6dl_imx_i2c_data_entry(3, 4), }; #endif /* ifdef CONFIG_SOC_IMX6Q */ diff --git a/arch/arm/plat-mxc/devices/platform-imx_vpu.c b/arch/arm/plat-mxc/devices/platform-imx_vpu.c index 9e00b2fd22aa..f0295ad16cf9 100755 --- a/arch/arm/plat-mxc/devices/platform-imx_vpu.c +++ b/arch/arm/plat-mxc/devices/platform-imx_vpu.c @@ -123,7 +123,7 @@ void mx6q_vpu_reset(void) __raw_writel(reg, src_base + 0x18); reg = __raw_readl(src_base); - reg |= 0x5; /* warm reset vpu */ + reg |= 0x4; /* warm reset vpu */ __raw_writel(reg, src_base); while (__raw_readl(src_base) & 0x04) ; diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 82b70d537df9..e12aee5b093b 100755 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c @@ -3,7 +3,7 @@ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * Based on code from Freescale, - * Copyright (C) 2004-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2013 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -283,8 +283,13 @@ static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset) { struct mxc_gpio_port *port = container_of(chip, struct mxc_gpio_port, chip); + u32 gpio_direction; - return (__raw_readl(port->base + GPIO_PSR) >> offset) & 1; + gpio_direction = __raw_readl(port->base + GPIO_GDIR); + if (((gpio_direction >> offset) & 1)) /* output mode */ + return (__raw_readl(port->base + GPIO_DR) >> offset) & 1; + else /* input mode */ + return (__raw_readl(port->base + GPIO_PSR) >> offset) & 1; } static int mxc_gpio_direction_input(struct gpio_chip *chip, unsigned offset) diff --git a/arch/arm/plat-mxc/include/mach/arc_otg.h b/arch/arm/plat-mxc/include/mach/arc_otg.h index f2bb01c6a8c9..fdd84503686b 100755 --- a/arch/arm/plat-mxc/include/mach/arc_otg.h +++ b/arch/arm/plat-mxc/include/mach/arc_otg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2005-2013 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 @@ -121,6 +121,7 @@ extern void __iomem *imx_otg_base; /* configured_flag (0x180) configflag (supports HS) */ #define UH1_PORTSC1 USBH1_REG32(0x184) /* port status and control */ /* end EHCI registers: */ +#define UH1_OTGSC USBH1_REG32(0x1a4) /* OTG status and control */ #define UH1_USBMODE USBH1_REG32(0x1a8) /* USB device mode */ /* diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx6dl.h b/arch/arm/plat-mxc/include/mach/iomux-mx6dl.h index dbfc9a2d8012..59f8399be39c 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-mx6dl.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx6dl.h @@ -84,11 +84,18 @@ PAD_CTL_DSE_40ohm | PAD_CTL_PUS_100K_DOWN | \ PAD_CTL_HYS | PAD_CTL_SPEED_MED) +#define MX6DL_HDMICEC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_100K_UP | \ + PAD_CTL_PUE | PAD_CTL_PKE | PAD_CTL_ODE | PAD_CTL_SPEED_MED | \ + PAD_CTL_DSE_40ohm | PAD_CTL_SRE_SLOW) + #define MX6DL_GPMI_PAD_CTRL0 (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP) #define MX6DL_GPMI_PAD_CTRL1 (PAD_CTL_DSE_40ohm | PAD_CTL_SPEED_MED | PAD_CTL_SRE_FAST) #define MX6DL_GPMI_PAD_CTRL2 (MX6DL_GPMI_PAD_CTRL0 | MX6DL_GPMI_PAD_CTRL1) #define MX6DL_SPDIF_OUT_PAD_CTRL (PAD_CTL_DSE_120ohm | PAD_CTL_SRE_FAST) +#define ENET_IRQ_PAD_CTRL (PAD_CTL_SRE_FAST | PAD_CTL_DSE_40ohm | \ + PAD_CTL_SPEED_MED) + #define MX6DL_PAD_CSI0_DAT10__IPU1_CSI0_D_10 \ IOMUX_PAD(0x0360, 0x004C, 0, 0x0000, 0, NO_PAD_CTRL) #define MX6DL_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC \ @@ -1425,7 +1432,7 @@ #define MX6DL_PAD_EIM_A25__GPIO_5_2 \ IOMUX_PAD(0x0504, 0x0134, 5, 0x0000, 0, NO_PAD_CTRL) #define MX6DL_PAD_EIM_A25__HDMI_TX_CEC_LINE \ - IOMUX_PAD(0x0504, 0x0134, 6, 0x085C, 0, NO_PAD_CTRL) + IOMUX_PAD(0x0504, 0x0134, 6, 0x085C, 0, MX6DL_HDMICEC_PAD_CTRL) #define MX6DL_PAD_EIM_A25__PL301_SIM_MX6DL_PER1_HBURST_0 \ IOMUX_PAD(0x0504, 0x0134, 7, 0x0000, 0, NO_PAD_CTRL) #define MX6DL_PAD_EIM_A25__EPDC_SDDO_15 \ @@ -2524,10 +2531,12 @@ #define MX6DL_PAD_GPIO_5__SIMBA_EVENTI \ IOMUX_PAD(0x0600, 0x0230, 7, 0x0000, 0, NO_PAD_CTRL) -#define MX6DL_PAD_GPIO_6__ESAI1_SCKT \ - IOMUX_PAD(0x0604, 0x0234, 0, 0x0840, 1, NO_PAD_CTRL) +#define MX6DL_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6 \ + IOMUX_PAD(0x0604, 0x0234, 1 | IOMUX_CONFIG_SION, 0x0000, 0, ENET_IRQ_PAD_CTRL) #define MX6DL_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 \ IOMUX_PAD(0x0604, 0x0234, 1, 0x0000, 0, NO_PAD_CTRL) +#define MX6DL_PAD_GPIO_6__ESAI1_SCKT \ + IOMUX_PAD(0x0604, 0x0234, 0, 0x0840, 1, NO_PAD_CTRL) #define MX6DL_PAD_GPIO_6__I2C3_SDA \ IOMUX_PAD(0x0604, 0x0234, 2 | IOMUX_CONFIG_SION, 0x087C, 2, MX6DL_I2C_PAD_CTRL) #define MX6DL_PAD_GPIO_6__CCM_CCM_OUT_0 \ @@ -2760,7 +2769,7 @@ #define MX6DL_PAD_KEY_ROW2__GPIO_4_11 \ IOMUX_PAD(0x0648, 0x0260, 5, 0x0000, 0, NO_PAD_CTRL) #define MX6DL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE \ - IOMUX_PAD(0x0648, 0x0260, 6, 0x085C, 1, NO_PAD_CTRL) + IOMUX_PAD(0x0648, 0x0260, 6, 0x085C, 1, MX6DL_HDMICEC_PAD_CTRL) #define MX6DL_PAD_KEY_ROW2__PL301_SIM_MX6DL_PER1_HADDR_4 \ IOMUX_PAD(0x0648, 0x0260, 7, 0x0000, 0, NO_PAD_CTRL) diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx6q.h b/arch/arm/plat-mxc/include/mach/iomux-mx6q.h index 557fc4398cd1..16cd87f46459 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-mx6q.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx6q.h @@ -85,7 +85,7 @@ #define MX6Q_ECSPI_PAD_CTRL (PAD_CTL_SRE_FAST | PAD_CTL_SPEED_MED | \ PAD_CTL_DSE_40ohm | PAD_CTL_HYS) -#define MX6Q_HDMICEC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_22K_UP | \ +#define MX6Q_HDMICEC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_100K_UP | \ PAD_CTL_PUE | PAD_CTL_PKE | PAD_CTL_ODE | PAD_CTL_SPEED_MED | \ PAD_CTL_DSE_40ohm | PAD_CTL_SRE_SLOW) @@ -2332,13 +2332,10 @@ #define _MX6Q_PAD_GPIO_6__ESAI1_SCKT \ IOMUX_PAD(0x0600, 0x0230, 0, 0x0870, 1, 0) -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO -#define _MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 \ +#define _MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6 \ IOMUX_PAD(0x0600, 0x0230, 1 | IOMUX_CONFIG_SION, 0x0000, 0, 0) -#else #define _MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 \ IOMUX_PAD(0x0600, 0x0230, 1, 0x0000, 0, 0) -#endif #define _MX6Q_PAD_GPIO_6__I2C3_SDA \ IOMUX_PAD(0x0600, 0x0230, 2 | IOMUX_CONFIG_SION, 0x08AC, 1, 0) #define _MX6Q_PAD_GPIO_6__CCM_CCM_OUT_0 \ @@ -5940,10 +5937,8 @@ #define MX6Q_PAD_GPIO_3__MLB_MLBCLK \ (_MX6Q_PAD_GPIO_3__MLB_MLBCLK | MUX_PAD_CTRL(MX6Q_MLB150_PAD_CTRL)) -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO -#define MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 \ - (_MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 | MUX_PAD_CTRL(ENET_IRQ_PAD_CTRL)) -#else +#define MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6 \ + (_MX6Q_PAD_GPIO_6__ENET_IRQ_TO_GPIO_6 | MUX_PAD_CTRL(ENET_IRQ_PAD_CTRL)) #define MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 \ (_MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 | MUX_PAD_CTRL(NO_PAD_CTRL)) #define MX6Q_PAD_GPIO_6__ESAI1_SCKT \ @@ -5960,7 +5955,6 @@ (_MX6Q_PAD_GPIO_6__USDHC2_LCTL | MUX_PAD_CTRL(MX6Q_USDHC_PAD_CTRL)) #define MX6Q_PAD_GPIO_6__MLB_MLBSIG \ (_MX6Q_PAD_GPIO_6__MLB_MLBSIG | MUX_PAD_CTRL(MX6Q_MLB150_PAD_CTRL)) -#endif #define MX6Q_PAD_GPIO_2__ESAI1_FST \ (_MX6Q_PAD_GPIO_2__ESAI1_FST | MUX_PAD_CTRL(NO_PAD_CTRL)) diff --git a/arch/arm/plat-mxc/include/mach/ipu-v3.h b/arch/arm/plat-mxc/include/mach/ipu-v3.h index f4f7a06e8b88..8dda339c4fb0 100755 --- a/arch/arm/plat-mxc/include/mach/ipu-v3.h +++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h @@ -641,7 +641,7 @@ int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi); int ipu_lowpwr_display_enable(void); int ipu_lowpwr_display_disable(void); -void ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq); +int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq); void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq); void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq); int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq, diff --git a/arch/arm/plat-mxc/include/mach/mxc_hdmi.h b/arch/arm/plat-mxc/include/mach/mxc_hdmi.h index 60946cadc441..94f76380caf6 100644 --- a/arch/arm/plat-mxc/include/mach/mxc_hdmi.h +++ b/arch/arm/plat-mxc/include/mach/mxc_hdmi.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. */ /* @@ -1085,4 +1085,11 @@ enum { }; +/* IOCTL commands */ +#define HDMI_IOC_MAGIC 'H' + +#define HDMI_IOC_GET_RESOURCE _IO(HDMI_IOC_MAGIC, 0) +#define HDMI_IOC_GET_CPU_TYPE _IO(HDMI_IOC_MAGIC, 1) + + #endif /* __MXC_HDMI_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mxc_vpu.h b/arch/arm/plat-mxc/include/mach/mxc_vpu.h index 7a6e24f2b0dd..7869d59c5eec 100755 --- a/arch/arm/plat-mxc/include/mach/mxc_vpu.h +++ b/arch/arm/plat-mxc/include/mach/mxc_vpu.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -16,7 +16,7 @@ */ /*! - * @file arch-mxc/mxc_vpu.h + * @file plat-mxc/include/mach/mxc_vpu.h * * @brief VPU system initialization and file operation definition * @@ -58,6 +58,7 @@ struct vpu_mem_desc { #define VPU_IOC_QUERY_BITWORK_MEM _IO(VPU_IOC_MAGIC, 13) #define VPU_IOC_SET_BITWORK_MEM _IO(VPU_IOC_MAGIC, 14) #define VPU_IOC_PHYMEM_CHECK _IO(VPU_IOC_MAGIC, 15) +#define VPU_IOC_LOCK_DEV _IO(VPU_IOC_MAGIC, 16) #define BIT_CODE_RUN 0x000 #define BIT_CODE_DOWN 0x004 diff --git a/arch/arm/plat-mxc/include/mach/pcie.h b/arch/arm/plat-mxc/include/mach/pcie.h index 2e8eb44be0c7..79b62c6374ad 100644 --- a/arch/arm/plat-mxc/include/mach/pcie.h +++ b/arch/arm/plat-mxc/include/mach/pcie.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -35,6 +35,7 @@ struct imx_pcie_platform_data { unsigned int pcie_rst; unsigned int pcie_wake_up; unsigned int pcie_dis; + unsigned int type_ep; /* 1 EP, 0 RC */ unsigned int pcie_power_always_on; }; #endif /* __ASM_ARCH_IMX_PCIE_H */ diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 9c2419e4fffb..9048f469337f 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -7,7 +7,7 @@ * * Based on code from Freescale: * - * Copyright 2004-2012 Freescale Semiconductor, Inc. + * Copyright 2004-2013 Freescale Semiconductor, Inc. * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License @@ -33,11 +33,14 @@ #include <linux/platform_device.h> #include <linux/dmaengine.h> #include <linux/delay.h> +#include <linux/genalloc.h> #include <asm/irq.h> #include <mach/sdma.h> #include <mach/dma.h> #include <mach/hardware.h> +#include <mach/iram.h> + /* SDMA registers */ #define SDMA_H_C0PTR 0x000 @@ -328,6 +331,7 @@ struct sdma_engine { struct clk *clk; struct sdma_script_start_addrs *script_addrs; spinlock_t irq_reg_lock; + spinlock_t channel_0_lock; }; #define SDMA_H_CONFIG_DSPDMA (1 << 12) /* indicates if the DSPDMA is used */ @@ -335,6 +339,35 @@ struct sdma_engine { #define SDMA_H_CONFIG_ACR (1 << 4) /* indicates if AHB freq /core freq = 2 or 1 */ #define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/ +#ifdef CONFIG_SDMA_IRAM +static unsigned long sdma_iram_paddr; +static void *sdma_iram_vaddr; +#define sdma_iram_phys_to_virt(p) (sdma_iram_vaddr + ((p) - sdma_iram_paddr)) +#define sdma_iram_virt_to_phys(v) (sdma_iram_paddr + ((v) - sdma_iram_vaddr)) +static struct gen_pool *sdma_iram_pool; + +/*! + * Allocates uncacheable buffer from IRAM + */ +void __iomem *sdma_iram_malloc(size_t size, unsigned long *buf) +{ + *buf = gen_pool_alloc(sdma_iram_pool, size); + if (!buf) + return NULL; + + return sdma_iram_phys_to_virt(*buf); +} + +void sdma_iram_free(unsigned long *buf, u32 size) +{ + if (!sdma_iram_pool) + return; + + gen_pool_free(sdma_iram_pool, buf, size); +} +#endif /*CONFIG_SDMA_IRAM */ + + static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event) { u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1); @@ -385,14 +418,23 @@ static int sdma_run_channel(struct sdma_channel *sdmac) { struct sdma_engine *sdma = sdmac->sdma; int channel = sdmac->channel; + unsigned long timeout = 1000; int ret; - init_completion(&sdmac->done); + writel(1 << channel, sdma->regs + SDMA_H_START); - wmb(); - writel_relaxed(1 << channel, sdma->regs + SDMA_H_START); + while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) { + if (timeout-- <= 0) + break; + udelay(1); + } - ret = wait_for_completion_timeout(&sdmac->done, HZ); + if (ret) { + /* Clear the interrupt status */ + writel_relaxed(ret, sdma->regs + SDMA_H_INTR); + } else { + dev_err(sdma->dev, "Timeout waiting for CH0 ready\n"); + } return ret ? 0 : -ETIMEDOUT; } @@ -403,14 +445,21 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; void *buf_virt; dma_addr_t buf_phys; + unsigned long flags; int ret; +#ifdef CONFIG_SDMA_IRAM + buf_virt = sdma_iram_malloc(size, (unsigned long)&buf_phys); +#else buf_virt = dma_alloc_coherent(NULL, size, &buf_phys, GFP_KERNEL); +#endif if (!buf_virt) return -ENOMEM; + spin_lock_irqsave(&sdma->channel_0_lock, flags); + bd0->mode.command = C0_SETPM; bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; bd0->mode.count = size / 2; @@ -421,7 +470,12 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, ret = sdma_run_channel(&sdma->channel[0]); + spin_unlock_irqrestore(&sdma->channel_0_lock, flags); +#ifdef CONFIG_SDMA_IRAM + sdma_iram_free(buf_phys, size); +#else dma_free_coherent(NULL, size, buf_virt, buf_phys); +#endif return ret; } @@ -518,10 +572,6 @@ static void mxc_sdma_handle_channel(struct sdma_channel *sdmac) { complete(&sdmac->done); - /* not interested in channel 0 interrupts */ - if (sdmac->channel == 0) - return; - switch (sdmac->mode) { case SDMA_MODE_LOOP: sdma_handle_channel_loop(sdmac); @@ -548,6 +598,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) spin_lock_irqsave(&sdma->irq_reg_lock, flag); stat = readl_relaxed(sdma->regs + SDMA_H_INTR); + /* not interested in channel 0 interrupts */ + stat &= ~1; writel_relaxed(stat, sdma->regs + SDMA_H_INTR); spin_unlock_irqrestore(&sdma->irq_reg_lock, flag); @@ -696,6 +748,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) struct sdma_context_data *context = sdma->context; struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; int ret; + unsigned long flags; if (sdmac->direction == DMA_DEV_TO_MEM) @@ -720,6 +773,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0); dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1); + spin_lock_irqsave(&sdma->channel_0_lock, flags); memset(context, 0, sizeof(*context)); context->channel_state.pc = load_address; @@ -736,6 +790,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) ret = sdma_run_channel(&sdma->channel[0]); + spin_unlock_irqrestore(&sdma->channel_0_lock, flags); return ret; } @@ -882,7 +937,12 @@ static int sdma_request_channel(struct sdma_channel *sdmac) int channel = sdmac->channel; int ret = -EBUSY; +#ifdef CONFIG_SDMA_IRAM + sdmac->bd = sdma_iram_malloc(sizeof(sdmac->bd), + (unsigned long)&sdmac->bd_phys); +#else sdmac->bd = dma_alloc_noncached(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL); +#endif if (!sdmac->bd) { ret = -ENOMEM; goto out; @@ -1045,8 +1105,11 @@ static void sdma_free_chan_resources(struct dma_chan *chan) sdma_set_channel_priority(sdmac, 0); +#ifdef CONFIG_SDMA_IRAM + sdma_iram_free(sdmac->bd_phys, sizeof(sdmac->bd)); +#else dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); - +#endif clk_disable(sdma->clk); } @@ -1430,10 +1493,22 @@ static int __init sdma_init(struct sdma_engine *sdma) /* Be sure SDMA has not started yet */ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); +#ifdef CONFIG_SDMA_IRAM + /* Allocate memory for SDMA channel and buffer descriptors */ + sdma_iram_vaddr = iram_alloc(SZ_4K, &sdma_iram_paddr); + sdma_iram_pool = gen_pool_create(PAGE_SHIFT/2, -1); + gen_pool_add(sdma_iram_pool, sdma_iram_paddr, SZ_4K, -1); + + sdma->channel_control = sdma_iram_malloc(MAX_DMA_CHANNELS * + sizeof(struct sdma_channel_control) + + sizeof(struct sdma_context_data), + &ccb_phys); +#else sdma->channel_control = dma_alloc_coherent(NULL, MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) + sizeof(struct sdma_context_data), &ccb_phys, GFP_KERNEL); +#endif if (!sdma->channel_control) { ret = -ENOMEM; @@ -1501,6 +1576,8 @@ static int __init sdma_probe(struct platform_device *pdev) if (!sdma) return -ENOMEM; + spin_lock_init(&sdma->channel_0_lock); + sdma->dev = &pdev->dev; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c index 745440911a1f..7e108f7bac03 100644 --- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c @@ -42,10 +42,13 @@ static int video_nr = -1; static cam_data *g_cam; +static int req_buf_number; static int csi_v4l2_master_attach(struct v4l2_int_device *slave); static void csi_v4l2_master_detach(struct v4l2_int_device *slave); static u8 camera_power(cam_data *cam, bool cameraOn); +struct v4l2_crop crop_current; +struct v4l2_window win_current; /*! Information about this driver. */ static struct v4l2_int_master csi_v4l2_master = { @@ -62,6 +65,37 @@ static struct v4l2_int_device csi_v4l2_int_device = { }, }; +static struct v4l2_queryctrl pxp_controls[] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Rotation", + .minimum = 0, + .maximum = 270, + .step = 90, + .default_value = 0, + .flags = 0, + }, +}; + /* Callback function triggered after PxP receives an EOF interrupt */ static void pxp_dma_done(void *arg) { @@ -108,7 +142,7 @@ static int pxp_chan_init(cam_data *cam) /* * Function to call PxP DMA driver and send our new V4L2 buffer - * through the PxP and PxP will process this buffer in place. + * through the PxP. * Note: This is a blocking call, so upon return the PxP tx should be complete. */ static int pxp_process_update(cam_data *cam) @@ -177,21 +211,41 @@ static int pxp_process_update(cam_data *cam) proc_data->srect.width = pxp_conf->s0_param.width; proc_data->srect.height = pxp_conf->s0_param.height; - proc_data->drect.top = 0; + if (crop_current.c.top != 0) + proc_data->srect.top = crop_current.c.top; + if (crop_current.c.left != 0) + proc_data->srect.left = crop_current.c.left; + if (crop_current.c.width != 0) + proc_data->srect.width = crop_current.c.width; + if (crop_current.c.height != 0) + proc_data->srect.height = crop_current.c.height; + proc_data->drect.left = 0; + proc_data->drect.top = 0; proc_data->drect.width = proc_data->srect.width; proc_data->drect.height = proc_data->srect.height; - proc_data->scaling = 0; - proc_data->hflip = 0; - proc_data->vflip = 0; - proc_data->rotate = 0; - proc_data->bgcolor = 0; + + if (win_current.w.left != 0) + proc_data->drect.left = win_current.w.left; + if (win_current.w.top != 0) + proc_data->drect.top = win_current.w.top; + if (win_current.w.width != 0) + proc_data->drect.width = win_current.w.width; + if (win_current.w.height != 0) + proc_data->drect.height = win_current.w.height; + + pr_debug("srect l: %d, t: %d, w: %d, h: %d; " + "drect l: %d, t: %d, w: %d, h: %d\n", + proc_data->srect.left, proc_data->srect.top, + proc_data->srect.width, proc_data->srect.height, + proc_data->drect.left, proc_data->drect.top, + proc_data->drect.width, proc_data->drect.height); pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565; pxp_conf->out_param.width = proc_data->drect.width; pxp_conf->out_param.height = proc_data->drect.height; - if (cam->rotation >= IPU_ROTATE_90_RIGHT) + if (cam->rotation % 180) pxp_conf->out_param.stride = pxp_conf->out_param.height; else pxp_conf->out_param.stride = pxp_conf->out_param.width; @@ -742,7 +796,7 @@ static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) * camera can change. */ pr_debug("csi_v4l2_s_fmt size changed\n"); } - if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + if (cam->rotation % 180) { height = &f->fmt.pix.width; width = &f->fmt.pix.height; } else { @@ -824,6 +878,11 @@ static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) case V4L2_BUF_TYPE_VIDEO_OVERLAY: pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); cam->win = f->fmt.win; + win_current = f->fmt.win; + size = win_current.w.width * win_current.w.height * 2; + if (cam->v2f.fmt.pix.sizeimage < size) + cam->v2f.fmt.pix.sizeimage = size; + break; default: retval = -EINVAL; @@ -897,6 +956,39 @@ exit: return err; } +static int pxp_set_cstate(cam_data *cam, struct v4l2_control *vc) +{ + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + + if (vc->id == V4L2_CID_HFLIP) { + proc_data->hflip = vc->value; + } else if (vc->id == V4L2_CID_VFLIP) { + proc_data->vflip = vc->value; + } else if (vc->id == V4L2_CID_PRIVATE_BASE) { + if (vc->value % 90) + return -ERANGE; + proc_data->rotate = vc->value; + cam->rotation = vc->value; + } + + return 0; +} + +static int pxp_get_cstate(cam_data *cam, struct v4l2_control *vc) +{ + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + + if (vc->id == V4L2_CID_HFLIP) + vc->value = proc_data->hflip; + else if (vc->id == V4L2_CID_VFLIP) + vc->value = proc_data->vflip; + else if (vc->id == V4L2_CID_PRIVATE_BASE) + vc->value = proc_data->rotate; + + return 0; +} + + /*! * Dequeue one V4L capture buffer * @@ -959,9 +1051,9 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) * to RGB565; but for encoding, usually we don't use RGB format. */ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { - /* PxP processes it in place */ sg_dma_address(&cam->sg[0]) = buf->m.offset; - sg_dma_address(&cam->sg[1]) = buf->m.offset; + sg_dma_address(&cam->sg[1]) = + cam->frame[req_buf_number].paddress; retval = pxp_process_update(cam); if (retval) { pr_err("Unable to submit PxP update task.\n"); @@ -970,6 +1062,9 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) pxp_complete_update(cam); } up(&cam->busy_lock); + memcpy(cam->frame[buf->index].vaddress, + cam->frame[req_buf_number].vaddress, + cam->v2f.fmt.pix.sizeimage); return retval; } @@ -1246,9 +1341,33 @@ static long csi_v4l_do_ioctl(struct file *file, } case VIDIOC_S_CROP: - pr_debug(" case not supported\n"); + { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + retval = -EINVAL; + break; + } + crop->c.width -= crop->c.width % 8; + crop->c.height -= crop->c.height % 8; + + crop_current.c = crop->c; + break; + } + case VIDIOC_G_CROP: + { + struct v4l2_crop *crop = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + retval = -EINVAL; + break; + } + crop->c = crop_current.c; + + break; + + } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; pr_debug(" case VIDIOC_REQBUFS\n"); @@ -1274,7 +1393,9 @@ static long csi_v4l_do_ioctl(struct file *file, INIT_LIST_HEAD(&cam->working_q); INIT_LIST_HEAD(&cam->done_q); if (req->memory & V4L2_MEMORY_MMAP) - retval = csi_allocate_frame_buf(cam, req->count); + retval = csi_allocate_frame_buf(cam, req->count + 1); + req_buf_number = req->count; + } break; } @@ -1401,16 +1522,63 @@ static long csi_v4l_do_ioctl(struct file *file, } case VIDIOC_S_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (vc->id == pxp_controls[i].id) { + if (vc->value < pxp_controls[i].minimum || + vc->value > pxp_controls[i].maximum) { + retval = -ERANGE; + break; + } + retval = pxp_set_cstate(cam, vc); + break; + } + + if (i >= ARRAY_SIZE(pxp_controls)) + retval = -EINVAL; + break; + + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *vc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (vc->id == pxp_controls[i].id) { + retval = pxp_get_cstate(cam, vc); + break; + } + + if (i >= ARRAY_SIZE(pxp_controls)) + retval = -EINVAL; + break; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (qc->id && qc->id == pxp_controls[i].id) { + memcpy(qc, &(pxp_controls[i]), sizeof(*qc)); + break; + } + + if (i >= ARRAY_SIZE(pxp_controls)) + retval = -EINVAL; + break; + } case VIDIOC_G_STD: case VIDIOC_G_OUTPUT: case VIDIOC_S_OUTPUT: case VIDIOC_ENUMSTD: - case VIDIOC_G_CROP: case VIDIOC_CROPCAP: case VIDIOC_S_STD: - case VIDIOC_G_CTRL: case VIDIOC_TRY_FMT: - case VIDIOC_QUERYCTRL: case VIDIOC_ENUMINPUT: case VIDIOC_G_INPUT: case VIDIOC_S_INPUT: @@ -1510,8 +1678,14 @@ static struct video_device csi_v4l_template = { */ static void init_camera_struct(cam_data *cam) { + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; pr_debug("In MVC: %s\n", __func__); + proc_data->hflip = 0; + proc_data->vflip = 0; + proc_data->rotate = 0; + proc_data->bgcolor = 0; + /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); @@ -1598,6 +1772,8 @@ static int __devinit csi_v4l2_probe(struct platform_device *pdev) err = -ENOMEM; goto out; } + memset(&crop_current, 0, sizeof(crop_current)); + memset(&win_current, 0, sizeof(win_current)); init_camera_struct(g_cam); platform_set_drvdata(pdev, (void *)g_cam); diff --git a/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c b/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c index 6d8d4399d7ad..856078a52b6f 100644 --- a/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c +++ b/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c @@ -396,6 +396,7 @@ static int foreground_start(void *private) fbvar.yres = cam->win.w.height; fbvar.yres_virtual = cam->win.w.height * 2; fbvar.yoffset = 0; + fbvar.vmode &= ~FB_VMODE_YWRAP; fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG; fbvar.activate |= FB_ACTIVATE_FORCE; fb_set_var(fbi, &fbvar); diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c index 175f9c6820f3..0b2e08c07775 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c @@ -2677,7 +2677,7 @@ static void init_camera_struct(cam_data *cam, struct platform_device *pdev) cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL); cam->self->module = THIS_MODULE; - sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi); + sprintf(cam->self->name, "mxc_v4l2_cap%d", pdev->id); cam->self->type = v4l2_int_type_master; cam->self->u.master = &mxc_v4l2_master; } diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c index 626bad59e151..452c5735e3ea 100644 --- a/drivers/media/video/mxc/output/mxc_vout.c +++ b/drivers/media/video/mxc/output/mxc_vout.c @@ -30,8 +30,8 @@ #define UYVY_BLACK (0x00800080) #define RGB_BLACK (0x0) -#define NV12_UV_BLACK (0x80) -#define NV12_Y_BLACK (0x0) +#define UV_BLACK (0x80) +#define Y_BLACK (0x0) #define MAX_FB_NUM 6 #define FB_BUFS 3 @@ -58,6 +58,16 @@ ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \ ((vout)->task.input.crop.h == FRAME_HEIGHT_1080P)) +#define IS_PLANAR_PIXEL_FORMAT(format) \ + (format == IPU_PIX_FMT_NV12 || \ + format == IPU_PIX_FMT_YUV420P2 || \ + format == IPU_PIX_FMT_YUV420P || \ + format == IPU_PIX_FMT_YVU420P || \ + format == IPU_PIX_FMT_YUV422P || \ + format == IPU_PIX_FMT_YVU422P || \ + format == IPU_PIX_FMT_YUV444P) + +#define NSEC_PER_FRAME_30FPS (33333333) struct mxc_vout_fb { char *name; @@ -108,12 +118,12 @@ struct mxc_vout_output { struct dma_mem vdoa_output[VDOA_FB_BUFS]; bool timer_stop; - struct timer_list timer; + struct hrtimer timer; struct workqueue_struct *v4l_wq; struct work_struct disp_work; unsigned long frame_count; unsigned long vdi_frame_cnt; - unsigned long start_jiffies; + ktime_t start_ktime; int ctrl_rotate; int ctrl_vflip; @@ -121,7 +131,8 @@ struct mxc_vout_output { dma_addr_t disp_bufs[FB_BUFS]; - struct videobuf_buffer *pre_vb; + struct videobuf_buffer *pre1_vb; + struct videobuf_buffer *pre2_vb; }; struct mxc_vout_dev { @@ -499,29 +510,26 @@ static bool is_pp_bypass(struct mxc_vout_output *vout) static void setup_buf_timer(struct mxc_vout_output *vout, struct videobuf_buffer *vb) { - unsigned long timeout; + ktime_t expiry_time, now; /* if timestamp is 0, then default to 30fps */ - if ((vb->ts.tv_sec == 0) - && (vb->ts.tv_usec == 0) - && vout->start_jiffies) - timeout = - vout->start_jiffies + vout->frame_count * HZ / 30; + if ((vb->ts.tv_sec == 0) && (vb->ts.tv_usec == 0)) + expiry_time = ktime_add_ns(vout->start_ktime, + NSEC_PER_FRAME_30FPS * vout->frame_count); else - timeout = get_jiffies(&vb->ts); + expiry_time = timeval_to_ktime(vb->ts); - if (jiffies >= timeout) { + now = hrtimer_cb_get_time(&vout->timer); + if ((now.tv64 > expiry_time.tv64)) { v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "warning: timer timeout already expired.\n"); + expiry_time = now; } - if (mod_timer(&vout->timer, timeout)) { - v4l2_warn(vout->vfd->v4l2_dev, - "warning: timer was already set\n"); - } + hrtimer_start(&vout->timer, expiry_time, HRTIMER_MODE_ABS); - v4l2_dbg(1, debug, vout->vfd->v4l2_dev, - "timer handler next schedule: %lu\n", timeout); + v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "timer handler next " + "schedule: %lldnsecs\n", expiry_time.tv64); } static int show_buf(struct mxc_vout_output *vout, int idx, @@ -598,10 +606,21 @@ static void disp_work_func(struct work_struct *work) } if (deinterlace_3_field(vout)) { if (list_is_singular(&vout->active_list)) { - v4l2_warn(vout->vfd->v4l2_dev, - "no enough entry for 3 fields deinterlacer\n"); - spin_unlock_irqrestore(q->irqlock, flags); - return; + if (list_empty(&vout->queue_list)) { + vout->timer_stop = true; + spin_unlock_irqrestore(q->irqlock, flags); + v4l2_warn(vout->vfd->v4l2_dev, + "no enough entry for 3 fields " + "deinterlacer\n"); + return; + } + + /* + * We need to use the next vb even if it is + * not on the active list. + */ + vb_next = list_first_entry(&vout->queue_list, + struct videobuf_buffer, queue); } else vb_next = list_first_entry(vout->active_list.next, struct videobuf_buffer, queue); @@ -719,21 +738,28 @@ vdi_frame_rate_double: list_del(&vb->queue); /* - * previous videobuf finish show, set VIDEOBUF_DONE state here - * to avoid tearing issue in pp bypass case, which make sure - * showing buffer will not be dequeue to write new data. It also - * bring side-effect that the last buffer can not be dequeue - * correctly, app need take care about it. + * The videobuf before the last one has been shown. Set + * VIDEOBUF_DONE state here to avoid tearing issue in ic bypass + * case, which makes sure a buffer being shown will not be + * dequeued to be overwritten. It also brings side-effect that + * the last 2 buffers can not be dequeued correctly, apps need + * to take care of it. */ - if (vout->pre_vb) { - vout->pre_vb->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->pre_vb->done); + if (vout->pre2_vb) { + vout->pre2_vb->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->pre2_vb->done); + vout->pre2_vb = NULL; } - if (vout->linear_bypass_pp) - vout->pre_vb = vb; - else { - vout->pre_vb = NULL; + if (vout->linear_bypass_pp) { + vout->pre2_vb = vout->pre1_vb; + vout->pre1_vb = vb; + } else { + if (vout->pre1_vb) { + vout->pre1_vb->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->pre1_vb->done); + vout->pre1_vb = NULL; + } vb->state = VIDEOBUF_DONE; wake_up_interruptible(&vb->done); } @@ -761,10 +787,11 @@ err: return; } -static void mxc_vout_timer_handler(unsigned long arg) +static enum hrtimer_restart mxc_vout_timer_handler(struct hrtimer *timer) { - struct mxc_vout_output *vout = - (struct mxc_vout_output *) arg; + struct mxc_vout_output *vout = container_of(timer, + struct mxc_vout_output, + timer); struct videobuf_queue *q = &vout->vbq; struct videobuf_buffer *vb; unsigned long flags = 0; @@ -777,7 +804,7 @@ static void mxc_vout_timer_handler(unsigned long arg) */ if (list_empty(&vout->queue_list)) { spin_unlock_irqrestore(q->irqlock, flags); - return; + return HRTIMER_NORESTART; } /* move videobuf from queued list to active list */ @@ -792,12 +819,14 @@ static void mxc_vout_timer_handler(unsigned long arg) list_del(&vb->queue); list_add(&vb->queue, &vout->queue_list); spin_unlock_irqrestore(q->irqlock, flags); - return; + return HRTIMER_NORESTART; } vb->state = VIDEOBUF_ACTIVE; spin_unlock_irqrestore(q->irqlock, flags); + + return HRTIMER_NORESTART; } /* Video buffer call backs */ @@ -850,21 +879,21 @@ static void mxc_vout_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct mxc_vout_output *vout = q->priv_data; + struct videobuf_buffer *active_vb; list_add_tail(&vb->queue, &vout->queue_list); vb->state = VIDEOBUF_QUEUED; if (vout->timer_stop) { if (deinterlace_3_field(vout) && - list_empty(&vout->active_list)) { - vb = list_first_entry(&vout->queue_list, + !list_empty(&vout->active_list)) { + active_vb = list_first_entry(&vout->active_list, struct videobuf_buffer, queue); - list_del(&vb->queue); - list_add_tail(&vb->queue, &vout->active_list); + setup_buf_timer(vout, active_vb); } else { setup_buf_timer(vout, vb); - vout->timer_stop = false; } + vout->timer_stop = false; } } @@ -1379,6 +1408,14 @@ static int mxc_vidioc_s_crop(struct file *file, void *fh, /* stride line limitation */ crop->c.height -= crop->c.height % 8; crop->c.width -= crop->c.width % 8; + if ((crop->c.width <= 0) || (crop->c.height <= 0) || + ((crop->c.left + crop->c.width) > (b->left + b->width)) || + ((crop->c.top + crop->c.height) > (b->top + b->height))) { + v4l2_err(vout->vfd->v4l2_dev, "s_crop err: %d, %d, %d, %d", + crop->c.left, crop->c.top, + crop->c.width, crop->c.height); + return -EINVAL; + } /* the same setting, return */ if (vout->disp_support_windows) { @@ -1397,7 +1434,7 @@ static int mxc_vidioc_s_crop(struct file *file, void *fh, /* wait current work finish */ if (vout->vbq.streaming) - cancel_work_sync(&vout->disp_work); + flush_workqueue(vout->v4l_wq); mutex_lock(&vout->task_lock); @@ -1551,7 +1588,7 @@ static int mxc_vidioc_s_ctrl(struct file *file, void *fh, /* wait current work finish */ if (vout->vbq.streaming) - cancel_work_sync(&vout->disp_work); + flush_workqueue(vout->v4l_wq); mutex_lock(&vout->task_lock); switch (ctrl->id) { @@ -1751,7 +1788,10 @@ static int config_disp_output(struct mxc_vout_output *vout) "ERR:%s fb_set_var ret:%d\n", __func__, ret); return ret; } - display_buf_size = fbi->fix.line_length * fbi->var.yres; + if (vout->linear_bypass_pp || vout->tiled_bypass_pp) + display_buf_size = fbi->fix.line_length * fbi->var.yres_virtual; + 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; if (vout->tiled_bypass_pp) { @@ -1784,11 +1824,11 @@ static int config_disp_output(struct mxc_vout_output *vout) /* fill black when video config changed */ color = colorspaceofpixel(vout->task.output.format) == YUV_CS ? UYVY_BLACK : RGB_BLACK; - if (vout->task.output.format == IPU_PIX_FMT_NV12) { + if (IS_PLANAR_PIXEL_FORMAT(vout->task.output.format)) { size = display_buf_size * 8 / fmt_to_bpp(vout->task.output.format); - memset(fbi->screen_base, NV12_Y_BLACK, size); - memset(fbi->screen_base + size, NV12_UV_BLACK, + memset(fbi->screen_base, Y_BLACK, size); + memset(fbi->screen_base + size, UV_BLACK, display_buf_size - size); } else { pixel = (u32 *)fbi->screen_base; @@ -1812,6 +1852,22 @@ err: return ret; } +static inline void wait_for_vsync(struct mxc_vout_output *vout) +{ + struct fb_info *fbi = vout->fbi; + mm_segment_t old_fs; + + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC, + (unsigned long)NULL); + set_fs(old_fs); + } + + return; +} + static void release_disp_output(struct mxc_vout_output *vout) { struct fb_info *fbi = vout->fbi; @@ -1871,14 +1927,14 @@ static int mxc_vidioc_streamon(struct file *file, void *fh, goto done; } - init_timer(&vout->timer); + hrtimer_init(&vout->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); vout->timer.function = mxc_vout_timer_handler; - vout->timer.data = (unsigned long)vout; vout->timer_stop = true; - vout->start_jiffies = jiffies; + vout->start_ktime = hrtimer_cb_get_time(&vout->timer); - vout->pre_vb = NULL; + vout->pre1_vb = NULL; + vout->pre2_vb = NULL; ret = videobuf_streamon(q); done: @@ -1893,10 +1949,17 @@ static int mxc_vidioc_streamoff(struct file *file, void *fh, int ret = 0; if (q->streaming) { - cancel_work_sync(&vout->disp_work); flush_workqueue(vout->v4l_wq); - del_timer_sync(&vout->timer); + hrtimer_cancel(&vout->timer); + + /* + * Wait for 2 vsyncs to make sure + * frames are drained on triple + * buffer. + */ + wait_for_vsync(vout); + wait_for_vsync(vout); release_disp_output(vout); @@ -2048,9 +2111,13 @@ static int mxc_vout_probe(struct platform_device *pdev) return -ENOMEM; dev->dev = &pdev->dev; - dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask), GFP_KERNEL); - *dev->dev->dma_mask = DMA_BIT_MASK(32); - dev->dev->coherent_dma_mask = DMA_BIT_MASK(32); + if (!dev->dev->dma_mask) { + dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask), + GFP_KERNEL); + if (dev->dev->dma_mask) + *dev->dev->dma_mask = DMA_BIT_MASK(32); + dev->dev->coherent_dma_mask = DMA_BIT_MASK(32); + } ret = v4l2_device_register(dev->dev, &dev->v4l2_dev); if (ret) { diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index af7ff78c9259..2a5623c5a213 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -284,7 +284,8 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, mem->size = PAGE_ALIGN(buf->bsize); mem->vaddr = dma_alloc_coherent(q->dev, mem->size, - &mem->dma_handle, GFP_DMA); + &mem->dma_handle, + GFP_DMA | GFP_KERNEL | __GFP_NOFAIL); if (!mem->vaddr) { dev_err(q->dev, "dma_alloc_coherent size %ld failed\n", mem->size); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a2f4b13bce21..8c1d5b2502c2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -496,7 +496,7 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int err, busy = 0; - u32 part, new_part; + u32 part; u8 *ext_csd, boot_config; struct mmc_command cmd; struct mmc_card *card = container_of(dev, struct mmc_card, dev); @@ -514,12 +514,28 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr, /* it's a normal SD/MMC but user request to configure boot partition */ if (card->ext_csd.boot_size <= 0) { - printk(KERN_ERR "%s: this is a normal SD/MMC card" - " but you request to access boot partition!\n", + pr_err("%s: fail to send SWITCH command to card " \ + "to update boot_config of the EXT_CSD!\n", mmc_hostname(card->host)); return -EINVAL; } + /* + * partition must be - + * 0 - user area + * 1 - boot partition 1 + * 2 - boot partition 2 + * DO NOT switch the partitions that used to be accessed + * in OS layer HERE + */ + if (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) { + pr_err("%s: DO NOT switch the partitions that used to be\n" \ + " accessed in OS layer HERE. please following the\n" \ + " guidance of Documentation/mmc/mmc-dev-parts.txt.\n", + mmc_hostname(card->host)); + return -EINVAL; + } + ext_csd = kmalloc(512, GFP_KERNEL); if (!ext_csd) { printk(KERN_ERR "%s: could not allocate a buffer to " @@ -574,29 +590,11 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr, goto err_rtn; } - /* switch the partitions that used to be accessed in OS layer */ - /* partition must be - - * 0 - user area - * 1 - boot partition 1 - * 2 - boot partition 2 - */ - if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) > 2) { - printk(KERN_ERR "%s: wrong partition id" - " 0 (user area), 1 (boot1), 2 (boot2)\n", - mmc_hostname(card->host)); - err = -EINVAL; - goto err_rtn; - } - - - /* Send SWITCH command to change partition for access */ - boot_config &= ~EXT_CSD_BOOT_PARTITION_ACCESS_MASK; - boot_config |= (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK); err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, boot_config, card->ext_csd.part_time); if (err) { - printk(KERN_ERR "%s: fail to send SWITCH command" - " to card to swich partition for access!\n", + pr_err("%s: fail to send SWITCH command to card " \ + "to update boot_config of the EXT_CSD!\n", mmc_hostname(card->host)); goto err_rtn; } @@ -634,14 +632,6 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr, goto err_rtn; } - new_part = ext_csd[EXT_CSD_PART_CONFIG] & - EXT_CSD_BOOT_PARTITION_ACCESS_MASK; - if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) != new_part) { - printk(KERN_ERR "%s: after SWITCH, current part id %d is not" - " same as requested partition %d!\n", - mmc_hostname(card->host), new_part, part); - goto err_rtn; - } card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG]; err_rtn: @@ -669,8 +659,8 @@ setup_boot_bus(struct device *dev, struct device_attribute *attr, sscanf(buf, "%d\n", &boot_bus); if (card->csd.mmca_vsn < CSD_SPEC_VER_4) { - printk(KERN_ERR "%s: invalid mmc version" - " mmc version is below version 4!)\n", + pr_err("%s: fail to send SWITCH command to card " \ + "to update boot_config of the EXT_CSD!\n", mmc_hostname(card->host)); return -EINVAL; } @@ -794,16 +784,6 @@ static ssize_t mmc_boot_info_show(struct device *dev, "Reserved", "User area enabled for boot"}; - char *boot_partition_access[8] = { - "No access to boot partition", - "R/W boot partition 1", - "R/W boot partition 2", - "R/W Replay Protected Memory Block (RPMB)", - "Access to General Purpose partition 1", - "Access to General Purpose partition 2", - "Access to General Purpose partition 3", - "Access to General Purpose partition 4"}; - char *bus_width[4] = { "x1 (sdr) or x4 (ddr) bus width in boot operation mode", "x4 (sdr/ddr) bus width in boot operation mode", @@ -817,7 +797,6 @@ static ssize_t mmc_boot_info_show(struct device *dev, "Reserved"}; int partition; - int access; int width; int mode; u8 *ext_csd = NULL; @@ -830,7 +809,6 @@ static ssize_t mmc_boot_info_show(struct device *dev, mmc_read_ext_csd(card, ext_csd); partition = (card->ext_csd.boot_config >> 3) & 0x7; - access = card->ext_csd.boot_config & 0x7; width = card->ext_csd.boot_bus_width & 0x3; mode = (card->ext_csd.boot_bus_width >> 3) & 0x3; @@ -843,7 +821,6 @@ static ssize_t mmc_boot_info_show(struct device *dev, "boot_partition:0x%02x;\n" " BOOT_ACK:%x - %s\n" " BOOT_PARTITION-ENABLE: %x - %s\n" - " PARTITION_ACCESS:%x - %s\n" "boot_bus:0x%02x\n" " BOOT_MODE:%x - %s\n" " RESET_BOOT_BUS_WIDTH:%x - %s\n" @@ -872,8 +849,6 @@ static ssize_t mmc_boot_info_show(struct device *dev, "No boot acknowledge sent", partition, boot_partition[partition], - access, - boot_partition_access[access], card->ext_csd.boot_bus_width, mode, diff --git a/drivers/mxc/asrc/mxc_asrc.c b/drivers/mxc/asrc/mxc_asrc.c index ecfd236b3e1b..ea6573867a5c 100644 --- a/drivers/mxc/asrc/mxc_asrc.c +++ b/drivers/mxc/asrc/mxc_asrc.c @@ -53,18 +53,18 @@ DEFINE_SPINLOCK(pair_lock); DEFINE_SPINLOCK(input_int_lock); DEFINE_SPINLOCK(output_int_lock); -#define AICPA 0 /* Input Clock Divider A Offset */ -#define AICDA 3 /* Input Clock Prescaler A Offset */ -#define AICPB 6 /* Input Clock Divider B Offset */ -#define AICDB 9 /* Input Clock Prescaler B Offset */ -#define AOCPA 12 /* Output Clock Divider A Offset */ -#define AOCDA 15 /* Output Clock Prescaler A Offset */ -#define AOCPB 18 /* Output Clock Divider B Offset */ -#define AOCDB 21 /* Output Clock Prescaler B Offset */ -#define AICPC 0 /* Input Clock Divider C Offset */ -#define AICDC 3 /* Input Clock Prescaler C Offset */ -#define AOCDC 6 /* Output Clock Prescaler C Offset */ -#define AOCPC 9 /* Output Clock Divider C Offset */ +#define AICPA 0 /* Input Clock Prescaler A Offset */ +#define AICDA 3 /* Input Clock Divider A Offset */ +#define AICPB 6 /* Input Clock Prescaler B Offset */ +#define AICDB 9 /* Input Clock Divider B Offset */ +#define AOCPA 12 /* Output Clock Prescaler A Offset */ +#define AOCDA 15 /* Output Clock Divider A Offset */ +#define AOCPB 18 /* Output Clock Prescaler B Offset */ +#define AOCDB 21 /* Output Clock Divider B Offset */ +#define AICPC 0 /* Input Clock Prescaler C Offset */ +#define AICDC 3 /* Input Clock Divider C Offset */ +#define AOCPC 6 /* Output Clock Prescaler C Offset */ +#define AOCDC 9 /* Output Clock Divider C Offset */ char *asrc_pair_id[] = { [0] = "ASRC RX PAIR A", @@ -144,12 +144,15 @@ static unsigned char output_clk_map_v1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; +/* V2 uses the same map for input and output */ static unsigned char input_clk_map_v2[] = { - 0, 1, 2, 3, 4, 5, 0xf, 0xf, 0xf, 8, 9, 0xa, 0xb, 0xc, 0xf, 0xd, +/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf*/ + 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, }; static unsigned char output_clk_map_v2[] = { - 8, 9, 0xa, 0, 0xc, 0x5, 0xf, 0xf, 0, 1, 2, 0xf, 0xf, 4, 0xf, 0xd, +/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf*/ + 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, }; static unsigned char *input_clk_map, *output_clk_map; @@ -318,34 +321,42 @@ int asrc_req_pair(int chn_num, enum asrc_pair_index *index) int err = 0; unsigned long lock_flags; struct asrc_pair *pair; + int imax = 0, busy = 0, i; + spin_lock_irqsave(&data_lock, lock_flags); - if (chn_num > 2) { - pair = &g_asrc->asrc_pair[ASRC_PAIR_B]; - if (pair->active || (chn_num > pair->chn_max)) - err = -EBUSY; - else { - *index = ASRC_PAIR_B; - pair->chn_num = chn_num; - pair->active = 1; + for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { + pair = &g_asrc->asrc_pair[i]; + if (chn_num > pair->chn_max) { + imax++; + continue; + } else if (pair->active) { + busy++; + continue; } + /* Save the current qualified pair */ + *index = i; + + /* Check if this pair is a perfect one */ + if (chn_num == pair->chn_max) + break; + } + + if (imax >= ASRC_PAIR_MAX_NUM) { + pr_err("No pair could afford requested channel number.\n"); + err = -EINVAL; + } else if (busy >= ASRC_PAIR_MAX_NUM) { + pr_err("All pairs are busy now.\n"); + err = -EBUSY; + } else if (busy + imax >= ASRC_PAIR_MAX_NUM) { + pr_err("All affordable pairs are busy now.\n"); + err = -EBUSY; } else { - pair = &g_asrc->asrc_pair[ASRC_PAIR_A]; - if (pair->active || (pair->chn_max == 0)) { - pair = &g_asrc->asrc_pair[ASRC_PAIR_C]; - if (pair->active || (pair->chn_max == 0)) - err = -EBUSY; - else { - *index = ASRC_PAIR_C; - pair->chn_num = 2; - pair->active = 1; - } - } else { - *index = ASRC_PAIR_A; - pair->chn_num = 2; - pair->active = 1; - } + pair = &g_asrc->asrc_pair[*index]; + pair->chn_num = chn_num; + pair->active = 1; } + spin_unlock_irqrestore(&data_lock, lock_flags); if (!err) { @@ -381,6 +392,9 @@ int asrc_config_pair(struct asrc_config *config) int err = 0; int reg, tmp, channel_num; unsigned long lock_flags; + unsigned long aicp_shift, aocp_shift; + unsigned long asrc_asrcdr_reg, dp_clear_mask; + /* Set the channel number */ reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCNCR_REG); spin_lock_irqsave(&data_lock, lock_flags); @@ -426,142 +440,68 @@ int asrc_config_pair(struct asrc_config *config) __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCTR_REG); /* Default Clock Divider Setting */ - reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR1_REG); - if (config->pair == ASRC_PAIR_A) { - reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR1_REG); - reg &= 0xfc0fc0; - /* Input Part */ - if ((config->inclk & 0x0f) == INCLK_SPDIF_RX) - reg |= 7 << AICPA; - else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX) - reg |= 6 << AICPA; - else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) { - tmp = - asrc_get_asrck_clock_divider(config-> - input_sample_rate); - reg |= tmp << AICPA; - } else { - if (config->input_word_width == ASRC_WIDTH_16_BIT) - reg |= 5 << AICPA; - else if (config->input_word_width == ASRC_WIDTH_24_BIT) - reg |= 6 << AICPA; - else - err = -EFAULT; - } - /* Output Part */ - if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX) - reg |= 7 << AOCPA; - else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX) - reg |= 6 << AOCPA; - else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) && - ((config->inclk & 0x0f) == INCLK_NONE)) - reg |= 5 << AOCPA; - else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) { - tmp = - asrc_get_asrck_clock_divider(config-> - output_sample_rate); - reg |= tmp << AOCPA; - } else { - if (config->output_word_width == ASRC_WIDTH_16_BIT) - reg |= 5 << AOCPA; - else if (config->output_word_width == ASRC_WIDTH_24_BIT) - reg |= 6 << AOCPA; - else - err = -EFAULT; - } - - __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCDR1_REG); - - } else if (config->pair == ASRC_PAIR_B) { - reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR1_REG); - reg &= 0x03f03f; - /* Input Part */ - if ((config->inclk & 0x0f) == INCLK_SPDIF_RX) - reg |= 7 << AICPB; - else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX) - reg |= 6 << AICPB; - else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) { - tmp = - asrc_get_asrck_clock_divider(config-> - input_sample_rate); - reg |= tmp << AICPB; - } else { - if (config->input_word_width == ASRC_WIDTH_16_BIT) - reg |= 5 << AICPB; - else if (config->input_word_width == ASRC_WIDTH_24_BIT) - reg |= 6 << AICPB; - else - err = -EFAULT; - } - /* Output Part */ - if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX) - reg |= 7 << AOCPB; - else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX) - reg |= 6 << AOCPB; - else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) && - ((config->inclk & 0x0f) == INCLK_NONE)) - reg |= 5 << AOCPB; - else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) { - tmp = - asrc_get_asrck_clock_divider(config-> - output_sample_rate); - reg |= tmp << AOCPB; - } else { - if (config->output_word_width == ASRC_WIDTH_16_BIT) - reg |= 5 << AOCPB; - else if (config->output_word_width == ASRC_WIDTH_24_BIT) - reg |= 6 << AOCPB; - else - err = -EFAULT; - } - - __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCDR1_REG); + switch (config->pair) { + case ASRC_PAIR_A: + asrc_asrcdr_reg = ASRC_ASRCDR1_REG; + dp_clear_mask = 0xfc0fc0; + aicp_shift = AICPA; + aocp_shift = AOCPA; + break; + case ASRC_PAIR_B: + asrc_asrcdr_reg = ASRC_ASRCDR1_REG; + dp_clear_mask = 0x03f03f; + aicp_shift = AICPB; + aocp_shift = AOCPB; + break; + case ASRC_PAIR_C: + asrc_asrcdr_reg = ASRC_ASRCDR2_REG; + dp_clear_mask = 0x00; + aicp_shift = AICPC; + aocp_shift = AOCPC; + break; + default: + pr_err("Invalid Pair number %d\n", config->pair); + return -EFAULT; + } + reg = __raw_readl(g_asrc->vaddr + asrc_asrcdr_reg); + reg &= dp_clear_mask; + /* Input Part */ + if ((config->inclk & 0x0f) == INCLK_SPDIF_RX) + reg |= 7 << aicp_shift; + else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX) + reg |= 6 << aicp_shift; + else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) { + tmp = asrc_get_asrck_clock_divider(config->input_sample_rate); + reg |= tmp << aicp_shift; } else { - reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR2_REG); - reg &= 0; - /* Input Part */ - if ((config->inclk & 0x0f) == INCLK_SPDIF_RX) - reg |= 7 << AICPC; - else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX) - reg |= 6 << AICPC; - else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) { - tmp = - asrc_get_asrck_clock_divider(config-> - input_sample_rate); - reg |= tmp << AICPC; - } else { - if (config->input_word_width == ASRC_WIDTH_16_BIT) - reg |= 5 << AICPC; - else if (config->input_word_width == ASRC_WIDTH_24_BIT) - reg |= 6 << AICPC; - else - err = -EFAULT; - } - /* Output Part */ - if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX) - reg |= 7 << AOCPC; - else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX) - reg |= 6 << AOCPC; - else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) && - ((config->inclk & 0x0f) == INCLK_NONE)) - reg |= 5 << AOCPC; - else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) { - tmp = - asrc_get_asrck_clock_divider(config-> - output_sample_rate); - reg |= tmp << AOCPC; - } else { - if (config->output_word_width == ASRC_WIDTH_16_BIT) - reg |= 5 << AOCPC; - else if (config->output_word_width == ASRC_WIDTH_24_BIT) - reg |= 6 << AOCPC; - else - err = -EFAULT; - } - __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCDR2_REG); - + if (config->input_word_width == ASRC_WIDTH_16_BIT) + reg |= 5 << aicp_shift; + else if (config->input_word_width == ASRC_WIDTH_24_BIT) + reg |= 6 << aicp_shift; + else + err = -EFAULT; } + /* Output Part */ + if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX) + reg |= 7 << aocp_shift; + else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX) + reg |= 6 << aocp_shift; + else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) + && ((config->inclk & 0x0f) == INCLK_NONE)) + reg |= 5 << aocp_shift; + else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) { + tmp = asrc_get_asrck_clock_divider(config->output_sample_rate); + reg |= tmp << aocp_shift; + } else { + if (config->output_word_width == ASRC_WIDTH_16_BIT) + reg |= 5 << aocp_shift; + else if (config->output_word_width == ASRC_WIDTH_24_BIT) + reg |= 6 << aocp_shift; + else + err = -EFAULT; + } + __raw_writel(reg, g_asrc->vaddr + asrc_asrcdr_reg); /* check whether ideal ratio is a must */ if ((config->inclk & 0x0f) == INCLK_NONE) { @@ -597,25 +537,6 @@ int asrc_config_pair(struct asrc_config *config) } } - if ((config->inclk == INCLK_NONE) && - (config->outclk == OUTCLK_ESAI_TX)) { - reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCTR_REG); - reg &= ~(1 << (20 + config->pair)); - reg |= (0x03 << (13 + (config->pair << 1))); - __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCTR_REG); - err = asrc_set_clock_ratio(config->pair, - config->input_sample_rate, - config->output_sample_rate); - if (err < 0) - return err; - err = asrc_set_process_configuration(config->pair, - config->input_sample_rate, - config-> - output_sample_rate); - if (err < 0) - return err; - } - /* Config input and output wordwidth */ reg = __raw_readl( g_asrc->vaddr + ASRC_ASRMCR1A_REG + (config->pair << 2)); @@ -877,10 +798,10 @@ static int mxc_init_asrc(void) __raw_writel(0x001f00, g_asrc->vaddr + ASRC_ASRTFR1); /* Set the processing clock for 76KHz, 133M */ - __raw_writel(0x30E, g_asrc->vaddr + ASRC_ASR76K_REG); + __raw_writel(0x06D6, g_asrc->vaddr + ASRC_ASR76K_REG); /* Set the processing clock for 56KHz, 133M */ - __raw_writel(0x0426, g_asrc->vaddr + ASRC_ASR56K_REG); + __raw_writel(0x0947, g_asrc->vaddr + ASRC_ASR56K_REG); return 0; } @@ -1035,7 +956,7 @@ static void mxc_free_dma_buf(struct asrc_pair_params *params) } if (params->output_dma_total.dma_vaddr != NULL) { - kfree(params->input_dma_total.dma_vaddr); + kfree(params->output_dma_total.dma_vaddr); params->output_dma_total.dma_vaddr = NULL; } @@ -1847,13 +1768,26 @@ static int asrc_write_proc_attr(struct file *file, const char *buffer, total = 10; else total = 5; - if ((na + nb + nc) != total) { - pr_info("Wrong ASRCNR settings\n"); - return -EFAULT; + + if ((na + nb + nc) > total) { + pr_err("Don't surpass %d for total.\n", total); + return -EINVAL; + } else if (na % 2 != 0 || nb % 2 != 0 || nc % 2 != 0) { + pr_err("Please set an even number for each pair.\n"); + return -EINVAL; + } else if (na < 0 || nb < 0 || nc < 0) { + pr_err("Please set an positive number for each pair.\n"); + return -EINVAL; } + reg = na | (nb << g_asrc->mxc_asrc_data->channel_bits) | (nc << (g_asrc->mxc_asrc_data->channel_bits * 2)); + /* Update chn_max */ + g_asrc->asrc_pair[ASRC_PAIR_A].chn_max = na; + g_asrc->asrc_pair[ASRC_PAIR_B].chn_max = nb; + g_asrc->asrc_pair[ASRC_PAIR_C].chn_max = nc; + clk_enable(g_asrc->mxc_asrc_data->asrc_core_clk); __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCNCR_REG); clk_disable(g_asrc->mxc_asrc_data->asrc_core_clk); diff --git a/drivers/mxc/gpu-viv/Kbuild b/drivers/mxc/gpu-viv/Kbuild index 0b18a7bdcc49..93b12591986d 100644 --- a/drivers/mxc/gpu-viv/Kbuild +++ b/drivers/mxc/gpu-viv/Kbuild @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (C) 2005 - 2012 by Vivante Corp. +# Copyright (C) 2005 - 2013 by Vivante Corp. # # 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 diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c index c768d8b2b420..3e2acf2f725c 100644 --- a/drivers/mxc/ipu3/ipu_capture.c +++ b/drivers/mxc/ipu3/ipu_capture.c @@ -98,6 +98,7 @@ ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height, cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444; break; case IPU_PIX_FMT_GENERIC: + case IPU_PIX_FMT_GENERIC_16: cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; break; case IPU_PIX_FMT_RGB565: diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 563d5320cc9d..e914a9b7baa3 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -110,6 +110,17 @@ static inline int _ipu_is_primary_disp_chan(uint32_t dma_chan) (dma_chan == 28) || (dma_chan == 41)); } +static inline int _ipu_is_sync_irq(uint32_t irq) +{ + /* sync interrupt register number */ + int reg_num = irq / 32 + 1; + + return ((reg_num == 1) || (reg_num == 2) || (reg_num == 3) || + (reg_num == 4) || (reg_num == 7) || (reg_num == 8) || + (reg_num == 11) || (reg_num == 12) || (reg_num == 13) || + (reg_num == 14) || (reg_num == 15)); +} + #define idma_is_valid(ch) (ch != NO_DMA) #define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0) #define idma_is_set(ipu, reg, dma) (ipu_idmac_read(ipu, reg(dma)) & idma_mask(dma)) @@ -1166,10 +1177,17 @@ int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, rot_mode); } else if (_ipu_is_smfc_chan(dma_chan)) { burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan); - if ((pixel_fmt == IPU_PIX_FMT_GENERIC) && - ((_ipu_ch_param_get_bpp(ipu, dma_chan) == 5) || - (_ipu_ch_param_get_bpp(ipu, dma_chan) == 3))) + /* + * This is different from IPUv3 spec, but it is confirmed + * in IPUforum that SMFC burst size should be NPB[6:3] + * when IDMAC works in 16-bit generic data mode. + */ + if (pixel_fmt == IPU_PIX_FMT_GENERIC) + /* 8 bits per pixel */ burst_size = burst_size >> 4; + else if (pixel_fmt == IPU_PIX_FMT_GENERIC_16) + /* 16 bits per pixel */ + burst_size = burst_size >> 3; else burst_size = burst_size >> 2; _ipu_smfc_set_burst_size(ipu, channel, burst_size-1); @@ -2458,23 +2476,40 @@ static irqreturn_t ipu_err_irq_handler(int irq, void *desc) * @param ipu ipu handler * @param irq Interrupt line to enable interrupt for. * + * @return This function returns 0 on success or negative error code on + * fail. */ -void ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq) +int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq) { uint32_t reg; unsigned long lock_flags; + int ret = 0; _ipu_get(ipu); spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags); + /* + * Check sync interrupt handler only, since we do nothing for + * error interrupts but than print out register values in the + * error interrupt source handler. + */ + if (_ipu_is_sync_irq(irq) && (ipu->irq_list[irq].handler == NULL)) { + dev_err(ipu->dev, "handler hasn't been registered on sync " + "irq %d\n", irq); + ret = -EACCES; + goto out; + } + reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq)); reg |= IPUIRQ_2_MASK(irq); ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq)); - +out: spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags); _ipu_put(ipu); + + return ret; } EXPORT_SYMBOL(ipu_enable_irq); @@ -2586,6 +2621,7 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq, { uint32_t reg; unsigned long lock_flags; + int ret = 0; BUG_ON(irq >= IPU_IRQ_COUNT); @@ -2596,8 +2632,19 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq, if (ipu->irq_list[irq].handler != NULL) { dev_err(ipu->dev, "handler already installed on irq %d\n", irq); - spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags); - return -EINVAL; + ret = -EINVAL; + goto out; + } + + /* + * Check sync interrupt handler only, since we do nothing for + * error interrupts but than print out register values in the + * error interrupt source handler. + */ + if (_ipu_is_sync_irq(irq) && (handler == NULL)) { + dev_err(ipu->dev, "handler is NULL for sync irq %d\n", irq); + ret = -EINVAL; + goto out; } ipu->irq_list[irq].handler = handler; @@ -2611,12 +2658,12 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq, reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq)); reg |= IPUIRQ_2_MASK(irq); ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq)); - +out: spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags); _ipu_put(ipu); - return 0; + return ret; } EXPORT_SYMBOL(ipu_request_irq); @@ -2791,6 +2838,7 @@ uint32_t bytes_per_pixel(uint32_t fmt) case IPU_PIX_FMT_YUV444P: return 1; break; + case IPU_PIX_FMT_GENERIC_16: /* generic data */ case IPU_PIX_FMT_RGB565: case IPU_PIX_FMT_YUYV: case IPU_PIX_FMT_UYVY: @@ -2798,6 +2846,7 @@ uint32_t bytes_per_pixel(uint32_t fmt) break; case IPU_PIX_FMT_BGR24: case IPU_PIX_FMT_RGB24: + case IPU_PIX_FMT_YUV444: return 3; break; case IPU_PIX_FMT_GENERIC_32: /*generic data */ diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index cdf76b0ca68c..b10ce2a16f3a 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -680,6 +680,11 @@ static void dump_check_warn(struct device *dev, int warn) static int set_crop(struct ipu_crop *crop, int width, int height, int fmt) { + if ((width == 0) || (height == 0)) { + pr_err("Invalid param: width=%d, height=%d\n", width, height); + return -EINVAL; + } + if ((IPU_PIX_FMT_TILED_NV12 == fmt) || (IPU_PIX_FMT_TILED_NV12F == fmt)) { if (crop->w || crop->h) { @@ -719,6 +724,12 @@ static int set_crop(struct ipu_crop *crop, int width, int height, int fmt) crop->h -= crop->h%8; } + if ((crop->w == 0) || (crop->h == 0)) { + pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n", + crop->w, crop->h); + return -EINVAL; + } + return 0; } @@ -733,26 +744,28 @@ static void update_offset(unsigned int fmt, case IPU_PIX_FMT_YUV420P: *off = pos_y * width + pos_x; *uoff = (width * (height - pos_y) - pos_x) - + ((width/2 * pos_y/2) + pos_x/2); - *voff = *uoff + (width/2 * height/2); + + (width/2) * (pos_y/2) + pos_x/2; + /* In case height is odd, round up to even */ + *voff = *uoff + (width/2) * ((height+1)/2); break; case IPU_PIX_FMT_YVU420P: *off = pos_y * width + pos_x; *voff = (width * (height - pos_y) - pos_x) - + ((width/2 * pos_y/2) + pos_x/2); - *uoff = *voff + (width/2 * height/2); + + (width/2) * (pos_y/2) + pos_x/2; + /* In case height is odd, round up to even */ + *uoff = *voff + (width/2) * ((height+1)/2); break; case IPU_PIX_FMT_YVU422P: *off = pos_y * width + pos_x; *voff = (width * (height - pos_y) - pos_x) - + ((width * pos_y)/2 + pos_x/2); - *uoff = *voff + (width * height)/2; + + (width/2) * pos_y + pos_x/2; + *uoff = *voff + (width/2) * height; break; case IPU_PIX_FMT_YUV422P: *off = pos_y * width + pos_x; *uoff = (width * (height - pos_y) - pos_x) - + (width * pos_y)/2 + pos_x/2; - *voff = *uoff + (width * height)/2; + + (width/2) * pos_y + pos_x/2; + *voff = *uoff + (width/2) * height; break; case IPU_PIX_FMT_YUV444P: *off = pos_y * width + pos_x; @@ -762,7 +775,7 @@ static void update_offset(unsigned int fmt, case IPU_PIX_FMT_NV12: *off = pos_y * width + pos_x; *uoff = (width * (height - pos_y) - pos_x) - + width * pos_y/2 + pos_x; + + width * (pos_y/2) + pos_x; break; case IPU_PIX_FMT_TILED_NV12: /* @@ -799,6 +812,7 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split) struct stripe_param down_stripe; u32 iw, ih, ow, oh; u32 max_width; + int ret; if (t->output.rotate >= IPU_ROTATE_90_RIGHT) return IPU_CHECK_ERR_SPLIT_WITH_ROT; @@ -809,12 +823,26 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split) ow = t->output.crop.w; oh = t->output.crop.h; + memset(&left_stripe, 0, sizeof(left_stripe)); + memset(&right_stripe, 0, sizeof(right_stripe)); + memset(&up_stripe, 0, sizeof(up_stripe)); + memset(&down_stripe, 0, sizeof(down_stripe)); + if (t->set.split_mode & RL_SPLIT) { + /* + * We do want equal strips: initialize stripes in case + * calc_stripes returns before actually doing the calculation + */ + left_stripe.input_width = iw / 2; + left_stripe.output_width = ow / 2; + right_stripe.input_column = iw / 2; + right_stripe.output_column = ow / 2; + if (vdi_split) max_width = soc_max_vdi_in_width(); else max_width = soc_max_out_width(); - ipu_calc_stripes_sizes(iw, + ret = ipu_calc_stripes_sizes(iw, ow, max_width, (((unsigned long long)1) << 32), /* 32bit for fractional*/ @@ -823,6 +851,9 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split) t->output.format, &left_stripe, &right_stripe); + if (ret) + dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n", + t->task_no, ret); t->set.sp_setting.iw = left_stripe.input_width; t->set.sp_setting.ow = left_stripe.output_width; t->set.sp_setting.outh_resize_ratio = left_stripe.irr; @@ -846,7 +877,15 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split) return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER; if (t->set.split_mode & UD_SPLIT) { - ipu_calc_stripes_sizes(ih, + /* + * We do want equal strips: initialize stripes in case + * calc_stripes returns before actually doing the calculation + */ + up_stripe.input_width = ih / 2; + up_stripe.output_width = oh / 2; + down_stripe.input_column = ih / 2; + down_stripe.output_column = oh / 2; + ret = ipu_calc_stripes_sizes(ih, oh, soc_max_out_height(), (((unsigned long long)1) << 32), /* 32bit for fractional*/ @@ -855,6 +894,9 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split) t->output.format, &up_stripe, &down_stripe); + if (ret) + dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n", + t->task_no, ret); t->set.sp_setting.ih = up_stripe.input_width; t->set.sp_setting.oh = up_stripe.output_width; t->set.sp_setting.outv_resize_ratio = up_stripe.irr; diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c index 35b78199b0df..87fa001b8246 100644 --- a/drivers/mxc/ipu3/ipu_disp.c +++ b/drivers/mxc/ipu3/ipu_disp.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -61,7 +61,7 @@ static unsigned long _ipu_pixel_clk_get_rate(struct clk *clk) { struct ipu_soc *ipu = pixelclk2ipu(clk); u32 div; - u64 final_rate = clk_get_rate(clk->parent) * 16; + u64 final_rate = (unsigned long long)clk_get_rate(clk->parent) * 16; _ipu_get(ipu); div = ipu_di_read(ipu, clk->id, DI_BS_CLKGEN0); @@ -1297,6 +1297,10 @@ int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk, msleep(5); /* Get integer portion of divider */ div = clk_get_rate(clk_get_parent(&ipu->pixel_clk[disp])) / rounded_pixel_clk; + if (!div) { + dev_err(ipu->dev, "invalid pixel clk div = 0\n"); + return -EINVAL; + } mutex_lock(&ipu->mutex_lock); diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h index 1387c4948446..6d0a470dfef1 100644 --- a/drivers/mxc/ipu3/ipu_param_mem.h +++ b/drivers/mxc/ipu3/ipu_param_mem.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -285,6 +285,13 @@ static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch, ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); /* burst size */ break; + case IPU_PIX_FMT_GENERIC_16: + /* Represents 16-bit generic data */ + ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ + ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */ + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ + + break; case IPU_PIX_FMT_GENERIC_32: /*Represents 32-bit Generic data */ break; @@ -695,6 +702,7 @@ static inline void _ipu_ch_offset_update(struct ipu_soc *ipu, switch (pixel_fmt) { case IPU_PIX_FMT_GENERIC: + case IPU_PIX_FMT_GENERIC_16: case IPU_PIX_FMT_GENERIC_32: case IPU_PIX_FMT_RGB565: case IPU_PIX_FMT_BGR24: diff --git a/drivers/mxc/mlb/mxc_mlb150.c b/drivers/mxc/mlb/mxc_mlb150.c index 6b07d0f0a428..3cc0289c57b8 100755 --- a/drivers/mxc/mlb/mxc_mlb150.c +++ b/drivers/mxc/mlb/mxc_mlb150.c @@ -288,8 +288,8 @@ enum CLK_SPEED { }; struct mlb_ringbuf { - s8 *virt_bufs[TRANS_RING_NODES + 1]; - u32 phy_addrs[TRANS_RING_NODES + 1]; + s8 *virt_bufs[TRANS_RING_NODES]; + u32 phy_addrs[TRANS_RING_NODES]; s32 head; s32 tail; s32 unit_size; @@ -1538,6 +1538,11 @@ static s32 mlb150_trans_complete_check(struct mlb_dev_info *pdevinfo) return -ETIME; } + /* Interrupt from TX can only inform that the data is sent + * to AHB bus, not mean that it is sent to MITB. Thus we add + * a delay here for data to be completed sent. */ + udelay(1000); + return 0; } @@ -1902,24 +1907,27 @@ static int mxc_mlb150_open(struct inode *inode, struct file *filp) pr_err("can not alloc rx/tx buffers: %d\n", buf_size); return ret; } + pr_debug("IRAM Range: Virt 0x%x - 0x%x, Phys 0x%x - 0x%x, size: 0x%x\n", + buf_addr, (buf_addr + buf_size - 1), phy_addr, + (phy_addr + buf_size - 1), buf_size); pdevinfo->rbuf_base_virt = buf_addr; pdevinfo->rbuf_base_phy = phy_addr; memset(buf_addr, 0, buf_size); - for (j = 0; j < (TRANS_RING_NODES + 1); + for (j = 0; j < (TRANS_RING_NODES); ++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) { pdevinfo->rx_rbuf.virt_bufs[j] = buf_addr; pdevinfo->rx_rbuf.phy_addrs[j] = phy_addr; + pr_debug("RX Ringbuf[%d]: 0x%x 0x%x\n", j, buf_addr, phy_addr); } pdevinfo->rx_rbuf.unit_size = ring_buf_size; pdevinfo->rx_rbuf.total_size = buf_size; - buf_addr += ring_buf_size; - phy_addr += ring_buf_size; for (j = 0; j < (TRANS_RING_NODES); ++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) { pdevinfo->tx_rbuf.virt_bufs[j] = buf_addr; pdevinfo->tx_rbuf.phy_addrs[j] = phy_addr; + pr_debug("TX Ringbuf[%d]: 0x%x 0x%x\n", j, buf_addr, phy_addr); } pdevinfo->tx_rbuf.unit_size = ring_buf_size; @@ -2347,9 +2355,8 @@ static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf, /* Set ADT for TX */ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr); - } else { + } else read_unlock_irqrestore(&tx_rbuf->rb_lock, flags); - } ret = count; out: @@ -2670,10 +2677,10 @@ static int mxc_mlb150_resume(struct platform_device *pdev) { struct mlb_data *drvdata = platform_get_drvdata(pdev); - mlb150_dev_init(); - clk_enable(drvdata->clk_mlb6p); + mlb150_dev_init(); + return 0; } #else diff --git a/drivers/mxc/thermal/thermal.c b/drivers/mxc/thermal/thermal.c index 4931ce1fa252..0cc5e5973271 100644 --- a/drivers/mxc/thermal/thermal.c +++ b/drivers/mxc/thermal/thermal.c @@ -277,6 +277,7 @@ static int anatop_thermal_get_temp(struct thermal_zone_device *thermal, struct anatop_thermal *tz = thermal->devdata; unsigned int tmp; unsigned int reg; + unsigned int val; if (!tz) return -EINVAL; @@ -311,11 +312,16 @@ static int anatop_thermal_get_temp(struct thermal_zone_device *thermal, anatop_base + HW_ANADIG_TEMPSENSE0_SET); tmp = 0; + val = jiffies; /* read temperature values */ while ((__raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0) - & BM_ANADIG_TEMPSENSE0_FINISHED) == 0) + & BM_ANADIG_TEMPSENSE0_FINISHED) == 0) { + if (time_after(jiffies, (unsigned long)(val + HZ / 2))) { + pr_info("Thermal sensor timeout, retry!\n"); + return 0; + } msleep(10); - + } reg = __raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0); tmp = (reg & BM_ANADIG_TEMPSENSE0_TEMP_VALUE) >> BP_ANADIG_TEMPSENSE0_TEMP_VALUE; @@ -339,6 +345,11 @@ static int anatop_thermal_get_temp(struct thermal_zone_device *thermal, *temp = (cooling_device_disable && tz->temperature >= KELVIN_TO_CEL(TEMP_CRITICAL, KELVIN_OFFSET)) ? KELVIN_TO_CEL(TEMP_CRITICAL - 1, KELVIN_OFFSET) : tz->temperature; + /* Set alarm threshold if necessary */ + if ((__raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0) & + BM_ANADIG_TEMPSENSE0_ALARM_VALUE) == 0) + anatop_update_alarm(raw_critical); + return 0; } @@ -883,7 +894,7 @@ static int anatop_thermal_counting_ratio(unsigned int fuse_data) raw_hot = (fuse_data & 0xfff00) >> 8; hot_temp = fuse_data & 0xff; - if (!calibration_valid && !cpu_is_mx6sl()) + if (!calibration_valid) /* * The universal equation for thermal sensor * is slope = 0.4297157 - (0.0015976 * 25C fuse), @@ -901,7 +912,6 @@ static int anatop_thermal_counting_ratio(unsigned int fuse_data) /* Init default critical temp to set alarm */ raw_critical = raw_25c - ratio * (KELVIN_TO_CEL(TEMP_CRITICAL, KELVIN_OFFSET) - 25) / 100; clk_enable(pll3_clk); - anatop_update_alarm(raw_critical); return ret; } diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c index 708e8e97112a..8c36d6abf852 100644 --- a/drivers/mxc/vpu/mxc_vpu.c +++ b/drivers/mxc/vpu/mxc_vpu.c @@ -126,7 +126,7 @@ static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem) mem->cpu_addr = (unsigned long) dma_alloc_coherent(NULL, PAGE_ALIGN(mem->size), (dma_addr_t *) (&mem->phy_addr), - GFP_DMA | GFP_KERNEL); + GFP_DMA | GFP_KERNEL | __GFP_NOFAIL); pr_debug("[ALLOC] mem alloc cpu_addr = 0x%x\n", mem->cpu_addr); if ((void *)(mem->cpu_addr) == NULL) { printk(KERN_ERR "Physical memory allocation error!\n"); @@ -258,7 +258,7 @@ static int vpu_open(struct inode *inode, struct file *filp) #ifdef CONFIG_SOC_IMX6Q clk_enable(vpu_clk); if (READ_REG(BIT_CUR_PC)) - printk(KERN_DEBUG "Not power off before vpu open!\n"); + pr_debug("Not power off before vpu open!\n"); clk_disable(vpu_clk); #endif } @@ -528,6 +528,20 @@ static long vpu_ioctl(struct file *filp, u_int cmd, } break; } + case VPU_IOC_LOCK_DEV: + { + u32 lock_en; + + if (get_user(lock_en, (u32 __user *) arg)) + return -EFAULT; + + if (lock_en) + mutex_lock(&vpu_data.lock); + else + mutex_unlock(&vpu_data.lock); + + break; + } default: { printk(KERN_ERR "No such IOCTL, cmd is %d\n", cmd); @@ -1055,6 +1069,16 @@ static void __exit vpu_exit(void) vpu_free_dma_buffer(&pic_para_mem); vpu_free_dma_buffer(&user_data_mem); + /* reset VPU state */ + if (!IS_ERR(vpu_regulator)) + regulator_enable(vpu_regulator); + clk_enable(vpu_clk); + if (vpu_plat->reset) + vpu_plat->reset(); + clk_disable(vpu_clk); + if (!IS_ERR(vpu_regulator)) + regulator_disable(vpu_regulator); + clk_put(vpu_clk); platform_driver_unregister(&mxcvpu_driver); diff --git a/drivers/net/fec.c b/drivers/net/fec.c index ebb09eb9a6f2..d2fea018f927 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -636,7 +636,7 @@ static int fec_rx_poll(struct napi_struct *napi, int budget) data = (__u8 *)__va(bdp->cbd_bufaddr); if (bdp->cbd_bufaddr) - dma_unmap_single(&ndev->dev, bdp->cbd_bufaddr, + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) @@ -664,7 +664,7 @@ static int fec_rx_poll(struct napi_struct *napi, int budget) netif_receive_skb(skb); } - bdp->cbd_bufaddr = dma_map_single(&ndev->dev, data, + bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); rx_processing_done: /* Clear the status flags for this buffer */ @@ -1873,32 +1873,33 @@ fec_probe(struct platform_device *pdev) if (pdata) fep->phy_interface = pdata->phy; -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - gpio_request(pdata->gpio_irq, "gpio_enet_irq"); - gpio_direction_input(pdata->gpio_irq); + if (pdata->gpio_irq < 0) { + gpio_request(pdata->gpio_irq, "gpio_enet_irq"); + gpio_direction_input(pdata->gpio_irq); - irq = gpio_to_irq(pdata->gpio_irq); - ret = request_irq(irq, fec_enet_interrupt, - IRQF_TRIGGER_RISING, - pdev->name, ndev); - if (ret) - goto failed_irq; -#else - /* This device has up to three irqs on some platforms */ - for (i = 0; i < 3; i++) { - irq = platform_get_irq(pdev, i); - if (i && irq < 0) - break; - ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); - if (ret) { - while (--i >= 0) { - irq = platform_get_irq(pdev, i); - free_irq(irq, ndev); - } + irq = gpio_to_irq(pdata->gpio_irq); + ret = request_irq(irq, fec_enet_interrupt, + IRQF_TRIGGER_RISING, + pdev->name, ndev); + if (ret) goto failed_irq; + } else { + /* This device has up to three irqs on some platforms */ + for (i = 0; i < 3; i++) { + irq = platform_get_irq(pdev, i); + if (i && irq < 0) + break; + ret = request_irq(irq, fec_enet_interrupt, + IRQF_DISABLED, pdev->name, ndev); + if (ret) { + while (--i >= 0) { + irq = platform_get_irq(pdev, i); + free_irq(irq, ndev); + } + goto failed_irq; + } } } -#endif fep->clk = clk_get(&pdev->dev, "fec_clk"); if (IS_ERR(fep->clk)) { @@ -1949,15 +1950,15 @@ failed_init: clk_disable(fep->clk); clk_put(fep->clk); failed_clk: -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - free_irq(irq, ndev); -#else - for (i = 0; i < 3; i++) { - irq = platform_get_irq(pdev, i); - if (irq > 0) - free_irq(irq, ndev); + if (pdata->gpio_irq < 0) + free_irq(irq, ndev); + else { + for (i = 0; i < 3; i++) { + irq = platform_get_irq(pdev, i); + if (irq > 0) + free_irq(irq, ndev); + } } -#endif failed_irq: iounmap(fep->hwp); failed_ioremap: diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 8ab80b70d276..bd356c40cec5 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -631,9 +631,9 @@ static int pfuze100_regulator_set_voltage_time_sel(struct regulator_dev *rdev, * 02: 8us, * 03: 16us, */ - step_delay >>= 5; + step_delay >>= 6; step_delay &= 0x3; - step_delay <<= 1; + step_delay = 2 << step_delay; if (pfuze100_regulators[id].voltages[old_sel] < pfuze100_regulators[id].voltages[new_sel]) diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index f3d3d3b4ee5a..e40a8ad0e460 100755 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -70,7 +70,6 @@ #endif #define DMA_ADDR_INVALID (~(dma_addr_t)0) DEFINE_MUTEX(udc_resume_mutex); -extern void usb_debounce_id_vbus(void); static const char driver_name[] = "fsl-usb2-udc"; static const char driver_desc[] = DRIVER_DESC; @@ -960,11 +959,8 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, (unsigned)EP_MAX_LENGTH_TRANSFER); if (NEED_IRAM(req->ep)) *length = min(*length, g_iram_size); -#ifdef CONFIG_FSL_UTP + dtd = dma_pool_alloc_nonbufferable(udc_controller->td_pool, GFP_ATOMIC, dma); -#else - dtd = dma_pool_alloc(udc_controller->td_pool, GFP_ATOMIC, dma); -#endif if (dtd == NULL) return dtd; @@ -3075,10 +3071,10 @@ static int __devinit fsl_udc_probe(struct platform_device *pdev) * do platform specific init: check the clock, grab/config pins, etc. */ if (pdata->init && pdata->init(pdev)) { - pdata->lowpower = false; ret = -ENODEV; goto err2a; } + pdata->lowpower = false; spin_lock_init(&pdata->lock); @@ -3234,6 +3230,7 @@ err4: err3: free_irq(udc_controller->irq, udc_controller); err2: + dr_phy_low_power_mode(udc_controller, true); if (pdata->exit) pdata->exit(pdata->pdev); err2a: @@ -3269,6 +3266,8 @@ static int fsl_udc_remove(struct platform_device *pdev) dr_wake_up_enable(udc_controller, false); dr_discharge_line(pdata, true); + + dr_clk_gate(false); /* DR has been stopped in usb_gadget_unregister_driver() */ remove_proc_file(); @@ -3303,9 +3302,9 @@ static int fsl_udc_remove(struct platform_device *pdev) device_unregister(&udc_controller->gadget.dev); /* free udc --wait for the release() finished */ wait_for_completion(&done); + /* - * do platform specific un-initialization: - * release iomux pins, etc. + * do platform specific un-initialization */ if (pdata->exit) pdata->exit(pdata->pdev); @@ -3449,7 +3448,6 @@ static int fsl_udc_resume(struct platform_device *pdev) u32 temp; if (udc_controller->stopped) dr_clk_gate(true); - usb_debounce_id_vbus(); if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) { temp = fsl_readl(&dr_regs->otgsc); /* if b_session_irq_en is cleared by otg */ @@ -3496,7 +3494,6 @@ static int fsl_udc_resume(struct platform_device *pdev) dr_clk_gate(true); dr_wake_up_enable(udc_controller, false); dr_phy_low_power_mode(udc_controller, false); - usb_debounce_id_vbus(); /* if in host mode, we need to do nothing */ if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) { dr_phy_low_power_mode(udc_controller, true); diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index e2000bd2e635..dde47dd76e5f 100755 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -246,10 +246,10 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver, * do platform specific init: check the clock, grab/config pins, etc. */ if (pdata->init && pdata->init(pdev)) { - pdata->lowpower = false; retval = -ENODEV; goto err4; } + pdata->lowpower = false; spin_lock_init(&pdata->lock); @@ -315,6 +315,9 @@ err2: usb_put_hcd(hcd); err1: dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); + fsl_usb_lowpower_mode(pdata, true); + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); if (pdata->exit && pdata->pdev) pdata->exit(pdata->pdev); return retval; @@ -333,7 +336,6 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - u32 tmp; if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { /* Need open clock for register access */ @@ -343,40 +345,44 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, /*disable the wakeup to avoid an abnormal wakeup interrupt*/ usb_host_set_wakeup(hcd->self.controller, false); - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - if (tmp & PORT_PTS_PHCD) { - tmp &= ~PORT_PTS_PHCD; - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - msleep(100); - } + /* Put the PHY out of low power mode */ + fsl_usb_lowpower_mode(pdata, false); } + /* disable the host wakeup */ + usb_host_set_wakeup(hcd->self.controller, false); + /*free the ehci_fsl_pre_irq */ + free_irq(hcd->irq, (void *)pdev); + + usb_remove_hcd(hcd); + + ehci_port_power(ehci, 0); + + iounmap(hcd->regs); + if (ehci->transceiver) { (void)otg_set_host(ehci->transceiver, 0); otg_put_transceiver(ehci->transceiver); } else { release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } - /*disable the host wakeup and put phy to low power mode */ - usb_host_set_wakeup(hcd->self.controller, false); - /*free the ehci_fsl_pre_irq */ - free_irq(hcd->irq, (void *)pdev); - usb_remove_hcd(hcd); + usb_put_hcd(hcd); fsl_usb_lowpower_mode(pdata, true); - /* DDD shouldn't we turn off the power here? */ - fsl_platform_set_vbus_power(pdata, 0); + /* Close the VBUS */ + if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power) + pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, 0); + + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); /* - * do platform specific un-initialization: - * release iomux pins clocks, etc. + * do platform specific un-initialization */ if (pdata->exit && pdata->pdev) pdata->exit(pdata->pdev); - - iounmap(hcd->regs); } static void fsl_setup_phy(struct ehci_hcd *ehci, @@ -676,17 +682,32 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, /* Only handles OTG mode switch event, system suspend event will be done in bus suspend */ if (pdata->pmflags == 0) { printk(KERN_DEBUG "%s, pm event \n", __func__); + disable_irq(hcd->irq); if (!host_can_wakeup_system(pdev)) { /* Need open clock for register access */ fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + /* + * Disable wakeup interrupt, since there is wakeup + * when phcd from 1->0 if wakeup interrupt is enabled + */ + usb_host_set_wakeup(hcd->self.controller, false); + + /* + * Open PHY's clock, then the wakeup settings + * can be wroten correctly + */ + fsl_usb_lowpower_mode(pdata, false); usb_host_set_wakeup(hcd->self.controller, false); + fsl_usb_lowpower_mode(pdata, true); + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); } else { if (pdata->platform_phy_power_on) pdata->platform_phy_power_on(); } + enable_irq(hcd->irq); printk(KERN_DEBUG "host suspend ends\n"); return 0; @@ -758,13 +779,18 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, return 0; } +#define OTGSC_OFFSET 0x64 +#define OTGSC_ID_VALUE (1 << 8) +#define OTGSC_ID_INT_STS (1 << 16) static int ehci_fsl_drv_resume(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct usb_device *roothub = hcd->self.root_hub; unsigned long flags; - u32 tmp; + u32 tmp, otgsc; + bool id_changed; + int id_value; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; struct fsl_usb2_wakeup_platform_data *wake_up_pdata = pdata->wakeup_pdata; /* Only handles OTG mode switch event */ @@ -772,29 +798,36 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) if (pdata->pmflags == 0) { printk(KERN_DEBUG "%s,pm event, wait for wakeup irq if needed\n", __func__); wait_event_interruptible(wake_up_pdata->wq, !wake_up_pdata->usb_wakeup_is_pending); + disable_irq(hcd->irq); if (!host_can_wakeup_system(pdev)) { /* Need open clock for register access */ fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + fsl_usb_lowpower_mode(pdata, false); - usb_host_set_wakeup(hcd->self.controller, true); - -#ifndef NO_FIX_DISCONNECT_ISSUE - /*Unplug&plug device during suspend without remote wakeup enabled - For Low and full speed device, we should power on and power off - the USB port to make sure USB internal state machine work well. - */ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - if ((tmp & PORT_CONNECT) && !(tmp & PORT_SUSPEND) && - ((tmp & (0x3<<26)) != (0x2<<26))) { - printk(KERN_DEBUG "%s will do power off and power on port.\n", pdata->name); - ehci_writel(ehci, tmp & ~(PORT_RWC_BITS | PORT_POWER), - &ehci->regs->port_status[0]); - ehci_writel(ehci, tmp | PORT_POWER, - &ehci->regs->port_status[0]); + if (pdata->operating_mode == FSL_USB2_DR_OTG) { + otgsc = ehci_readl(ehci, (u32 __iomem *)ehci->regs + OTGSC_OFFSET / 4); + id_changed = !!(otgsc & OTGSC_ID_INT_STS); + id_value = !!(otgsc & OTGSC_ID_VALUE); + if (((tmp & PORT_CONNECT) && !id_value) || id_changed) { + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + } else if (!(tmp & PORT_CONNECT)) { + usb_host_set_wakeup(hcd->self.controller, true); + fsl_usb_lowpower_mode(pdata, true); + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + } + } else { + if (tmp & PORT_CONNECT) { + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + } else { + usb_host_set_wakeup(hcd->self.controller, true); + fsl_usb_lowpower_mode(pdata, true); + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + } + } -#endif - fsl_usb_clk_gate(hcd->self.controller->platform_data, false); } + enable_irq(hcd->irq); return 0; } if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index 9fd3c87babfb..00bd2e609525 100755 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -690,9 +690,16 @@ static int fsl_otg_set_peripheral(struct otg_transceiver *otg_p, return -ENODEV; if (!gadget) { - if (!otg_dev->otg.default_a) + /* + * At i.mx platform, we still not implement fully + * OTG. + */ + /* + if (!otg_dev->otg.default_a) { otg_p->gadget->ops->vbus_draw(otg_p->gadget, 0); - usb_gadget_vbus_disconnect(otg_dev->otg.gadget); + usb_gadget_vbus_disconnect(otg_dev->otg.gadget); + } + */ otg_dev->otg.gadget = 0; otg_dev->fsm.b_bus_req = 0; pdata->port_enables = 0; diff --git a/drivers/video/mxc/mxc_edid.c b/drivers/video/mxc/mxc_edid.c index a3e374bc5158..721ff88660df 100644 --- a/drivers/video/mxc/mxc_edid.c +++ b/drivers/video/mxc/mxc_edid.c @@ -207,7 +207,9 @@ int mxc_edid_fb_mode_is_equal(bool use_aspect, mode1->upper_margin == mode2->upper_margin && mode1->lower_margin == mode2->lower_margin && mode1->sync == mode2->sync && - mode1->refresh == mode2->refresh && + /* refresh check, 59.94Hz and 60Hz have the same parameter + * in struct of mxc_cea_mode */ + abs(mode1->refresh - mode2->refresh) <= 1 && (mode1->vmode & mask) == (mode2->vmode & mask)); } diff --git a/drivers/video/mxc/mxc_elcdif_fb.c b/drivers/video/mxc/mxc_elcdif_fb.c index 0fd076537fb8..ebec7bcfcfa6 100644 --- a/drivers/video/mxc/mxc_elcdif_fb.c +++ b/drivers/video/mxc/mxc_elcdif_fb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. */ /* @@ -940,14 +940,14 @@ static int mxc_elcdif_fb_set_par(struct fb_info *fbi) setup_dotclk_panel((PICOS2KHZ(fbi->var.pixclock)) * 1000UL, fbi->var.vsync_len, - fbi->var.upper_margin + - fbi->var.yres + fbi->var.lower_margin, - fbi->var.upper_margin, + fbi->var.upper_margin + fbi->var.yres + + fbi->var.lower_margin + fbi->var.vsync_len, + fbi->var.upper_margin + fbi->var.vsync_len, fbi->var.yres, fbi->var.hsync_len, - fbi->var.left_margin + - fbi->var.xres + fbi->var.right_margin, - fbi->var.left_margin, + fbi->var.left_margin + fbi->var.xres + + fbi->var.right_margin + fbi->var.hsync_len, + fbi->var.left_margin + fbi->var.hsync_len, fbi->var.xres, bpp_to_pixfmt(fbi), data->output_pix_fmt, diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c index 1122e219642b..4103498dc1b0 100644 --- a/drivers/video/mxc/mxc_epdc_fb.c +++ b/drivers/video/mxc/mxc_epdc_fb.c @@ -2253,7 +2253,7 @@ static int epdc_submit_merge(struct update_desc_list *upd_desc_list, /* Merged update should take on the earliest order */ upd_desc_list->update_order = (upd_desc_list->update_order > update_to_merge->update_order) ? - update_to_merge->update_order : upd_desc_list->update_order; + upd_desc_list->update_order : update_to_merge->update_order; return MERGE_OK; } diff --git a/drivers/video/mxc/mxcfb_sii902x_elcdif.c b/drivers/video/mxc/mxcfb_sii902x_elcdif.c index ceab3e66e91c..ecba5b8b380d 100644 --- a/drivers/video/mxc/mxcfb_sii902x_elcdif.c +++ b/drivers/video/mxc/mxcfb_sii902x_elcdif.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -238,11 +238,6 @@ static void det_worker(struct work_struct *work) dev_dbg(&sii902x.pdev->dev, "EVENT=plugin\n"); sprintf(event_string, "EVENT=plugin"); - /* make sure fb is powerdown */ - console_lock(); - fb_blank(sii902x.fbi, FB_BLANK_POWERDOWN); - console_unlock(); - if (sii902x_read_edid(sii902x.fbi) < 0) dev_err(&sii902x.client->dev, "Sii902x: read edid fail\n"); @@ -286,18 +281,15 @@ static void det_worker(struct work_struct *work) sii902x.fbi->flags &= ~FBINFO_MISC_USEREVENT; console_unlock(); } - - console_lock(); - fb_blank(sii902x.fbi, FB_BLANK_UNBLANK); - console_unlock(); + /* Power on sii902x */ + sii902x_poweron(); } } else { sii902x.cable_plugin = 0; dev_dbg(&sii902x.pdev->dev, "EVENT=plugout\n"); sprintf(event_string, "EVENT=plugout"); - console_lock(); - fb_blank(sii902x.fbi, FB_BLANK_POWERDOWN); - console_unlock(); + /* Power off sii902x */ + sii902x_poweroff(); } kobject_uevent_env(&sii902x.pdev->dev.kobj, KOBJ_CHANGE, envp); } @@ -461,18 +453,6 @@ static int __devexit sii902x_remove(struct i2c_client *client) return 0; } -static int sii902x_suspend(struct i2c_client *client, pm_message_t message) -{ - /*TODO*/ - return 0; -} - -static int sii902x_resume(struct i2c_client *client) -{ - /*TODO*/ - return 0; -} - static void sii902x_poweron(void) { struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data; @@ -522,8 +502,6 @@ static struct i2c_driver sii902x_i2c_driver = { }, .probe = sii902x_probe, .remove = sii902x_remove, - .suspend = sii902x_suspend, - .resume = sii902x_resume, .id_table = sii902x_id, }; diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c index 9c9620c67f1d..8902fb2b0b5e 100644 --- a/drivers/video/mxc_hdmi.c +++ b/drivers/video/mxc_hdmi.c @@ -54,6 +54,7 @@ #include <linux/types.h> #include <linux/switch.h> +#include "edid.h" #include <mach/mxc_edid.h> #include "mxc/mxc_dispdrv.h" @@ -167,6 +168,7 @@ struct mxc_hdmi { struct clk *hdmi_isfr_clk; struct clk *hdmi_iahb_clk; struct delayed_work hotplug_work; + struct delayed_work hdcp_hdp_work; struct notifier_block nb; struct hdmi_data_info hdmi_data; @@ -192,7 +194,10 @@ struct mxc_hdmi { struct switch_dev sdev_display; }; +static int hdmi_major; +static struct class *hdmi_class; struct i2c_client *hdmi_i2c; +struct mxc_hdmi *g_hdmi; static bool hdmi_inited; @@ -200,6 +205,8 @@ extern const struct fb_videomode mxc_cea_mode[64]; extern void mxc_hdmi_cec_handle(u16 cec_stat); static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event); +static void mxc_hdmi_enable_pins(struct mxc_hdmi *hdmi); +static void mxc_hdmi_disable_pins(struct mxc_hdmi *hdmi); #ifdef DEBUG static void dump_fb_videomode(struct fb_videomode *m) @@ -296,6 +303,51 @@ static DEVICE_ATTR(rgb_out_enable, S_IRUGO | S_IWUSR, mxc_hdmi_show_rgb_out_enable, mxc_hdmi_store_rgb_out_enable); +static ssize_t mxc_hdmi_show_hdcp_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mxc_hdmi *hdmi = dev_get_drvdata(dev); + + if (hdmi->hdmi_data.hdcp_enable == false) + strcpy(buf, "hdcp disable\n"); + else + strcpy(buf, "hdcp enable\n"); + + return strlen(buf); +} + +static ssize_t mxc_hdmi_store_hdcp_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mxc_hdmi *hdmi = dev_get_drvdata(dev); + char event_string[32]; + char *envp[] = { event_string, NULL }; + unsigned long value; + int ret; + + ret = strict_strtoul(buf, 10, &value); + if (ret) + return ret; + + hdmi->hdmi_data.hdcp_enable = value; + + /* Reconfig HDMI for HDCP */ + mxc_hdmi_setup(hdmi, 0); + + if (hdmi->hdmi_data.hdcp_enable == false) { + sprintf(event_string, "EVENT=hdcpdisable"); + kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp); + } else { + sprintf(event_string, "EVENT=hdcpenable"); + kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp); + } + + return count; + +} + +static DEVICE_ATTR(hdcp_enable, S_IRUGO | S_IWUSR, + mxc_hdmi_show_hdcp_enable, mxc_hdmi_store_hdcp_enable); /*! * this submodule is responsible for the video data synchronization. @@ -830,6 +882,45 @@ static int hdmi_phy_i2c_write_verify(struct mxc_hdmi *hdmi, unsigned short data, } #endif +static bool hdmi_edid_wait_i2c_done(struct mxc_hdmi *hdmi, int msec) +{ + unsigned char val = 0; + val = hdmi_readb(HDMI_IH_I2CM_STAT0) & 0x2; + while (val == 0) { + udelay(1000); + if (msec-- == 0) { + dev_dbg(&hdmi->pdev->dev, + "HDMI EDID i2c operation time out!!\n"); + return false; + } + val = hdmi_readb(HDMI_IH_I2CM_STAT0) & 0x2; + } + return true; +} + +static u8 hdmi_edid_i2c_read(struct mxc_hdmi *hdmi, + u8 addr, u8 blockno) +{ + u8 spointer = blockno / 2; + u8 edidaddress = ((blockno % 2) * 0x80) + addr; + u8 data; + + hdmi_writeb(0xFF, HDMI_IH_I2CM_STAT0); + hdmi_writeb(edidaddress, HDMI_I2CM_ADDRESS); + hdmi_writeb(spointer, HDMI_I2CM_SEGADDR); + if (spointer == 0) + hdmi_writeb(HDMI_I2CM_OPERATION_READ, + HDMI_I2CM_OPERATION); + else + hdmi_writeb(HDMI_I2CM_OPERATION_READ_EXT, + HDMI_I2CM_OPERATION); + + hdmi_edid_wait_i2c_done(hdmi, 1000); + data = hdmi_readb(HDMI_I2CM_DATAI); + hdmi_writeb(0xFF, HDMI_IH_I2CM_STAT0); + return data; +} + /* "Power-down enable (active low)" * That mean that power up == 1! */ static void mxc_hdmi_phy_enable_power(u8 enable) @@ -1174,28 +1265,13 @@ static void mxc_hdmi_phy_init(struct mxc_hdmi *hdmi) static void hdmi_tx_hdcp_config(struct mxc_hdmi *hdmi) { - u8 de, val; - - if (hdmi->hdmi_data.video_mode.mDataEnablePolarity) - de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; - else - de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW; - - /* disable rx detect */ - val = hdmi_readb(HDMI_A_HDCPCFG0); - val &= HDMI_A_HDCPCFG0_RXDETECT_MASK; - val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE; - hdmi_writeb(val, HDMI_A_HDCPCFG0); - - val = hdmi_readb(HDMI_A_VIDPOLCFG); - val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK; - val |= de; - hdmi_writeb(val, HDMI_A_VIDPOLCFG); - - val = hdmi_readb(HDMI_A_HDCPCFG1); - val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK; - val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE; - hdmi_writeb(val, HDMI_A_HDCPCFG1); + if (hdmi->hdmi_data.hdcp_enable) { + /* Enable HDMI DDC pin */ + mxc_hdmi_enable_pins(hdmi); + } else { + /* Disable HDMI DDC pin */ + mxc_hdmi_disable_pins(hdmi); + } } static void hdmi_config_AVI(struct mxc_hdmi *hdmi) @@ -1422,19 +1498,131 @@ static void hdmi_av_composer(struct mxc_hdmi *hdmi) dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__); } +static int mxc_edid_read_internal(struct mxc_hdmi *hdmi, unsigned char *edid, + struct mxc_edid_cfg *cfg, struct fb_info *fbi) +{ + int extblknum; + int i, j, ret; + unsigned char *ediddata = edid; + unsigned char tmpedid[EDID_LENGTH]; + + dev_info(&hdmi->pdev->dev, "%s\n", __func__); + + if (!edid || !cfg || !fbi) + return -EINVAL; + + /* init HDMI I2CM for read edid*/ + hdmi_writeb(0x0, HDMI_I2CM_DIV); + hdmi_writeb(0x00, HDMI_I2CM_SS_SCL_HCNT_1_ADDR); + hdmi_writeb(0x79, HDMI_I2CM_SS_SCL_HCNT_0_ADDR); + hdmi_writeb(0x00, HDMI_I2CM_SS_SCL_LCNT_1_ADDR); + hdmi_writeb(0x91, HDMI_I2CM_SS_SCL_LCNT_0_ADDR); + + hdmi_writeb(0x00, HDMI_I2CM_FS_SCL_HCNT_1_ADDR); + hdmi_writeb(0x0F, HDMI_I2CM_FS_SCL_HCNT_0_ADDR); + hdmi_writeb(0x00, HDMI_I2CM_FS_SCL_LCNT_1_ADDR); + hdmi_writeb(0x21, HDMI_I2CM_FS_SCL_LCNT_0_ADDR); + + hdmi_writeb(0x50, HDMI_I2CM_SLAVE); + hdmi_writeb(0x30, HDMI_I2CM_SEGADDR); + + /* Umask edid interrupt */ + hdmi_writeb(HDMI_I2CM_INT_DONE_POL, + HDMI_I2CM_INT); + + hdmi_writeb(HDMI_I2CM_CTLINT_NAC_POL | + HDMI_I2CM_CTLINT_ARBITRATION_POL, + HDMI_I2CM_CTLINT); + + /* reset edid data zero */ + memset(edid, 0, EDID_LENGTH*4); + memset(cfg, 0, sizeof(struct mxc_edid_cfg)); + + /* Check first three byte of EDID head */ + if (!(hdmi_edid_i2c_read(hdmi, 0, 0) == 0x00) || + !(hdmi_edid_i2c_read(hdmi, 1, 0) == 0xFF) || + !(hdmi_edid_i2c_read(hdmi, 2, 0) == 0xFF)) { + dev_info(&hdmi->pdev->dev, "EDID head check failed!"); + return -ENOENT; + } + + for (i = 0; i < 128; i++) { + *ediddata = hdmi_edid_i2c_read(hdmi, i, 0); + ediddata++; + } + + extblknum = edid[0x7E]; + if (extblknum < 0) + return extblknum; + + if (extblknum) { + ediddata = edid + EDID_LENGTH; + for (i = 0; i < 128; i++) { + *ediddata = hdmi_edid_i2c_read(hdmi, i, 1); + ediddata++; + } + } + + /* edid first block parsing */ + memset(&fbi->monspecs, 0, sizeof(fbi->monspecs)); + fb_edid_to_monspecs(edid, &fbi->monspecs); + + ret = mxc_edid_parse_ext_blk(edid + EDID_LENGTH, + cfg, &fbi->monspecs); + if (ret < 0) + return -ENOENT; + + /* need read segment block? */ + if (extblknum > 1) { + for (j = 1; j <= extblknum; j++) { + for (i = 0; i < 128; i++) + *(tmpedid + 1) = hdmi_edid_i2c_read(hdmi, i, j); + + /* edid ext block parsing */ + ret = mxc_edid_parse_ext_blk(tmpedid + EDID_LENGTH, + cfg, &fbi->monspecs); + if (ret < 0) + return -ENOENT; + } + } + + return 0; +} + static int mxc_hdmi_read_edid(struct mxc_hdmi *hdmi) { int ret; u8 edid_old[HDMI_EDID_LEN]; + u8 clkdis; dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); /* save old edid */ memcpy(edid_old, hdmi->edid, HDMI_EDID_LEN); - ret = mxc_edid_read(hdmi_i2c->adapter, hdmi_i2c->addr, hdmi->edid, + if (!hdmi->hdmi_data.hdcp_enable) + ret = mxc_edid_read(hdmi_i2c->adapter, hdmi_i2c->addr, + hdmi->edid, &hdmi->edid_cfg, hdmi->fbi); + else { + + /* Disable HDCP clk */ + if (hdmi->hdmi_data.hdcp_enable) { + clkdis = hdmi_readb(HDMI_MC_CLKDIS); + clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE; + hdmi_writeb(clkdis, HDMI_MC_CLKDIS); + } + + ret = mxc_edid_read_internal(hdmi, hdmi->edid, &hdmi->edid_cfg, hdmi->fbi); + /* Enable HDCP clk */ + if (hdmi->hdmi_data.hdcp_enable) { + clkdis = hdmi_readb(HDMI_MC_CLKDIS); + clkdis &= ~HDMI_MC_CLKDIS_HDCPCLK_DISABLE; + hdmi_writeb(clkdis, HDMI_MC_CLKDIS); + } + + } if (ret < 0) return HDMI_EDID_FAIL; @@ -1454,6 +1642,28 @@ static int mxc_hdmi_read_edid(struct mxc_hdmi *hdmi) return HDMI_EDID_SUCCESS; } +static void mxc_hdmi_enable_pins(struct mxc_hdmi *hdmi) +{ + struct fsl_mxc_hdmi_platform_data *plat = hdmi->pdev->dev.platform_data; + + dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); + + /* Enable pins to HDMI */ + if (plat->enable_pins) + plat->enable_pins(); +} + +static void mxc_hdmi_disable_pins(struct mxc_hdmi *hdmi) +{ + struct fsl_mxc_hdmi_platform_data *plat = hdmi->pdev->dev.platform_data; + + dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); + + /* Disable pins to HDMI */ + if (plat->disable_pins) + plat->disable_pins(); +} + static void mxc_hdmi_phy_disable(struct mxc_hdmi *hdmi) { dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); @@ -1696,7 +1906,7 @@ static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi) return; } - /* If video mode same as previous, init HDMI PHY and return */ + /* If video mode same as previous, init HDMI again */ if (fb_mode_is_equal(&hdmi->previous_non_vga_mode, mode)) { dev_dbg(&hdmi->pdev->dev, "%s: Video mode same as previous\n", __func__); @@ -1707,7 +1917,6 @@ static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi) } else { dev_dbg(&hdmi->pdev->dev, "%s: New video mode\n", __func__); mxc_hdmi_set_mode_to_vga_dvi(hdmi); - fb_videomode_to_var(&hdmi->fbi->var, mode); dump_fb_videomode((struct fb_videomode *)mode); mxc_hdmi_notify_fb(hdmi); @@ -1779,10 +1988,13 @@ static void mxc_hdmi_cable_disconnected(struct mxc_hdmi *hdmi) { dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); - hdmi_disable_overflow_interrupts(); + /* Disable All HDMI clock */ + hdmi_writeb(0xff, HDMI_MC_CLKDIS); mxc_hdmi_phy_disable(hdmi); + hdmi_disable_overflow_interrupts(); + hdmi->cable_plugin = false; } @@ -1794,7 +2006,7 @@ static void hotplug_worker(struct work_struct *work) u32 phy_int_stat, phy_int_pol, phy_int_mask; u8 val; unsigned long flags; - char event_string[16]; + char event_string[32]; char *envp[] = { event_string, NULL }; phy_int_stat = hdmi->latest_intr_stat; @@ -1869,6 +2081,21 @@ static void hotplug_worker(struct work_struct *work) spin_unlock_irqrestore(&hdmi->irq_lock, flags); } +static void hdcp_hdp_worker(struct work_struct *work) +{ + struct delayed_work *delay_work = to_delayed_work(work); + struct mxc_hdmi *hdmi = + container_of(delay_work, struct mxc_hdmi, hdcp_hdp_work); + char event_string[32]; + char *envp[] = { event_string, NULL }; + + /* HDCP interrupt */ + sprintf(event_string, "EVENT=hdcpint"); + kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp); + + /* Unmute interrupts in HDCP application*/ +} + static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) { struct mxc_hdmi *hdmi = data; @@ -1917,6 +2144,17 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) schedule_delayed_work(&(hdmi->hotplug_work), msecs_to_jiffies(20)); } + /* Check HDCP interrupt state */ + if (hdmi->hdmi_data.hdcp_enable) { + val = hdmi_readb(HDMI_A_APIINTSTAT); + if (val != 0) { + /* Mute interrupts until interrupt handled */ + val = 0xFF; + hdmi_writeb(val, HDMI_A_APIINTMSK); + schedule_delayed_work(&(hdmi->hdcp_hdp_work), msecs_to_jiffies(50)); + } + } + spin_unlock_irqrestore(&hdmi->irq_lock, flags); return IRQ_HANDLED; } @@ -1931,15 +2169,6 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event) fb_var_to_videomode(&m, &hdmi->fbi->var); dump_fb_videomode(&m); - /* Exit the setup if we get mode change and are already set to - * this video mode */ - if ((event == FB_EVENT_MODE_CHANGE) && - fb_mode_is_equal(&hdmi->previous_mode, &m)) { - dev_dbg(&hdmi->pdev->dev, - "%s video mode did not change.\n", __func__); - mxc_hdmi_phy_init(hdmi); - return; - } dev_dbg(&hdmi->pdev->dev, "%s - video mode changed\n", __func__); /* Save mode as 'previous_mode' so that we can know if mode changed. */ @@ -1961,17 +2190,12 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event) hdmi_disable_overflow_interrupts(); - if (hdmi->vic == 0) { - dev_dbg(&hdmi->pdev->dev, "Non-CEA mode used in HDMI\n"); + dev_dbg(&hdmi->pdev->dev, "CEA mode used vic=%d\n", hdmi->vic); + if (hdmi->edid_cfg.hdmi_cap) + hdmi->hdmi_data.video_mode.mDVI = false; + else { + dev_dbg(&hdmi->pdev->dev, "CEA mode vic=%d work in DVI\n", hdmi->vic); hdmi->hdmi_data.video_mode.mDVI = true; - } else { - dev_dbg(&hdmi->pdev->dev, "CEA mode used vic=%d\n", hdmi->vic); - if (hdmi->edid_cfg.hdmi_cap) - hdmi->hdmi_data.video_mode.mDVI = false; - else { - dev_dbg(&hdmi->pdev->dev, "CEA mode vic=%d work in DVI\n", hdmi->vic); - hdmi->hdmi_data.video_mode.mDVI = true; - } } if ((hdmi->vic == 6) || (hdmi->vic == 7) || @@ -2013,7 +2237,6 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event) /* IPU not support depth color output */ hdmi->hdmi_data.enc_color_depth = 8; hdmi->hdmi_data.pix_repet_factor = 0; - hdmi->hdmi_data.hdcp_enable = 0; hdmi->hdmi_data.video_mode.mDataEnablePolarity = true; /* HDMI Initialization Step B.1 */ @@ -2308,6 +2531,7 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp, hdmi->edid_cfg.hdmi_cap = true; INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_worker); + INIT_DELAYED_WORK(&hdmi->hdcp_hdp_work, hdcp_hdp_worker); /* Configure registers related to HDMI interrupt * generation before registering IRQ. */ @@ -2346,11 +2570,17 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp, if (ret < 0) dev_warn(&hdmi->pdev->dev, "cound not create sys node for edid\n"); + ret = device_create_file(&hdmi->pdev->dev, &dev_attr_rgb_out_enable); if (ret < 0) dev_warn(&hdmi->pdev->dev, "cound not create sys node for rgb out enable\n"); + ret = device_create_file(&hdmi->pdev->dev, &dev_attr_hdcp_enable); + if (ret < 0) + dev_warn(&hdmi->pdev->dev, + "cound not create sys node for hdcp enable\n"); + dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__); hdmi_inited = true; @@ -2408,9 +2638,50 @@ static struct mxc_dispdrv_driver mxc_hdmi_drv = { .disable = mxc_hdmi_power_off, }; + +static int mxc_hdmi_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static long mxc_hdmi_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int __user *argp = (void __user *)arg; + int ret = 0; + + switch (cmd) { + case HDMI_IOC_GET_RESOURCE: + ret = copy_to_user(argp, &g_hdmi->hdmi_data, + sizeof(g_hdmi->hdmi_data)) ? -EFAULT : 0; + break; + case HDMI_IOC_GET_CPU_TYPE: + *argp = mxc_cpu_type; + break; + default: + pr_debug("Unsupport cmd %d\n", cmd); + break; + } + return ret; +} + +static int mxc_hdmi_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations mxc_hdmi_fops = { + .owner = THIS_MODULE, + .open = mxc_hdmi_open, + .release = mxc_hdmi_release, + .unlocked_ioctl = mxc_hdmi_ioctl, +}; + + static int __devinit mxc_hdmi_probe(struct platform_device *pdev) { struct mxc_hdmi *hdmi; + struct device *temp_class; int ret = 0; /* Check that I2C driver is loaded and available */ @@ -2423,6 +2694,28 @@ static int __devinit mxc_hdmi_probe(struct platform_device *pdev) ret = -ENOMEM; goto ealloc; } + g_hdmi = hdmi; + + hdmi_major = register_chrdev(hdmi_major, "mxc_hdmi", &mxc_hdmi_fops); + if (hdmi_major < 0) { + printk(KERN_ERR "HDMI: unable to get a major for HDMI\n"); + ret = -EBUSY; + goto ealloc; + } + + hdmi_class = class_create(THIS_MODULE, "mxc_hdmi"); + if (IS_ERR(hdmi_class)) { + ret = PTR_ERR(hdmi_class); + goto err_out_chrdev; + } + + temp_class = device_create(hdmi_class, NULL, MKDEV(hdmi_major, 0), + NULL, "mxc_hdmi"); + if (IS_ERR(temp_class)) { + ret = PTR_ERR(temp_class); + goto err_out_class; + } + hdmi->pdev = pdev; @@ -2460,6 +2753,11 @@ edispdrv: platform_device_put(hdmi->core_pdev); ecore: kfree(hdmi); +err_out_class: + device_destroy(hdmi_class, MKDEV(hdmi_major, 0)); + class_destroy(hdmi_class); +err_out_chrdev: + unregister_chrdev(hdmi_major, "mxc_hdmi"); ealloc: return ret; } @@ -2479,6 +2777,7 @@ static int mxc_hdmi_remove(struct platform_device *pdev) /* No new work will be scheduled, wait for running ISR */ free_irq(irq, hdmi); kfree(hdmi); + g_hdmi = NULL; return 0; } @@ -2500,6 +2799,13 @@ module_init(mxc_hdmi_init); static void __exit mxc_hdmi_exit(void) { + if (hdmi_major > 0) { + device_destroy(hdmi_class, MKDEV(hdmi_major, 0)); + class_destroy(hdmi_class); + unregister_chrdev(hdmi_major, "mxc_hdmi"); + hdmi_major = 0; + } + platform_driver_unregister(&mxc_hdmi_driver); } module_exit(mxc_hdmi_exit); diff --git a/include/linux/dmapool.h b/include/linux/dmapool.h index 450950163272..c3c41efe2424 100644 --- a/include/linux/dmapool.h +++ b/include/linux/dmapool.h @@ -22,10 +22,8 @@ void dma_pool_destroy(struct dma_pool *pool); void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle); -#ifdef CONFIG_FSL_UTP void *dma_pool_alloc_nonbufferable(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle); -#endif void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr); diff --git a/include/linux/fec.h b/include/linux/fec.h index a9d659456eba..7d4e73d138ce 100644 --- a/include/linux/fec.h +++ b/include/linux/fec.h @@ -21,9 +21,7 @@ struct fec_platform_data { int (*power_hibernate) (struct phy_device *); phy_interface_t phy; unsigned char mac[ETH_ALEN]; -#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO - unsigned int gpio_irq; -#endif + int gpio_irq; }; #endif diff --git a/include/linux/ipu.h b/include/linux/ipu.h index ef55d80da4a3..358d315b1194 100644 --- a/include/linux/ipu.h +++ b/include/linux/ipu.h @@ -94,6 +94,7 @@ typedef enum { /*! @{ */ #define IPU_PIX_FMT_GENERIC fourcc('I', 'P', 'U', '0') /*!< IPU Generic Data */ #define IPU_PIX_FMT_GENERIC_32 fourcc('I', 'P', 'U', '1') /*!< IPU Generic Data */ +#define IPU_PIX_FMT_GENERIC_16 fourcc('I', 'P', 'U', '2') /*!< IPU Generic Data */ #define IPU_PIX_FMT_LVDS666 fourcc('L', 'V', 'D', '6') /*!< IPU Generic Data */ #define IPU_PIX_FMT_LVDS888 fourcc('L', 'V', 'D', '8') /*!< IPU Generic Data */ /*! @} */ diff --git a/include/linux/mxc_asrc.h b/include/linux/mxc_asrc.h index 7594ee68ae1c..8de07b92b0ac 100644 --- a/include/linux/mxc_asrc.h +++ b/include/linux/mxc_asrc.h @@ -40,16 +40,21 @@ enum asrc_pair_index { ASRC_PAIR_C }; +#define ASRC_PAIR_MAX_NUM (ASRC_PAIR_C + 1) + enum asrc_inclk { INCLK_NONE = 0x03, INCLK_ESAI_RX = 0x00, INCLK_SSI1_RX = 0x01, INCLK_SSI2_RX = 0x02, + INCLK_SSI3_RX = 0x07, INCLK_SPDIF_RX = 0x04, INCLK_MLB_CLK = 0x05, + INCLK_PAD = 0x06, INCLK_ESAI_TX = 0x08, INCLK_SSI1_TX = 0x09, INCLK_SSI2_TX = 0x0a, + INCLK_SSI3_TX = 0x0b, INCLK_SPDIF_TX = 0x0c, INCLK_ASRCK1_CLK = 0x0f, }; @@ -59,11 +64,14 @@ enum asrc_outclk { OUTCLK_ESAI_TX = 0x00, OUTCLK_SSI1_TX = 0x01, OUTCLK_SSI2_TX = 0x02, + OUTCLK_SSI3_TX = 0x07, OUTCLK_SPDIF_TX = 0x04, OUTCLK_MLB_CLK = 0x05, + OUTCLK_PAD = 0x06, OUTCLK_ESAI_RX = 0x08, OUTCLK_SSI1_RX = 0x09, OUTCLK_SSI2_RX = 0x0a, + OUTCLK_SSI3_RX = 0x0b, OUTCLK_SPDIF_RX = 0x0c, OUTCLK_ASRCK1_CLK = 0x0f, }; diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h index af792f516cfd..69ea4d7d5403 100644 --- a/include/linux/mxcfb.h +++ b/include/linux/mxcfb.h @@ -110,7 +110,7 @@ struct mxcfb_update_data { __u32 update_mode; __u32 update_marker; int temp; - uint flags; + unsigned int flags; struct mxcfb_alt_buffer_data alt_buffer_data; }; diff --git a/mm/dmapool.c b/mm/dmapool.c index 98798f414cb9..0d19926ce740 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -212,7 +212,6 @@ static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page) } while (offset < pool->allocation); } -#ifdef CONFIG_FSL_UTP static struct dma_page *pool_alloc_page_nonbufferable(struct dma_pool *pool, gfp_t mem_flags) { struct dma_page *page; @@ -236,7 +235,6 @@ static struct dma_page *pool_alloc_page_nonbufferable(struct dma_pool *pool, gfp } return page; } -#endif static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) { @@ -379,7 +377,6 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, } EXPORT_SYMBOL(dma_pool_alloc); -#ifdef CONFIG_FSL_UTP /** * dma_pool_alloc_nonbufferable - get a block of consistent memory * @pool: dma pool that will produce the block @@ -439,7 +436,6 @@ void *dma_pool_alloc_nonbufferable(struct dma_pool *pool, gfp_t mem_flags, return retval; } EXPORT_SYMBOL(dma_pool_alloc_nonbufferable); -#endif static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma) { diff --git a/sound/soc/imx/imx-si4763.c b/sound/soc/imx/imx-si4763.c index 1dd50e769235..7b2458edffa8 100644 --- a/sound/soc/imx/imx-si4763.c +++ b/sound/soc/imx/imx-si4763.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -131,7 +131,7 @@ static struct snd_soc_card snd_soc_card_imx_3stack = { .num_links = 1, }; -static int __init imx_3stack_si4763_probe(struct platform_device *pdev) +static int __devinit imx_3stack_si4763_probe(struct platform_device *pdev) { struct mxc_audio_platform_data *plat = pdev->dev.platform_data; diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c index 50da297c50f4..fed3a7f1e07d 100644 --- a/sound/soc/imx/imx-wm8962.c +++ b/sound/soc/imx/imx-wm8962.c @@ -117,6 +117,56 @@ static void imx_hifi_shutdown(struct snd_pcm_substream *substream) return; } +static int check_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct imx_priv *priv = &card_priv; + unsigned int channels = params_channels(params); + unsigned int sample_rate = params_rate(params); + snd_pcm_format_t sample_format = params_format(params); + + substream->runtime->sample_bits = + snd_pcm_format_physical_width(sample_format); + substream->runtime->rate = sample_rate; + substream->runtime->format = sample_format; + substream->runtime->channels = channels; + + if (!priv->first_stream) { + priv->first_stream = substream; + } else { + priv->second_stream = substream; + + /* Check two sample rates of two streams */ + if (priv->first_stream->runtime->rate != + priv->second_stream->runtime->rate) { + pr_err("\n!KEEP THE SAME SAMPLE RATE: %d!\n", + priv->first_stream->runtime->rate); + return -EINVAL; + } + + /* Check two sample bits of two streams */ + if (priv->first_stream->runtime->sample_bits != + priv->second_stream->runtime->sample_bits) { + snd_pcm_format_t first_format = + priv->first_stream->runtime->format; + + pr_err("\n!KEEP THE SAME FORMAT: %s!\n", + snd_pcm_format_name(first_format)); + return -EINVAL; + } + + /* Check two channel numbers of two streams */ + if (priv->first_stream->runtime->channels != + priv->second_stream->runtime->channels) { + pr_err("\n!KEEP THE SAME CHANNEL NUMBER: %d!\n", + priv->first_stream->runtime->channels); + return -EINVAL; + } + } + + return 0; +} + static int imx_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -130,10 +180,17 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream, u32 dai_format; unsigned int pll_out; - if (!priv->first_stream) - priv->first_stream = substream; - else - priv->second_stream = substream; + /* + * WM8962 doesn't support two substreams in different parameters + * (i.e. different sample rates, audio formats, channel numbers) + * So we here check the three parameters above of two substreams + * if they are running in the same time. + */ + ret = check_hw_params(substream, params); + if (ret < 0) { + pr_err("Failed to match hw params: %d\n", ret); + return ret; + } dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM; |