diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-10-09 16:47:47 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-10-09 16:47:47 +0800 |
commit | eba86309d9ba74153b7853cd8fb97f2484679219 (patch) | |
tree | 2eca312c9a1dde28c0e376156e5cad1704de08c9 | |
parent | 58d8257e51439a6c1ac2c95441f7ec119568dd5b (diff) | |
parent | 45c27e3123e45eb27f3e5933862936e9beda38cd (diff) |
Merge remote branch 'fsl-linux-sdk/imx_3.0.35' into imx_3.0.35_android
Conflicts:
arch/arm/configs/imx6s_updater_defconfig
arch/arm/include/asm/hardware/coresight.h
arch/arm/kernel/etm.c
arch/arm/mach-mx6/board-mx6q_sabresd.c
arch/arm/mach-mx6/cpu_op-mx6.c
arch/arm/mach-mx6/mx6_suspend.S
arch/arm/mach-mx6/pm.c
arch/arm/mach-mx6/system.c
arch/arm/plat-mxc/cpufreq.c
drivers/mfd/mxc-hdmi-core.c
drivers/power/sabresd_battery.c
drivers/video/mxc/mxc_ipuv3_fb.c
drivers/video/mxc_hdmi.c
include/linux/mfd/mxc-hdmi-core.h
85 files changed, 3443 insertions, 697 deletions
diff --git a/arch/arm/configs/imx6_defconfig b/arch/arm/configs/imx6_defconfig index f9a4eacce42b..173fcc874cd1 100644 --- a/arch/arm/configs/imx6_defconfig +++ b/arch/arm/configs/imx6_defconfig @@ -2305,7 +2305,7 @@ CONFIG_MXC_MLB150=m # # MXC Vivante GPU support # -CONFIG_MXC_GPU_VIV=m +CONFIG_MXC_GPU_VIV=y # # ANATOP_THERMAL diff --git a/arch/arm/configs/imx6s_defconfig b/arch/arm/configs/imx6s_defconfig index f03e456d7386..ac7afdfdf5ff 100644 --- a/arch/arm/configs/imx6s_defconfig +++ b/arch/arm/configs/imx6s_defconfig @@ -294,6 +294,7 @@ CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_DSI=y CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_CSI2=y CONFIG_IMX_HAVE_PLATFORM_IMX_VDOA=y CONFIG_IMX_HAVE_PLATFORM_IMX_PCIE=y +CONFIG_IMX_HAVE_PLATFORM_IMX_FSL_CSI=y # # Freescale MXC Implementations @@ -384,6 +385,7 @@ CONFIG_ARM_GIC=y # # Bus support # +CONFIG_ARM_AMBA=y # CONFIG_PCI_SYSCALL is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set @@ -1104,6 +1106,7 @@ CONFIG_INPUT_ISL29023=y # CONFIG_SERIO=y CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # CONFIG_SERIO_ALTERA_PS2 is not set @@ -1135,6 +1138,8 @@ CONFIG_DEVKMEM=y # # Non-8250 serial port support # +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set # CONFIG_SERIAL_MAX3100 is not set # CONFIG_SERIAL_MAX3107 is not set CONFIG_SERIAL_IMX=y @@ -1208,6 +1213,7 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_IMX_VER_2_3=y CONFIG_SPI_IMX=y # CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set # CONFIG_SPI_PXA2XX_PCI is not set # CONFIG_SPI_XILINX is not set # CONFIG_SPI_DESIGNWARE is not set @@ -1243,6 +1249,7 @@ CONFIG_GPIO_SYSFS=y # # CONFIG_GPIO_BASIC_MMIO is not set # CONFIG_GPIO_IT8761E is not set +# CONFIG_GPIO_PL061 is not set # # I2C GPIO expanders: @@ -1287,7 +1294,8 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17040 is not set # CONFIG_BATTERY_MAX17042 is not set # CONFIG_CHARGER_ISP1704 is not set -CONFIG_CHARGER_MAX8903=y +# CONFIG_CHARGER_MAX8903 is not set +CONFIG_SABRESD_MAX8903=y # CONFIG_CHARGER_GPIO is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set @@ -1393,6 +1401,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y # Watchdog Device Drivers # # CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set # CONFIG_MAX63XX_WATCHDOG is not set CONFIG_IMX2_WDT=y @@ -1595,10 +1604,23 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y # CONFIG_VIDEO_THS7303 is not set # CONFIG_VIDEO_M52790 is not set # CONFIG_VIDEO_VIVI is not set -# CONFIG_VIDEO_MXC_CAMERA is not set +CONFIG_VIDEO_MXC_CAMERA=y + +# +# MXC Camera/V4L2 PRP Features support +# +CONFIG_VIDEO_MXC_CSI_CAMERA=y +# CONFIG_MXC_CAMERA_MICRON111 is not set +# CONFIG_MXC_CAMERA_OV2640 is not set +# CONFIG_MXC_CAMERA_OV3640 is not set +CONFIG_MXC_CAMERA_OV5640=y +# CONFIG_MXC_CAMERA_OV8820_MIPI is not set +# CONFIG_MXC_CAMERA_OV5642 is not set +# CONFIG_MXC_TVIN_ADV7180 is not set +# CONFIG_MXC_CAMERA_OV5640_MIPI is not set +CONFIG_MXC_CAMERA_SENSOR_CLK=y CONFIG_VIDEO_MXC_OUTPUT=y -CONFIG_VIDEO_MXC_IPU_OUTPUT=y -# CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT is not set +# CONFIG_VIDEO_MXC_PXP_V4L2 is not set # CONFIG_VIDEO_MXC_OPL is not set # CONFIG_VIDEO_CPIA2 is not set # CONFIG_VIDEO_TIMBERDALE is not set @@ -1694,6 +1716,7 @@ CONFIG_FB_MODE_HELPERS=y # # Frame buffer hardware drivers # +# CONFIG_FB_ARMCLCD is not set # CONFIG_FB_UVESA is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_TMIO is not set @@ -1717,20 +1740,18 @@ CONFIG_FB_MXC=y CONFIG_FB_MXC_EDID=y CONFIG_FB_MXC_SYNC_PANEL=y # CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL is not set -CONFIG_FB_MXC_LDB=y -CONFIG_FB_MXC_MIPI_DSI=y -CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y # CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL is not set -# CONFIG_FB_MXC_SEIKO_WVGA_SYNC_PANEL is not set +CONFIG_FB_MXC_SEIKO_WVGA_SYNC_PANEL=y # CONFIG_FB_MXC_SII902X is not set +CONFIG_FB_MXC_SII902X_ELCDIF=y # CONFIG_FB_MXC_CH7026 is not set # CONFIG_FB_MXC_TVOUT_CH7024 is not set # CONFIG_FB_MXC_ASYNC_PANEL is not set CONFIG_FB_MXC_EINK_PANEL=y # CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE is not set # CONFIG_FB_MXC_SIPIX_PANEL is not set -# CONFIG_FB_MXC_ELCDIF_FB is not set -CONFIG_FB_MXC_HDMI=y +CONFIG_FB_MXC_ELCDIF_FB=y +# CONFIG_FB_MXC_HDMI is not set # # Console display driver support @@ -1783,6 +1804,7 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set CONFIG_SND_ARM=y +# CONFIG_SND_ARMAACI is not set CONFIG_SND_SPI=y CONFIG_SND_USB=y CONFIG_SND_USB_AUDIO=y @@ -1995,7 +2017,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=2 CONFIG_USB_GADGET_SELECTED=y CONFIG_USB_GADGET_ARC=y -CONFIG_IMX_USB_CHARGER=y +# CONFIG_IMX_USB_CHARGER is not set CONFIG_USB_ARC=y # CONFIG_USB_GADGET_FSL_USB2 is not set # CONFIG_USB_GADGET_FUSB300 is not set @@ -2050,6 +2072,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y # # MMC/SD/SDIO Host Controller Drivers # +# CONFIG_MMC_ARMMMCI is not set CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_IO_ACCESSORS=y CONFIG_MMC_SDHCI_PLTFM=y @@ -2161,12 +2184,15 @@ CONFIG_RTC_DRV_SNVS=y # # on-CPU RTC drivers # +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set CONFIG_DMADEVICES=y # CONFIG_DMADEVICES_DEBUG is not set # # DMA Devices # +# CONFIG_AMBA_PL08X is not set # CONFIG_DW_DMAC is not set CONFIG_MXC_PXP_V2=y CONFIG_MXC_PXP_CLIENT_DEVICE=y @@ -2190,9 +2216,7 @@ CONFIG_CLKSRC_MMIO=y # # MXC support drivers # -CONFIG_MXC_IPU=y -CONFIG_MXC_IPU_V3=y -CONFIG_MXC_IPU_V3H=y +# CONFIG_MXC_IPU is not set # # MXC SSI support @@ -2234,6 +2258,7 @@ CONFIG_MXC_IPU_V3H=y # CONFIG_MXC_VPU=y # CONFIG_MXC_VPU_DEBUG is not set +# CONFIG_MX6_VPU_352M is not set # # MXC Asynchronous Sample Rate Converter support @@ -2262,7 +2287,7 @@ CONFIG_MXC_MLB150=m # # MXC Vivante GPU support # -CONFIG_MXC_GPU_VIV=m +CONFIG_MXC_GPU_VIV=y # # ANATOP_THERMAL @@ -2507,7 +2532,7 @@ CONFIG_HAVE_ARCH_KGDB=y # CONFIG_STRICT_DEVMEM is not set CONFIG_ARM_UNWIND=y # CONFIG_DEBUG_USER is not set -# CONFIG_OC_ETM is not set +CONFIG_OC_ETM=y # # Security options diff --git a/arch/arm/configs/imx6s_updater_defconfig b/arch/arm/configs/imx6s_updater_defconfig index 0bd3bcaac829..bd227b39c4e5 100644 --- a/arch/arm/configs/imx6s_updater_defconfig +++ b/arch/arm/configs/imx6s_updater_defconfig @@ -299,6 +299,7 @@ CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_DSI=y CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_CSI2=y CONFIG_IMX_HAVE_PLATFORM_IMX_VDOA=y CONFIG_IMX_HAVE_PLATFORM_IMX_PCIE=y +CONFIG_IMX_HAVE_PLATFORM_IMX_FSL_CSI=y # # Freescale MXC Implementations @@ -388,6 +389,7 @@ CONFIG_ARM_GIC=y # # Bus support # +CONFIG_ARM_AMBA=y # CONFIG_PCI_SYSCALL is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set @@ -1040,6 +1042,8 @@ CONFIG_DEVKMEM=y # # Non-8250 serial port support # +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set # CONFIG_SERIAL_MAX3100 is not set # CONFIG_SERIAL_MAX3107 is not set CONFIG_SERIAL_IMX=y @@ -1113,6 +1117,7 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_IMX_VER_2_3=y CONFIG_SPI_IMX=y # CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set # CONFIG_SPI_PXA2XX_PCI is not set # CONFIG_SPI_XILINX is not set # CONFIG_SPI_DESIGNWARE is not set @@ -1148,6 +1153,7 @@ CONFIG_GPIOLIB=y # # CONFIG_GPIO_BASIC_MMIO is not set # CONFIG_GPIO_IT8761E is not set +# CONFIG_GPIO_PL061 is not set # # I2C GPIO expanders: @@ -1192,6 +1198,7 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17042 is not set # CONFIG_CHARGER_ISP1704 is not set # CONFIG_CHARGER_MAX8903 is not set +# CONFIG_SABRESD_MAX8903 is not set # CONFIG_CHARGER_GPIO is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y @@ -1202,6 +1209,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y # Watchdog Device Drivers # # CONFIG_SOFT_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set # CONFIG_MAX63XX_WATCHDOG is not set CONFIG_IMX2_WDT=y @@ -1405,8 +1413,6 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y # CONFIG_VIDEO_VIVI is not set # CONFIG_VIDEO_MXC_CAMERA is not set CONFIG_VIDEO_MXC_OUTPUT=y -CONFIG_VIDEO_MXC_IPU_OUTPUT=y -# CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT is not set # CONFIG_VIDEO_MXC_PXP_V4L2 is not set # CONFIG_VIDEO_MXC_OPL is not set # CONFIG_VIDEO_CPIA2 is not set @@ -1447,6 +1453,7 @@ CONFIG_FB_MODE_HELPERS=y # # Frame buffer hardware drivers # +# CONFIG_FB_ARMCLCD is not set # CONFIG_FB_UVESA is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_TMIO is not set @@ -1464,18 +1471,17 @@ CONFIG_FB_MXC=y CONFIG_FB_MXC_EDID=y CONFIG_FB_MXC_SYNC_PANEL=y # CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL is not set -CONFIG_FB_MXC_LDB=y -# CONFIG_FB_MXC_MIPI_DSI is not set # CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL is not set # CONFIG_FB_MXC_SEIKO_WVGA_SYNC_PANEL is not set # CONFIG_FB_MXC_SII902X is not set +# CONFIG_FB_MXC_SII902X_ELCDIF is not set # CONFIG_FB_MXC_CH7026 is not set # CONFIG_FB_MXC_TVOUT_CH7024 is not set # CONFIG_FB_MXC_ASYNC_PANEL is not set # CONFIG_FB_MXC_EINK_PANEL is not set # CONFIG_FB_MXC_SIPIX_PANEL is not set # CONFIG_FB_MXC_ELCDIF_FB is not set -CONFIG_FB_MXC_HDMI=y +# CONFIG_FB_MXC_HDMI is not set # # Console display driver support @@ -1526,6 +1532,7 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set CONFIG_SND_ARM=y +# CONFIG_SND_ARMAACI is not set CONFIG_SND_SPI=y CONFIG_SND_USB=y # CONFIG_SND_USB_AUDIO is not set @@ -1774,6 +1781,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y # # MMC/SD/SDIO Host Controller Drivers # +# CONFIG_MMC_ARMMMCI is not set CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_IO_ACCESSORS=y CONFIG_MMC_SDHCI_PLTFM=y @@ -1859,12 +1867,15 @@ CONFIG_RTC_DRV_SNVS=y # # on-CPU RTC drivers # +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set CONFIG_DMADEVICES=y # CONFIG_DMADEVICES_DEBUG is not set # # DMA Devices # +# CONFIG_AMBA_PL08X is not set # CONFIG_DW_DMAC is not set # CONFIG_MXC_PXP_V2 is not set # CONFIG_TIMB_DMA is not set @@ -1917,9 +1928,7 @@ CONFIG_CLKSRC_MMIO=y # # MXC support drivers # -CONFIG_MXC_IPU=y -CONFIG_MXC_IPU_V3=y -CONFIG_MXC_IPU_V3H=y +# CONFIG_MXC_IPU is not set # # MXC SSI support @@ -2234,7 +2243,7 @@ CONFIG_HAVE_ARCH_KGDB=y # CONFIG_STRICT_DEVMEM is not set CONFIG_ARM_UNWIND=y # CONFIG_DEBUG_USER is not set -# CONFIG_OC_ETM is not set +CONFIG_OC_ETM=y # # Security options diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h index 6643d6c4f35e..0b21c331bb04 100644 --- a/arch/arm/include/asm/hardware/coresight.h +++ b/arch/arm/include/asm/hardware/coresight.h @@ -18,10 +18,16 @@ #define TRACER_RUNNING_BIT 1 #define TRACER_CYCLE_ACC_BIT 2 #define TRACER_TRACE_DATA_BIT 3 +#define TRACER_TIMESTAMP_BIT 4 +#define TRACER_BRANCHOUTPUT_BIT 5 +#define TRACER_RETURN_STACK_BIT 6 #define TRACER_ACCESSED BIT(TRACER_ACCESSED_BIT) #define TRACER_RUNNING BIT(TRACER_RUNNING_BIT) #define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT) #define TRACER_TRACE_DATA BIT(TRACER_TRACE_DATA_BIT) +#define TRACER_TIMESTAMP BIT(TRACER_TIMESTAMP_BIT) +#define TRACER_BRANCHOUTPUT BIT(TRACER_BRANCHOUTPUT_BIT) +#define TRACER_RETURN_STACK BIT(TRACER_RETURN_STACK_BIT) #define TRACER_TIMEOUT 10000 @@ -45,7 +51,7 @@ #define ETMCTRL_POWERDOWN 1 #define ETMCTRL_PROGRAM (1 << 10) #define ETMCTRL_PORTSEL (1 << 11) -#define ETMCTRL_DO_CONTEXTID (3 << 14) +#define ETMCTRL_CONTEXTIDSIZE(x) (((x) & 3) << 14) #define ETMCTRL_PORTMASK1 (7 << 4) #define ETMCTRL_PORTMASK2 (1 << 21) #define ETMCTRL_PORTMASK (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2) @@ -57,9 +63,12 @@ #define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR) #define ETMCTRL_BRANCH_OUTPUT (1 << 8) #define ETMCTRL_CYCLEACCURATE (1 << 12) +#define ETMCTRL_TIMESTAMP_EN (1 << 28) +#define ETMCTRL_RETURN_STACK_EN (1 << 29) /* ETM configuration code register */ #define ETMR_CONFCODE (0x04) +#define ETMCCR_ETMIDR_PRESENT BIT(31) /* ETM trace start/stop resource control register */ #define ETMR_TRACESSCTRL (0x18) @@ -122,9 +131,18 @@ #define ETMR_VIEWDATACTRL3 0x3c #define ETMVDC3_EXCLONLY BIT(16) -#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT | \ - ETMCTRL_BRANCH_OUTPUT | \ - ETMCTRL_DO_CONTEXTID) +#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT) + +#define ETMR_ID 0x1e4 +#define ETMIDR_VERSION(x) (((x) >> 4) & 0xff) +#define ETMIDR_VERSION_3_1 0x21 +#define ETMIDR_VERSION_PFT_1_0 0x30 + +#define ETMR_CCE 0x1e8 +#define ETMCCER_RETURN_STACK_IMPLEMENTED BIT(23) +#define ETMCCER_TIMESTAMPING_IMPLEMENTED BIT(22) + +#define ETMR_TRACEIDR 0x200 #define ETMR_TRACEIDR 0x200 diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c index 496b8b84e455..93d06ba0fb60 100644 --- a/arch/arm/kernel/etm.c +++ b/arch/arm/kernel/etm.c @@ -42,6 +42,7 @@ struct tracectx { unsigned long flags; int ncmppairs; int etm_portsz; + int etm_contextid_size; u32 etb_fc; unsigned long range_start; unsigned long range_end; @@ -108,13 +109,23 @@ static int trace_start_etm(struct tracectx *t, int id) unsigned long timeout = TRACER_TIMEOUT; v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz); + v |= ETMCTRL_CONTEXTIDSIZE(t->etm_contextid_size); if (t->flags & TRACER_CYCLE_ACC) v |= ETMCTRL_CYCLEACCURATE; + if (t->flags & TRACER_BRANCHOUTPUT) + v |= ETMCTRL_BRANCH_OUTPUT; + if (t->flags & TRACER_TRACE_DATA) v |= ETMCTRL_DATA_DO_ADDR; + if (t->flags & TRACER_TIMESTAMP) + v |= ETMCTRL_TIMESTAMP_EN; + + if (t->flags & TRACER_RETURN_STACK) + v |= ETMCTRL_RETURN_STACK_EN; + etm_unlock(t, id); etm_writel(t, id, v, ETMR_CTRL); @@ -199,15 +210,36 @@ static int trace_stop_etm(struct tracectx *t, int id) etm_unlock(t, id); - etm_writel(t, id, 0x441, ETMR_CTRL); + etm_writel(t, id, 0x440, ETMR_CTRL); while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) ; if (!timeout) { - dev_dbg(t->dev, "Waiting for progbit to assert timed out\n"); + dev_err(t->dev, + "etm%d: Waiting for progbit to assert timed out\n", + id); + etm_lock(t, id); + return -EFAULT; + } + + etm_lock(t, id); + return 0; +} + +static int trace_power_down_etm(struct tracectx *t, int id) +{ + unsigned long timeout = TRACER_TIMEOUT; + etm_unlock(t, id); + while (!(etm_readl(t, id, ETMR_STATUS) & ETMST_PROGBIT) && --timeout) + ; + if (!timeout) { + dev_err(t->dev, "etm%d: Waiting for status progbit to assert timed out\n", + id); etm_lock(t, id); return -EFAULT; } + etm_writel(t, id, 0x441, ETMR_CTRL); + etm_lock(t, id); return 0; } @@ -215,15 +247,14 @@ static int trace_stop_etm(struct tracectx *t, int id) static int trace_stop(struct tracectx *t) { int id; - int ret; unsigned long timeout = TRACER_TIMEOUT; u32 etb_fc = t->etb_fc; - for (id = 0; id < t->etm_regs_count; id++) { - ret = trace_stop_etm(t, id); - if (ret) - return ret; - } + for (id = 0; id < t->etm_regs_count; id++) + trace_stop_etm(t, id); + + for (id = 0; id < t->etm_regs_count; id++) + trace_power_down_etm(t, id); etb_unlock(t); if (etb_fc) { @@ -626,6 +657,133 @@ static ssize_t trace_mode_store(struct kobject *kobj, static struct kobj_attribute trace_mode_attr = __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store); +static ssize_t trace_contextid_size_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + /* 0: No context id tracing, 1: One byte, 2: Two bytes, 3: Four bytes */ + return sprintf(buf, "%d\n", (1 << tracer.etm_contextid_size) >> 1); +} + +static ssize_t trace_contextid_size_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned int contextid_size; + + if (sscanf(buf, "%u", &contextid_size) != 1) + return -EINVAL; + + if (contextid_size == 3 || contextid_size > 4) + return -EINVAL; + + mutex_lock(&tracer.mutex); + tracer.etm_contextid_size = fls(contextid_size); + mutex_unlock(&tracer.mutex); + + return n; +} + +static struct kobj_attribute trace_contextid_size_attr = + __ATTR(trace_contextid_size, 0644, + trace_contextid_size_show, trace_contextid_size_store); + +static ssize_t trace_branch_output_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_BRANCHOUTPUT)); +} + +static ssize_t trace_branch_output_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned int branch_output; + + if (sscanf(buf, "%u", &branch_output) != 1) + return -EINVAL; + + mutex_lock(&tracer.mutex); + if (branch_output) { + tracer.flags |= TRACER_BRANCHOUTPUT; + /* Branch broadcasting is incompatible with the return stack */ + tracer.flags &= ~TRACER_RETURN_STACK; + } else { + tracer.flags &= ~TRACER_BRANCHOUTPUT; + } + mutex_unlock(&tracer.mutex); + + return n; +} + +static struct kobj_attribute trace_branch_output_attr = + __ATTR(trace_branch_output, 0644, + trace_branch_output_show, trace_branch_output_store); + +static ssize_t trace_return_stack_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_RETURN_STACK)); +} + +static ssize_t trace_return_stack_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned int return_stack; + + if (sscanf(buf, "%u", &return_stack) != 1) + return -EINVAL; + + mutex_lock(&tracer.mutex); + if (return_stack) { + tracer.flags |= TRACER_RETURN_STACK; + /* Return stack is incompatible with branch broadcasting */ + tracer.flags &= ~TRACER_BRANCHOUTPUT; + } else { + tracer.flags &= ~TRACER_RETURN_STACK; + } + mutex_unlock(&tracer.mutex); + + return n; +} + +static struct kobj_attribute trace_return_stack_attr = + __ATTR(trace_return_stack, 0644, + trace_return_stack_show, trace_return_stack_store); + +static ssize_t trace_timestamp_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP)); +} + +static ssize_t trace_timestamp_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned int timestamp; + + if (sscanf(buf, "%u", ×tamp) != 1) + return -EINVAL; + + mutex_lock(&tracer.mutex); + if (timestamp) + tracer.flags |= TRACER_TIMESTAMP; + else + tracer.flags &= ~TRACER_TIMESTAMP; + mutex_unlock(&tracer.mutex); + + return n; +} + +static struct kobj_attribute trace_timestamp_attr = + __ATTR(trace_timestamp, 0644, + trace_timestamp_show, trace_timestamp_store); + static ssize_t trace_range_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -703,6 +861,10 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id int ret = 0; void __iomem **new_regs; int new_count; + u32 etmccr; + u32 etmidr; + u32 etmccer = 0; + u8 etm_version = 0; mutex_lock(&t->mutex); new_count = t->etm_regs_count + 1; @@ -729,15 +891,23 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]); - t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA; + t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA | TRACER_BRANCHOUTPUT; t->etm_portsz = 1; + t->etm_contextid_size = 3; etm_unlock(t, t->etm_regs_count); (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR); /* dummy first read */ (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR); - t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf; + etmccr = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE); + t->ncmppairs = etmccr & 0xf; + if (etmccr & ETMCCR_ETMIDR_PRESENT) { + etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID); + etm_version = ETMIDR_VERSION(etmidr); + if (etm_version >= ETMIDR_VERSION_3_1) + etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE); + } etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL); etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR); etm_lock(t, t->etm_regs_count); @@ -756,14 +926,47 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id if (ret) dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n"); - ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr); + ret = sysfs_create_file(&dev->dev.kobj, + &trace_contextid_size_attr.attr); if (ret) - dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n"); + dev_dbg(&dev->dev, + "Failed to create trace_contextid_size in sysfs\n"); - ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr); + ret = sysfs_create_file(&dev->dev.kobj, + &trace_branch_output_attr.attr); if (ret) dev_dbg(&dev->dev, - "Failed to create trace_data_range in sysfs\n"); + "Failed to create trace_branch_output in sysfs\n"); + + if (etmccer & ETMCCER_RETURN_STACK_IMPLEMENTED) { + ret = sysfs_create_file(&dev->dev.kobj, + &trace_return_stack_attr.attr); + if (ret) + dev_dbg(&dev->dev, + "Failed to create trace_return_stack in sysfs\n"); + } + + if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) { + ret = sysfs_create_file(&dev->dev.kobj, + &trace_timestamp_attr.attr); + if (ret) + dev_dbg(&dev->dev, + "Failed to create trace_timestamp in sysfs\n"); + } + + ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr); + if (ret) + dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n"); + + if (etm_version < ETMIDR_VERSION_PFT_1_0) { + ret = sysfs_create_file(&dev->dev.kobj, + &trace_data_range_attr.attr); + if (ret) + dev_dbg(&dev->dev, + "Failed to create trace_data_range in sysfs\n"); + } else { + tracer.flags &= ~TRACER_TRACE_DATA; + } dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n"); diff --git a/arch/arm/mach-mx5/devices-imx50.h b/arch/arm/mach-mx5/devices-imx50.h index bdaf32213c21..8cba79c489ec 100755 --- a/arch/arm/mach-mx5/devices-imx50.h +++ b/arch/arm/mach-mx5/devices-imx50.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -29,8 +29,8 @@ extern const struct imx_srtc_data imx50_imx_srtc_data __initconst; #define imx50_add_srtc() \ imx_add_srtc(&imx50_imx_srtc_data) -extern const struct imx_dma_data imx50_dma_data __initconst; -#define imx50_add_dma() imx_add_dma(&imx50_dma_data); +extern const struct imx_dma_res_data imx50_dma_res_data __initconst; +#define imx50_add_dma() imx_add_dma(&imx50_dma_res_data); extern const struct imx_fec_data imx50_fec_data; #define imx50_add_fec(pdata) \ diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig index d50f1a795a09..97262dced063 100644 --- a/arch/arm/mach-mx6/Kconfig +++ b/arch/arm/mach-mx6/Kconfig @@ -7,6 +7,7 @@ config ARCH_MX6Q select ARCH_MXC_AUDMUX_V2 select ARM_GIC select ARCH_HAS_CPUFREQ + select OC_ETM select IMX_HAVE_PLATFORM_IMX_UART select IMX_HAVE_PLATFORM_FEC select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL @@ -136,6 +137,7 @@ config MACH_MX6SL_EVK select IMX_HAVE_PLATFORM_IMX_EPDC select IMX_HAVE_PLATFORM_IMX_SPDC select IMX_HAVE_PLATFORM_IMX_PXP + select IMX_HAVE_PLATFORM_IMX_FSL_CSI select IMX_HAVE_PLATFORM_IMX_KEYPAD select IMX_HAVE_PLATFORM_IMX_DCP select IMX_HAVE_PLATFORM_RANDOM_RNGC diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile index 49b5f86a6920..05dc62dac468 100644 --- a/arch/arm/mach-mx6/Makefile +++ b/arch/arm/mach-mx6/Makefile @@ -5,7 +5,7 @@ # Object file lists. obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h2.o usb_h3.o\ pm.o cpu_op-mx6.o mx6_wfi.o mx6_fec.o mx6_anatop_regulator.o cpu_regulator-mx6.o \ -mx6_mmdc.o mx6_ddr_freq.o mx6sl_ddr.o mx6sl_wfi.o +mx6_mmdc.o mx6_ddr_freq.o mx6sl_ddr.o mx6sl_wfi.o etm.o obj-$(CONFIG_ARCH_MX6) += clock.o mx6_suspend.o clock_mx6sl.o obj-$(CONFIG_MACH_MX6Q_ARM2) += board-mx6q_arm2.o diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c index 61d595cddb79..a15daef0c4bb 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c @@ -103,7 +103,6 @@ #define SABREAUTO_DISP0_PWR IMX_GPIO_NR(3, 24) #define SABREAUTO_DISP0_I2C_EN IMX_GPIO_NR(3, 28) #define SABREAUTO_DISP0_DET_INT IMX_GPIO_NR(3, 31) -#define SABREAUTO_CSI0_RST IMX_GPIO_NR(4, 5) #define SABREAUTO_DISP0_RESET IMX_GPIO_NR(5, 0) #define SABREAUTO_I2C3_STEER IMX_GPIO_NR(5, 4) #define SABREAUTO_WEIM_NOR_WDOG1 IMX_GPIO_NR(4, 29) @@ -111,7 +110,6 @@ #define SABREAUTO_PMIC_INT IMX_GPIO_NR(5, 16) #define SABREAUTO_ALS_INT IMX_GPIO_NR(5, 17) #define SABREAUTO_SD1_WP IMX_GPIO_NR(5, 20) -#define SABREAUTO_CSI0_PWN IMX_GPIO_NR(5, 23) #define SABREAUTO_USB_HOST1_OC IMX_GPIO_NR(5, 0) #define SABREAUTO_SD3_CD IMX_GPIO_NR(6, 15) @@ -603,18 +601,6 @@ static struct pca953x_platform_data max7310_u43_platdata = { .setup = max7310_u43_setup, }; -static struct fsl_mxc_camera_platform_data camera_data = { - .analog_regulator = "DA9052_LDO7", - .core_regulator = "DA9052_LDO9", - .mclk = 24000000, - .csi = 0, -}; - -static struct fsl_mxc_camera_platform_data ov5640_mipi_data = { - .mclk = 24000000, - .csi = 0, -}; - static void adv7180_pwdn(int pwdn) { int status = -1; @@ -672,10 +658,6 @@ static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { I2C_BOARD_INFO("adv7180", 0x21), .platform_data = (void *)&adv7180_data, }, { - I2C_BOARD_INFO("ov3640", 0x3c), - .platform_data = (void *)&camera_data, - }, - { I2C_BOARD_INFO("isl29023", 0x44), .irq = gpio_to_irq(SABREAUTO_ALS_INT), .platform_data = &ls_data, @@ -693,17 +675,13 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { }, { I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50), }, { - I2C_BOARD_INFO("ov5640_mipi", 0x3c), - .platform_data = (void *)&ov5640_mipi_data, - }, { I2C_BOARD_INFO("cs42888", 0x48), .platform_data = (void *)&cs42888_data, - }, - { + }, { I2C_BOARD_INFO("si4763_i2c", 0x63), }, - }; + struct platform_device mxc_si4763_audio_device = { .name = "imx-tuner-si4763", .id = 0, @@ -1316,16 +1294,6 @@ early_param("can0", early_enable_can0); static inline void __init mx6q_csi0_io_init(void) { - /* Camera reset */ - gpio_request(SABREAUTO_CSI0_RST, "cam-reset"); - gpio_direction_output(SABREAUTO_CSI0_RST, 1); - - /* Camera power down */ - gpio_request(SABREAUTO_CSI0_PWN, "cam-pwdn"); - gpio_direction_output(SABREAUTO_CSI0_PWN, 1); - msleep(1); - gpio_set_value(SABREAUTO_CSI0_PWN, 0); - if (cpu_is_mx6q()) mxc_iomux_set_gpr_register(1, 19, 1, 1); else if (cpu_is_mx6dl()) diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.h b/arch/arm/mach-mx6/board-mx6q_sabreauto.h index c087de6fb789..9b5af3c2a68c 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabreauto.h +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.h @@ -207,10 +207,6 @@ static iomux_v3_cfg_t mx6q_sabreauto_pads[] = { /* HDMI */ MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE, - /* camera reset */ - MX6Q_PAD_GPIO_19__GPIO_4_5, - MX6Q_PAD_EIM_D24__GPIO_3_24, - /* MLB150 */ MX6Q_PAD_ENET_TXD1__MLB_MLBCLK, MX6Q_PAD_GPIO_6__MLB_MLBSIG, diff --git a/arch/arm/mach-mx6/board-mx6sl_arm2.c b/arch/arm/mach-mx6/board-mx6sl_arm2.c index 419b2447e215..2959d0de6263 100755 --- a/arch/arm/mach-mx6/board-mx6sl_arm2.c +++ b/arch/arm/mach-mx6/board-mx6sl_arm2.c @@ -610,7 +610,7 @@ static struct mxc_dvfs_platform_data mx6sl_arm2_dvfscore_data = { }; static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = { - .reserved_mem_size = SZ_128M, + .reserved_mem_size = SZ_32M, }; void __init early_console_setup(unsigned long base, struct clk *clk); diff --git a/arch/arm/mach-mx6/board-mx6sl_common.h b/arch/arm/mach-mx6/board-mx6sl_common.h index d005e02cb6ac..4a04cbea0694 100644 --- a/arch/arm/mach-mx6/board-mx6sl_common.h +++ b/arch/arm/mach-mx6/board-mx6sl_common.h @@ -20,6 +20,8 @@ #define _BOARD_MX6SL_COMMON_H #include <mach/iomux-mx6sl.h> +#define MX6_BRD_LCD_RESET IMX_GPIO_NR(2, 19) /* LCD_REST */ + #define MX6_BRD_USBOTG1_PWR IMX_GPIO_NR(4, 0) /* KEY_COL4 */ #define MX6_BRD_USBOTG2_PWR IMX_GPIO_NR(4, 2) /* KEY_COL5 */ #define MX6_BRD_LCD_PWR_EN IMX_GPIO_NR(4, 3) /* KEY_ROW5 */ @@ -31,6 +33,10 @@ #define MX6_BRD_SD2_CD IMX_GPIO_NR(5, 0) /* SD2_DAT7 */ #define MX6_BRD_SD3_CD IMX_GPIO_NR(3, 22) /* REF_CLK_32K */ #define MX6_BRD_FEC_PWR_EN IMX_GPIO_NR(4, 21) /* FEC_TX_CLK */ +#define MX6_BRD_CHG_FLT IMX_GPIO_NR(4, 14) /* ECSPI2_MISO */ +#define MX6_BRD_CHG_UOK IMX_GPIO_NR(4, 13) /* ECSPI2_MOSI */ +#define MX6_BRD_CHG_DOK IMX_GPIO_NR(4, 13) /* ECSPI2_MOSI */ +#define MX6_BRD_CHG_STATUS IMX_GPIO_NR(4, 15) /* ECSPI2_SS0 */ /* EPDC GPIO pins */ #define MX6SL_BRD_EPDC_SDDO_0 IMX_GPIO_NR(1, 7) @@ -76,6 +82,9 @@ #define MX6SL_BRD_ELAN_CE IMX_GPIO_NR(2, 9) #define MX6SL_BRD_ELAN_INT IMX_GPIO_NR(2, 10) #define MX6SL_BRD_ELAN_RST IMX_GPIO_NR(4, 4) +/* CSI */ +#define MX6SL_BRD_CSI_PWDN IMX_GPIO_NR(1, 25) +#define MX6SL_BRD_CSI_RST IMX_GPIO_NR(1, 26) static iomux_v3_cfg_t mx6sl_brd_pads[] = { @@ -89,6 +98,9 @@ static iomux_v3_cfg_t mx6sl_brd_pads[] = { /* Audio Codec */ MX6SL_PAD_FEC_RX_ER__GPIO_4_19, /* HEADPHONE_DET */ + /* SPDIF TX */ + MX6SL_PAD_SD2_DAT4__SPDIF_OUT1, + /* UART1 */ MX6SL_PAD_UART1_RXD__UART1_RXD, MX6SL_PAD_UART1_TXD__UART1_TXD, @@ -213,6 +225,11 @@ static iomux_v3_cfg_t mx6sl_brd_pads[] = { /* WDOG */ MX6SL_PAD_WDOG_B__WDOG1_WDOG_B, + + /* Charge */ + MX6SL_PAD_ECSPI2_MISO__GPIO_4_14, /* CHG_FLT */ + MX6SL_PAD_ECSPI2_SS0__GPIO_4_15, /* CHG_STATUS */ + MX6SL_PAD_ECSPI2_MOSI__GPIO_4_13, /* CHG_UOK ,CHG_DOK*/ }; static iomux_v3_cfg_t mx6sl_brd_epdc_enable_pads[] = { @@ -372,11 +389,40 @@ static iomux_v3_cfg_t mx6sl_brd_spdc_disable_pads[] = { MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14, }; +static iomux_v3_cfg_t mx6sl_brd_csi_enable_pads[] = { + MX6SL_PAD_EPDC_GDRL__CSI_MCLK, + MX6SL_PAD_EPDC_SDCE3__I2C3_SDA, + MX6SL_PAD_EPDC_SDCE2__I2C3_SCL, + MX6SL_PAD_EPDC_GDCLK__CSI_PIXCLK, + MX6SL_PAD_EPDC_GDSP__CSI_VSYNC, + MX6SL_PAD_EPDC_GDOE__CSI_HSYNC, + MX6SL_PAD_EPDC_SDLE__CSI_D_9, + MX6SL_PAD_EPDC_SDCLK__CSI_D_8, + MX6SL_PAD_EPDC_D7__CSI_D_7, + MX6SL_PAD_EPDC_D6__CSI_D_6, + MX6SL_PAD_EPDC_D5__CSI_D_5, + MX6SL_PAD_EPDC_D4__CSI_D_4, + MX6SL_PAD_EPDC_D3__CSI_D_3, + MX6SL_PAD_EPDC_D2__CSI_D_2, + MX6SL_PAD_EPDC_D1__CSI_D_1, + MX6SL_PAD_EPDC_D0__CSI_D_0, + + MX6SL_PAD_EPDC_SDSHR__GPIO_1_26, /* CMOS_RESET_B GPIO */ + MX6SL_PAD_EPDC_SDOE__GPIO_1_25, /* CMOS_PWDN GPIO */ +}; + static iomux_v3_cfg_t mx6sl_brd_elan_pads[] = { MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, /* INT */ MX6SL_PAD_EPDC_PWRCTRL2__GPIO_2_9, /* CE */ MX6SL_PAD_KEY_COL6__GPIO_4_4, /* RST */ }; + /* uart2 pins */ +static iomux_v3_cfg_t mx6sl_uart2_pads[] = { + MX6SL_PAD_SD2_DAT5__UART2_TXD, + MX6SL_PAD_SD2_DAT4__UART2_RXD, + MX6SL_PAD_SD2_DAT6__UART2_RTS, + MX6SL_PAD_SD2_DAT7__UART2_CTS, +}; #define MX6SL_USDHC_8BIT_PAD_SETTING(id, speed) \ mx6sl_sd##id##_##speed##mhz[] = { \ diff --git a/arch/arm/mach-mx6/board-mx6sl_evk.c b/arch/arm/mach-mx6/board-mx6sl_evk.c index 81654a0c99fd..e656638c31d6 100644 --- a/arch/arm/mach-mx6/board-mx6sl_evk.c +++ b/arch/arm/mach-mx6/board-mx6sl_evk.c @@ -52,6 +52,7 @@ #include <linux/mfd/max17135.h> #include <sound/wm8962.h> #include <sound/pcm.h> +#include <linux/power/sabresd_battery.h> #include <mach/common.h> #include <mach/hardware.h> @@ -83,12 +84,21 @@ extern char *soc_reg_id; extern char *pu_reg_id; extern int __init mx6sl_evk_init_pfuze100(u32 int_gpio); +static int csi_enabled; + enum sd_pad_mode { SD_PAD_MODE_LOW_SPEED, SD_PAD_MODE_MED_SPEED, SD_PAD_MODE_HIGH_SPEED, }; +static int __init csi_setup(char *__unused) +{ + csi_enabled = 1; + return 1; +} +__setup("csi", csi_setup); + static int plt_sd_pad_change(unsigned int index, int clock) { /* LOW speed is the default state of SD pads */ @@ -556,6 +566,115 @@ static int __init imx6q_init_audio(void) return 0; } +static int spdif_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long rate_actual; + rate_actual = clk_round_rate(clk, rate); + clk_set_rate(clk, rate_actual); + return 0; +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 1, + .spdif_clk_48000 = -1, + .spdif_div_44100 = 23, + .spdif_clk_set_rate = spdif_clk_set_rate, + .spdif_clk = NULL, +}; + +int hdmi_enabled; +static int __init hdmi_setup(char *__unused) +{ + hdmi_enabled = 1; + return 1; +} +__setup("hdmi", hdmi_setup); + +static iomux_v3_cfg_t mx6sl_sii902x_hdmi_pads_enabled[] = { + MX6SL_PAD_LCD_RESET__GPIO_2_19, + MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, +}; + +static int sii902x_get_pins(void) +{ + /* Sii902x HDMI controller */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_sii902x_hdmi_pads_enabled, \ + ARRAY_SIZE(mx6sl_sii902x_hdmi_pads_enabled)); + + /* Reset Pin */ + gpio_request(MX6_BRD_LCD_RESET, "disp0-reset"); + gpio_direction_output(MX6_BRD_LCD_RESET, 1); + + /* Interrupter pin GPIO */ + gpio_request(MX6SL_BRD_EPDC_PWRCTRL3, "disp0-detect"); + gpio_direction_input(MX6SL_BRD_EPDC_PWRCTRL3); + return 1; +} + +static void sii902x_put_pins(void) +{ + gpio_free(MX6_BRD_LCD_RESET); + gpio_free(MX6SL_BRD_EPDC_PWRCTRL3); +} + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(MX6_BRD_LCD_RESET, 0); + msleep(10); + gpio_set_value(MX6_BRD_LCD_RESET, 1); + msleep(10); +} + +static struct fsl_mxc_lcd_platform_data sii902x_hdmi_data = { + .ipu_id = 0, + .disp_id = 0, + .reset = sii902x_hdmi_reset, + .get_pins = sii902x_get_pins, + .put_pins = sii902x_put_pins, +}; + +static void mx6sl_csi_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_csi_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_csi_enable_pads)); + + /* Camera reset */ + gpio_request(MX6SL_BRD_CSI_RST, "cam-reset"); + gpio_direction_output(MX6SL_BRD_CSI_RST, 1); + + /* Camera power down */ + gpio_request(MX6SL_BRD_CSI_PWDN, "cam-pwdn"); + gpio_direction_output(MX6SL_BRD_CSI_PWDN, 1); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_PWDN, 0); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_RST, 0); + msleep(1); + gpio_set_value(MX6SL_BRD_CSI_RST, 1); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_PWDN, 1); +} + +static void mx6sl_csi_cam_powerdown(int powerdown) +{ + if (powerdown) + gpio_set_value(MX6SL_BRD_CSI_PWDN, 1); + else + gpio_set_value(MX6SL_BRD_CSI_PWDN, 0); + + msleep(2); +} + +static struct fsl_mxc_camera_platform_data camera_data = { + .mclk = 24000000, + .io_init = mx6sl_csi_io_init, + .pwdn = mx6sl_csi_cam_powerdown, + .core_regulator = "VGEN2_1V5", + .analog_regulator = "VGEN6_2V8", +}; + static struct imxi2c_platform_data mx6_evk_i2c0_data = { .bitrate = 100000, }; @@ -565,7 +684,7 @@ static struct imxi2c_platform_data mx6_evk_i2c1_data = { }; static struct imxi2c_platform_data mx6_evk_i2c2_data = { - .bitrate = 400000, + .bitrate = 100000, }; static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { @@ -585,10 +704,17 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { I2C_BOARD_INFO("wm8962", 0x1a), .platform_data = &wm8962_config_data, }, + { + I2C_BOARD_INFO("sii902x", 0), + .platform_data = &sii902x_hdmi_data, + .irq = gpio_to_irq(MX6SL_BRD_EPDC_PWRCTRL3) + }, }; static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { { + I2C_BOARD_INFO("ov5640", 0x3c), + .platform_data = (void *)&camera_data, }, }; @@ -623,11 +749,17 @@ static struct mxc_dvfs_platform_data mx6sl_evk_dvfscore_data = { }; static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = { - .reserved_mem_size = SZ_128M, + .reserved_mem_size = SZ_32M, }; void __init early_console_setup(unsigned long base, struct clk *clk); +static const struct imxuart_platform_data mx6sl_evk_uart1_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS | IMXUART_SDMA, + .dma_req_rx = MX6Q_DMA_REQ_UART2_RX, + .dma_req_tx = MX6Q_DMA_REQ_UART2_TX, +}; + static inline void mx6_evk_init_uart(void) { imx6q_add_imx_uart(0, NULL); /* DEBUG UART1 */ @@ -1105,7 +1237,7 @@ static struct platform_pwm_backlight_data mx6_evk_pwm_backlight_data = { .dft_brightness = 128, .pwm_period_ns = 50000, }; -static struct fb_videomode video_modes[] = { +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, @@ -1114,12 +1246,12 @@ static struct fb_videomode video_modes[] = { 0,}, }; -static struct mxc_fb_platform_data fb_data[] = { +static struct mxc_fb_platform_data wvga_fb_data[] = { { .interface_pix_fmt = V4L2_PIX_FMT_RGB24, .mode_str = "SEIKO-WVGA", - .mode = video_modes, - .num_modes = ARRAY_SIZE(video_modes), + .mode = wvga_video_modes, + .num_modes = ARRAY_SIZE(wvga_video_modes), }, }; @@ -1127,6 +1259,24 @@ static struct platform_device lcd_wvga_device = { .name = "lcd_seiko", }; +static struct fb_videomode hdmi_video_modes[] = { + { + /* 1920x1080 @ 60 Hz , pixel clk @ 148MHz */ + "sii9022x_1080p60", 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data hdmi_fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB24, + .mode_str = "1920x1080M@60", + .mode = hdmi_video_modes, + .num_modes = ARRAY_SIZE(hdmi_video_modes), + }, +}; + static int mx6sl_evk_keymap[] = { KEY(0, 0, KEY_SELECT), KEY(0, 1, KEY_BACK), @@ -1174,6 +1324,33 @@ static void __init elan_ts_init(void) gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); } +/* + *Usually UOK and DOK should have separate + *line to differentiate its behaviour (with different + * GPIO irq),because connect max8903 pin UOK to + *pin DOK from hardware design,cause software cannot + *process and distinguish two interrupt, so default + *enable dc_valid for ac charger + */ +static struct max8903_pdata charger1_data = { + .dok = MX6_BRD_CHG_DOK, + .uok = MX6_BRD_CHG_UOK, + .chg = MX6_BRD_CHG_STATUS, + .flt = MX6_BRD_CHG_FLT, + .dcm_always_high = true, + .dc_valid = true, + .usb_valid = false, + .feature_flag = 1, +}; + +static struct platform_device evk_max8903_charger_1 = { + .name = "max8903-charger", + .dev = { + .platform_data = &charger1_data, + }, +}; + + #define SNVS_LPCR 0x38 static void mx6_snvs_poweroff(void) { @@ -1185,11 +1362,27 @@ static void mx6_snvs_poweroff(void) writel(value | 0x60, mx6_snvs_base + SNVS_LPCR); } +static int uart2_enabled; +static int __init uart2_setup(char * __unused) +{ + uart2_enabled = 1; + return 1; +} +__setup("bluetooth", uart2_setup); + +static void __init uart2_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_uart2_pads, + ARRAY_SIZE(mx6sl_uart2_pads)); + imx6sl_add_imx_uart(1, &mx6sl_evk_uart1_data); +} /*! * Board specific initialization. */ static void __init mx6_evk_init(void) { + u32 i; + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_pads, ARRAY_SIZE(mx6sl_brd_pads)); @@ -1211,11 +1404,25 @@ static void __init mx6_evk_init(void) imx6q_add_imx_i2c(1, &mx6_evk_i2c1_data); i2c_register_board_info(0, mxc_i2c0_board_info, ARRAY_SIZE(mxc_i2c0_board_info)); + + /* setting sii902x address when hdmi enabled */ + if (hdmi_enabled) { + for (i = 0; i < ARRAY_SIZE(mxc_i2c1_board_info); i++) { + if (!strcmp(mxc_i2c1_board_info[i].type, "sii902x")) { + mxc_i2c1_board_info[i].addr = 0x39; + break; + } + } + } + i2c_register_board_info(1, mxc_i2c1_board_info, ARRAY_SIZE(mxc_i2c1_board_info)); - imx6q_add_imx_i2c(2, &mx6_evk_i2c2_data); - i2c_register_board_info(2, mxc_i2c2_board_info, - ARRAY_SIZE(mxc_i2c2_board_info)); + /* only camera on I2C3, that's why we can do so */ + if (csi_enabled == 1) { + imx6q_add_imx_i2c(2, &mx6_evk_i2c2_data); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + } /* SPI */ imx6q_add_ecspi(0, &mx6_evk_spi_data); @@ -1243,24 +1450,37 @@ static void __init mx6_evk_init(void) imx6q_add_otp(); imx6q_add_mxc_pwm(0); imx6q_add_mxc_pwm_backlight(0, &mx6_evk_pwm_backlight_data); - imx6dl_add_imx_elcdif(&fb_data[0]); - gpio_request(MX6_BRD_LCD_PWR_EN, "elcdif-power-on"); - gpio_direction_output(MX6_BRD_LCD_PWR_EN, 1); - mxc_register_device(&lcd_wvga_device, NULL); + if (hdmi_enabled) { + imx6dl_add_imx_elcdif(&hdmi_fb_data[0]); + } else { + imx6dl_add_imx_elcdif(&wvga_fb_data[0]); + + gpio_request(MX6_BRD_LCD_PWR_EN, "elcdif-power-on"); + gpio_direction_output(MX6_BRD_LCD_PWR_EN, 1); + mxc_register_device(&lcd_wvga_device, NULL); + } imx6dl_add_imx_pxp(); imx6dl_add_imx_pxp_client(); mxc_register_device(&max17135_sensor_device, NULL); setup_spdc(); - if (!spdc_sel) - imx6dl_add_imx_epdc(&epdc_data); - else - imx6sl_add_imx_spdc(&spdc_data); + if (csi_enabled) { + imx6sl_add_fsl_csi(); + } else { + if (!spdc_sel) + imx6dl_add_imx_epdc(&epdc_data); + else + imx6sl_add_imx_spdc(&spdc_data); + } imx6q_add_dvfs_core(&mx6sl_evk_dvfscore_data); imx6q_init_audio(); + /* uart2 for bluetooth */ + if (uart2_enabled) + uart2_init(); + imx6q_add_viim(); imx6q_add_imx2_wdt(0, NULL); @@ -1271,10 +1491,17 @@ static void __init mx6_evk_init(void) imx6sl_add_rngb(); imx6sl_add_imx_pxp_v4l2(); + mxc_spdif_data.spdif_core_clk = clk_get_sys("mxc_spdif.0", NULL); + clk_put(mxc_spdif_data.spdif_core_clk); + imx6q_add_spdif(&mxc_spdif_data); + imx6q_add_spdif_dai(); + imx6q_add_spdif_audio_device(); + imx6q_add_perfmon(0); imx6q_add_perfmon(1); imx6q_add_perfmon(2); - + /* Register charger chips */ + platform_device_register(&evk_max8903_charger_1); pm_power_off = mx6_snvs_poweroff; } diff --git a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h index 9111e6bc9b19..b752faae33ba 100644 --- a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h +++ b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h @@ -207,10 +207,6 @@ static iomux_v3_cfg_t mx6dl_sabreauto_pads[] = { /* HDMI */ MX6DL_PAD_EIM_A25__HDMI_TX_CEC_LINE, - /* camera reset */ - MX6DL_PAD_GPIO_19__GPIO_4_5, - MX6DL_PAD_EIM_D24__GPIO_3_24, - /* MLB150 */ MX6DL_PAD_ENET_TXD1__MLB_MLBCLK, MX6DL_PAD_GPIO_6__MLB_MLBSIG, diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c index 9d18423c85c5..d96ac6a1e928 100644 --- a/arch/arm/mach-mx6/bus_freq.c +++ b/arch/arm/mach-mx6/bus_freq.c @@ -412,7 +412,7 @@ void bus_freq_update(struct clk *clk, bool flag) */ high_cpu_freq = 1; if (low_bus_freq_mode || audio_bus_freq_mode) - set_high_bus_freq(0); + set_high_bus_freq(1); } else { /* Update count */ if (clk->flags & AHB_HIGH_SET_POINT) @@ -471,7 +471,7 @@ void bus_freq_update(struct clk *clk, bool flag) /* Set to either high or * medium setpoint. */ - set_high_bus_freq(0); + set_high_bus_freq(1); } } } @@ -506,7 +506,7 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev, #else bus_freq_scaling_is_active = 1; #endif - set_high_bus_freq(0); + set_high_bus_freq(1); /* Make sure system can enter low bus mode if it should be in low bus mode */ if (low_freq_bus_used() && !low_bus_freq_mode) diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c index 5c3f053ce5fd..0c05c37f81d5 100644 --- a/arch/arm/mach-mx6/clock.c +++ b/arch/arm/mach-mx6/clock.c @@ -4854,7 +4854,7 @@ static struct clk usboh3_clk[] = { .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, .disable = _clk_disable, .secondary = &usboh3_clk[1], - .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, }, { .parent = &mmdc_ch0_axi_clk[0], @@ -5304,6 +5304,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "mlb150_clk", mlb150_clk), _REGISTER_CLOCK(NULL, "anaclk_1", anaclk_1), _REGISTER_CLOCK(NULL, "anaclk_2", anaclk_2), + _REGISTER_CLOCK(NULL, "apb_pclk", dummy_clk), }; static void clk_tree_init(void) diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c index 616099180008..6de15622eede 100755 --- a/arch/arm/mach-mx6/clock_mx6sl.c +++ b/arch/arm/mach-mx6/clock_mx6sl.c @@ -1945,8 +1945,8 @@ static unsigned long _clk_ipu_round_rate(struct clk *clk, } static struct clk ipu1_clk = { - __INIT_CLK_DEBUG(ipu1_clk) - .parent = &pll2_pfd2_400M, + __INIT_CLK_DEBUG(csi_clk) + .parent = &osc_clk, .enable_reg = MXC_CCM_CCGR3, .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, .enable = _clk_enable, @@ -4065,9 +4065,9 @@ int __init mx6sl_clocks_init(unsigned long ckil, unsigned long osc, 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR1); __raw_writel(1 << MXC_CCM_CCGRx_CG12_OFFSET | 1 << MXC_CCM_CCGRx_CG11_OFFSET | - 1 << MXC_CCM_CCGRx_CG10_OFFSET | - 1 << MXC_CCM_CCGRx_CG9_OFFSET | - 1 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR2); + 3 << MXC_CCM_CCGRx_CG10_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR2); __raw_writel(1 << MXC_CCM_CCGRx_CG14_OFFSET | 3 << MXC_CCM_CCGRx_CG13_OFFSET | 3 << MXC_CCM_CCGRx_CG12_OFFSET | diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c index be5011aeab34..fbb3827668e0 100644 --- a/arch/arm/mach-mx6/cpu.c +++ b/arch/arm/mach-mx6/cpu.c @@ -119,8 +119,14 @@ static int __init post_cpu_init(void) { unsigned int reg; void __iomem *base; + u32 iram_size; - iram_init(MX6Q_IRAM_BASE_ADDR, MX6Q_IRAM_SIZE); + if (cpu_is_mx6q()) + iram_size = MX6Q_IRAM_SIZE; + else + iram_size = MX6DL_MX6SL_IRAM_SIZE; + + iram_init(MX6Q_IRAM_BASE_ADDR, iram_size); base = ioremap(AIPS1_ON_BASE_ADDR, PAGE_SIZE); __raw_writel(0x0, base + 0x40); diff --git a/arch/arm/mach-mx6/cpu_op-mx6.c b/arch/arm/mach-mx6/cpu_op-mx6.c index 7e054c1d743c..99336d873756 100644 --- a/arch/arm/mach-mx6/cpu_op-mx6.c +++ b/arch/arm/mach-mx6/cpu_op-mx6.c @@ -162,7 +162,7 @@ static struct cpu_op mx6dl_cpu_op_1_2G[] = { .cpu_podf = 0, .pu_voltage = 1175000, .soc_voltage = 1175000, - .cpu_voltage = 1150000,}, + .cpu_voltage = 1175000,}, { .pll_rate = 396000000, .cpu_rate = 396000000, @@ -177,16 +177,16 @@ static struct cpu_op mx6dl_cpu_op_1G[] = { .pll_rate = 996000000, .cpu_rate = 996000000, .cpu_podf = 0, - .pu_voltage = 1250000, - .soc_voltage = 1250000, - .cpu_voltage = 1250000,}, + .pu_voltage = 1275000, + .soc_voltage = 1275000, + .cpu_voltage = 1275000,}, { .pll_rate = 792000000, .cpu_rate = 792000000, .cpu_podf = 0, .pu_voltage = 1175000, .soc_voltage = 1175000, - .cpu_voltage = 1150000,}, + .cpu_voltage = 1175000,}, { .pll_rate = 396000000, .cpu_rate = 396000000, @@ -202,7 +202,7 @@ static struct cpu_op mx6dl_cpu_op[] = { .cpu_podf = 0, .pu_voltage = 1175000, .soc_voltage = 1175000, - .cpu_voltage = 1150000,}, + .cpu_voltage = 1175000,}, { .pll_rate = 396000000, .cpu_rate = 396000000, diff --git a/arch/arm/mach-mx6/cpu_regulator-mx6.c b/arch/arm/mach-mx6/cpu_regulator-mx6.c index cb08cad48204..5019f8bedff2 100644 --- a/arch/arm/mach-mx6/cpu_regulator-mx6.c +++ b/arch/arm/mach-mx6/cpu_regulator-mx6.c @@ -37,6 +37,7 @@ static struct cpu_op *cpu_op_tbl; extern struct cpu_op *(*get_cpu_op)(int *op); extern unsigned long loops_per_jiffy; +int external_pureg; static inline unsigned long mx6_cpu_jiffies(unsigned long old, u_int div, u_int mult) @@ -62,6 +63,7 @@ void mx6_cpu_regulator_init(void) int cpu; u32 curr_cpu = 0; + external_pureg = 0; cpu_regulator = regulator_get(NULL, gp_reg_id); if (IS_ERR(cpu_regulator)) printk(KERN_ERR "%s: failed to get cpu regulator\n", __func__); @@ -108,5 +110,21 @@ void mx6_cpu_regulator_init(void) pu_regulator = regulator_get(NULL, pu_reg_id); if (IS_ERR(pu_regulator)) printk(KERN_ERR "%s: failed to get pu regulator\n", __func__); + /*If enable CONFIG_MX6_INTER_LDO_BYPASS and VDDPU_IN is single supplied + *by external pmic, it means VDDPU_IN can be turned off if GPU/VPU driver + *not running.In this case we should set external_pureg which can be used + *in pu_enable/pu_disable of arch/arm/mach-mx6/mx6_anatop_regulator.c to + *enable or disable external VDDPU regulator from pmic. But for FSL + *reference boards, VDDSOC_IN connect with VDDPU_IN, so we didn't set + *pu_reg_id to the external pmic regulator supply name in the board file. + *In this case external_pureg should be 0 and can't turn off extern pmic + *regulator, but can turn off VDDPU by internal anatop power gate. + * + *If disable CONFIG_MX6_INTER_LDO_BYPASS, external_pureg will be 0, and + *VDDPU can be turned off by internal anatop anatop power gate. + * + */ + else if (!IS_ERR(pu_regulator) && strcmp(pu_reg_id, "cpu_vddvpu")) + external_pureg = 1; } diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h index bd948cecbcd2..4525e29a472a 100644 --- a/arch/arm/mach-mx6/devices-imx6q.h +++ b/arch/arm/mach-mx6/devices-imx6q.h @@ -23,6 +23,10 @@ extern const struct imx_imx_uart_1irq_data imx6q_imx_uart_data[] __initconst; #define imx6q_add_imx_uart(id, pdata) \ imx_add_imx_uart_1irq(&imx6q_imx_uart_data[id], pdata) +extern const struct imx_imx_uart_1irq_data imx6sl_imx_uart_data[] __initconst; +#define imx6sl_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx6sl_imx_uart_data[id], pdata) + extern const struct imx_snvs_rtc_data imx6q_imx_snvs_rtc_data __initconst; #define imx6q_add_imx_snvs_rtc() \ imx_add_snvs_rtc(&imx6q_imx_snvs_rtc_data) @@ -36,8 +40,8 @@ imx6q_anatop_thermal_imx_data __initconst; #define imx6q_add_anatop_thermal_imx(id, pdata) \ imx_add_anatop_thermal_imx(&imx6q_anatop_thermal_imx_data, pdata) -extern const struct imx_dma_data imx6q_dma_data __initconst; -#define imx6q_add_dma() imx_add_dma(&imx6q_dma_data); +extern const struct imx_dma_res_data imx6q_dma_res_data __initconst; +#define imx6q_add_dma() imx_add_dma(&imx6q_dma_res_data); #define imx6q_add_gpmi(platform_data) imx_add_gpmi(platform_data); @@ -219,6 +223,10 @@ extern const struct imx_pxp_data imx6dl_pxp_data __initconst; #define imx6sl_add_imx_pxp_v4l2() \ imx_add_imx_pxp_v4l2() +extern const struct imx_fsl_csi_data imx6sl_csi_data __initconst; +#define imx6sl_add_fsl_csi() \ + imx_add_fsl_csi(&imx6sl_csi_data) + extern const struct imx_epdc_data imx6dl_epdc_data __initconst; #define imx6dl_add_imx_epdc(pdata) \ imx_add_imx_epdc(&imx6dl_epdc_data, pdata) diff --git a/arch/arm/mach-mx6/etm.c b/arch/arm/mach-mx6/etm.c new file mode 100644 index 000000000000..8f328608ebfd --- /dev/null +++ b/arch/arm/mach-mx6/etm.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/iram_alloc.h> +#include <linux/delay.h> +#include <linux/amba/bus.h> + +#include <mach/hardware.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include <asm/hardware/coresight.h> + +static struct __init amba_device mx6_etb_device = { + .dev = { + .init_name = "etb", + }, + .res = { + .start = MX6Q_ETB_BASE_ADDR, + .end = MX6Q_ETB_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .periphid = 0x3bb907, +}; + +static struct __init amba_device mx6_etm_device[] = { + { + .dev = { + .init_name = "etm.0", + }, + .res = { + .start = MX6Q_PTM0_BASE_ADDR, + .end = MX6Q_PTM0_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, + { + .dev = { + .init_name = "etm.1", + }, + .res = { + .start = MX6Q_PTM1_BASE_ADDR, + .end = MX6Q_PTM1_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, + { + .dev = { + .init_name = "etm.2", + }, + .res = { + .start = MX6Q_PTM2_BASE_ADDR, + .end = MX6Q_PTM2_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, + { + .dev = { + .init_name = "etm.3", + }, + .res = { + .start = MX6Q_PTM3_BASE_ADDR, + .end = MX6Q_PTM3_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, +}; + +#define FUNNEL_CTL 0 +static int __init etm_init(void) +{ + int i; + __iomem void *base; + base = ioremap(0x02144000, SZ_4K); + /*Unlock Funnel*/ + __raw_writel(UNLOCK_MAGIC, base + CSMR_LOCKACCESS); + /*Enable all funnel port*/ + __raw_writel(__raw_readl(base + FUNNEL_CTL) | 0xFF, + base + FUNNEL_CTL); + /*Lock Funnel*/ + __raw_writel(0, base + CSMR_LOCKACCESS); + iounmap(base); + + amba_device_register(&mx6_etb_device, &iomem_resource); + for (i = 0; i < num_possible_cpus(); i++) + amba_device_register(mx6_etm_device + i, &iomem_resource); + + return 0; +} + +subsys_initcall(etm_init); diff --git a/arch/arm/mach-mx6/mx6_anatop_regulator.c b/arch/arm/mach-mx6/mx6_anatop_regulator.c index 945adbdb759a..f2c2ebf600b3 100644 --- a/arch/arm/mach-mx6/mx6_anatop_regulator.c +++ b/arch/arm/mach-mx6/mx6_anatop_regulator.c @@ -22,6 +22,7 @@ * mx6_anatop_regulator.c -- i.MX6 Driver for Anatop regulators */ #include <linux/device.h> +#include <linux/err.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/regulator/anatop-regulator.h> @@ -30,6 +31,9 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/clk.h> + +#include <mach/clock.h> #include "crm_regs.h" #include "regs-anadig.h" @@ -41,8 +45,17 @@ extern struct platform_device sgtl5000_vdda_reg_devices; extern struct platform_device sgtl5000_vddio_reg_devices; extern struct platform_device sgtl5000_vddd_reg_devices; extern void __iomem *gpc_base; -/* Default PU voltage value set to 1.1V */ -static unsigned int org_ldo = 0x2000; +/* we use the below flag to keep PU regulator state, because enable/disable +of PU regulator share with the same register as voltage set of PU regulator. +PU voltage set by cpufreq driver if the flag is set, and enable/disable by +GPU/VPU driver*/ +static unsigned int pu_is_enabled; +static unsigned int get_clk; +static struct clk *gpu3d_clk, *gpu3d_shade_clk, *gpu2d_clk, *gpu2d_axi_clk; +static struct clk *openvg_axi_clk, *vpu_clk; +extern int external_pureg; +extern struct regulator *pu_regulator; + static int get_voltage(struct anatop_regulator *sreg) { @@ -90,17 +103,56 @@ static int set_voltage(struct anatop_regulator *sreg, int uv) static int pu_enable(struct anatop_regulator *sreg) { - unsigned int reg; + unsigned int reg, vddsoc; + int ret = 0; + /*get PU related clk to finish PU regulator power up*/ + if (!get_clk) { + if (!cpu_is_mx6sl()) { + gpu3d_clk = clk_get(NULL, "gpu3d_clk"); + if (IS_ERR(gpu3d_clk)) + printk(KERN_ERR "%s: failed to get gpu3d_clk!\n" + , __func__); + gpu3d_shade_clk = clk_get(NULL, "gpu3d_shader_clk"); + if (IS_ERR(gpu3d_shade_clk)) + printk(KERN_ERR "%s: failed to get shade_clk!\n" + , __func__); + if (IS_ERR(vpu_clk)) + printk(KERN_ERR "%s: failed to get vpu_clk!\n", + __func__); + } + gpu2d_clk = clk_get(NULL, "gpu2d_clk"); + if (IS_ERR(gpu2d_clk)) + printk(KERN_ERR "%s: failed to get gpu2d_clk!\n", + __func__); + gpu2d_axi_clk = clk_get(NULL, "gpu2d_axi_clk"); + if (IS_ERR(gpu2d_axi_clk)) + printk(KERN_ERR "%s: failed to get gpu2d_axi_clk!\n", + __func__); + openvg_axi_clk = clk_get(NULL, "openvg_axi_clk"); + if (IS_ERR(openvg_axi_clk)) + printk(KERN_ERR "%s: failed to get openvg_axi_clk!\n", + __func__); + get_clk = 1; - /* Do not enable PU LDO if it is already enabled */ - reg = __raw_readl(ANADIG_REG_CORE) & (ANADIG_REG_TARGET_MASK - << ANADIG_REG1_PU_TARGET_OFFSET); - if (reg != 0) - return 0; - - /* Set the voltage of VDDPU as in normal mode. */ - __raw_writel(org_ldo | (__raw_readl(ANADIG_REG_CORE) & - (~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET))), ANADIG_REG_CORE); + } + if (external_pureg) { + /*enable extern PU regulator*/ + ret = regulator_enable(pu_regulator); + if (ret < 0) + printk(KERN_ERR "%s: enable pu error!\n", __func__); + } else { + /*Track the voltage of VDDPU with VDDSOC if use internal PU + *regulator. + */ + reg = __raw_readl(ANADIG_REG_CORE); + vddsoc = reg & (ANADIG_REG_TARGET_MASK << + ANADIG_REG2_SOC_TARGET_OFFSET); + reg &= ~(ANADIG_REG_TARGET_MASK << + ANADIG_REG1_PU_TARGET_OFFSET); + reg |= vddsoc >> (ANADIG_REG2_SOC_TARGET_OFFSET + -ANADIG_REG1_PU_TARGET_OFFSET); + __raw_writel(reg, ANADIG_REG_CORE); + } /* Need to wait for the regulator to come back up */ /* @@ -109,7 +161,17 @@ static int pu_enable(struct anatop_regulator *sreg) * 25mV step. */ udelay(150); - + /*enable gpu clock to powerup GPU right.*/ + if (get_clk) { + if (!cpu_is_mx6sl()) { + clk_enable(gpu3d_clk); + clk_enable(gpu3d_shade_clk); + clk_enable(vpu_clk); + } + clk_enable(gpu2d_clk); + clk_enable(gpu2d_axi_clk); + clk_enable(openvg_axi_clk); + } /* enable power up request */ reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET); __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); @@ -119,7 +181,6 @@ static int pu_enable(struct anatop_regulator *sreg) /* Wait for the power up bit to clear */ while (__raw_readl(gpc_base + GPC_CNTR_OFFSET) & 0x2) ; - /* Enable the Brown Out detection. */ reg = __raw_readl(ANA_MISC2_BASE_ADDR); reg |= ANADIG_ANA_MISC2_REG1_BO_EN; @@ -131,19 +192,24 @@ static int pu_enable(struct anatop_regulator *sreg) reg &= ~0x80000000; __raw_writel(reg, gpc_base + 0x14); #endif - + pu_is_enabled = 1; + if (get_clk) { + if (!cpu_is_mx6sl()) { + clk_disable(gpu3d_clk); + clk_disable(gpu3d_shade_clk); + clk_disable(vpu_clk); + } + clk_disable(gpu2d_clk); + clk_disable(gpu2d_axi_clk); + clk_disable(openvg_axi_clk); + } return 0; } static int pu_disable(struct anatop_regulator *sreg) { unsigned int reg; - - /* Do not disable PU LDO if it is not enabled */ - reg = __raw_readl(ANADIG_REG_CORE) & (ANADIG_REG_TARGET_MASK - << ANADIG_REG1_PU_TARGET_OFFSET); - if (reg == 0) - return 0; + int ret = 0; /* Disable the brown out detection since we are going to be * disabling the LDO. @@ -163,7 +229,6 @@ static int pu_disable(struct anatop_regulator *sreg) /* Wait for power down to complete. */ while (__raw_readl(gpc_base + GPC_CNTR_OFFSET) & 0x1) ; - #ifndef CONFIG_MX6_INTER_LDO_BYPASS /* Mask the ANATOP brown out interrupt in the GPC. */ reg = __raw_readl(gpc_base + 0x14); @@ -171,12 +236,19 @@ static int pu_disable(struct anatop_regulator *sreg) __raw_writel(reg, gpc_base + 0x14); #endif - /* PU power gating. */ - reg = __raw_readl(ANADIG_REG_CORE); - org_ldo = reg & (ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET); - reg &= ~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET); - __raw_writel(reg, ANADIG_REG_CORE); - + if (external_pureg) { + /*disable extern PU regulator*/ + ret = regulator_disable(pu_regulator); + if (ret < 0) + printk(KERN_ERR "%s: disable pu error!\n", __func__); + } else { + /* PU power gating. */ + reg = __raw_readl(ANADIG_REG_CORE); + reg &= ~(ANADIG_REG_TARGET_MASK << + ANADIG_REG1_PU_TARGET_OFFSET); + __raw_writel(reg, ANADIG_REG_CORE); + } + pu_is_enabled = 0; /* Clear the BO interrupt in the ANATOP. */ reg = __raw_readl(ANADIG_MISC1_REG); reg |= 0x80000000; @@ -185,14 +257,7 @@ static int pu_disable(struct anatop_regulator *sreg) } static int is_pu_enabled(struct anatop_regulator *sreg) { - unsigned int reg; - - reg = __raw_readl(ANADIG_REG_CORE) & (ANADIG_REG_TARGET_MASK - << ANADIG_REG1_PU_TARGET_OFFSET); - if (reg == 0) - return 0; - else - return 1; + return pu_is_enabled; } static int enable(struct anatop_regulator *sreg) { @@ -447,6 +512,9 @@ static int __init regulators_init(void) anatop_register_regulator(&vdd1p1_reg, ANATOP_VDD1P1, &vdd1p1_init); anatop_register_regulator(&vdd3p0_reg, ANATOP_VDD3P0, &vdd3p0_init); + /* clear flag in boot*/ + pu_is_enabled = 0; + get_clk = 0; return 0; } postcore_initcall(regulators_init); diff --git a/arch/arm/mach-mx6/mx6_suspend.S b/arch/arm/mach-mx6/mx6_suspend.S index 0533ad1b20ef..e8fd2b259aae 100644 --- a/arch/arm/mach-mx6/mx6_suspend.S +++ b/arch/arm/mach-mx6/mx6_suspend.S @@ -32,7 +32,7 @@ #define MMDC_MAPSR_OFFSET 0x404 #define MMDC_MAPSR_PSS (1 << 4) #define MMDC_MAPSR_PSD (1 << 0) -#define IRAM_SUSPEND_SIZE (1 << 12) +#define IRAM_SUSPEND_SIZE (1 << 13) /************************************************************* mx6_suspend: @@ -50,6 +50,333 @@ see define in include/linux/suspend.h r1: iram_paddr r2: suspend_iram_base *************************************************************/ + .macro mx6sl_standy_saving_set + + /* Move periph_clk to OSC_CLK. */ + ldr r1, =CCM_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Ensure the periph_clk2_sel to OSC clk. */ + ldr r0, [r1, #0x18] + bic r0, r0, #0x3000 + orr r0, r0, #0x1000 + str r0, [r1, #0x18] + + ldr r0, [r1, #0x14] + orr r0, r0, #0x2000000 + str r0, [r1, #0x14] + +periph_clk_switch: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne periph_clk_switch + + /* Set the divider to divider by 8 */ + ldr r0, [r1, #0x14] + orr r0, r0, #0x70000 + orr r0, r0, #0x1c00 + str r0, [r1, #0x14] + +ahb_podf: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne ahb_podf + + /* Move DDR clk to PLL3 clock. + */ + /* First set the divider to 2. */ + ldr r0, [r1, #0x14] + orr r0, r0, #0x1 + str r0, [r1, #0x14] + + ldr r0, [r1, #0x18] + bic r0, r0, #0x100000 + str r0, [r1, #0x18] + + ldr r0, [r1, #0x14] + orr r0, r0, #0x4000000 + str r0, [r1, #0x14] + +ddr_switch: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne ddr_switch + + /* Set DDR clock to divide by 8. */ + ldr r0, [r1, #0x14] + orr r0, r0, #0x38 + str r0, [r1, #0x14] + +mmdc_div: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne mmdc_div + + /* Now Switch ARM to run from + * step_clk sourced from OSC. + */ + ldr r0, [r1, #0xc] + bic r0, r1, #0x100 + str r0, [r1, #0x0c] + + /* Now switch PLL1_SW_CLK to step_clk. */ + ldr r0, [r1, #0x0c] + orr r0, r0, #0x4 + str r0, [r1, #0x0c] + + ldr r1, =ANATOP_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Need to clock gate the 528 PFDs before + * powering down PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC/AHB + */ + ldr r0, [r1, #0x100] + orr r0, r0, #0x800000 + str r0, [r1, #0x100] + + /* Now bypass PLL1 and PLL2. */ + ldr r0, =0x10000 + str r0, [r1, #0x4] + str r0, [r1, #0x34] + + /* Now do all the analog savings. */ + + /* Disable 1p1 brown out. */ + ldr r0, [r1, #0x110] + bic r0, r0, #0x2 + str r0, [r1, #0x110] + + /* Enable the weak 2P5 */ + ldr r0, [r1, #0x130] + orr r0, r0, #0x40000 + str r0, [r1, #0x130] + + /*Disable main 2p5. */ + ldr r0, [r1, #0x130] + bic r0, r0, #0x1 + str r0, [r1, #0x130] + + + /* Set the OSC bias current to -37.5% + * to drop the power on VDDHIGH. + */ + ldr r0, [r1, #0x150] + orr r0, r0, #0xC000 + str r0, [r1, #0x150] + .endm + + .macro mx6sl_standby_savings_restore + + /* Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r1, #0x150] + bic r6, r6, #0xC000 + str r6, [r1, #0x150] + + /*Enable main 2p5. */ + ldr r6, [r1, #0x130] + orr r6, r6, #0x1 + str r6, [r1, #0x130] + + /* Ensure the 2P5 is up. */ +loop_2p5: + ldr r6, [r1, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne loop_2p5 + + /* Disable the weak 2P5 */ + ldr r6, [r1, #0x130] + bic r6, r6, #0x40000 + str r6, [r1, #0x130] + + /* Enable 1p1 brown out. */ + ldr r6, [r1, #0x110] + orr r6, r6, #0x2 + str r6, [r1, #0x110] + + /* Unbypass PLLs and + * wait for relock. + */ + ldr r6, =(1 << 16) + str r6, [r1, #0x08] + str r6, [r1, #0x38] + +wait_for_pll_lock: + ldr r6, [r1, #0x0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock + + /* Set PLL1_sw_clk back to PLL1. */ + ldr r6, [r3, #0x0c] + bic r6, r6, #0x4 + str r6, [r3, #0xc] + + /* Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r1, #0x100] + bic r6, r6, #0x800000 + str r6, [r1, #0x100] + + /* Move periph_clk back + * to PLL2_PFD2_400. + */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x2000000 + str r6, [r3, #0x14] + + /* Set the dividers to default value. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x70000 + bic r6, r6, #0x1c00 + orr r6, r6, #0x10800 + str r6, [r3, #0x14] + +ahb_podf1: + ldr r0, [r3, #0x48] + cmp r0, #0 + bne ahb_podf1 + +periph_clk_switch1: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne periph_clk_switch1 + + /* Move MMDC back to PLL2_PFD2_400 */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x4000000 + str r6, [r3, #0x14] + +mmdc_loop2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_loop2 + + /* Set DDR clock to divide by 1. */ + ldr r6, [r3, #0x14] + bic r6, r0, #0x38 + str r6, [r3, #0x14] + +mmdc_div1: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_div1 + + .endm + + .macro mx6sl_standby_pg_savings_restore + + /* Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r1, #0x150] + bic r6, r6, #0xC000 + str r6, [r1, #0x150] + + /*Enable main 2p5. */ + ldr r6, [r1, #0x130] + orr r6, r6, #0x1 + str r6, [r1, #0x130] + + /* Ensure the 2P5 is up. */ +loop_2p5_1: + ldr r6, [r1, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne loop_2p5_1 + + /* Disable the weak 2P5 */ + ldr r6, [r1, #0x130] + bic r6, r6, #0x40000 + str r6, [r1, #0x130] + + /* Enable 1p1 brown out. */ + ldr r6, [r1, #0x110] + orr r6, r6, #0x2 + str r6, [r1, #0x110] + + /* Unbypass PLLs and + * wait for relock. + */ + ldr r6, =(1 << 16) + str r6, [r1, #0x08] + str r6, [r1, #0x38] + +wait_for_pll_lock1: + ldr r6, [r1, #0x0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock1 + + /* Set PLL1_sw_clk back to PLL1. */ + ldr r6, [r3, #0x0c] + bic r6, r6, #0x4 + str r6, [r3, #0xc] + + /* Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r1, #0x100] + bic r6, r6, #0x800000 + str r6, [r1, #0x100] + + /* Move DDR clock back to PLL2_PFD2_400 */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x4000000 + str r6, [r3, #0x14] + +mmdc_loop3: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_loop3 + + /* Set DDR clock to divide by 1. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x38 + str r6, [r3, #0x14] + +mmdc_div2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_div2 + + /* Move periph_clk back + * to PLL2_PFD2_400. + */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x2000000 + str r6, [r3, #0x14] + +periph_clk_switch2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne periph_clk_switch2 + + /* Set the dividers to default value. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x70000 + bic r6, r6, #0x1c00 + orr r6, r6, #0x10800 + str r6, [r3, #0x14] + +ahb_podf2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne ahb_podf2 + + .endm + .macro sl_ddr_io_save ldr r4, [r1, #0x30c] /* DRAM_DQM0 */ @@ -58,12 +385,6 @@ r2: suspend_iram_base ldr r7, [r1, #0x318] /* DRAM_DQM3 */ stmfd r0!, {r4-r7} - ldr r4, [r1, #0x344] /* DRAM_SDQS0 */ - ldr r5, [r1, #0x348] /* DRAM_SDQS1 */ - ldr r6, [r1, #0x34c] /* DRAM_SDQS2 */ - ldr r7, [r1, #0x350] /* DRAM_SDQS3 */ - stmfd r0!, {r4-r7} - ldr r4, [r1, #0x5c4] /* GPR_B0DS */ ldr r5, [r1, #0x5cc] /* GPR_B1DS */ ldr r6, [r1, #0x5d4] /* GPR_B2DS */ @@ -73,7 +394,7 @@ r2: suspend_iram_base ldr r4, [r1, #0x300] /* DRAM_CAS */ ldr r5, [r1, #0x31c] /* DRAM_RAS */ ldr r6, [r1, #0x338] /* DRAM_SDCLK_0 */ - ldr r7, [r1, #0x5ac] /* GPR_ADDS*/ + ldr r7, [r1, #0x5ac] /* GPR_ADDS*/ stmfd r0!, {r4-r7} ldr r4, [r1, #0x5b0] /* DDRMODE_CTL */ @@ -98,22 +419,16 @@ r2: suspend_iram_base str r7, [r1, #0x318] /* DRAM_DQM3 */ ldmea r0!, {r4-r7} - str r4, [r1, #0x344] /* DRAM_SDQS0 */ - str r5, [r1, #0x348] /* DRAM_SDQS1 */ - str r6, [r1, #0x34c] /* DRAM_SDQS2 */ - str r7, [r1, #0x350] /* DRAM_SDQS3 */ - - ldmea r0!, {r4-r7} str r4, [r1, #0x5c4] /* GPR_B0DS */ str r5, [r1, #0x5cc] /* GPR_B1DS */ - str r6, [r1, #0x5d4] /* GPR_B2DS */ - str r7, [r1, #0x5d8] /* GPR_B3DS */ + str r6, [r1, #0x5d4] /* GPR_B2DS */ + str r7, [r1, #0x5d8] /* GPR_B3DS */ ldmea r0!, {r4-r7} str r4, [r1, #0x300] /* DRAM_CAS */ str r5, [r1, #0x31c] /* DRAM_RAS */ str r6, [r1, #0x338] /* DRAM_SDCLK_0 */ - str r7, [r1, #0x5ac] /* GPR_ADDS*/ + str r7, [r1, #0x5ac] /* GPR_ADDS*/ ldmea r0!, {r4-r7} str r4, [r1, #0x5b0] /* DDRMODE_CTL */ @@ -136,27 +451,15 @@ r2: suspend_iram_base str r0, [r1, #0x314] /* DRAM_DQM2 */ str r0, [r1, #0x318] /* DRAM_DQM3 */ - /* Make sure the Pull Ups are enabled. - * So only reduce the drive stength, but - * leave the pull-ups in the original state. - * This is required for LPDDR2. - */ - ldr r0, [r1, #0x344] - orr r0, r0, #0x3000 - str r0, [r1, #0x344] /* DRAM_SDQS0 */ - str r0, [r1, #0x348] /* DRAM_SDQS1 */ - str r0, [r1, #0x34c] /* DRAM_SDQS2 */ - str r0, [r1, #0x350] /* DRAM_SDQS3 */ - str r0, [r1, #0x5c4] /* GPR_B0DS */ str r0, [r1, #0x5cc] /* GPR_B1DS */ - str r0, [r1, #0x5d4] /* GPR_B2DS */ - str r0, [r1, #0x5d8] /* GPR_B3DS */ + str r0, [r1, #0x5d4] /* GPR_B2DS */ + str r0, [r1, #0x5d8] /* GPR_B3DS */ str r0, [r1, #0x300] /* DRAM_CAS */ str r0, [r1, #0x31c] /* DRAM_RAS */ str r0, [r1, #0x338] /* DRAM_SDCLK_0 */ - str r0, [r1, #0x5ac] /* GPR_ADDS*/ + str r0, [r1, #0x5ac] /* GPR_ADDS*/ str r0, [r1, #0x5b0] /* DDRMODE_CTL */ str r0, [r1, #0x5c0] /* DDRMODE */ @@ -617,6 +920,10 @@ ENTRY(mx6_suspend) suspend mode entry *************************************************************/ mov r12, r3 /* Save CPU type to r12*/ + mov r11, r0 /* Save the state in r11 */ + + cmp r12, #MXC_CPU_MX6SL + beq dormant cmp r0, #0x1 bne dormant /* dormant mode */ @@ -666,14 +973,17 @@ suspend mode entry never run to here ************************************************************/ b out /* exit standby */ - + /* Place the literal pool here so that + * literals are within 4KB range + */ + .ltorg /************************************************************ dormant entry, data save in stack, save sp in the src_gpr2 ************************************************************/ dormant: mov r3, r1 mov r0, r1 - add r0, r0, #IRAM_SUSPEND_SIZE /* 4K */ + add r0, r0, #IRAM_SUSPEND_SIZE /* 8K */ ldr r4, =SRC_BASE_ADDR add r4, r4, #PERIPBASE_VIRT str r0, [r4, #SRC_GPR2_OFFSET] /* set src_gpr2 */ @@ -701,10 +1011,12 @@ saved register and context as below: iram_suspend base */ mov r0, r2 /* get suspend_iram_base */ - add r0, r0, #IRAM_SUSPEND_SIZE /* 4K */ + add r0, r0, #IRAM_SUSPEND_SIZE /* 8K */ mov r4, r12 @ Store cpu type stmfd r0!, {r4} + mov r4, r11 @ Store state entered + stmfd r0!, {r4} ldr r1, =MX6Q_IOMUXC_BASE_ADDR add r1, r1, #PERIPBASE_VIRT @@ -784,6 +1096,9 @@ set ddr iomux to low power mode ldr r1, =SRC_BASE_ADDR add r1, r1, #PERIPBASE_VIRT ldr r0, [r1] + ldr r1, =CCM_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r0, [r1] #ifdef CONFIG_MX6_INTER_LDO_BYPASS ldr r1, =ANATOP_BASE_ADDR add r1, r1, #PERIPBASE_VIRT @@ -795,14 +1110,23 @@ set ddr iomux to low power mode ldr r1, =MMDC_P0_BASE_ADDR add r1, r1, #PERIPBASE_VIRT - ldr r0, [r1, #MMDC_MAPSR_OFFSET] - bic r0, #MMDC_MAPSR_PSD /* enable lpm */ - str r0, [r1, #MMDC_MAPSR_OFFSET] -refresh: - ldr r0, [r1, #MMDC_MAPSR_OFFSET] /* MMDC_MAPSR */ - and r0, r0, #MMDC_MAPSR_PSS /* PSS bit */ - cmp r0, #0 - beq refresh + + /* Put DDR explicitly into self-refresh. */ + /* Disable Automatic power savings. */ + ldr r0, [r1, #0x404] + orr r0, r0, #0x01 + str r0, [r1, #0x404] + + /* Make the DDR explicitly enter self-refresh. */ + ldr r0, [r1, #0x404] + orr r0, r0, #0x200000 + str r0, [r1, #0x404] + + poll_dvfs_set_1: + ldr r0, [r1, #0x404] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + bne poll_dvfs_set_1 /* set mmdc iomux to low power mode */ ldr r1, =MX6Q_IOMUXC_BASE_ADDR @@ -822,6 +1146,22 @@ sl_io_set_lpm: ddr_io_set_lpm_done: + /* Do Analog Power Optimizations + * for MX6SL in standby mode. + */ + cmp r12, #MXC_CPU_MX6SL + bne no_analog_savings + cmp r11, #1 + bne no_analog_savings + + /* We are here because on + * MX6SL, we want to lower + * the power in Standby mode. + */ + mx6sl_standy_saving_set + +no_analog_savings: + /**************************************************************** save resume pointer into SRC_GPR1 ****************************************************************/ @@ -832,13 +1172,14 @@ save resume pointer into SRC_GPR1 ldr r1, =SRC_BASE_ADDR add r1, r1, #PERIPBASE_VIRT str r3, [r1, #SRC_GPR1_OFFSET] + #ifdef CONFIG_MX6_INTER_LDO_BYPASS ldr r1, =ANATOP_BASE_ADDR add r1, r1, #PERIPBASE_VIRT - ldr r3, [r1, #0x140] - bic r3, r3, #0x1f - orr r3, r3, #0x1e - str r3, [r1, #0x140] + ldr r4, [r1, #0x140] + bic r4, r4, #0x1f + orr r4, r4, #0x1e + str r4, [r1, #0x140] #endif /**************************************************************** execute a wfi instruction to let SOC go into stop mode. @@ -863,11 +1204,26 @@ system immediately. #endif mov r0, r2 /* get suspend_iram_base */ - add r0, r0, #IRAM_SUSPEND_SIZE /* 4K */ + add r0, r0, #IRAM_SUSPEND_SIZE /* 8K */ ldmea r0!, {r12} @ get cpu type to make ddr io @ offset right + ldmea r0!, {r11} @ standby or mem + + cmp r12, #MXC_CPU_MX6SL + bne no_analog_restore + + cmp r11, #0x1 + bne no_analog_restore + + ldr r3, =CCM_BASE_ADDR + add r3, r3, #PERIPBASE_VIRT + + /* Restore the analog settings. */ + mx6sl_standby_savings_restore + +no_analog_restore: ldr r1, =MX6Q_IOMUXC_BASE_ADDR add r1, r1, #PERIPBASE_VIRT @@ -882,8 +1238,46 @@ dl_io_restore: b ddr_io_restore_done sl_io_restore: sl_ddr_io_restore + ldr r1, =MMDC_P0_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =0x83c + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +fifo_reset1_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne fifo_reset1_wait + + /* reset FIFO a second time */ + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +fifo_reset2_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne fifo_reset2_wait ddr_io_restore_done: + /* Ensure DDR exits self-refresh. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x200000 + str r6, [r1, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r1, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x01 + str r6, [r1, #0x404] + /* Add enough nops so that the * prefetcher will not get instructions * from DDR before its IO pads @@ -930,6 +1324,7 @@ when SOC exit stop mode, arm core restart from here, currently are running with MMU off. ****************************************************************/ resume: + #ifdef CONFIG_MX6_INTER_LDO_BYPASS ldr r1, =ANATOP_BASE_ADDR ldr r3, [r1, #0x140] @@ -954,6 +1349,22 @@ resume: ldmea r0!, {r12} @ get cpu type + ldmea r0!, {r11} @ standby or mem + + + cmp r12, #MXC_CPU_MX6SL + bne no_analog_restore1 + + cmp r11, #0x1 + bne no_analog_restore1 + + ldr r1, =ANATOP_BASE_ADDR + ldr r3, =CCM_BASE_ADDR + + /* Restore the analog settings. */ + mx6sl_standby_pg_savings_restore + +no_analog_restore1: /* Restore DDR IO */ ldr r1, =MX6Q_IOMUXC_BASE_ADDR @@ -968,8 +1379,44 @@ dl_io_dsm_restore: b ddr_io_restore_dsm_done sl_io_dsm_restore: sl_ddr_io_restore + ldr r1, =MMDC_P0_BASE_ADDR + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =0x83c + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +dsm_fifo_reset1_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne dsm_fifo_reset1_wait + + /* reset FIFO a second time */ + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +dsm_fifo_reset2_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne dsm_fifo_reset2_wait ddr_io_restore_dsm_done: + /* Ensure DDR exits self-refresh. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x200000 + str r6, [r1, #0x404] + +poll_dvfs_clear_2: + ldr r6, [r1, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_2 + + /* Enable Automatic power savings. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x01 + str r6, [r1, #0x404] #ifdef CONFIG_CACHE_L2X0 ldr r2, =L2_BASE_ADDR @@ -1084,11 +1531,11 @@ restore control register to enable cache #endif mov r8, lr - push {r0} + push {r0-r12} /* Set up the per-CPU stacks */ bl cpu_init - pop {r0} + pop {r0-r12} /* * Restore the MMU table entry that was modified for diff --git a/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c index 134700a6d200..5cf34073bdc1 100644 --- a/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c +++ b/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c @@ -40,13 +40,13 @@ #define PFUZE100_I2C_ADDR (0x08) /*SWBST*/ #define PFUZE100_SW1ASTANDBY 33 -#define PFUZE100_SW1ASTANDBY_STBY_VAL (0x16) +#define PFUZE100_SW1ASTANDBY_STBY_VAL (0x19) /* 925mV */ #define PFUZE100_SW1ASTANDBY_STBY_M (0x3f<<0) #define PFUZE100_SW1BSTANDBY 40 -#define PFUZE100_SW1BSTANDBY_STBY_VAL (0x16) +#define PFUZE100_SW1BSTANDBY_STBY_VAL (0x19) /* 925mV */ #define PFUZE100_SW1BSTANDBY_STBY_M (0x3f<<0) #define PFUZE100_SW1CSTANDBY 47 -#define PFUZE100_SW1CSTANDBY_STBY_VAL (0x16) +#define PFUZE100_SW1CSTANDBY_STBY_VAL (0x19) /* 925mV */ #define PFUZE100_SW1CSTANDBY_STBY_M (0x3f<<0) #define PFUZE100_SW2STANDBY 54 #define PFUZE100_SW2STANDBY_STBY_VAL 0x0 diff --git a/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c index ee66541f8bff..981d149d7aee 100644 --- a/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c +++ b/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c @@ -40,13 +40,13 @@ #define PFUZE100_I2C_ADDR (0x08) /*SWBST*/ #define PFUZE100_SW1ASTANDBY 33 -#define PFUZE100_SW1ASTANDBY_STBY_VAL (0x16) +#define PFUZE100_SW1ASTANDBY_STBY_VAL (0x19) /* 925mv */ #define PFUZE100_SW1ASTANDBY_STBY_M (0x3f<<0) #define PFUZE100_SW1BSTANDBY 40 -#define PFUZE100_SW1BSTANDBY_STBY_VAL (0x16) +#define PFUZE100_SW1BSTANDBY_STBY_VAL (0x19) /* 925mv */ #define PFUZE100_SW1BSTANDBY_STBY_M (0x3f<<0) #define PFUZE100_SW1CSTANDBY 47 -#define PFUZE100_SW1CSTANDBY_STBY_VAL (0x16) +#define PFUZE100_SW1CSTANDBY_STBY_VAL (0x19) /* 925mv */ #define PFUZE100_SW1CSTANDBY_STBY_M (0x3f<<0) #define PFUZE100_SW2STANDBY 54 #define PFUZE100_SW2STANDBY_STBY_VAL 0x0 @@ -143,7 +143,7 @@ static struct regulator_consumer_supply vgen5_consumers[] = { }; static struct regulator_consumer_supply vgen6_consumers[] = { { - .supply = "VGEN6_3V3", + .supply = "VGEN6_2V8", } }; diff --git a/arch/arm/mach-mx6/mx6sl_wfi.S b/arch/arm/mach-mx6/mx6sl_wfi.S index 89fe4e292352..dc4107dff7e8 100644 --- a/arch/arm/mach-mx6/mx6sl_wfi.S +++ b/arch/arm/mach-mx6/mx6sl_wfi.S @@ -235,15 +235,53 @@ mmdc_podf: /* Set the DDR IO in LPM state. */ sl_ddr_io_set_lpm - /* Set AHB to 8MHz., AXI to 3MHz */ - /* We want to ensure IPG_PERCLK to AHB - * clk ratio is 1:2.5 + /* Check if none of the PLLs are + * locked, except PLL1 which will get + * bypassed below. + * We should not be here if PLL2 is not + * bypassed. */ - /* Store the AXI/AHB podfs. */ + ldr r7, =1 + /* USB1 PLL3 */ + ldr r6, [r3, #0x10] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* USB2 PLL7 */ + ldr r6, [r3, #0x20] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* Audio PLL4 */ + ldr r6, [r3, #0x70] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* Video PLL5 */ + ldr r6, [r3, #0xA0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* ENET PLL8 */ + ldr r6, [r3, #0xE0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + b cont + +no_analog_saving: + ldr r7, =0 + +cont: + /*Set the AHB to 3MHz. AXI to 3MHz. */ ldr r9, [r2, #0x14] mov r6, r9 - bic r6, r6, #0x1c00 - orr r6, r6, #0x800 + orr r6, r6, #0x1c00 orr r6, r6, #0x70000 str r6, [r2, #0x14] @@ -271,7 +309,7 @@ ahb_podf: str r6, [r3, #0x04] /* Set the ARM PODF to divide by 8. */ - /* IPG is at 4MHz here, we need ARM to + /* IPG is at 1.5MHz here, we need ARM to * run at the 12:5 ratio (WAIT mode issue). */ ldr r6, =0x7 @@ -283,9 +321,62 @@ podf_loop: cmp r6, #0x0 bne podf_loop - /* Now do WFI. */ - dsb + /* Check if we can save some + * in the Analog section. + */ + cmp r7, #0x1 + bne do_wfi + + /* Disable 1p1 brown out. */ + ldr r6, [r3, #0x110] + bic r6, r6, #0x2 + str r6, [r3, #0x110] + + /* Enable the weak 2P5 */ + ldr r6, [r3, #0x130] + orr r6, r6, #0x40000 + str r6, [r3, #0x130] + + /*Disable main 2p5. */ + ldr r6, [r3, #0x130] + bic r6, r6, #0x1 + str r6, [r3, #0x130] + + /* Set the OSC bias current to -37.5% + * to drop the power on VDDHIGH. + */ + ldr r6, [r3, #0x150] + orr r6, r6, #0xC000 + str r6, [r3, #0x150] + + /* Enable low power bandgap */ + ldr r6, [r3, #0x260] + orr r6, r6, #0x20 + str r6, [r3, #0x260] + + /* turn off the bias current + * from the regular bandgap. + */ + ldr r6, [r3, #0x260] + orr r6, r6, #0x80 + str r6, [r3, #0x260] + + /* Clear the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r6, [r3, #0x150] + bic r6, r6, #0x8 + str r6, [r3, #0x150] + + /*Power down the regular bandgap. */ + ldr r6, [r3, #0x150] + orr r6, r6, #0x1 + str r6, [r3, #0x150] +do_wfi: + /* Now do WFI. */ wfi /* Set original ARM PODF back. */ @@ -297,6 +388,60 @@ podf_loop1: cmp r6, #0x0 bne podf_loop1 + /* Check if powered down + * analog components. + */ + cmp r7, #0x1 + bne skip_analog_restore + + /*Power up the regular bandgap. */ + ldr r6, [r3, #0x150] + bic r6, r6, #0x1 + str r6, [r3, #0x150] + + /* turn on the bias current + * from the regular bandgap. + */ + ldr r6, [r3, #0x260] + bic r6, r6, #0x80 + str r6, [r3, #0x260] + + /* Disable the low power bandgap */ + ldr r6, [r3, #0x260] + bic r6, r6, #0x20 + str r6, [r3, #0x260] + + /* Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r3, #0x150] + bic r6, r6, #0xC000 + str r6, [r3, #0x150] + + /*Enable main 2p5. */ + ldr r6, [r3, #0x130] + orr r6, r6, #0x1 + str r6, [r3, #0x130] + + /* Ensure the 2P5 is up. */ +loop_2p5: + ldr r6, [r3, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne loop_2p5 + + /* Disable the weak 2P5 */ + ldr r6, [r3, #0x130] + bic r6, r6, #0x40000 + str r6, [r3, #0x130] + + /* Enable 1p1 brown out. */ + ldr r6, [r3, #0x110] + orr r6, r6, #0x2 + str r6, [r3, #0x110] + +skip_analog_restore: + /* Power up PLL1 and un-bypass it. */ ldr r6, =(1 << 12) str r6, [r3, #0x08] diff --git a/arch/arm/mach-mx6/pm.c b/arch/arm/mach-mx6/pm.c index 45b2e6fffbeb..faf1a59ec2d6 100644 --- a/arch/arm/mach-mx6/pm.c +++ b/arch/arm/mach-mx6/pm.c @@ -73,7 +73,6 @@ static struct clk *cpu_clk; static struct clk *axi_clk; static struct clk *periph_clk; static struct clk *axi_org_parent; -static struct clk *gpu2d_core_clk; static struct clk *pll3_usb_otg_main_clk; static struct pm_platform_data *pm_data; @@ -114,7 +113,6 @@ static u32 ccm_analog_pll3_480; static u32 ccm_anadig_ana_misc2; static bool usb_vbus_wakeup_enabled; - /* * The USB VBUS wakeup should be disabled to avoid vbus wake system * up due to vbus comparator is closed at weak 2p5 mode. @@ -178,85 +176,6 @@ static void usb_power_up_handler(void) } } -static void gpu_power_down(void) -{ - int reg; - - /* enable power down request */ - reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET); - __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); - /* power down request */ - reg = __raw_readl(gpc_base + GPC_CNTR_OFFSET); - __raw_writel(reg | 0x1, gpc_base + GPC_CNTR_OFFSET); - /* disable clocks */ - __raw_writel(ccgr1 & - ~MXC_CCM_CCGRx_CG12_MASK & - ~MXC_CCM_CCGRx_CG13_MASK, MXC_CCM_CCGR1); - __raw_writel(ccgr3 & ~MXC_CCM_CCGRx_CG15_MASK, MXC_CCM_CCGR3); - __raw_writel(ccgr6 & ~MXC_CCM_CCGRx_CG7_MASK, MXC_CCM_CCGR6); - /* power off pu */ - reg = __raw_readl(anatop_base + ANATOP_REG_CORE_OFFSET); - reg &= ~0x0003fe00; - __raw_writel(reg, anatop_base + ANATOP_REG_CORE_OFFSET); -} - -static void gpu_power_up(void) -{ - int reg; - int i; - /* power on pu */ - reg = __raw_readl(anatop_base + ANATOP_REG_CORE_OFFSET); - reg &= ~0x0003fe00; - reg |= 0x10 << 9; /* 1.1v */ - __raw_writel(reg, anatop_base + ANATOP_REG_CORE_OFFSET); - mdelay(10); - - /* enable clocks */ - /* PLL2 PFD0 and PFD1 clock enable */ - __raw_writel(ccm_analog_pfd528 & - ~ANADIG_PFD0_CLKGATE & - ~ANADIG_PFD1_CLKGATE, PFD_528_BASE_ADDR); - - /* PLL3 480M clock enable which may be used by gpu2d*/ - if (clk_get_parent(gpu2d_core_clk) == pll3_usb_otg_main_clk) { - __raw_writel(ccm_analog_pll3_480 | - ANADIG_PLL_POWER_DOWN, PLL3_480_USB1_BASE_ADDR); - __raw_writel(ccm_anadig_ana_misc2 & - (~BM_ANADIG_ANA_MISC2_CONTROL0), - MXC_PLL_BASE + HW_ANADIG_ANA_MISC2); - for (i = 0; i < 100; i++) { - if (!(__raw_readl(PLL3_480_USB1_BASE_ADDR) & ANADIG_PLL_LOCK)) - udelay(1); - else - break; - } - __raw_writel((ccm_analog_pll3_480 & (~ANADIG_PLL_BYPASS)) | - ANADIG_PLL_ENABLE | ANADIG_PLL_POWER_DOWN, - PLL3_480_USB1_BASE_ADDR); - } - /* gpu3d and gpu2d clock enable */ - __raw_writel(ccgr1 | - MXC_CCM_CCGRx_CG12_MASK | - MXC_CCM_CCGRx_CG13_MASK, MXC_CCM_CCGR1); - /* tzasrc1 clock enable for gpu3d core clock */ - __raw_writel(ccgr2 | MXC_CCM_CCGRx_CG11_MASK, MXC_CCM_CCGR2); - /* openvgaxi clock enable, mmdc_core_ipg_clk_p0 clock and - mmdc_core_aclk_fast_core_p0 clock enable for gpu3d core clock */ - __raw_writel(ccgr3 | - MXC_CCM_CCGRx_CG15_MASK | - MXC_CCM_CCGRx_CG12_MASK | - MXC_CCM_CCGRx_CG10_MASK, MXC_CCM_CCGR3); - /* vpu clock enable */ - __raw_writel(ccgr6 | MXC_CCM_CCGRx_CG7_MASK, MXC_CCM_CCGR6); - - /* enable power up request */ - reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET); - __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); - /* power up request */ - reg = __raw_readl(gpc_base + GPC_CNTR_OFFSET); - __raw_writel(reg | 0x2, gpc_base + GPC_CNTR_OFFSET); - udelay(10); -} static void disp_power_down(void) { @@ -266,12 +185,32 @@ static void disp_power_down(void) __raw_writel(0x1, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); __raw_writel(0x10, gpc_base + GPC_CNTR_OFFSET); + + /* Disable EPDC/LCDIF pix clock, and EPDC/LCDIF/PXP axi clock */ + __raw_writel(ccgr3 & + ~MXC_CCM_CCGRx_CG5_MASK & + ~MXC_CCM_CCGRx_CG4_MASK & + ~MXC_CCM_CCGRx_CG3_MASK & + ~MXC_CCM_CCGRx_CG2_MASK & + ~MXC_CCM_CCGRx_CG1_MASK, MXC_CCM_CCGR3); + } } static void disp_power_up(void) { if (cpu_is_mx6sl()) { + /* + * Need to enable EPDC/LCDIF pix clock, and + * EPDC/LCDIF/PXP axi clock before power up. + */ + __raw_writel(ccgr3 | + MXC_CCM_CCGRx_CG5_MASK | + MXC_CCM_CCGRx_CG4_MASK | + MXC_CCM_CCGRx_CG3_MASK | + MXC_CCM_CCGRx_CG2_MASK | + MXC_CCM_CCGRx_CG1_MASK, MXC_CCM_CCGR3); + __raw_writel(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); __raw_writel(0x20, gpc_base + GPC_CNTR_OFFSET); __raw_writel(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); @@ -343,6 +282,7 @@ static int mx6_suspend_enter(suspend_state_t state) unsigned int cpu_type; struct gic_dist_state gds; struct gic_cpu_state gcs; + bool arm_pg = false; if (cpu_is_mx6q()) cpu_type = MXC_CPU_MX6Q; @@ -377,13 +317,19 @@ static int mx6_suspend_enter(suspend_state_t state) switch (state) { case PM_SUSPEND_MEM: - gpu_power_down(); disp_power_down(); usb_power_down_handler(); mxc_cpu_lp_set(ARM_POWER_OFF); + arm_pg = true; break; case PM_SUSPEND_STANDBY: - mxc_cpu_lp_set(STOP_POWER_OFF); + if (cpu_is_mx6sl()) { + disp_power_down(); + usb_power_down_handler(); + mxc_cpu_lp_set(STOP_XTAL_ON); + arm_pg = true; + } else + mxc_cpu_lp_set(STOP_POWER_OFF); break; default: return -EINVAL; @@ -399,7 +345,7 @@ static int mx6_suspend_enter(suspend_state_t state) local_flush_tlb_all(); flush_cache_all(); - if (state == PM_SUSPEND_MEM) { + if (arm_pg) { /* preserve gic state */ save_gic_dist_state(0, &gds); save_gic_cpu_state(0, &gcs); @@ -408,17 +354,21 @@ static int mx6_suspend_enter(suspend_state_t state) suspend_in_iram(state, (unsigned long)iram_paddr, (unsigned long)suspend_iram_base, cpu_type); - if (state == PM_SUSPEND_MEM) { + if (arm_pg) { /* restore gic registers */ restore_gic_dist_state(0, &gds); restore_gic_cpu_state(0, &gcs); + } + if (state == PM_SUSPEND_MEM || (cpu_is_mx6sl())) { usb_power_up_handler(); disp_power_up(); - gpu_power_up(); } mx6_suspend_restore(); + __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, + anatop_base + HW_ANADIG_ANA_MISC0_CLR); + if (pm_data && pm_data->suspend_exit) pm_data->suspend_exit(); } else { @@ -517,10 +467,10 @@ static int __init pm_init(void) suspend_set_ops(&mx6_suspend_ops); /* Move suspend routine into iRAM */ - cpaddr = (unsigned long)iram_alloc(SZ_4K, &iram_paddr); + cpaddr = (unsigned long)iram_alloc(SZ_8K, &iram_paddr); /* Need to remap the area here since we want the memory region to be executable. */ - suspend_iram_base = __arm_ioremap(iram_paddr, SZ_4K, + suspend_iram_base = __arm_ioremap(iram_paddr, SZ_8K, MT_MEMORY_NONCACHED); pr_info("cpaddr = %x suspend_iram_base=%x\n", (unsigned int)cpaddr, (unsigned int)suspend_iram_base); @@ -529,7 +479,7 @@ static int __init pm_init(void) * Need to run the suspend code from IRAM as the DDR needs * to be put into low power mode manually. */ - memcpy((void *)cpaddr, mx6_suspend, SZ_4K); + memcpy((void *)cpaddr, mx6_suspend, SZ_8K); suspend_in_iram = (void *)suspend_iram_base; @@ -548,11 +498,6 @@ static int __init pm_init(void) printk(KERN_DEBUG "%s: failed to get periph_clk\n", __func__); return PTR_ERR(periph_clk); } - gpu2d_core_clk = clk_get(NULL, "gpu2d_clk"); - if (IS_ERR(gpu2d_core_clk)) { - printk(KERN_DEBUG "%s: failed to get gpu2d_clk\n", __func__); - return PTR_ERR(periph_clk); - } pll3_usb_otg_main_clk = clk_get(NULL, "pll3_main_clk"); if (IS_ERR(pll3_usb_otg_main_clk)) { printk(KERN_DEBUG "%s: failed to get pll3_main_clk\n", __func__); diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c index 800c7cc4e8bd..533d4f5dbfab 100644 --- a/arch/arm/mach-mx6/system.c +++ b/arch/arm/mach-mx6/system.c @@ -51,6 +51,7 @@ extern unsigned int gpc_wake_irq[4]; static void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); +static struct clk *ddr_clk; volatile unsigned int num_cpu_idle; volatile unsigned int num_cpu_idle_lock = 0x0; @@ -132,8 +133,16 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) stop_mode = 2; } break; - case STOP_POWER_ON: + case STOP_XTAL_ON: ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET; + ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + if (cpu_is_mx6sl()) { + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS; + ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY; + } else + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS; + stop_mode = 3; break; default: @@ -146,7 +155,7 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) /* Power down and power up sequence */ __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); - if (stop_mode == 2) { + if (stop_mode >= 2) { /* dormant mode, need to power off the arm core */ __raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET); if (cpu_is_mx6q() || cpu_is_mx6dl()) { @@ -171,38 +180,48 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) HW_ANADIG_REG_CORE); } } else { - /* Disable VDDHIGH_IN to VDDSNVS_IN power path, - * only used when VDDSNVS_IN is powered by dedicated - * power rail */ - anatop_val = __raw_readl(anatop_base + - HW_ANADIG_ANA_MISC0); - anatop_val |= BM_ANADIG_ANA_MISC0_RTC_RINGOSC_EN; - __raw_writel(anatop_val, anatop_base + - HW_ANADIG_ANA_MISC0); - /* We need to allow the memories to be clock gated - * in STOP mode, else the power consumption will - * be very high. */ - reg = __raw_readl(MXC_CCM_CGPR); - reg |= MXC_CCM_CGPR_MEM_IPG_STOP_MASK; - __raw_writel(reg, MXC_CCM_CGPR); + if (stop_mode == 2) { + /* Disable VDDHIGH_IN to VDDSNVS_IN + * power path, only used when VDDSNVS_IN + * is powered by dedicated + * power rail */ + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_ANA_MISC0); + anatop_val |= BM_ANADIG_ANA_MISC0_RTC_RINGOSC_EN; + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_ANA_MISC0); + /* Need to enable pull down if 2P5 is disabled */ + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_REG_2P5); + anatop_val |= BM_ANADIG_REG_2P5_ENABLE_PULLDOWN; + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_REG_2P5); + } } /* DL's TO1.0 can't support DSM mode due to ipg glitch */ - if (mx6dl_revision() != IMX_CHIP_REVISION_1_0) + if ((mx6dl_revision() != IMX_CHIP_REVISION_1_0) + && stop_mode != 3) __raw_writel(__raw_readl(MXC_CCM_CCR) | MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR); - /* Make sure we clear WB_COUNT and re-config it */ - __raw_writel(__raw_readl(MXC_CCM_CCR) & - (~MXC_CCM_CCR_WB_COUNT_MASK) & - (~MXC_CCM_CCR_REG_BYPASS_CNT_MASK), MXC_CCM_CCR); - udelay(80); - /* Reconfigurate WB and RBC counter */ - __raw_writel(__raw_readl(MXC_CCM_CCR) | - (0x1 << MXC_CCM_CCR_WB_COUNT_OFFSET) | - (0x20 << MXC_CCM_CCR_REG_BYPASS_CNT_OFFSET), MXC_CCM_CCR); - - /* Set WB_PER enable */ - ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM; + if (stop_mode != 3) { + /* Make sure we clear WB_COUNT + * and re-config it. + */ + __raw_writel(__raw_readl(MXC_CCM_CCR) & + (~MXC_CCM_CCR_WB_COUNT_MASK) & + (~MXC_CCM_CCR_REG_BYPASS_CNT_MASK), MXC_CCM_CCR); + udelay(80); + /* Reconfigurate WB and RBC counter, need to set WB counter + * to 0x7 to make sure it work normally */ + __raw_writel(__raw_readl(MXC_CCM_CCR) | + (0x7 << MXC_CCM_CCR_WB_COUNT_OFFSET) | + (0x20 << MXC_CCM_CCR_REG_BYPASS_CNT_OFFSET), + MXC_CCM_CCR); + + /* Set WB_PER enable */ + ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM; + } } if (cpu_is_mx6sl() || (mx6q_revision() > IMX_CHIP_REVISION_1_1) || @@ -253,7 +272,14 @@ void arch_idle_single_core(void) ca9_do_idle(); } else { if (low_bus_freq_mode || audio_bus_freq_mode) { - if (cpu_is_mx6sl() && low_bus_freq_mode) { + u32 ddr_usecount; + if (ddr_clk == NULL) + ddr_clk = clk_get(NULL , + "mmdc_ch0_axi"); + ddr_usecount = clk_get_usecount(ddr_clk); + + if (cpu_is_mx6sl() && low_bus_freq_mode + && ddr_usecount == 1) { /* 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 @@ -272,17 +298,41 @@ void arch_idle_single_core(void) * is at 12MHz. This is valid for audio mode on * MX6SL, and all low power modes on MX6DLS. */ - /* PLL1_SW_CLK is sourced from PLL2_PFD2400MHz - * at this point. Move it to bypassed PLL1. - */ - reg = __raw_readl(MXC_CCM_CCSR); - reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - __raw_writel(reg, MXC_CCM_CCSR); - + if (cpu_is_mx6sl() && low_bus_freq_mode) { + /* ARM is from PLL1, need to switch to + * STEP_CLK sourced from 24MHz. + */ + /* Swtich STEP_CLK to 24MHz. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_STEP_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set PLL1_SW_CLK to be from + *STEP_CLK. + */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + + } else { + /* PLL1_SW_CLK is sourced from + * PLL2_PFD2_400MHz at this point. + * Move it to bypassed PLL1. + */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } ca9_do_idle(); - reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - __raw_writel(reg, MXC_CCM_CCSR); + if (cpu_is_mx6sl() && low_bus_freq_mode) { + /* Set PLL1_SW_CLK to be from PLL1 */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } else { + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } } } else { /* diff --git a/arch/arm/mach-mx6/usb.h b/arch/arm/mach-mx6/usb.h index 6914246826f6..f796e7dad87c 100644 --- a/arch/arm/mach-mx6/usb.h +++ b/arch/arm/mach-mx6/usb.h @@ -30,9 +30,6 @@ extern void gpio_usbotg_utmi_inactive(void); extern void __init mx6_usb_dr_init(void); extern bool usb_icbug_swfix_need(void); -extern int usb_stop_mode_refcount(bool enable); -extern void usb_stop_mode_lock(void); -extern void usb_stop_mode_unlock(void); extern void __init mx6_usb_h2_init(void); extern void __init mx6_usb_h3_init(void); diff --git a/arch/arm/mach-mx6/usb_dr.c b/arch/arm/mach-mx6/usb_dr.c index 8fe9700a658f..7b79d98c7d5c 100644 --- a/arch/arm/mach-mx6/usb_dr.c +++ b/arch/arm/mach-mx6/usb_dr.c @@ -173,9 +173,6 @@ static int usb_phy_enable(struct fsl_usb2_platform_data *pdata) static int usbotg_init_ext(struct platform_device *pdev) { struct clk *usb_clk; -#ifdef CONFIG_USB_EHCI_ARC_OTG - void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); -#endif u32 ret; /* at mx6q: this clock is AHB clock for usb core */ @@ -201,12 +198,6 @@ static int usbotg_init_ext(struct platform_device *pdev) mdelay(3); } otg_used++; -#ifdef CONFIG_USB_EHCI_ARC_OTG - usb_stop_mode_lock(); - if (usb_stop_mode_refcount(true) == 1) - __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, anatop_base_addr + HW_ANADIG_ANA_MISC0_SET); - usb_stop_mode_unlock(); -#endif return ret; } @@ -214,9 +205,6 @@ static int usbotg_init_ext(struct platform_device *pdev) static void usbotg_uninit_ext(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; -#ifdef CONFIG_USB_EHCI_ARC_OTG - void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); -#endif clk_disable(usb_phy1_clk); clk_put(usb_phy1_clk); @@ -226,12 +214,6 @@ static void usbotg_uninit_ext(struct platform_device *pdev) usbotg_uninit(pdata); otg_used--; -#ifdef CONFIG_USB_EHCI_ARC_OTG - usb_stop_mode_lock(); - if (usb_stop_mode_refcount(false) == 0) - __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, anatop_base_addr + HW_ANADIG_ANA_MISC0_CLR); - usb_stop_mode_unlock(); -#endif } static void usbotg_clock_gate(bool on) @@ -247,6 +229,13 @@ static void usbotg_clock_gate(bool on) pr_debug("usb_oh3_clk:%d, usb_phy_clk1_ref_count:%d\n", clk_get_usecount(usb_oh3_clk), clk_get_usecount(usb_phy1_clk)); } +static void dr_platform_phy_power_on(void) +{ + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, + anatop_base_addr + HW_ANADIG_ANA_MISC0_SET); +} + void mx6_set_otghost_vbus_func(driver_vbus_func driver_vbus) { dr_utmi_config.platform_driver_vbus = driver_vbus; @@ -643,6 +632,7 @@ void __init mx6_usb_dr_init(void) dr_utmi_config.is_wakeup_event = _is_host_wakeup; dr_utmi_config.wakeup_pdata = &dr_wakeup_config; dr_utmi_config.wakeup_handler = host_wakeup_handler; + dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on; pdev = imx6q_add_fsl_ehci_otg(&dr_utmi_config); dr_wakeup_config.usb_pdata[1] = pdev->dev.platform_data; #endif @@ -657,6 +647,7 @@ void __init mx6_usb_dr_init(void) dr_utmi_config.wakeup_pdata = &dr_wakeup_config; dr_utmi_config.wakeup_handler = device_wakeup_handler; dr_utmi_config.charger_base_addr = anatop_base_addr; + dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on; pdev = imx6q_add_fsl_usb2_udc(&dr_utmi_config); dr_wakeup_config.usb_pdata[2] = pdev->dev.platform_data; #endif diff --git a/arch/arm/mach-mx6/usb_h1.c b/arch/arm/mach-mx6/usb_h1.c index bece29f7d44b..f86a4f42b0bd 100644 --- a/arch/arm/mach-mx6/usb_h1.c +++ b/arch/arm/mach-mx6/usb_h1.c @@ -90,6 +90,13 @@ static void usbh1_internal_phy_clock_gate(bool on) } } +static void usbh1_platform_phy_power_on(void) +{ + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, + anatop_base_addr + HW_ANADIG_ANA_MISC0_SET); +} + static int usb_phy_enable(struct fsl_usb2_platform_data *pdata) { u32 tmp; @@ -134,7 +141,6 @@ static int fsl_usb_host_init_ext(struct platform_device *pdev) { int ret; struct clk *usb_clk; - void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); usb_clk = clk_get(NULL, "usboh3_clk"); clk_enable(usb_clk); usb_oh3_clk = usb_clk; @@ -146,25 +152,19 @@ static int fsl_usb_host_init_ext(struct platform_device *pdev) } usbh1_internal_phy_clock_gate(true); usb_phy_enable(pdev->dev.platform_data); - usb_stop_mode_lock(); - if (usb_stop_mode_refcount(true) == 1) - __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, anatop_base_addr + HW_ANADIG_ANA_MISC0_SET); - usb_stop_mode_unlock(); + return 0; } static void fsl_usb_host_uninit_ext(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + fsl_usb_host_uninit(pdata); clk_disable(usb_oh3_clk); clk_put(usb_oh3_clk); - usb_stop_mode_lock(); - if (usb_stop_mode_refcount(false) == 0) - __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, anatop_base_addr + HW_ANADIG_ANA_MISC0_CLR); - usb_stop_mode_unlock(); + } static void usbh1_clock_gate(bool on) @@ -374,6 +374,7 @@ static struct fsl_usb2_platform_data usbh1_config = { .phy_lowpower_suspend = _phy_lowpower_suspend, .is_wakeup_event = _is_usbh1_wakeup, .wakeup_handler = h1_wakeup_handler, + .platform_phy_power_on = usbh1_platform_phy_power_on, .transceiver = "utmi", .phy_regs = USB_PHY1_BASE_ADDR, }; diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c index e7278d9501a5..cc26b7adbc76 100755 --- a/arch/arm/plat-mxc/cpufreq.c +++ b/arch/arm/plat-mxc/cpufreq.c @@ -95,15 +95,19 @@ int set_cpu_freq(int freq) ret = regulator_set_voltage(soc_regulator, soc_volt, soc_volt); if (ret < 0) { - printk(KERN_DEBUG "COULD NOT SET SOC VOLTAGE!!!!\n"); + printk(KERN_DEBUG + "COULD NOT SET SOC VOLTAGE!!!!\n"); return ret; } } - if (!IS_ERR(pu_regulator)) { + /*if pu_regulator is enabled, it will be tracked with VDDARM*/ + if (!IS_ERR(pu_regulator) && + regulator_is_enabled(pu_regulator)) { ret = regulator_set_voltage(pu_regulator, pu_volt, pu_volt); if (ret < 0) { - printk(KERN_DEBUG "COULD NOT SET PU VOLTAGE!!!!\n"); + printk(KERN_DEBUG + "COULD NOT SET PU VOLTAGE!!!!\n"); return ret; } } @@ -132,15 +136,19 @@ int set_cpu_freq(int freq) ret = regulator_set_voltage(soc_regulator, soc_volt, soc_volt); if (ret < 0) { - printk(KERN_DEBUG "COULD NOT SET SOC VOLTAGE BACK!!!!\n"); + printk(KERN_DEBUG + "COULD NOT SET SOC VOLTAGE BACK!!!!\n"); return ret; } } - if (!IS_ERR(pu_regulator)) { + /*if pu_regulator is enabled, it will be tracked with VDDARM*/ + if (!IS_ERR(pu_regulator) && + regulator_is_enabled(pu_regulator)) { ret = regulator_set_voltage(pu_regulator, pu_volt, pu_volt); if (ret < 0) { - printk(KERN_DEBUG "COULD NOT SET PU VOLTAGE!!!!\n"); + printk(KERN_DEBUG + "COULD NOT SET PU VOLTAGE!!!!\n"); return ret; } } diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index bdea66b7a1f4..2e666bac3afd 100755 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -185,3 +185,6 @@ config IMX_HAVE_PLATFORM_IMX_VDOA config IMX_HAVE_PLATFORM_IMX_PCIE bool + +config IMX_HAVE_PLATFORM_IMX_FSL_CSI + bool diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index 41287783cb80..102eeaaff38b 100755 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -66,4 +66,5 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_DSI) += platform-imx-mipi_dsi.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_CSI2) += platform-imx-mipi_csi2.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_VDOA) += platform-imx-vdoa.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_PCIE) += platform-imx-pcie.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_FSL_CSI) += platform-imx-fsl-csi.o obj-y += platform-imx-pmu.o diff --git a/arch/arm/plat-mxc/devices/platform-dma.c b/arch/arm/plat-mxc/devices/platform-dma.c index b2cba3db6d6d..7f731954192e 100644 --- a/arch/arm/plat-mxc/devices/platform-dma.c +++ b/arch/arm/plat-mxc/devices/platform-dma.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the @@ -13,19 +13,19 @@ #include <mach/devices-common.h> #ifdef CONFIG_SOC_IMX50 -const struct imx_dma_data imx50_dma_data __initconst = { +const struct imx_dma_res_data imx50_dma_res_data __initconst = { .iobase = MX50_APBHDMA_BASE_ADDR, }; #endif #ifdef CONFIG_SOC_IMX6Q -const struct imx_dma_data imx6q_dma_data __initconst = { +const struct imx_dma_res_data imx6q_dma_res_data __initconst = { .iobase = APBH_DMA_ARB_BASE_ADDR, }; #endif struct platform_device *__init imx_add_dma( - const struct imx_dma_data *data) + const struct imx_dma_res_data *data) { struct resource res[] = { { diff --git a/arch/arm/plat-mxc/devices/platform-imx-fsl-csi.c b/arch/arm/plat-mxc/devices/platform-imx-fsl-csi.c new file mode 100644 index 000000000000..8b6601ccc5a0 --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-imx-fsl-csi.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <asm/sizes.h> +#include <mach/hardware.h> +#include <mach/devices-common.h> + +#define imx_fsl_csi_data_entry_single(soc, size) \ + { \ + .iobase = soc ## _CSI_BASE_ADDR, \ + .irq = soc ## _INT_CSI, \ + .iosize = size, \ + } + +#ifdef CONFIG_SOC_IMX6SL +const struct imx_fsl_csi_data imx6sl_csi_data __initconst = + imx_fsl_csi_data_entry_single(MX6SL, SZ_16K); +#endif + +struct platform_device *__init imx_add_fsl_csi( + const struct imx_fsl_csi_data *data) +{ + struct resource res[] = { + { + .start = data->iobase, + .end = data->iobase + data->iosize - 1, + .flags = IORESOURCE_MEM, + }, { + .start = data->irq, + .end = data->irq, + .flags = IORESOURCE_IRQ, + }, + }; + + return imx_add_platform_device("fsl_csi", -1, + res, ARRAY_SIZE(res), NULL, 0); +} + diff --git a/arch/arm/plat-mxc/devices/platform-imx-uart.c b/arch/arm/plat-mxc/devices/platform-imx-uart.c index ecfadc3060ea..7f70dc9f8e07 100644 --- a/arch/arm/plat-mxc/devices/platform-imx-uart.c +++ b/arch/arm/plat-mxc/devices/platform-imx-uart.c @@ -137,6 +137,18 @@ const struct imx_imx_uart_1irq_data imx6q_imx_uart_data[] __initconst = { }; #endif /* ifdef CONFIG_SOC_IMX6Q */ +#ifdef CONFIG_SOC_IMX6SL +const struct imx_imx_uart_1irq_data imx6sl_imx_uart_data[] __initconst = { +#define imx6sl_imx_uart_data_entry(_id, _hwid) \ + imx_imx_uart_1irq_data_entry(MX6SL, _id, _hwid, SZ_4K) + imx6sl_imx_uart_data_entry(0, 1), + imx6sl_imx_uart_data_entry(1, 2), + imx6sl_imx_uart_data_entry(2, 3), + imx6sl_imx_uart_data_entry(3, 4), + imx6sl_imx_uart_data_entry(4, 5), +}; +#endif /* ifdef CONFIG_SOC_IMX6SL */ + struct platform_device *__init imx_add_imx_uart_3irq( const struct imx_imx_uart_3irq_data *data, const struct imxuart_platform_data *pdata) diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index 99ef8abee1e3..1ff68bd8b6dd 100755 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -25,10 +25,10 @@ static inline struct platform_device *imx_add_platform_device( name, id, res, num_resources, data, size_data, 0); } -struct imx_dma_data { +struct imx_dma_res_data { resource_size_t iobase; }; -struct platform_device *__init imx_add_dma(const struct imx_dma_data *data); +struct platform_device *__init imx_add_dma(const struct imx_dma_res_data *data); #include <linux/fec.h> struct imx_fec_data { @@ -690,3 +690,11 @@ struct platform_device *__init imx_add_pcie( const struct imx_pcie_platform_data *pdata); void __init imx_add_imx_armpmu(void); + +struct imx_fsl_csi_data { + resource_size_t iobase; + resource_size_t iosize; + resource_size_t irq; +}; +struct platform_device *__init imx_add_fsl_csi( + const struct imx_fsl_csi_data *data); diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx6sl.h b/arch/arm/plat-mxc/include/mach/iomux-mx6sl.h index 296df42d3ef7..90de1dd8f4fb 100755 --- a/arch/arm/plat-mxc/include/mach/iomux-mx6sl.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx6sl.h @@ -77,6 +77,9 @@ #define MX6SL_ADU_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ PAD_CTL_DSE_40ohm | PAD_CTL_PUS_100K_DOWN | \ PAD_CTL_HYS | PAD_CTL_SPEED_MED) +#define MX6SL_CHG_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \ + PAD_CTL_PUS_47K_UP) + #define MX6SL_PAD_AUD_MCLK 0x02A4 #define MX6SL_PAD_AUD_RXD 0x02AC @@ -510,7 +513,7 @@ IOMUX_PAD(0x0364, 0x0074, 7, 0x0000, 0, NO_PAD_CTRL) #define MX6SL_PAD_ECSPI2_MISO__GPIO_4_14 \ - IOMUX_PAD(0x0368, 0x0078, 5, 0x0000, 0, NO_PAD_CTRL) + IOMUX_PAD(0x0368, 0x0078, 5, 0x0000, 0, MX6SL_CHG_PAD_CTRL) #define MX6SL_PAD_ECSPI2_MISO__USB_USBOTG1_OC \ IOMUX_PAD(0x0368, 0x0078, 6, 0x0824, 0, NO_PAD_CTRL) #define MX6SL_PAD_ECSPI2_MISO__TPSMP_HDATA_23 \ @@ -541,7 +544,7 @@ #define MX6SL_PAD_ECSPI2_MOSI__USDHC1_VSELECT \ IOMUX_PAD(0x036C, 0x007C, 4, 0x0000, 0, MX6SL_USDHC_PAD_CTRL) #define MX6SL_PAD_ECSPI2_MOSI__GPIO_4_13 \ - IOMUX_PAD(0x036C, 0x007C, 5, 0x0000, 0, NO_PAD_CTRL) + IOMUX_PAD(0x036C, 0x007C, 5, 0x0000, 0, MX6SL_CHG_PAD_CTRL) #define MX6SL_PAD_ECSPI2_MOSI__ANATOP_ANATOP_TESTO_1 \ IOMUX_PAD(0x036C, 0x007C, 6, 0x0000, 0, NO_PAD_CTRL) #define MX6SL_PAD_ECSPI2_MOSI__TPSMP_HDATA_22 \ @@ -579,7 +582,7 @@ #define MX6SL_PAD_ECSPI2_SS0__USDHC1_CD \ IOMUX_PAD(0x0374, 0x0084, 4, 0x0828, 0, MX6SL_USDHC_PAD_CTRL) #define MX6SL_PAD_ECSPI2_SS0__GPIO_4_15 \ - IOMUX_PAD(0x0374, 0x0084, 5, 0x0000, 0, NO_PAD_CTRL) + IOMUX_PAD(0x0374, 0x0084, 5, 0x0000, 0, MX6SL_CHG_PAD_CTRL) #define MX6SL_PAD_ECSPI2_SS0__USB_USBOTG1_PWR \ IOMUX_PAD(0x0374, 0x0084, 6, 0x0000, 0, NO_PAD_CTRL) #define MX6SL_PAD_ECSPI2_SS0__PL301_SIM_MX6SL_PER1_HADDR_24 \ diff --git a/arch/arm/plat-mxc/include/mach/mx6.h b/arch/arm/plat-mxc/include/mach/mx6.h index aaf8b998ca63..dfb3f6489cc1 100644 --- a/arch/arm/plat-mxc/include/mach/mx6.h +++ b/arch/arm/plat-mxc/include/mach/mx6.h @@ -77,7 +77,7 @@ #define MX6Q_IRAM_BASE_ADDR IRAM_BASE_ADDR /* The last 4K is for cpu hotplug to workaround wdog issue*/ #define MX6Q_IRAM_SIZE (SZ_256K - SZ_4K) -#define MX6DL_IRAM_SIZE (SZ_128K - SZ_4K) +#define MX6DL_MX6SL_IRAM_SIZE (SZ_128K - SZ_4K) /* Blocks connected via pl301periph */ #define ROMCP_ARB_BASE_ADDR 0x00000000 @@ -145,6 +145,7 @@ #define MX6SL_UART5_BASE_ADDR (ATZ1_BASE_ADDR + 0x18000) /* MX6SL */ #define UART1_BASE_ADDR (ATZ1_BASE_ADDR + 0x20000) /* slot 8 */ #define ESAI1_BASE_ADDR (ATZ1_BASE_ADDR + 0x24000) /* slot 9 */ +#define MX6SL_UART1_BASE_ADDR (ATZ1_BASE_ADDR + 0x20000) /* MX6SL */ #define MX6SL_UART2_BASE_ADDR (ATZ1_BASE_ADDR + 0x24000) /* MX6SL */ #define MX6Q_SSI1_BASE_ADDR (ATZ1_BASE_ADDR + 0x28000) /* slot 10 */ #define MX6Q_SSI2_BASE_ADDR (ATZ1_BASE_ADDR + 0x2C000) /* slot 11 */ @@ -215,6 +216,14 @@ /* ARM Cortex A9 MPCore Platform */ #define MX6Q_A9_PLATFRM_BASE (ARM_BASE_ADDR + 0x20000) +/* ARM Cortex A9 PTM */ +#define MX6Q_PTM0_BASE_ADDR 0x0215C000 +#define MX6Q_PTM1_BASE_ADDR 0x0215D000 +#define MX6Q_PTM2_BASE_ADDR 0x0215E000 +#define MX6Q_PTM3_BASE_ADDR 0x0215F000 +#define MX6Q_FUNNEL_BASE_ADDR 0x02144000 +#define MX6Q_ETB_BASE_ADDR 0x02141000 + #define MX6Q_PL301_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x0000) #define MX6Q_USB_OTG_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x4000) #define MX6Q_USB_HS1_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x4200) @@ -327,6 +336,7 @@ #define MX6SL_INT_SPDC 38 #define MX6Q_INT_IPU2_ERR 39 #define MX6DL_INT_CSI 39 +#define MX6SL_INT_CSI 39 #define MX6Q_INT_IPU2_SYN 40 #define MXC_INT_GPU3D_IRQ 41 #define MXC_INT_GPU2D_IRQ 42 @@ -474,6 +484,11 @@ #define MX6Q_INT_UART2 MXC_INT_UART2_ANDED #define MX6Q_INT_UART3 MXC_INT_UART3_ANDED #define MX6Q_INT_UART4 MXC_INT_UART4_ANDED +#define MX6SL_INT_UART1 MXC_INT_UART1_ANDED +#define MX6SL_INT_UART2 MXC_INT_UART2_ANDED +#define MX6SL_INT_UART3 MXC_INT_UART3_ANDED +#define MX6SL_INT_UART4 MXC_INT_UART4_ANDED +#define MX6SL_INT_UART5 MXC_INT_UART5_ANDED #define MX6Q_INT_FEC MXC_INT_ENET1 #define MX6Q_INT_DSI MXC_INT_DSI diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h index 23159090ace8..4260d4a25c2c 100755 --- a/arch/arm/plat-mxc/include/mach/mxc.h +++ b/arch/arm/plat-mxc/include/mach/mxc.h @@ -266,8 +266,8 @@ enum mxc_cpu_pwr_mode { WAIT_CLOCKED, /* wfi only */ WAIT_UNCLOCKED, /* WAIT */ WAIT_UNCLOCKED_POWER_OFF, /* WAIT + SRPG */ - STOP_POWER_ON, /* just STOP */ - STOP_POWER_OFF, /* STOP + SRPG */ + STOP_XTAL_ON, /* STOP + SRPG + XTAL_ON*/ + STOP_POWER_OFF, /* STOP + XTAL_OFF */ ARM_POWER_OFF, /* STOP + SRPG + ARM power off */ }; diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c index d85d8d663571..97d963a54a54 100755 --- a/arch/arm/plat-mxc/usb_common.c +++ b/arch/arm/plat-mxc/usb_common.c @@ -53,9 +53,7 @@ typedef void (*driver_vbus_func)(bool); void __iomem *imx_otg_base; static driver_vbus_func s_driver_vbus; -static int stop_mode_refcount; -DEFINE_MUTEX(usb_common_mutex); EXPORT_SYMBOL(imx_otg_base); #define MXC_NUMBER_USB_TRANSCEIVER 6 @@ -73,41 +71,6 @@ bool usb_icbug_swfix_need(void) } EXPORT_SYMBOL(usb_icbug_swfix_need); -/* - * The Mx6 phy sometimes work abnormally after system suspend/resume if the 1V1 is off. - * So we should keep the 1V1 active during the system suspend if any USB host enabled. - * Set stop_mode_config when any USB host enabled by default, it will impact on system power. - * #define DISABLE_STOP_MODE will disable the feature. - */ -#ifndef DISABLE_STOP_MODE -int usb_stop_mode_refcount(bool enable) -{ - if (enable) - stop_mode_refcount++; - else - stop_mode_refcount--; - return stop_mode_refcount; -} -#else -int usb_stop_mode_refcount(bool enable) -{ - return 0; -} -#endif -EXPORT_SYMBOL(usb_stop_mode_refcount); - -void usb_stop_mode_lock(void) -{ - mutex_lock(&usb_common_mutex); -} -EXPORT_SYMBOL(usb_stop_mode_lock); - -void usb_stop_mode_unlock(void) -{ - mutex_unlock(&usb_common_mutex); -} -EXPORT_SYMBOL(usb_stop_mode_unlock); - void mx6_set_host1_vbus_func(driver_vbus_func driver_vbus) { s_driver_vbus = driver_vbus; diff --git a/drivers/dma/pxp/pxp_dma_v2.c b/drivers/dma/pxp/pxp_dma_v2.c index 87b8f558ae8c..b74f62cac032 100644 --- a/drivers/dma/pxp/pxp_dma_v2.c +++ b/drivers/dma/pxp/pxp_dma_v2.c @@ -264,6 +264,9 @@ static void pxp_set_ctrl(struct pxps *pxp) case PXP_PIX_FMT_YUV422P: fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV422; break; + case PXP_PIX_FMT_UYVY: + fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422; + break; default: fmt_ctrl = 0; } @@ -654,7 +657,7 @@ static void pxp_set_csc(struct pxps *pxp) /* CSC1 - YUV->RGB */ __raw_writel(0x84ab01f0, pxp->base + HW_PXP_CSC1_COEF0); - __raw_writel(0x01230204, pxp->base + HW_PXP_CSC1_COEF1); + __raw_writel(0x01980204, pxp->base + HW_PXP_CSC1_COEF1); __raw_writel(0x0730079c, pxp->base + HW_PXP_CSC1_COEF2); /* CSC2 - Bypass */ diff --git a/drivers/media/video/mxc/capture/Kconfig b/drivers/media/video/mxc/capture/Kconfig index a7b14cb23b9b..febe9d874fb8 100644 --- a/drivers/media/video/mxc/capture/Kconfig +++ b/drivers/media/video/mxc/capture/Kconfig @@ -13,7 +13,7 @@ config VIDEO_MXC_EMMA_CAMERA default y config VIDEO_MXC_CSI_CAMERA - tristate "MX25 CSI camera support" + tristate "CSI camera support" depends on !VIDEO_MXC_EMMA_CAMERA config VIDEO_MXC_CSI_DMA diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c index eb824ddf5eb3..ada6d5e8afbd 100644 --- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c @@ -1,5 +1,5 @@ /* - * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -15,7 +15,7 @@ * @file drivers/media/video/mxc/capture/csi_v4l2_capture.c * This file is derived from mxc_v4l2_capture.c * - * @brief MX25 Video For Linux 2 driver + * @brief Video For Linux 2 capture driver * * @ingroup MXC_V4L2_CAPTURE */ @@ -61,6 +61,198 @@ static struct v4l2_int_device csi_v4l2_int_device = { }, }; +/* Callback function triggered after PxP receives an EOF interrupt */ +static void pxp_dma_done(void *arg) +{ + struct pxp_tx_desc *tx_desc = to_tx_desc(arg); + struct dma_chan *chan = tx_desc->txd.chan; + struct pxp_channel *pxp_chan = to_pxp_channel(chan); + cam_data *cam = pxp_chan->client; + + /* This call will signal wait_for_completion_timeout() */ + complete(&cam->pxp_tx_cmpl); +} + +static bool chan_filter(struct dma_chan *chan, void *arg) +{ + if (imx_dma_is_pxp(chan)) + return true; + else + return false; +} + +/* Function to request PXP DMA channel */ +static int pxp_chan_init(cam_data *cam) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + + /* Request a free channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_PRIVATE, mask); + chan = dma_request_channel(mask, chan_filter, NULL); + if (!chan) { + pr_err("Unsuccessfully request channel!\n"); + return -EBUSY; + } + + cam->pxp_chan = to_pxp_channel(chan); + cam->pxp_chan->client = cam; + + init_completion(&cam->pxp_tx_cmpl); + + return 0; +} + +/* + * Function to call PxP DMA driver and send our new V4L2 buffer + * through the PxP and PxP will process this buffer in place. + * Note: This is a blocking call, so upon return the PxP tx should be complete. + */ +static int pxp_process_update(cam_data *cam) +{ + dma_cookie_t cookie; + struct scatterlist *sg = cam->sg; + struct dma_chan *dma_chan; + struct pxp_tx_desc *desc; + struct dma_async_tx_descriptor *txd; + struct pxp_config_data *pxp_conf = &cam->pxp_conf; + struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; + int i, ret; + int length; + + pr_debug("Starting PxP Send Buffer\n"); + + /* First, check to see that we have acquired a PxP Channel object */ + if (cam->pxp_chan == NULL) { + /* + * PxP Channel has not yet been created and initialized, + * so let's go ahead and try + */ + ret = pxp_chan_init(cam); + if (ret) { + /* + * PxP channel init failed, and we can't use the + * PxP until the PxP DMA driver has loaded, so we abort + */ + pr_err("PxP chan init failed\n"); + return -ENODEV; + } + } + + /* + * Init completion, so that we can be properly informed of + * the completion of the PxP task when it is done. + */ + init_completion(&cam->pxp_tx_cmpl); + + dma_chan = &cam->pxp_chan->dma_chan; + + txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2, + DMA_TO_DEVICE, + DMA_PREP_INTERRUPT); + if (!txd) { + pr_err("Error preparing a DMA transaction descriptor.\n"); + return -EIO; + } + + txd->callback_param = txd; + txd->callback = pxp_dma_done; + + /* + * Configure PxP for processing of new v4l2 buf + */ + pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_UYVY; + pxp_conf->s0_param.color_key = -1; + pxp_conf->s0_param.color_key_enable = false; + pxp_conf->s0_param.width = cam->v2f.fmt.pix.width; + pxp_conf->s0_param.height = cam->v2f.fmt.pix.height; + + pxp_conf->ol_param[0].combine_enable = false; + + proc_data->srect.top = 0; + proc_data->srect.left = 0; + proc_data->srect.width = pxp_conf->s0_param.width; + proc_data->srect.height = pxp_conf->s0_param.height; + + proc_data->drect.top = 0; + proc_data->drect.left = 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; + + 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) + pxp_conf->out_param.stride = pxp_conf->out_param.height; + else + pxp_conf->out_param.stride = pxp_conf->out_param.width; + + desc = to_tx_desc(txd); + length = desc->len; + for (i = 0; i < length; i++) { + if (i == 0) {/* S0 */ + memcpy(&desc->proc_data, proc_data, + sizeof(struct pxp_proc_data)); + pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]); + memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param, + sizeof(struct pxp_layer_param)); + } else if (i == 1) { + pxp_conf->out_param.paddr = sg_dma_address(&sg[1]); + memcpy(&desc->layer_param.out_param, + &pxp_conf->out_param, + sizeof(struct pxp_layer_param)); + } + + desc = desc->next; + } + + /* Submitting our TX starts the PxP processing task */ + cookie = txd->tx_submit(txd); + if (cookie < 0) { + pr_err("Error sending FB through PxP\n"); + return -EIO; + } + + cam->txd = txd; + + /* trigger PxP */ + dma_async_issue_pending(dma_chan); + + return 0; +} + +static int pxp_complete_update(cam_data *cam) +{ + int ret; + /* + * Wait for completion event, which will be set + * through our TX callback function. + */ + ret = wait_for_completion_timeout(&cam->pxp_tx_cmpl, HZ / 10); + if (ret <= 0) { + pr_warning("PxP operation failed due to %s\n", + ret < 0 ? "user interrupt" : "timeout"); + dma_release_channel(&cam->pxp_chan->dma_chan); + cam->pxp_chan = NULL; + return ret ? : -ETIMEDOUT; + } + + dma_release_channel(&cam->pxp_chan->dma_chan); + cam->pxp_chan = NULL; + + pr_debug("TX completed\n"); + + return 0; +} + /*! * Camera V4l2 callback function. * @@ -666,6 +858,23 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) buf->flags = frame->buffer.flags; buf->m = cam->frame[frame->index].buffer.m; + /* + * Note: + * If want to do preview on LCD, use PxP CSC to convert from UYVY + * 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; + retval = pxp_process_update(cam); + if (retval) { + pr_err("Unable to submit PxP update task.\n"); + return retval; + } + pxp_complete_update(cam); + } + return retval; } @@ -1186,8 +1395,8 @@ static void init_camera_struct(cam_data *cam) /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); - init_MUTEX(&cam->param_lock); - init_MUTEX(&cam->busy_lock); + sema_init(&cam->param_lock, 1); + sema_init(&cam->busy_lock, 1); cam->video_dev = video_device_alloc(); if (cam->video_dev == NULL) @@ -1382,6 +1591,7 @@ static void csi_v4l2_master_detach(struct v4l2_int_device *slave) */ static __init int camera_init(void) { + struct scatterlist *sg; u8 err = 0; /* Register the device driver structure. */ @@ -1430,6 +1640,11 @@ static __init int camera_init(void) pr_debug(" Video device registered: %s #%d\n", g_cam->video_dev->name, g_cam->video_dev->minor); + g_cam->pxp_chan = NULL; + /* Initialize Scatter-gather list containing 2 buffer addresses. */ + sg = g_cam->sg; + sg_init_table(sg, 2); + return err; } diff --git a/drivers/media/video/mxc/capture/fsl_csi.c b/drivers/media/video/mxc/capture/fsl_csi.c index dba35c4499e2..33a82242e95e 100644 --- a/drivers/media/video/mxc/capture/fsl_csi.c +++ b/drivers/media/video/mxc/capture/fsl_csi.c @@ -1,5 +1,5 @@ /* - * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -20,6 +20,7 @@ */ #include <linux/types.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/device.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -27,11 +28,14 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/clk.h> +#include <linux/sched.h> #include <mach/clock.h> #include "mxc_v4l2_capture.h" #include "fsl_csi.h" +void __iomem *csi_regbase; +static int irq_nr; static bool g_csi_mclk_on; static csi_irq_callback_t g_callback; static void *g_callback_data; @@ -164,7 +168,7 @@ void csi_start_callback(void *data) { cam_data *cam = (cam_data *) data; - if (request_irq(MXC_INT_CSI, csi_irq_handler, 0, "csi", cam) < 0) + if (request_irq(irq_nr, csi_irq_handler, 0, "csi", cam) < 0) pr_debug("CSI error: irq request fail\n"); } @@ -174,7 +178,7 @@ void csi_stop_callback(void *data) { cam_data *cam = (cam_data *) data; - free_irq(MXC_INT_CSI, cam); + free_irq(irq_nr, cam); } EXPORT_SYMBOL(csi_stop_callback); @@ -254,10 +258,32 @@ void csi_mclk_disable(void) __raw_writel(__raw_readl(CSI_CSICR1) & ~BIT_MCLKEN, CSI_CSICR1); } -int32_t __init csi_init_module(void) +static int __devinit csi_probe(struct platform_device *pdev) { int ret = 0; struct clk *per_clk; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "No csi irq found.\n"); + ret = -ENODEV; + goto err; + } + irq_nr = res->start; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "No csi base address found.\n"); + ret = -ENODEV; + goto err; + } + csi_regbase = ioremap(res->start, resource_size(res)); + if (!csi_regbase) { + dev_err(&pdev->dev, "ioremap failed with csi base\n"); + ret = -ENOMEM; + goto err; + } csihw_reset(); csi_init_interface(); @@ -271,12 +297,34 @@ int32_t __init csi_init_module(void) clk_enable(per_clk); csi_mclk_recalc(&csi_mclk); +err: return ret; } -void __exit csi_cleanup_module(void) +static int __devexit csi_remove(struct platform_device *pdev) { clk_disable(&csi_mclk); + iounmap(csi_regbase); + + return 0; +} + +static struct platform_driver csi_driver = { + .driver = { + .name = "fsl_csi", + }, + .probe = csi_probe, + .remove = __devexit_p(csi_remove), +}; + +int32_t __init csi_init_module(void) +{ + return platform_driver_register(&csi_driver); +} + +void __exit csi_cleanup_module(void) +{ + platform_driver_unregister(&csi_driver); } module_init(csi_init_module); diff --git a/drivers/media/video/mxc/capture/fsl_csi.h b/drivers/media/video/mxc/capture/fsl_csi.h index 00c389892224..8dfce286fe53 100644 --- a/drivers/media/video/mxc/capture/fsl_csi.h +++ b/drivers/media/video/mxc/capture/fsl_csi.h @@ -1,5 +1,5 @@ /* - * Copyright 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -102,23 +102,22 @@ #define CSI_MCLK_I2C 8 #endif -#define CSI_CSICR1 (IO_ADDRESS(CSI_BASE_ADDR)) -#define CSI_CSICR2 (IO_ADDRESS(CSI_BASE_ADDR + 0x4)) -#define CSI_CSICR3 (IO_ADDRESS(CSI_BASE_ADDR + 0x8)) -#define CSI_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0xC)) -#define CSI_CSIRXFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x10)) -#define CSI_CSIRXCNT (IO_ADDRESS(CSI_BASE_ADDR + 0x14)) -#define CSI_CSISR (IO_ADDRESS(CSI_BASE_ADDR + 0x18)) - -#define CSI_CSIDBG (IO_ADDRESS(CSI_BASE_ADDR + 0x1C)) -#define CSI_CSIDMASA_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x20)) -#define CSI_CSIDMATS_STATFIFO (IO_ADDRESS(CSI_BASE_ADDR + 0x24)) -#define CSI_CSIDMASA_FB1 (IO_ADDRESS(CSI_BASE_ADDR + 0x28)) -#define CSI_CSIDMASA_FB2 (IO_ADDRESS(CSI_BASE_ADDR + 0x2C)) -#define CSI_CSIFBUF_PARA (IO_ADDRESS(CSI_BASE_ADDR + 0x30)) -#define CSI_CSIIMAG_PARA (IO_ADDRESS(CSI_BASE_ADDR + 0x34)) - -#define CSI_CSIRXFIFO_PHYADDR (CSI_BASE_ADDR + 0x10) +extern void __iomem *csi_regbase; +#define CSI_CSICR1 (csi_regbase) +#define CSI_CSICR2 (csi_regbase + 0x4) +#define CSI_CSICR3 (csi_regbase + 0x8) +#define CSI_STATFIFO (csi_regbase + 0xC) +#define CSI_CSIRXFIFO (csi_regbase + 0x10) +#define CSI_CSIRXCNT (csi_regbase + 0x14) +#define CSI_CSISR (csi_regbase + 0x18) + +#define CSI_CSIDBG (csi_regbase + 0x1C) +#define CSI_CSIDMASA_STATFIFO (csi_regbase + 0x20) +#define CSI_CSIDMATS_STATFIFO (csi_regbase + 0x24) +#define CSI_CSIDMASA_FB1 (csi_regbase + 0x28) +#define CSI_CSIDMASA_FB2 (csi_regbase + 0x2C) +#define CSI_CSIFBUF_PARA (csi_regbase + 0x30) +#define CSI_CSIIMAG_PARA (csi_regbase + 0x34) static inline void csi_clear_status(unsigned long status) { diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c index 4305c56c82d9..3ae65db04486 100644 --- a/drivers/media/video/mxc/capture/mt9v111.c +++ b/drivers/media/video/mxc/capture/mt9v111.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -879,7 +879,7 @@ static int ioctl_dev_init(struct v4l2_int_device *s) gpio_sensor_active(); - set_mclk_rate(&clock_rate); + set_mclk_rate(&clock_rate, 0); mt9v111_rate_cal(&reset_frame_rate, clock_rate); mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg); diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h index 27f8a78a93b3..034fd168290f 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h @@ -31,6 +31,10 @@ #include <linux/list.h> #include <linux/ipu.h> #include <linux/mxc_v4l2.h> +#include <linux/completion.h> +#include <linux/dmaengine.h> +#include <linux/pxp_dma.h> +#include <mach/dma.h> #include <mach/ipu-v3.h> #include <media/v4l2-dev.h> @@ -205,6 +209,14 @@ typedef struct _cam_data { struct v4l2_int_device *self; int sensor_index; void *ipu; + + /* v4l2 buf elements related to PxP DMA */ + struct completion pxp_tx_cmpl; + struct pxp_channel *pxp_chan; + struct pxp_config_data pxp_conf; + struct dma_async_tx_descriptor *txd; + dma_cookie_t cookie; + struct scatterlist sg[2]; } cam_data; struct sensor_data { @@ -232,11 +244,5 @@ struct sensor_data { void (*io_init)(void); }; -#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA_MODULE) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA) -void set_mclk_rate(uint32_t *p_mclk_freq); -#else void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi); -#endif #endif /* __MXC_V4L2_CAPTURE_H__ */ diff --git a/drivers/media/video/mxc/capture/ov2640.c b/drivers/media/video/mxc/capture/ov2640.c index a0a050bca2e9..24ebd5027ff1 100644 --- a/drivers/media/video/mxc/capture/ov2640.c +++ b/drivers/media/video/mxc/capture/ov2640.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -801,7 +801,7 @@ static int ioctl_dev_init(struct v4l2_int_device *s) pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); - set_mclk_rate(&ov2640_data.mclk); + set_mclk_rate(&ov2640_data.mclk, 0); return ov2640_init_mode(sensor); } diff --git a/drivers/media/video/mxc/capture/sensor_clock.c b/drivers/media/video/mxc/capture/sensor_clock.c index 8004aeee5dc2..150659fa5dc0 100644 --- a/drivers/media/video/mxc/capture/sensor_clock.c +++ b/drivers/media/video/mxc/capture/sensor_clock.c @@ -26,31 +26,6 @@ #include <mach/hardware.h> #include <asm/mach-types.h> -#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA_MODULE) \ - || defined(CONFIG_VIDEO_MXC_CSI_CAMERA) -/* - * set_mclk_rate - * - * @param p_mclk_freq mclk frequence - * - */ -void set_mclk_rate(uint32_t *p_mclk_freq) -{ - struct clk *clk; - uint32_t freq = 0; - - clk = clk_get(NULL, "csi_clk"); - - freq = clk_round_rate(clk, *p_mclk_freq); - clk_set_rate(clk, freq); - - *p_mclk_freq = freq; - - clk_put(clk); - pr_debug("mclk frequency = %d\n", *p_mclk_freq); -} -#else /* * set_mclk_rate * @@ -81,6 +56,8 @@ void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi) pr_err("invalid csi num %d\n", csi); return; }; + } else if (cpu_is_mx25() || cpu_is_mx6sl()) { /* only has CSI0 */ + mclk = "csi_clk"; } else { if (csi == 0) { mclk = "csi_mclk1"; @@ -102,7 +79,6 @@ void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi) clk_put(clk); pr_debug("%s frequency = %d\n", mclk, *p_mclk_freq); } -#endif /* Exported symbols for modules. */ EXPORT_SYMBOL(set_mclk_rate); diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c index 366d27a92286..388c4b39570f 100644 --- a/drivers/media/video/mxc/output/mxc_vout.c +++ b/drivers/media/video/mxc/output/mxc_vout.c @@ -861,6 +861,7 @@ static int mxc_vout_open(struct file *file) vout->win_pos.x = 0; vout->win_pos.y = 0; + vout->release = true; } file->private_data = vout; @@ -973,6 +974,7 @@ static inline int vdoaipu_try_task(struct mxc_vout_output *vout) int is_1080p_stream; size_t size; struct ipu_task *ipu_task = &vout->task; + struct ipu_crop *icrop = &ipu_task->input.crop; struct ipu_task *vdoa_task = &vout->vdoa_task; u32 deinterlace = 0; u32 in_fmt; @@ -981,15 +983,23 @@ static inline int vdoaipu_try_task(struct mxc_vout_output *vout) deinterlace = 1; memset(vdoa_task, 0, sizeof(*vdoa_task)); - memcpy(&vdoa_task->input, &ipu_task->input, sizeof(ipu_task->input)); vdoa_task->output.format = IPU_PIX_FMT_NV12; - vdoa_task->output.width = ipu_task->input.crop.w; - vdoa_task->output.height = ipu_task->input.crop.h; - vdoa_task->output.crop.w = ipu_task->input.crop.w; - vdoa_task->output.crop.h = ipu_task->input.crop.h; - - size = PAGE_ALIGN(ipu_task->input.crop.w * - ipu_task->input.crop.h * + memcpy(&vdoa_task->input, &ipu_task->input, + sizeof(ipu_task->input)); + if ((icrop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (icrop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) { + vdoa_task->input.crop.w = + ALIGN(icrop->w, IPU_PIX_FMT_TILED_NV12_MBALIGN); + vdoa_task->input.crop.h = + ALIGN(icrop->h, IPU_PIX_FMT_TILED_NV12_MBALIGN); + } + vdoa_task->output.width = vdoa_task->input.crop.w; + vdoa_task->output.height = vdoa_task->input.crop.h; + vdoa_task->output.crop.w = vdoa_task->input.crop.w; + vdoa_task->output.crop.h = vdoa_task->input.crop.h; + + size = PAGE_ALIGN(vdoa_task->input.crop.w * + vdoa_task->input.crop.h * fmt_to_bpp(vdoa_task->output.format)/8); if (size > vout->vdoa_work.size) { if (vout->vdoa_work.vaddr) @@ -1029,6 +1039,7 @@ static int mxc_vout_try_task(struct mxc_vout_output *vout) u32 o_height = 0; u32 ocrop_h = 0; bool tiled_fmt = false; + bool tiled_need_pp = false; vout->vdoa_1080p = CHECK_TILED_1080P_DISPLAY(vout); if (vout->vdoa_1080p) { @@ -1041,10 +1052,17 @@ static int mxc_vout_try_task(struct mxc_vout_output *vout) if ((IPU_PIX_FMT_TILED_NV12 == input->format) || (IPU_PIX_FMT_TILED_NV12F == input->format)) { - crop->w -= crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN; - crop->h -= crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN; - crop->pos.x -= crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN; - crop->pos.y -= crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN; + if ((input->width % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (input->height % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) { + v4l2_err(vout->vfd->v4l2_dev, + "ERR: tiled fmt needs 16 pixel align.\n"); + return -EINVAL; + } + if ((crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) || + (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) + tiled_need_pp = true; } else { crop->w -= crop->w % 8; crop->h -= crop->h % 8; @@ -1072,7 +1090,8 @@ static int mxc_vout_try_task(struct mxc_vout_output *vout) if ((IPU_PIX_FMT_TILED_NV12 == input->format) || (IPU_PIX_FMT_TILED_NV12F == input->format)) { /* check resize/rotate/flip, or csc task */ - if (!((IPU_ROTATE_NONE != output->rotate) || + if (!(tiled_need_pp || + (IPU_ROTATE_NONE != output->rotate) || (input->crop.w != output->crop.w) || (input->crop.h != output->crop.h) || (!vout->disp_support_csc && diff --git a/drivers/mfd/mxc-hdmi-core.c b/drivers/mfd/mxc-hdmi-core.c index e9322477ff6d..a07db1b0c070 100644 --- a/drivers/mfd/mxc-hdmi-core.c +++ b/drivers/mfd/mxc-hdmi-core.c @@ -41,6 +41,7 @@ #include <linux/mfd/mxc-hdmi-core.h> #include <linux/fsl_devices.h> #include <mach/hardware.h> +#include <linux/mfd/mxc-hdmi-core.h> struct mxc_hdmi_data { struct platform_device *pdev; @@ -72,22 +73,29 @@ static spinlock_t hdmi_audio_lock, hdmi_blank_state_lock, hdmi_cable_state_lock; unsigned int hdmi_set_cable_state(unsigned int state) { unsigned long flags; + struct snd_pcm_substream *substream = hdmi_audio_stream_playback; spin_lock_irqsave(&hdmi_cable_state_lock, flags); hdmi_cable_state = state; spin_unlock_irqrestore(&hdmi_cable_state_lock, flags); + if (check_hdmi_state() && substream) + substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); return 0; } unsigned int hdmi_set_blank_state(unsigned int state) { unsigned long flags; + struct snd_pcm_substream *substream = hdmi_audio_stream_playback; spin_lock_irqsave(&hdmi_blank_state_lock, flags); hdmi_blank_state = state; spin_unlock_irqrestore(&hdmi_blank_state_lock, flags); + if (check_hdmi_state() && substream) + substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); + return 0; } @@ -98,7 +106,7 @@ static void hdmi_audio_abort_stream(struct snd_pcm_substream *substream) snd_pcm_stream_lock_irqsave(substream, flags); if (snd_pcm_running(substream)) - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); snd_pcm_stream_unlock_irqrestore(substream, flags); } @@ -114,7 +122,7 @@ int mxc_hdmi_abort_stream(void) return 0; } -static int check_hdmi_state(void) +int check_hdmi_state(void) { unsigned long flags1, flags2; unsigned int ret; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index e4cd11b97c24..9db650f00734 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -658,6 +658,9 @@ static int mmc_sdio_suspend(struct mmc_host *host) mmc_release_host(host); } + if (!err) + mmc_claim_host(host); + return err; } @@ -668,9 +671,6 @@ static int mmc_sdio_resume(struct mmc_host *host) BUG_ON(!host); BUG_ON(!host->card); - /* Basic card reinitialization. */ - mmc_claim_host(host); - /* No need to reinitialize powered-resumed nonremovable cards */ if (mmc_card_is_removable(host) && !mmc_card_keep_power(host)) err = mmc_sdio_init_card(host, host->ocr, host->card, diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index f25b7c27b101..cc353ce5ae7e 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -873,7 +873,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this, } static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { struct gpmi_nand_data *this = chip->priv; struct bch_geometry *nfc_geo = &this->bch_geometry; @@ -939,17 +939,20 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, mtd->ecc_stats.corrected += corrected; } - /* - * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for - * details about our policy for delivering the OOB. - * - * We fill the caller's buffer with set bits, and then copy the block - * mark to th caller's buffer. Note that, if block mark swapping was - * necessary, it has already been done, so we can rely on the first - * byte of the auxiliary buffer to contain the block mark. - */ - memset(chip->oob_poi, ~0, mtd->oobsize); - chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + if (oob_required) { + /* + * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() + * for details about our policy for delivering the OOB. + * + * We fill the caller's buffer with set bits, and then copy the + * block mark to th caller's buffer. Note that, if block mark + * swapping was necessary, it has already been done, so we can + * rely on the first byte of the auxiliary buffer to contain + * the block mark. + */ + memset(chip->oob_poi, ~0, mtd->oobsize); + chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + } read_page_swap_end(this, buf, mtd->writesize, this->payload_virt, this->payload_phys, @@ -959,8 +962,8 @@ exit_nfc: return ret; } -static void gpmi_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) +static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) { struct gpmi_nand_data *this = chip->priv; struct bch_geometry *nfc_geo = &this->bch_geometry; @@ -1040,7 +1043,7 @@ static int gpmi_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len) { struct nand_chip *nand = mtd->priv; - gpmi_ecc_read_page(mtd, nand, verify_buf, len); + gpmi_ecc_read_page(mtd, nand, verify_buf, 0, len); if (memcmp(buf, verify_buf, len)) return -EFAULT; return 0; @@ -1353,7 +1356,7 @@ static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the first page of the current stride. */ dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - chip->ecc.write_page_raw(mtd, chip, buffer); + chip->ecc.write_page_raw(mtd, chip, buffer, 0); chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); /* Wait for the write to finish. */ diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e14f8284e79f..6367eac4461b 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1051,12 +1051,13 @@ EXPORT_SYMBOL(nand_lock); * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * Not for syndrome calculating ecc controllers, which use a special oob layout */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -1068,13 +1069,14 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * We need a special oob layout and handling even when OOB isn't used. */ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1111,10 +1113,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1124,7 +1127,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; - chip->ecc.read_page_raw(mtd, chip, buf, page); + chip->ecc.read_page_raw(mtd, chip, buf, 1, page); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1239,12 +1242,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * Not for syndrome calculating ecc controllers which need a special oob layout */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1284,6 +1288,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * Hardware ECC for large page chips, require OOB to be read first. @@ -1294,7 +1299,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * overwriting the NAND manufacturer bad block markings. */ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1333,13 +1338,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1443,7 +1449,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, int nand_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int chipnr, page, realpage, col, bytes, aligned; + int chipnr, page, realpage, col, bytes, aligned, oob_required; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; @@ -1468,6 +1474,7 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from, buf = ops->datbuf; oob = ops->oobbuf; + oob_required = oob ? 1 : 0; while (1) { bytes = min(mtd->writesize - col, readlen); @@ -1485,13 +1492,15 @@ int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Now read the page into the buffer */ if (unlikely(ops->mode == MTD_OOB_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, - bufpoi, page); + bufpoi, + oob_required, + page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi, - page); + oob_required, page); if (ret < 0) break; @@ -1893,11 +1902,12 @@ out: * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB * * Not for syndrome calculating ecc controllers, which use a special oob layout */ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, int oob_required) { chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -1908,12 +1918,13 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB * * We need a special oob layout and handling even when ECC isn't checked. */ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, int oob_required) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1947,9 +1958,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB */ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1965,7 +1977,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->ecc.write_page_raw(mtd, chip, buf); + chip->ecc.write_page_raw(mtd, chip, buf, 1); } /** @@ -1973,9 +1985,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB */ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2001,12 +2014,14 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */ static void nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) + struct nand_chip *chip, + const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2045,21 +2060,23 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, * @mtd: MTD device structure * @chip: NAND chip descriptor * @buf: the data to write + * @oob_required: must write chip->oob_poi to OOB * @page: page number to write * @cached: cached programming * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, int cached, int raw) + const uint8_t *buf, int oob_required, int page, + int cached, int raw) { int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf); + chip->ecc.write_page_raw(mtd, chip, buf, oob_required); else - chip->ecc.write_page(mtd, chip, buf); + chip->ecc.write_page(mtd, chip, buf, oob_required); /* * Cached progamming disabled for now, Not sure if its worth the @@ -2176,6 +2193,7 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; int ret, subpage; + int oob_required = oob ? 1 : 0; ops->retlen = 0; if (!writelen) @@ -2238,7 +2256,7 @@ int nand_do_write_ops(struct mtd_info *mtd, loff_t to, memset(chip->oob_poi, 0xff, mtd->oobsize); } - ret = chip->write_page(mtd, chip, wbuf, page, cached, + ret = chip->write_page(mtd, chip, wbuf, oob_required, page, cached, (ops->mode == MTD_OOB_RAW)); if (ret) break; diff --git a/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c b/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c index e09a46b3d7b5..36b7bcfab997 100644 --- a/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c +++ b/drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c @@ -4282,7 +4282,7 @@ gckHARDWARE_SetFscaleValue( gctUINT32 clock; gctBOOL acquired = gcvFALSE; - gcmkHEADER_ARG("Hardware=0x%x FscaleVal=%d", Hardware, FscaleVal); + gcmkHEADER_ARG("Hardware=0x%x FscaleValue=%d", Hardware, FscaleValue); gcmkVERIFY_ARGUMENT(FscaleValue > 0 && FscaleValue <= 64); diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c index 8cf0509cfd92..e05a143f41c3 100644 --- a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c +++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c @@ -30,6 +30,9 @@ #define _GC_OBJ_ZONE gcvZONE_COMMAND +#if gcdENABLE_FSCALE_VAL_ADJUST +extern int thermal_hot; +#endif /******************************************************************************\ ********************************* Support Code ********************************* \******************************************************************************/ @@ -1080,6 +1083,24 @@ gckCOMMAND_Commit( /* Extract the gckHARDWARE and gckEVENT objects. */ hardware = Command->kernel->hardware; +#if gcdENABLE_FSCALE_VAL_ADJUST + if(hardware->core == gcvCORE_MAJOR){ + static gctUINT orgFscale,minFscale,maxFscale; + static gctBOOL bAlreadyTooHot = gcvFALSE; + if((thermal_hot > 0) && (!bAlreadyTooHot)) { + gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale); + gckHARDWARE_SetFscaleValue(hardware, minFscale); + bAlreadyTooHot = gcvTRUE; + gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale); + } else if((!(thermal_hot > 0)) && bAlreadyTooHot) { + gckHARDWARE_SetFscaleValue(hardware, orgFscale); + gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale); + bAlreadyTooHot = gcvFALSE; + } + + } +#endif + /* Check wehther we need to copy the structures or not. */ gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy)); diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c index 890d13e17c50..eba81b64be92 100644 --- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c +++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c @@ -358,6 +358,15 @@ gckGALDEVICE_Construct( gckDebugFileSystemSetCurrentNode(device->dbgnode); } } + /*get gpu regulator*/ + device->gpu_regulator = regulator_get(NULL, "cpu_vddgpu"); + if (IS_ERR(device->gpu_regulator)) { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Failed to get gpu regulator %s/%s \n", + __FUNCTION__, __LINE__, + PARENT_FILE, DEBUG_FILE); + gcmkONERROR(gcvSTATUS_NOT_FOUND); + } /*Initialize the clock structure*/ if (IrqLine != -1) { diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h index 03f7f9b2201e..c15989894600 100644 --- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h +++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h @@ -89,6 +89,9 @@ typedef struct _gckGALDEVICE struct clk *clk_2d_axi; struct clk *clk_vg_axi; + /*Power management.*/ + struct regulator *gpu_regulator; + } * gckGALDEVICE; diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h index 30fb13596dda..a6ed03ffc0f9 100644 --- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h +++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h @@ -47,6 +47,7 @@ #if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) #include <linux/clk.h> +#include <linux/regulator/consumer.h> #endif #define NTSTRSAFE_NO_CCH_FUNCTIONS diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c index 4d1a71dfa91a..4091ccdb61d4 100644 --- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c +++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c @@ -6947,6 +6947,7 @@ gckOS_SetGPUPower( struct clk *clk_vg_axi = Os->device->clk_vg_axi; gctBOOL oldClockState = gcvFALSE; + gctBOOL oldPowerState = gcvFALSE; gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power); @@ -6956,15 +6957,20 @@ gckOS_SetGPUPower( if (Core == gcvCORE_VG) { oldClockState = Os->device->kernels[Core]->vg->hardware->clockState; + oldPowerState = Os->device->kernels[Core]->vg->hardware->powerState; } else { #endif oldClockState = Os->device->kernels[Core]->hardware->clockState; + oldPowerState = Os->device->kernels[Core]->hardware->powerState; #if gcdENABLE_VG } #endif } + if((Power == gcvTRUE) && (oldPowerState == gcvFALSE) && + !IS_ERR(Os->device->gpu_regulator)) + regulator_enable(Os->device->gpu_regulator); if (Clock == gcvTRUE) { if (oldClockState == gcvFALSE) { @@ -7007,8 +7013,10 @@ gckOS_SetGPUPower( } } } - - + if((Power == gcvFALSE) && (oldPowerState == gcvTRUE) && + !IS_ERR(Os->device->gpu_regulator)) + regulator_disable(Os->device->gpu_regulator); + /* TODO: Put your code here. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; } diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index d12ffdfc7847..be1725129ce2 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -340,6 +340,7 @@ struct ipu_alloc_list { dma_addr_t phy_addr; void *cpu_addr; u32 size; + void *file_index; }; static LIST_HEAD(ipu_alloc_list); @@ -350,6 +351,7 @@ static DEFINE_SPINLOCK(ipu_task_list_lock); static DECLARE_WAIT_QUEUE_HEAD(thread_waitq); static DECLARE_WAIT_QUEUE_HEAD(res_waitq); static atomic_t req_cnt; +static atomic_t file_index = ATOMIC_INIT(1); static int major; static int max_ipu_no; static int thread_id; @@ -3274,6 +3276,7 @@ EXPORT_SYMBOL_GPL(ipu_queue_task); static int mxc_ipu_open(struct inode *inode, struct file *file) { + file->private_data = (void *)atomic_inc_return(&file_index); return 0; } @@ -3330,6 +3333,7 @@ static long mxc_ipu_ioctl(struct file *file, kfree(mem); return -ENOMEM; } + mem->file_index = file->private_data; mutex_lock(&ipu_alloc_lock); list_add(&mem->list, &ipu_alloc_list); mutex_unlock(&ipu_alloc_lock); @@ -3413,6 +3417,26 @@ static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma) static int mxc_ipu_release(struct inode *inode, struct file *file) { + struct ipu_alloc_list *mem; + struct ipu_alloc_list *n; + + mutex_lock(&ipu_alloc_lock); + list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) { + if ((mem->cpu_addr != 0) && + (file->private_data == mem->file_index)) { + list_del(&mem->list); + dma_free_coherent(ipu_dev, + mem->size, + mem->cpu_addr, + mem->phy_addr); + dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n", + mem->size, mem->phy_addr); + kfree(mem); + } + } + mutex_unlock(&ipu_alloc_lock); + atomic_dec(&file_index); + return 0; } diff --git a/drivers/mxc/thermal/cooling.c b/drivers/mxc/thermal/cooling.c index 0feefeaa6008..7019d9949c8a 100644 --- a/drivers/mxc/thermal/cooling.c +++ b/drivers/mxc/thermal/cooling.c @@ -57,6 +57,7 @@ cpufreq, it minor 1, and when we promote cpufreq, it add 1, so if it is 0, mean we didn't change the cpufreq */ static int cpufreq_change_count; +extern int thermal_hot; int anatop_thermal_get_cpufreq_cur(void) { int ret = -EINVAL; @@ -237,6 +238,7 @@ imx_processor_set_cur_state(struct thermal_cooling_device *cdev, secondary CPUs that detached by thermal driver */ if (cooling_cpuhotplug) { if (!state) { + thermal_hot = 0; for (i = 1; i < 4; i++) { if (cpu_mask && (0x1 << i)) { anatop_thermal_cpu_hotplug(true); @@ -247,6 +249,7 @@ imx_processor_set_cur_state(struct thermal_cooling_device *cdev, } } else { if (!state) { + thermal_hot = 0; if (cpufreq_change_count < 0) anatop_thermal_cpufreq_up(); else if (cpufreq_change_count > 0) diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c index 92a1d0dc98c7..8178824ab80a 100644 --- a/drivers/mxc/vpu/mxc_vpu.c +++ b/drivers/mxc/vpu/mxc_vpu.c @@ -39,6 +39,7 @@ #include <linux/workqueue.h> #include <linux/sched.h> #include <linux/vmalloc.h> +#include <linux/regulator/consumer.h> #include <linux/page-flags.h> #include <linux/mm_types.h> #include <linux/types.h> @@ -110,6 +111,7 @@ static int vpu_jpu_irq; #endif static unsigned int regBk[64]; +static struct regulator *vpu_regulator; #define READ_REG(x) __raw_readl(vpu_base + x) #define WRITE_REG(val, x) __raw_writel(val, vpu_base + x) @@ -245,8 +247,12 @@ bool vpu_is_valid_phy_memory(u32 paddr) */ static int vpu_open(struct inode *inode, struct file *filp) { + mutex_lock(&vpu_data.lock); - open_count++; + + if (open_count++ == 0 && !IS_ERR(vpu_regulator)) + regulator_enable(vpu_regulator); + filp->private_data = (void *)(&vpu_data); mutex_unlock(&vpu_data.lock); return 0; @@ -531,6 +537,9 @@ static int vpu_release(struct inode *inode, struct file *filp) mutex_lock(&vpu_data.lock); if (open_count > 0 && !(--open_count)) { + if (!IS_ERR(vpu_regulator)) + regulator_disable(vpu_regulator); + vpu_free_buffers(); /* Free shared memory when vpu device is idle */ @@ -705,6 +714,12 @@ static int vpu_dev_probe(struct platform_device *pdev) (void *)(&vpu_data)); if (err) goto err_out_class; + vpu_regulator = regulator_get(NULL, "cpu_vddvpu"); + if (IS_ERR(vpu_regulator)) { + printk(KERN_ERR + "%s: failed to get vpu regulator\n", __func__); + goto err_out_class; + } #ifdef MXC_VPU_HAS_JPU vpu_jpu_irq = platform_get_irq_byname(pdev, "vpu_jpu_irq"); @@ -752,7 +767,8 @@ static int vpu_dev_remove(struct platform_device *pdev) iounmap(vpu_base); if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size) iram_free(iram.start, vpu_plat->iram_size); - + if (!IS_ERR(vpu_regulator)) + regulator_put(vpu_regulator); return 0; } @@ -762,6 +778,8 @@ static int vpu_suspend(struct platform_device *pdev, pm_message_t state) int i; unsigned long timeout; + if (!IS_ERR(vpu_regulator)) + regulator_enable(vpu_regulator); /* Wait for vpu go to idle state, suspect vpu cannot be changed to idle state after about 1 sec */ if (open_count > 0) { @@ -794,10 +812,14 @@ static int vpu_suspend(struct platform_device *pdev, pm_message_t state) if (vpu_plat->pg) vpu_plat->pg(1); + if (!IS_ERR(vpu_regulator)) + regulator_disable(vpu_regulator); return 0; out: clk_disable(vpu_clk); + if (!IS_ERR(vpu_regulator)) + regulator_disable(vpu_regulator); return -EAGAIN; } @@ -809,6 +831,8 @@ static int vpu_resume(struct platform_device *pdev) if (cpu_is_mx53()) goto recover_clk; + if (!IS_ERR(vpu_regulator)) + regulator_enable(vpu_regulator); if (vpu_plat->pg) vpu_plat->pg(0); @@ -869,6 +893,8 @@ recover_clk: /* Recover vpu clock */ for (i = 0; i < vpu_clk_usercount; i++) clk_enable(vpu_clk); + if (!IS_ERR(vpu_regulator)) + regulator_disable(vpu_regulator); return 0; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 5af378f391ee..86e4ea3404b3 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -397,7 +397,12 @@ fec_timeout(struct net_device *ndev) ndev->stats.tx_errors++; + netif_device_detach(ndev); + fec_stop(ndev); + fec_restart(ndev, fep->full_duplex); + netif_device_attach(ndev); + ndev->trans_start = jiffies; /* prevent tx timeout */ if (fep->link && !fep->tx_full) netif_wake_queue(ndev); } @@ -1320,10 +1325,7 @@ fec_enet_close(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); - /* Don't know what to do yet. */ fep->opened = 0; - netif_stop_queue(ndev); - netif_carrier_off(ndev); if (fep->use_napi) napi_disable(&fep->napi); @@ -1760,7 +1762,10 @@ fec_stop(struct net_device *dev) if (fep->ptimer_present) fec_ptp_stop(fep->ptp_priv); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); - netif_stop_queue(dev); + + if (netif_running(dev)) + netif_stop_queue(dev); + netif_carrier_off(dev); /* prevent tx timeout */ fep->link = 0; } @@ -1921,7 +1926,6 @@ fec_suspend(struct device *dev) if (netif_running(ndev)) { netif_device_detach(ndev); fec_stop(ndev); - netif_carrier_off(ndev); clk_disable(fep->clk); } diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 6e53cce3c7fd..a24653787d1d 100755 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -222,7 +222,6 @@ config CHARGER_MAX8903 config SABRESD_MAX8903 tristate "Sabresd Board Battery DC-DC Charger for USB and Adapter Power" depends on GENERIC_HARDIRQS - depends on TOUCHSCREEN_MAX11801 help Say Y to enable support for the MAX8903 DC-DC charger and sysfs on sabresd board.The driver supports controlling charger and battery diff --git a/drivers/power/sabresd_battery.c b/drivers/power/sabresd_battery.c index c7318a6eb02c..648922139790 100755 --- a/drivers/power/sabresd_battery.c +++ b/drivers/power/sabresd_battery.c @@ -65,13 +65,11 @@ typedef struct { u32 voltage; u32 percent; } battery_capacity , *pbattery_capacity; - static int cpu_type_flag; static int offset_discharger; static int offset_charger; static int offset_usb_charger; - static battery_capacity chargingTable[] = { {4050, 99}, {4040, 98}, @@ -188,9 +186,9 @@ static enum power_supply_property max8903_battery_props[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_CAPACITY_LEVEL, }; - +#ifdef CONFIG_TOUCHSCREEN_MAX11801 extern u32 max11801_read_adc(void); - +#endif static void max8903_charger_update_status(struct max8903_data *data) { if (data->usb_in || data->ta_in) { @@ -205,26 +203,35 @@ static void max8903_charger_update_status(struct max8903_data *data) } if (data->charger_online == 0 && data->usb_charger_online == 0) { data->battery_status = POWER_SUPPLY_STATUS_DISCHARGING; - } else { - if (gpio_get_value(data->pdata->chg) == 0) { - data->battery_status = POWER_SUPPLY_STATUS_CHARGING; - } else if (data->ta_in && - gpio_get_value(data->pdata->chg) == 1) { - if (data->percent >= 99) - data->battery_status = POWER_SUPPLY_STATUS_FULL; - else - data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - } - else if (data->usb_in && - gpio_get_value(data->pdata->chg) == 1) { - if (data->percent >= 99) - data->battery_status = POWER_SUPPLY_STATUS_FULL; - else - data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - } + } else { + if (gpio_get_value(data->pdata->chg) == 0) { + data->battery_status = POWER_SUPPLY_STATUS_CHARGING; + } else if (data->ta_in && gpio_get_value(data->pdata->chg) == 1) { + if (!data->pdata->feature_flag) { + if (data->percent >= 99) + data->battery_status = POWER_SUPPLY_STATUS_FULL; + else + data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else { + data->battery_status = POWER_SUPPLY_STATUS_FULL; + } + } else if (data->usb_in && gpio_get_value(data->pdata->chg) == 1) { + if (!data->pdata->feature_flag) { + if (data->percent >= 99) + data->battery_status = POWER_SUPPLY_STATUS_FULL; + else + data->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else { + data->battery_status = POWER_SUPPLY_STATUS_FULL; + } } - pr_debug("chg: %d \n", gpio_get_value(data->pdata->chg)); + } + pr_debug("chg: %d\n", gpio_get_value(data->pdata->chg)); + pr_debug("dc: %d\n", gpio_get_value(data->pdata->dok)); + pr_debug("flt: %d\n", gpio_get_value(data->pdata->flt)); } + +#ifdef CONFIG_TOUCHSCREEN_MAX11801 static int cmp_func(const void *_a, const void *_b) { const int *a = _a, *b = _b; @@ -235,6 +242,7 @@ static int cmp_func(const void *_a, const void *_b) return -1; return 0; } + u32 calibration_voltage(struct max8903_data *data) { int volt[ADC_SAMPLE_COUNT]; @@ -275,51 +283,54 @@ u32 calibration_voltage(struct max8903_data *data) voltage_data = (volt[2] + volt[ADC_SAMPLE_COUNT - 3]) / 2; return voltage_data; } - +#endif static void max8903_battery_update_status(struct max8903_data *data) { - int temp; + int temp = 0; static int temp_last; bool changed_flag; changed_flag = false; mutex_lock(&data->work_lock); - temp = calibration_voltage(data); - if (temp_last == 0) { - data->voltage_uV = temp; - temp_last = temp; - } - if (data->charger_online == 0 && temp_last != 0) { - if (temp < temp_last) { - temp_last = temp; - data->voltage_uV = temp; - } else { - data->voltage_uV = temp_last; + if (!data->pdata->feature_flag) { +#ifdef CONFIG_TOUCHSCREEN_MAX11801 + temp = calibration_voltage(data); +#endif + if (temp_last == 0) { + data->voltage_uV = temp; + temp_last = temp; + } + if (data->charger_online == 0 && temp_last != 0) { + if (temp < temp_last) { + temp_last = temp; + data->voltage_uV = temp; + } else { + data->voltage_uV = temp_last; + } + } + if (data->charger_online == 1 || data->usb_charger_online == 1) { + data->voltage_uV = temp; + temp_last = temp; + } + data->percent = calibrate_battery_capability_percent(data); + if (data->percent != data->old_percent) { + data->old_percent = data->percent; + changed_flag = true; + } + if (changed_flag) { + changed_flag = false; + power_supply_changed(&data->bat); + } + /* + *because boot time gap between led framwork and charger + *framwork,when system boots with charger attatched, + *charger led framwork loses the first charger online event, + *add once extra power_supply_changed can fix this issure + */ + if (data->first_delay_count < 200) { + data->first_delay_count = data->first_delay_count + 1 ; + power_supply_changed(&data->bat); } } - if (data->charger_online == 1 || data->usb_charger_online == 1) { - data->voltage_uV = temp; - temp_last = temp; - } - data->percent = calibrate_battery_capability_percent(data); - if (data->percent != data->old_percent) { - data->old_percent = data->percent; - changed_flag = true; - } - if (changed_flag) { - changed_flag = false; - power_supply_changed(&data->bat); - } - /* - because boot time gap between led framwork and charger - framwork,when system boots with charger attatched, charger - led framwork loses the first charger online event,add once extra - power_supply_changed can fix this issure - */ - if (data->first_delay_count < 200) { - data->first_delay_count = data->first_delay_count + 1 ; - power_supply_changed(&data->bat); - } - mutex_unlock(&data->work_lock); } @@ -332,22 +343,27 @@ static int max8903_battery_get_property(struct power_supply *bat, switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = POWER_SUPPLY_STATUS_UNKNOWN; - if (gpio_get_value(di->pdata->chg) == 0) { - di->battery_status = POWER_SUPPLY_STATUS_CHARGING; - } else if (di->ta_in && - gpio_get_value(di->pdata->chg) == 1) { + if (gpio_get_value(di->pdata->chg) == 0) { + di->battery_status = POWER_SUPPLY_STATUS_CHARGING; + } else if (di->ta_in && gpio_get_value(di->pdata->chg) == 1) { + if (!di->pdata->feature_flag) { if (di->percent >= 99) di->battery_status = POWER_SUPPLY_STATUS_FULL; else di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else { + di->battery_status = POWER_SUPPLY_STATUS_FULL; } - else if (di->usb_in && - gpio_get_value(di->pdata->chg) == 1) { + } else if (di->usb_in && gpio_get_value(di->pdata->chg) == 1) { + if (!di->pdata->feature_flag) { if (di->percent >= 99) di->battery_status = POWER_SUPPLY_STATUS_FULL; else - di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else { + di->battery_status = POWER_SUPPLY_STATUS_FULL; } + } val->intval = di->battery_status; return 0; default: @@ -795,14 +811,13 @@ static __devinit int max8903_probe(struct platform_device *pdev) ret = request_threaded_irq(gpio_to_irq(pdata->chg), NULL, max8903_chg, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "MAX8903 Fault", data); + "MAX8903 Status", data); if (ret) { - dev_err(dev, "Cannot request irq %d for Fault (%d)\n", + dev_err(dev, "Cannot request irq %d for Status (%d)\n", gpio_to_irq(pdata->flt), ret); goto err_chg_irq; } } - ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr); if (ret) dev_err(&pdev->dev, "create device file failed!\n"); @@ -822,7 +837,6 @@ static __devinit int max8903_probe(struct platform_device *pdev) offset_charger = 1485; offset_usb_charger = 1285; } - max8903_charger_update_status(data); max8903_battery_update_status(data); return 0; @@ -888,10 +902,14 @@ static int max8903_suspend(struct platform_device *pdev, if (data) { struct max8903_pdata *pdata = data->pdata; if (pdata) { - irq = gpio_to_irq(pdata->dok); - enable_irq_wake(irq); - irq = gpio_to_irq(pdata->uok); - enable_irq_wake(irq); + if (pdata->dc_valid) { + irq = gpio_to_irq(pdata->dok); + enable_irq_wake(irq); + } + if (pdata->usb_valid) { + irq = gpio_to_irq(pdata->uok); + enable_irq_wake(irq); + } cancel_delayed_work(&data->work); } } @@ -923,10 +941,14 @@ static int max8903_resume(struct platform_device *pdev) max8903_charger_update_status(data); power_supply_changed(&data->usb); } - irq = gpio_to_irq(pdata->dok); - disable_irq_wake(irq); - irq = gpio_to_irq(pdata->uok); - disable_irq_wake(irq); + if (pdata->dc_valid) { + irq = gpio_to_irq(pdata->dok); + disable_irq_wake(irq); + } + if (pdata->usb_valid) { + irq = gpio_to_irq(pdata->uok); + disable_irq_wake(irq); + } schedule_delayed_work(&data->work, BATTERY_UPDATE_INTERVAL); } } diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index c3a48307c918..b91cf9f82543 100755 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -3323,10 +3323,13 @@ static int udc_suspend(struct fsl_udc *udc) * charge using usb */ if (pdata->pmflags == 0) { - if (!udc_can_wakeup_system()) + if (!udc_can_wakeup_system()) { dr_wake_up_enable(udc, false); - else + } else { + if (pdata->platform_phy_power_on) + pdata->platform_phy_power_on(); dr_wake_up_enable(udc, true); + } } /* diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index b872d94b3fc3..e09f4dfd05d9 100755 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -678,6 +678,9 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, usb_host_set_wakeup(hcd->self.controller, false); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + } else { + if (pdata->platform_phy_power_on) + pdata->platform_phy_power_on(); } printk(KERN_DEBUG "host suspend ends\n"); diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig index f0afddc95bd3..8a4a0792724f 100644 --- a/drivers/video/mxc/Kconfig +++ b/drivers/video/mxc/Kconfig @@ -1,6 +1,6 @@ config FB_MXC tristate "MXC Framebuffer support" - depends on FB && (MXC_IPU || ARCH_MX21 || ARCH_MX27 || ARCH_MX25) + depends on FB && (MXC_IPU || ARCH_MX21 || ARCH_MX27 || ARCH_MX25 || ARCH_MX6) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -60,6 +60,10 @@ config FB_MXC_SII902X depends on FB_MXC_SYNC_PANEL && I2C tristate "Si Image SII9022 DVI/HDMI Interface Chip" +config FB_MXC_SII902X_ELCDIF + depends on FB_MXC_SYNC_PANEL && I2C + tristate "Si Image SII9022 DVI/HDMI Interface Chip for ELCDIF FB" + config FB_MXC_CH7026 depends on FB_MXC_SYNC_PANEL tristate "Chrontel CH7026 VGA Interface Chip" diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile index 21aef052ecd6..092d0aacba27 100644 --- a/drivers/video/mxc/Makefile +++ b/drivers/video/mxc/Makefile @@ -1,9 +1,10 @@ obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o obj-$(CONFIG_FB_MXC_SII902X) += mxcfb_sii902x.o +obj-$(CONFIG_FB_MXC_SII902X_ELCDIF) += mxcfb_sii902x_elcdif.o obj-$(CONFIG_FB_MXC_LDB) += ldb.o obj-$(CONFIG_FB_MXC_MIPI_DSI) += mipi_dsi.o obj-$(CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL) += mxcfb_hx8369_wvga.o -obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o mxc_dvi.o +obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o ifeq ($(CONFIG_ARCH_MX21)$(CONFIG_ARCH_MX27)$(CONFIG_ARCH_MX25),y) obj-$(CONFIG_FB_MXC_TVOUT) += fs453.o obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mx2fb.o mxcfb_modedb.o @@ -11,8 +12,10 @@ ifeq ($(CONFIG_ARCH_MX21)$(CONFIG_ARCH_MX27)$(CONFIG_ARCH_MX25),y) else ifeq ($(CONFIG_MXC_IPU_V1),y) obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxcfb.o mxcfb_modedb.o -else +endif +ifeq ($(CONFIG_MXC_IPU_V3),y) obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o + obj-$(CONFIG_FB_MXC_EDID) += mxc_dvi.o endif obj-$(CONFIG_FB_MXC_EPSON_PANEL) += mxcfb_epson.o obj-$(CONFIG_FB_MXC_EPSON_QVGA_PANEL) += mxcfb_epson_qvga.o diff --git a/drivers/video/mxc/mxc_elcdif_fb.c b/drivers/video/mxc/mxc_elcdif_fb.c index 9c3b7b99a411..be521ddbdf9d 100644 --- a/drivers/video/mxc/mxc_elcdif_fb.c +++ b/drivers/video/mxc/mxc_elcdif_fb.c @@ -86,6 +86,12 @@ struct elcdif_signal_cfg { unsigned Vsync_pol:1; /* true = active high */ }; +struct mxcfb_mode { + int dev_mode; + int num_modes; + struct fb_videomode *mode; +}; + static int mxc_elcdif_fb_blank(int blank, struct fb_info *info); static int mxc_elcdif_fb_map_video_memory(struct fb_info *info); static int mxc_elcdif_fb_unmap_video_memory(struct fb_info *info); @@ -97,6 +103,15 @@ static bool g_elcdif_axi_clk_enable; static bool g_elcdif_pix_clk_enable; static struct clk *g_elcdif_axi_clk; static struct clk *g_elcdif_pix_clk; +static struct mxcfb_mode mxc_disp_mode; + +static void dump_fb_videomode(struct fb_videomode *m) +{ + pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n", + m->refresh, m->xres, m->yres, m->pixclock, m->left_margin, + m->right_margin, m->upper_margin, m->lower_margin, + m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag); +} static inline void setup_dotclk_panel(u32 pixel_clk, u16 v_pulse_width, @@ -113,16 +128,39 @@ static inline void setup_dotclk_panel(u32 pixel_clk, int enable_present) { u32 val, rounded_pixel_clk; + u32 rounded_parent_clk; + struct clk *clk_parent; if (!g_elcdif_axi_clk_enable) { clk_enable(g_elcdif_axi_clk); g_elcdif_axi_clk_enable = true; } + /* Init clocking */ dev_dbg(g_elcdif_dev, "pixel clk = %d\n", pixel_clk); - rounded_pixel_clk = clk_round_rate(g_elcdif_pix_clk, pixel_clk); + + clk_parent = clk_get_parent(g_elcdif_pix_clk); + if (clk_parent == NULL) + dev_err(g_elcdif_dev, "%s Failed get clk parent\n", __func__); + + rounded_pixel_clk = pixel_clk * 2; + + rounded_parent_clk = clk_round_rate(clk_parent, + rounded_pixel_clk); + + while (rounded_pixel_clk < rounded_parent_clk) { + /* the max divider from parent to di is 8 */ + if (rounded_parent_clk / pixel_clk < 8) + rounded_pixel_clk += pixel_clk * 2; + } + + clk_set_rate(clk_parent, rounded_pixel_clk); + rounded_pixel_clk = + clk_round_rate(g_elcdif_pix_clk, pixel_clk); clk_set_rate(g_elcdif_pix_clk, rounded_pixel_clk); + msleep(5); + __raw_writel(BM_ELCDIF_CTRL_DATA_SHIFT_DIR, elcdif_base + HW_ELCDIF_CTRL_CLR); @@ -519,6 +557,35 @@ static inline void mxc_init_elcdif(void) return; } +void mxcfb_elcdif_register_mode(const struct fb_videomode *modedb, + int num_modes, int dev_mode) +{ + struct fb_videomode *mode; + + mode = kzalloc(num_modes * sizeof(struct fb_videomode), GFP_KERNEL); + + if (!mode) { + dev_err(g_elcdif_dev, "%s Failed to allocate mode data\n", __func__); + return; + } + + if (mxc_disp_mode.num_modes) + memcpy(mode, mxc_disp_mode.mode, + mxc_disp_mode.num_modes * sizeof(struct fb_videomode)); + if (modedb) + memcpy(mode + mxc_disp_mode.num_modes, modedb, + num_modes * sizeof(struct fb_videomode)); + + if (mxc_disp_mode.num_modes) + kfree(mxc_disp_mode.mode); + + mxc_disp_mode.mode = mode; + mxc_disp_mode.num_modes += num_modes; + mxc_disp_mode.dev_mode = dev_mode; + + return; +} + int mxc_elcdif_frame_addr_setup(dma_addr_t phys) { int ret = 0; @@ -1236,6 +1303,9 @@ static int mxc_elcdif_fb_probe(struct platform_device *pdev) struct resource *res; struct fb_info *fbi; struct mxc_fb_platform_data *pdata = pdev->dev.platform_data; + const struct fb_videomode *mode; + struct fb_videomode m; + int num; fbi = framebuffer_alloc(sizeof(struct mxc_elcdif_fb_data), &pdev->dev); if (fbi == NULL) { @@ -1296,20 +1366,63 @@ static int mxc_elcdif_fb_probe(struct platform_device *pdev) if (pdata && !data->output_pix_fmt) data->output_pix_fmt = pdata->interface_pix_fmt; + INIT_LIST_HEAD(&fbi->modelist); + if (pdata && pdata->mode && pdata->num_modes) fb_videomode_to_modelist(pdata->mode, pdata->num_modes, &fbi->modelist); + if (mxc_disp_mode.num_modes) { + int i; + mode = mxc_disp_mode.mode; + num = mxc_disp_mode.num_modes; + + for (i = 0; i < num; i++) { + /* + * FIXME now we do not support interlaced + * mode for ddc mode + */ + if ((mxc_disp_mode.dev_mode + & MXC_DISP_DDC_DEV) && + (mode[i].vmode & FB_VMODE_INTERLACED)) + continue; + else { + dev_dbg(&pdev->dev, "Added mode %d:", i); + dev_dbg(&pdev->dev, + "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n", + mode[i].xres, mode[i].yres, mode[i].refresh, mode[i].vmode, + mode[i].flag); + fb_add_videomode(&mode[i], &fbi->modelist); + } + } + } + if (!fb_mode && pdata && pdata->mode_str) fb_mode = pdata->mode_str; if (fb_mode) { + dev_dbg(&pdev->dev, "default video mode %s\n", fb_mode); ret = fb_find_mode(&fbi->var, fbi, fb_mode, NULL, 0, NULL, default_bpp); - if ((!ret || (ret > 2)) && pdata && pdata->mode && - pdata->num_modes) - fb_find_mode(&fbi->var, fbi, fb_mode, pdata->mode, + if ((ret == 1) || (ret == 2)) { + fb_var_to_videomode(&m, &fbi->var); + dump_fb_videomode(&m); + mode = fb_find_nearest_mode(&m, + &fbi->modelist); + fb_videomode_to_var(&fbi->var, mode); + } else if (pdata && pdata->mode && pdata->num_modes) { + ret = fb_find_mode(&fbi->var, fbi, fb_mode, pdata->mode, pdata->num_modes, NULL, default_bpp); + if (!ret) { + dev_err(fbi->device, + "No valid video mode found"); + goto err2; + } + } else { + dev_err(fbi->device, + "No valid video mode found"); + goto err2; + } } mxc_elcdif_fb_check_var(&fbi->var, fbi); @@ -1343,6 +1456,19 @@ static int mxc_elcdif_fb_probe(struct platform_device *pdev) */ clk_set_rate(g_elcdif_pix_clk, 25000000); + fbi->var.activate |= FB_ACTIVATE_FORCE; + console_lock(); + fbi->flags |= FBINFO_MISC_USEREVENT; + ret = fb_set_var(fbi, &fbi->var); + fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + + if (data->cur_blank == FB_BLANK_UNBLANK) { + console_lock(); + fb_blank(fbi, FB_BLANK_UNBLANK); + console_unlock(); + } + ret = register_framebuffer(fbi); if (ret) goto err3; diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c index 0b3923c2cea6..b702788ae823 100644 --- a/drivers/video/mxc/mxc_epdc_fb.c +++ b/drivers/video/mxc/mxc_epdc_fb.c @@ -50,6 +50,7 @@ #include <linux/bitops.h> #include <mach/epdc.h> #include <mach/dma.h> +#include <asm/cacheflush.h> #include "epdc_regs.h" @@ -69,6 +70,10 @@ #define INVALID_LUT (-1) #define DRY_RUN_NO_LUT 100 +/* Maximum update buffer image width due to v2.0 and v2.1 errata ERR005313. */ +#define EPDC_V2_MAX_UPDATE_WIDTH 2047 +#define EPDC_V2_ROTATION_ALIGNMENT 8 + #define DEFAULT_TEMP_INDEX 0 #define DEFAULT_TEMP 20 /* room temp in deg Celsius */ @@ -202,6 +207,8 @@ struct mxc_epdc_fb_data { bool updates_active; int pwrdown_delay; unsigned long tce_prevent; + bool restrict_width; /* work around rev >=2.0 width and + stride restriction */ /* FB elements related to PxP DMA */ struct completion pxp_tx_cmpl; @@ -262,6 +269,16 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat) static void draw_mode0(struct mxc_epdc_fb_data *fb_data); static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data); +static void do_dithering_processing_Y1_v1_0( + unsigned char *update_region_ptr, + struct mxcfb_rect *update_region, + unsigned long update_region_stride, + int *err_dist); +static void do_dithering_processing_Y4_v1_0( + unsigned char *update_region_ptr, + struct mxcfb_rect *update_region, + unsigned long update_region_stride, + int *err_dist); #ifdef DEBUG static void dump_pxp_config(struct mxc_epdc_fb_data *fb_data, @@ -1930,10 +1947,10 @@ static int epdc_process_update(struct update_data_list *upd_data_list, * to copybuf in addition to the PxP structures */ mutex_lock(&fb_data->pxp_mutex); - if ((((width_unaligned || height_unaligned || input_unaligned) && + if (((((width_unaligned || height_unaligned || input_unaligned) && (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) - || line_overflow) && (fb_data->rev < 20)) { - + || line_overflow) && (fb_data->rev < 20)) || + fb_data->restrict_width) { dev_dbg(fb_data->dev, "Copying update before processing.\n"); /* Update to reflect what the new source buffer will be */ @@ -2137,7 +2154,8 @@ static int epdc_process_update(struct update_data_list *upd_data_list, } static int epdc_submit_merge(struct update_desc_list *upd_desc_list, - struct update_desc_list *update_to_merge) + struct update_desc_list *update_to_merge, + struct mxc_epdc_fb_data *fb_data) { struct mxcfb_update_data *a, *b; struct mxcfb_rect *arect, *brect; @@ -2195,6 +2213,19 @@ static int epdc_submit_merge(struct update_desc_list *upd_desc_list, (arect->top + arect->height - combine.top) : (brect->top + brect->height - combine.top); + /* Don't merge if combined width exceeds max width */ + if (fb_data->restrict_width) { + u32 max_width = EPDC_V2_MAX_UPDATE_WIDTH; + u32 combined_width = combine.width; + if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR) + max_width -= EPDC_V2_ROTATION_ALIGNMENT; + if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_CW) || + (fb_data->epdc_fb_var.rotate == FB_ROTATE_CCW)) + combined_width = combine.height; + if (combined_width > max_width) + return MERGE_FAIL; + } + *arect = combine; /* Use flags of the later update */ @@ -2226,6 +2257,7 @@ static void epdc_submit_work_func(struct work_struct *work) bool end_merge = false; bool is_transform; u32 update_addr; + int *err_dist; int ret; /* Protect access to buffer queues and to update HW */ @@ -2260,7 +2292,8 @@ static void epdc_submit_work_func(struct work_struct *work) break; } else { switch (epdc_submit_merge(upd_data_list->update_desc, - next_update->update_desc)) { + next_update->update_desc, + fb_data)) { case MERGE_OK: dev_dbg(fb_data->dev, "Update merged [collision]\n"); @@ -2330,7 +2363,7 @@ static void epdc_submit_work_func(struct work_struct *work) break; } else { switch (epdc_submit_merge(upd_data_list->update_desc, - next_desc)) { + next_desc, fb_data)) { case MERGE_OK: dev_dbg(fb_data->dev, "Update merged [queue]\n"); @@ -2371,12 +2404,14 @@ static void epdc_submit_work_func(struct work_struct *work) * PxP in versions 2.0 and earlier of EPDC. */ is_transform = upd_data_list->update_desc->upd_data.flags & - (EPDC_FLAG_ENABLE_INVERSION | - EPDC_FLAG_FORCE_MONOCHROME | EPDC_FLAG_USE_CMAP) ? - true : false; + (EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 | + EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME | + EPDC_FLAG_USE_CMAP) ? true : false; + if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) && (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT) && - !is_transform && (fb_data->rev > 20)) { + !is_transform && (fb_data->rev > 20) && + !fb_data->restrict_width) { /* If needed, enable EPDC HW while ePxP is processing */ if ((fb_data->power_state == POWER_STATE_OFF) @@ -2391,7 +2426,6 @@ static void epdc_submit_work_func(struct work_struct *work) update_addr = fb_data->info.fix.smem_start + ((upd_region->top * fb_data->info.var.xres_virtual) + upd_region->left) * fb_data->info.var.bits_per_pixel/8; - upd_data_list->update_desc->epdc_stride = fb_data->info.var.xres_virtual * fb_data->info.var.bits_per_pixel/8; @@ -2457,6 +2491,45 @@ static void epdc_submit_work_func(struct work_struct *work) } /* + * Dithering Processing (Version 1.0 - for i.MX508 and i.MX6SL) + */ + if (upd_data_list->update_desc->upd_data.flags & + EPDC_FLAG_USE_DITHERING_Y1) { + + err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3 + * sizeof(int), GFP_KERNEL); + + /* Dithering Y8 -> Y1 */ + do_dithering_processing_Y1_v1_0( + (uint8_t *)(upd_data_list->virt_addr + + upd_data_list->update_desc->epdc_offs), + &adj_update_region, + (fb_data->rev < 20) ? + ALIGN(adj_update_region.width, 8) : + adj_update_region.width, + err_dist); + + kfree(err_dist); + } else if (upd_data_list->update_desc->upd_data.flags & + EPDC_FLAG_USE_DITHERING_Y4) { + + err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3 + * sizeof(int), GFP_KERNEL); + + /* Dithering Y8 -> Y1 */ + do_dithering_processing_Y4_v1_0( + (uint8_t *)(upd_data_list->virt_addr + + upd_data_list->update_desc->epdc_offs), + &adj_update_region, + (fb_data->rev < 20) ? + ALIGN(adj_update_region.width, 8) : + adj_update_region.width, + err_dist); + + kfree(err_dist); + } + + /* * If there are no LUTs available, * then we must wait for the resource to become free. * The IST will signal this event. @@ -2572,8 +2645,7 @@ static void epdc_submit_work_func(struct work_struct *work) mutex_unlock(&fb_data->queue_mutex); } - -int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data, +static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data, struct fb_info *info) { struct mxc_epdc_fb_data *fb_data = info ? @@ -2868,6 +2940,63 @@ int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data, mutex_unlock(&fb_data->queue_mutex); return 0; } + +int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data, + struct fb_info *info) +{ + struct mxc_epdc_fb_data *fb_data = info ? + (struct mxc_epdc_fb_data *)info:g_fb_data; + + if (!fb_data->restrict_width) { + /* No width restriction, send entire update region */ + return mxc_epdc_fb_send_single_update(upd_data, info); + } else { + int ret; + __u32 width, left; + __u32 marker; + __u32 *region_width, *region_left; + u32 max_upd_width = EPDC_V2_MAX_UPDATE_WIDTH; + + /* Further restrict max width due to pxp rotation + * alignment requirement + */ + if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR) + max_upd_width -= EPDC_V2_ROTATION_ALIGNMENT; + + /* Select split of width or height based on rotation */ + if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) || + (fb_data->epdc_fb_var.rotate == FB_ROTATE_UD)) { + region_width = &upd_data->update_region.width; + region_left = &upd_data->update_region.left; + } else { + region_width = &upd_data->update_region.height; + region_left = &upd_data->update_region.top; + } + + if (*region_width <= max_upd_width) + return mxc_epdc_fb_send_single_update(upd_data, info); + + width = *region_width; + left = *region_left; + marker = upd_data->update_marker; + upd_data->update_marker = 0; + + do { + *region_width = max_upd_width; + *region_left = left; + ret = mxc_epdc_fb_send_single_update(upd_data, info); + if (ret) + return ret; + width -= max_upd_width; + left += max_upd_width; + } while (width > max_upd_width); + + *region_width = width; + *region_left = left; + upd_data->update_marker = marker; + return mxc_epdc_fb_send_single_update(upd_data, info); + } +} EXPORT_SYMBOL(mxc_epdc_fb_send_update); int mxc_epdc_fb_wait_update_complete(struct mxcfb_update_marker_data *marker_data, @@ -3041,6 +3170,25 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = 0; break; } + + case MXCFB_GET_WORK_BUFFER: + { + /* copy the epdc working buffer to the user space */ + struct mxc_epdc_fb_data *fb_data = info ? + (struct mxc_epdc_fb_data *)info:g_fb_data; + flush_cache_all(); + outer_flush_all(); + if (copy_to_user((void __user *)arg, + (const void *) fb_data->working_buffer_virt, + fb_data->working_buffer_size)) + ret = -EFAULT; + else + ret = 0; + flush_cache_all(); + outer_flush_all(); + break; + } + default: break; } @@ -4076,7 +4224,8 @@ static void mxc_epdc_fb_fw_handler(const struct firmware *fw, &fb_data->info); if (ret < 0) dev_err(fb_data->dev, - "Wait for update complete failed. Error = 0x%x", ret); + "Wait for initial update complete failed." + " Error = 0x%x", ret); } static int mxc_epdc_fb_init_hw(struct fb_info *info) @@ -4417,6 +4566,8 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) } else { fb_data->num_luts = EPDC_V2_NUM_LUTS; fb_data->max_num_updates = EPDC_V2_MAX_NUM_UPDATES; + if (vmode->xres > EPDC_V2_MAX_UPDATE_WIDTH) + fb_data->restrict_width = true; } fb_data->max_num_buffers = EPDC_MAX_NUM_BUFFERS; @@ -4454,8 +4605,9 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) * be as big as the full-screen frame buffer */ fb_data->virt_addr_updbuf[i] = - dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size, - &fb_data->phys_addr_updbuf[i], GFP_DMA); + kmalloc(fb_data->max_pix_size, GFP_KERNEL); + fb_data->phys_addr_updbuf[i] = + virt_to_phys(fb_data->virt_addr_updbuf[i]); if (fb_data->virt_addr_updbuf[i] == NULL) { ret = -ENOMEM; goto out_upd_buffers; @@ -4737,10 +4889,7 @@ out_copybuffer: out_upd_buffers: for (i = 0; i < fb_data->max_num_buffers; i++) if (fb_data->virt_addr_updbuf[i] != NULL) - dma_free_writecombine(&pdev->dev, - fb_data->max_pix_size, - fb_data->virt_addr_updbuf[i], - fb_data->phys_addr_updbuf[i]); + kfree(fb_data->virt_addr_updbuf[i]); if (fb_data->virt_addr_updbuf != NULL) kfree(fb_data->virt_addr_updbuf); if (fb_data->phys_addr_updbuf != NULL) @@ -4785,9 +4934,7 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev) for (i = 0; i < fb_data->max_num_buffers; i++) if (fb_data->virt_addr_updbuf[i] != NULL) - dma_free_writecombine(&pdev->dev, fb_data->max_pix_size, - fb_data->virt_addr_updbuf[i], - fb_data->phys_addr_updbuf[i]); + kfree(fb_data->virt_addr_updbuf[i]); if (fb_data->virt_addr_updbuf != NULL) kfree(fb_data->virt_addr_updbuf); if (fb_data->phys_addr_updbuf != NULL) @@ -5082,6 +5229,124 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat) return 0; } +/* + * Different dithering algorithm can be used. We chose + * to implement Bill Atkinson's algorithm as an example + * Thanks Bill Atkinson for his dithering algorithm. + */ + +/* + * Dithering algorithm implementation - Y8->Y1 version 1.0 for i.MX + */ +static void do_dithering_processing_Y1_v1_0( + unsigned char *update_region_ptr, + struct mxcfb_rect *update_region, + unsigned long update_region_stride, + int *err_dist) +{ + + /* create a temp error distribution array */ + int bwPix; + int y; + int col; + int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error; + int width_3 = update_region->width + 3; + char *y8buf; + int x_offset = 0; + + /* prime a few elements the error distribution array */ + for (y = 0; y < update_region->height; y++) { + /* Dithering the Y8 in sbuf to BW suitable for A2 waveform */ + err_dist_l0 = err_dist + (width_3) * (y % 3); + err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3); + err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3); + + y8buf = update_region_ptr + x_offset; + + /* scan the line and convert the Y8 to BW */ + for (col = 1; col <= update_region->width; col++) { + bwPix = *(err_dist_l0 + col) + *y8buf; + + if (bwPix >= 128) { + *y8buf++ = 0xff; + distrib_error = (bwPix - 255) >> 3; + } else { + *y8buf++ = 0; + distrib_error = bwPix >> 3; + } + + /* modify the error distribution buffer */ + *(err_dist_l0 + col + 2) += distrib_error; + *(err_dist_l1 + col + 1) += distrib_error; + *(err_dist_l0 + col + 1) += distrib_error; + *(err_dist_l1 + col - 1) += distrib_error; + *(err_dist_l1 + col) += distrib_error; + *(err_dist_l2 + col) = distrib_error; + } + x_offset += update_region_stride; + } + + flush_cache_all(); + outer_flush_all(); +} + +/* + * Dithering algorithm implementation - Y8->Y4 version 1.0 for i.MX + */ + +static void do_dithering_processing_Y4_v1_0( + unsigned char *update_region_ptr, + struct mxcfb_rect *update_region, + unsigned long update_region_stride, + int *err_dist) +{ + + /* create a temp error distribution array */ + int gcPix; + int y; + int col; + int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error; + int width_3 = update_region->width + 3; + char *y8buf; + int x_offset = 0; + + /* prime a few elements the error distribution array */ + for (y = 0; y < update_region->height; y++) { + /* Dithering the Y8 in sbuf to Y4 */ + err_dist_l0 = err_dist + (width_3) * (y % 3); + err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3); + err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3); + + y8buf = update_region_ptr + x_offset; + + /* scan the line and convert the Y8 to Y4 */ + for (col = 1; col <= update_region->width; col++) { + gcPix = *(err_dist_l0 + col) + *y8buf; + + if (gcPix > 255) + gcPix = 255; + else if (gcPix < 0) + gcPix = 0; + + distrib_error = (*y8buf - (gcPix & 0xf0)) >> 3; + + *y8buf++ = gcPix & 0xf0; + + /* modify the error distribution buffer */ + *(err_dist_l0 + col + 2) += distrib_error; + *(err_dist_l1 + col + 1) += distrib_error; + *(err_dist_l0 + col + 1) += distrib_error; + *(err_dist_l1 + col - 1) += distrib_error; + *(err_dist_l1 + col) += distrib_error; + *(err_dist_l2 + col) = distrib_error; + } + x_offset += update_region_stride; + } + + flush_cache_all(); + outer_flush_all(); +} + static int __init mxc_epdc_fb_init(void) { return platform_driver_register(&mxc_epdc_fb_driver); diff --git a/drivers/video/mxc/mxcfb_sii902x_elcdif.c b/drivers/video/mxc/mxcfb_sii902x_elcdif.c new file mode 100644 index 000000000000..ceab3e66e91c --- /dev/null +++ b/drivers/video/mxc/mxcfb_sii902x_elcdif.c @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + * @defgroup Framebuffer Framebuffer Driver for SDC and ADC. + */ + +/*! + * @file mxcfb_sii902x_elcdif.c + * + * @brief MXC ELCDIF Frame buffer driver for SII902x + * + * @ingroup Framebuffer + */ + +/*! + * Include files + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/i2c.h> +#include <linux/mxcfb.h> +#include <linux/fsl_devices.h> +#include <linux/interrupt.h> +#include <asm/mach-types.h> +#include <mach/hardware.h> +#include <mach/mxc_edid.h> + +#define SII_EDID_LEN 512 +#define MXC_ENABLE 1 +#define MXC_DISABLE 2 + +struct sii902x_data { + struct platform_device *pdev; + struct i2c_client *client; + struct delayed_work det_work; + struct fb_info *fbi; + struct mxc_edid_cfg edid_cfg; + u8 cable_plugin; + u8 edid[SII_EDID_LEN]; + bool waiting_for_fb; +} sii902x; + +static void sii902x_poweron(void); +static void sii902x_poweroff(void); +static void (*sii902x_reset) (void); + +#ifdef DEBUG +static void dump_fb_videomode(struct fb_videomode *m) +{ + pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n", + m->refresh, m->xres, m->yres, m->pixclock, m->left_margin, + m->right_margin, m->upper_margin, m->lower_margin, + m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag); +} +#else +static void dump_fb_videomode(struct fb_videomode *m) +{} +#endif + +static __attribute__ ((unused)) void dump_regs(u8 reg, int len) +{ + u8 buf[50]; + int i; + + i2c_smbus_read_i2c_block_data(sii902x.client, reg, len, buf); + for (i = 0; i < len; i++) + dev_dbg(&sii902x.client->dev, "reg[0x%02X]: 0x%02X\n", + i+reg, buf[i]); +} + +static ssize_t sii902x_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + strcpy(buf, sii902x.fbi->fix.id); + sprintf(buf+strlen(buf), "\n"); + + return strlen(buf); +} + +static DEVICE_ATTR(fb_name, S_IRUGO, sii902x_show_name, NULL); + +static ssize_t sii902x_show_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (sii902x.cable_plugin == 0) + strcpy(buf, "plugout\n"); + else + strcpy(buf, "plugin\n"); + + return strlen(buf); +} + +static DEVICE_ATTR(cable_state, S_IRUGO, sii902x_show_state, NULL); + +static ssize_t sii902x_show_edid(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, j, len = 0; + + for (j = 0; j < SII_EDID_LEN/16; j++) { + for (i = 0; i < 16; i++) + len += sprintf(buf+len, "0x%02X ", + sii902x.edid[j*16 + i]); + len += sprintf(buf+len, "\n"); + } + + return len; +} + +static DEVICE_ATTR(edid, S_IRUGO, sii902x_show_edid, NULL); + +static void sii902x_setup(struct fb_info *fbi) +{ + u16 data[4]; + u32 refresh; + u8 *tmp; + int i; + + dev_dbg(&sii902x.client->dev, "Sii902x: setup..\n"); + + /* Power up */ + i2c_smbus_write_byte_data(sii902x.client, 0x1E, 0x00); + + /* set TPI video mode */ + data[0] = PICOS2KHZ(fbi->var.pixclock) / 10; + data[2] = fbi->var.hsync_len + fbi->var.left_margin + + fbi->var.xres + fbi->var.right_margin; + data[3] = fbi->var.vsync_len + fbi->var.upper_margin + + fbi->var.yres + fbi->var.lower_margin; + refresh = data[2] * data[3]; + refresh = (PICOS2KHZ(fbi->var.pixclock) * 1000) / refresh; + data[1] = refresh * 100; + tmp = (u8 *)data; + for (i = 0; i < 8; i++) + i2c_smbus_write_byte_data(sii902x.client, i, tmp[i]); + + /* input bus/pixel: full pixel wide (24bit), rising edge */ + i2c_smbus_write_byte_data(sii902x.client, 0x08, 0x70); + /* Set input format to RGB */ + i2c_smbus_write_byte_data(sii902x.client, 0x09, 0x00); + /* set output format to RGB */ + i2c_smbus_write_byte_data(sii902x.client, 0x0A, 0x00); + /* audio setup */ + i2c_smbus_write_byte_data(sii902x.client, 0x25, 0x00); + i2c_smbus_write_byte_data(sii902x.client, 0x26, 0x40); + i2c_smbus_write_byte_data(sii902x.client, 0x27, 0x00); +} + +#ifdef CONFIG_FB_MODE_HELPERS +static int sii902x_read_edid(struct fb_info *fbi) +{ + int old, dat, ret, cnt = 100; + unsigned short addr = 0x50; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); + + old = i2c_smbus_read_byte_data(sii902x.client, 0x1A); + + i2c_smbus_write_byte_data(sii902x.client, 0x1A, old | 0x4); + do { + cnt--; + msleep(10); + dat = i2c_smbus_read_byte_data(sii902x.client, 0x1A); + } while ((!(dat & 0x2)) && cnt); + + if (!cnt) { + ret = -1; + goto done; + } + + i2c_smbus_write_byte_data(sii902x.client, 0x1A, old | 0x06); + + /* edid reading */ + ret = mxc_edid_read(sii902x.client->adapter, addr, + sii902x.edid, &sii902x.edid_cfg, fbi); + + cnt = 100; + do { + cnt--; + i2c_smbus_write_byte_data(sii902x.client, 0x1A, old & ~0x6); + msleep(10); + dat = i2c_smbus_read_byte_data(sii902x.client, 0x1A); + } while ((dat & 0x6) && cnt); + + if (!cnt) + ret = -1; + +done: + + i2c_smbus_write_byte_data(sii902x.client, 0x1A, old); + return ret; +} +#else +static int sii902x_read_edid(struct fb_info *fbi) +{ + return -1; +} +#endif + +static void det_worker(struct work_struct *work) +{ + int dat; + char event_string[16]; + char *envp[] = { event_string, NULL }; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); + + dat = i2c_smbus_read_byte_data(sii902x.client, 0x3D); + if (dat & 0x1) { + /* cable connection changes */ + if (dat & 0x4) { + sii902x.cable_plugin = 1; + 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"); + else { + if (sii902x.fbi->monspecs.modedb_len > 0) { + + int i; + const struct fb_videomode *mode; + struct fb_videomode m; + + fb_destroy_modelist(&sii902x.fbi->modelist); + + for (i = 0; i < sii902x.fbi->monspecs.modedb_len; i++) { + /*FIXME now we do not support interlaced mode */ + mode = &sii902x.fbi->monspecs.modedb[i]; + + if (!(mode->vmode & FB_VMODE_INTERLACED)) { + + dev_dbg(&sii902x.pdev->dev, "Added mode %d:", i); + dev_dbg(&sii902x.pdev->dev, + "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n", + mode->xres, mode->yres, mode->refresh, + mode->vmode, mode->flag); + + fb_add_videomode(mode, &sii902x.fbi->modelist); + } + } + + fb_var_to_videomode(&m, &sii902x.fbi->var); + dump_fb_videomode(&m); + + mode = fb_find_nearest_mode(&m, + &sii902x.fbi->modelist); + + fb_videomode_to_var(&sii902x.fbi->var, mode); + + sii902x.fbi->var.activate |= FB_ACTIVATE_FORCE; + console_lock(); + sii902x.fbi->flags |= FBINFO_MISC_USEREVENT; + fb_set_var(sii902x.fbi, &sii902x.fbi->var); + sii902x.fbi->flags &= ~FBINFO_MISC_USEREVENT; + console_unlock(); + } + + console_lock(); + fb_blank(sii902x.fbi, FB_BLANK_UNBLANK); + console_unlock(); + } + } 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(); + } + kobject_uevent_env(&sii902x.pdev->dev.kobj, KOBJ_CHANGE, envp); + } + i2c_smbus_write_byte_data(sii902x.client, 0x3D, dat); + + dev_dbg(&sii902x.pdev->dev, "exit %s\n", __func__); + +} + +static irqreturn_t sii902x_detect_handler(int irq, void *data) +{ + if (sii902x.fbi) + schedule_delayed_work(&(sii902x.det_work), msecs_to_jiffies(20)); + else + sii902x.waiting_for_fb = true; + + return IRQ_HANDLED; +} + +static int sii902x_fb_event(struct notifier_block *nb, unsigned long val, void *v) +{ + struct fb_event *event = v; + struct fb_info *fbi = event->info; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); + + switch (val) { + case FB_EVENT_FB_REGISTERED: + if (sii902x.fbi == NULL) { + sii902x.fbi = fbi; + if (sii902x.waiting_for_fb) + det_worker(NULL); + } + fb_show_logo(fbi, 0); + break; + case FB_EVENT_MODE_CHANGE: + sii902x_setup(fbi); + break; + case FB_EVENT_BLANK: + if (*((int *)event->data) == FB_BLANK_UNBLANK) { + dev_dbg(&sii902x.pdev->dev, "FB_BLANK_UNBLANK\n"); + sii902x_poweron(); + } else { + dev_dbg(&sii902x.pdev->dev, "FB_BLANK_BLANK\n"); + sii902x_poweroff(); + } + break; + } + return 0; +} + +static struct notifier_block nb = { + .notifier_call = sii902x_fb_event, +}; + +static int __devinit sii902x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int i, dat, ret; + struct fsl_mxc_lcd_platform_data *plat = client->dev.platform_data; + struct fb_info edid_fbi; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__);; + + sii902x.client = client; + + /* Claim HDMI pins */ + if (plat->get_pins) + if (!plat->get_pins()) + return -EACCES; + + if (plat->reset) { + sii902x_reset = plat->reset; + sii902x_reset(); + } + + /* Set 902x in hardware TPI mode on and jump out of D3 state */ + if (i2c_smbus_write_byte_data(sii902x.client, 0xc7, 0x00) < 0) { + dev_err(&sii902x.client->dev, + "Sii902x: cound not find device\n"); + return -ENODEV; + } + + /* read device ID */ + for (i = 10; i > 0; i--) { + dat = i2c_smbus_read_byte_data(sii902x.client, 0x1B); + printk(KERN_DEBUG "Sii902x: read id = 0x%02X", dat); + if (dat == 0xb0) { + dat = i2c_smbus_read_byte_data(sii902x.client, 0x1C); + printk(KERN_DEBUG "-0x%02X", dat); + dat = i2c_smbus_read_byte_data(sii902x.client, 0x1D); + printk(KERN_DEBUG "-0x%02X", dat); + dat = i2c_smbus_read_byte_data(sii902x.client, 0x30); + printk(KERN_DEBUG "-0x%02X\n", dat); + break; + } + } + if (i == 0) { + dev_err(&sii902x.client->dev, + "Sii902x: cound not find device\n"); + return -ENODEV; + } + + /* try to read edid */ + ret = sii902x_read_edid(&edid_fbi); + if (ret < 0) + dev_warn(&sii902x.client->dev, "Can not read edid\n"); + + if (ret >= 0) + mxcfb_elcdif_register_mode(edid_fbi.monspecs.modedb, + edid_fbi.monspecs.modedb_len, MXC_DISP_DDC_DEV); + + if (sii902x.client->irq) { + ret = request_irq(sii902x.client->irq, sii902x_detect_handler, + IRQF_TRIGGER_FALLING, + "SII902x_det", &sii902x); + if (ret < 0) + dev_warn(&sii902x.client->dev, + "Sii902x: cound not request det irq %d\n", + sii902x.client->irq); + else { + /*enable cable hot plug irq*/ + i2c_smbus_write_byte_data(sii902x.client, 0x3c, 0x01); + INIT_DELAYED_WORK(&(sii902x.det_work), det_worker); + } + ret = device_create_file(&sii902x.pdev->dev, &dev_attr_fb_name); + if (ret < 0) + dev_warn(&sii902x.client->dev, + "Sii902x: cound not create sys node for fb name\n"); + ret = device_create_file(&sii902x.pdev->dev, &dev_attr_cable_state); + if (ret < 0) + dev_warn(&sii902x.client->dev, + "Sii902x: cound not create sys node for cable state\n"); + ret = device_create_file(&sii902x.pdev->dev, &dev_attr_edid); + if (ret < 0) + dev_warn(&sii902x.client->dev, + "Sii902x: cound not create sys node for edid\n"); + + } + + fb_register_client(&nb); + + dev_dbg(&sii902x.pdev->dev, "%s exit\n", __func__);; + + return 0; +} + +static int __devexit sii902x_remove(struct i2c_client *client) +{ + struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); + + fb_unregister_client(&nb); + sii902x_poweroff(); + + /* Release HDMI pins */ + if (plat->put_pins) + plat->put_pins(); + + 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; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); + + /* Enable pins to HDMI */ + if (plat->enable_pins) + plat->enable_pins(); + + /* Turn on DVI or HDMI */ + if (sii902x.edid_cfg.hdmi_cap) + i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x01); + else + i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x00); + return; +} + +static void sii902x_poweroff(void) +{ + struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data; + + dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); + + /* disable tmds before changing resolution */ + if (sii902x.edid_cfg.hdmi_cap) + i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x11); + else + i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x10); + + /* Disable pins to HDMI */ + if (plat->disable_pins) + plat->disable_pins(); + + return; +} + +static const struct i2c_device_id sii902x_id[] = { + { "sii902x", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, sii902x_id); + +static struct i2c_driver sii902x_i2c_driver = { + .driver = { + .name = "sii902x", + }, + .probe = sii902x_probe, + .remove = sii902x_remove, + .suspend = sii902x_suspend, + .resume = sii902x_resume, + .id_table = sii902x_id, +}; + +static int __init sii902x_init(void) +{ + int ret; + + memset(&sii902x, 0, sizeof(sii902x)); + + sii902x.pdev = platform_device_register_simple("sii902x", 0, NULL, 0); + if (IS_ERR(sii902x.pdev)) { + printk(KERN_ERR + "Unable to register Sii902x as a platform device\n"); + ret = PTR_ERR(sii902x.pdev); + goto err; + } + + return i2c_add_driver(&sii902x_i2c_driver); +err: + return ret; +} + +static void __exit sii902x_exit(void) +{ + i2c_del_driver(&sii902x_i2c_driver); + platform_device_unregister(sii902x.pdev); +} + +module_init(sii902x_init); +module_exit(sii902x_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("SII902x DVI/HDMI driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 2a9557307643..ab22c4a9472e 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -135,6 +135,7 @@ struct fsl_usb2_platform_data { void (*platform_rh_suspend)(struct fsl_usb2_platform_data *); void (*platform_rh_resume)(struct fsl_usb2_platform_data *); void (*platform_set_disconnect_det)(struct fsl_usb2_platform_data *, bool); + void (*platform_phy_power_on)(void); struct fsl_usb2_wakeup_platform_data *wakeup_pdata; struct platform_device *pdev; diff --git a/include/linux/mfd/mxc-hdmi-core.h b/include/linux/mfd/mxc-hdmi-core.h index f16b11cb5cf4..26fa47d09abf 100644 --- a/include/linux/mfd/mxc-hdmi-core.h +++ b/include/linux/mfd/mxc-hdmi-core.h @@ -60,5 +60,6 @@ int mxc_hdmi_register_audio(struct snd_pcm_substream *substream); void mxc_hdmi_unregister_audio(struct snd_pcm_substream *substream); unsigned int hdmi_set_cable_state(unsigned int state); unsigned int hdmi_set_blank_state(unsigned int state); +int check_hdmi_state(void); #endif diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 1cd6d901dcd4..57aac193a943 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -373,15 +373,15 @@ struct nand_ecc_ctrl { int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc); int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page); + uint8_t *buf, int oob_required, int page); void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf); + const uint8_t *buf, int oob_required); int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page); + uint8_t *buf, int oob_required, int page); int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offs, uint32_t len, uint8_t *buf); void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf); + const uint8_t *buf, int oob_required); int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd); int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, @@ -507,7 +507,8 @@ struct nand_chip { int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, int cached, int raw); + const uint8_t *buf, int oob_required, int page, + int cached, int raw); int chip_delay; unsigned int options; diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h index 7588d9d09d16..962aa6072b82 100644 --- a/include/linux/mxcfb.h +++ b/include/linux/mxcfb.h @@ -92,6 +92,8 @@ struct mxcfb_rect { #define EPDC_FLAG_USE_ALT_BUFFER 0x100 #define EPDC_FLAG_TEST_COLLISION 0x200 #define EPDC_FLAG_GROUP_UPDATE 0x400 +#define EPDC_FLAG_USE_DITHERING_Y1 0x2000 +#define EPDC_FLAG_USE_DITHERING_Y4 0x4000 #define FB_POWERDOWN_DISABLE -1 @@ -153,6 +155,7 @@ struct mxcfb_waveform_modes { #define MXCFB_SET_PWRDOWN_DELAY _IOW('F', 0x30, int32_t) #define MXCFB_GET_PWRDOWN_DELAY _IOR('F', 0x31, int32_t) #define MXCFB_SET_UPDATE_SCHEME _IOW('F', 0x32, __u32) +#define MXCFB_GET_WORK_BUFFER _IOWR('F', 0x34, unsigned long) #ifdef __KERNEL__ @@ -160,6 +163,11 @@ extern struct fb_videomode mxcfb_modedb[]; extern int mxcfb_modedb_sz; enum { + MXC_DISP_SPEC_DEV = 0, + MXC_DISP_DDC_DEV = 1, +}; + +enum { MXCFB_REFRESH_OFF, MXCFB_REFRESH_AUTO, MXCFB_REFRESH_PARTIAL, @@ -168,5 +176,8 @@ enum { int mxcfb_set_refresh_mode(struct fb_info *fbi, int mode, struct mxcfb_rect *update_region); int mxc_elcdif_frame_addr_setup(dma_addr_t phys); +void mxcfb_elcdif_register_mode(const struct fb_videomode *modedb, + int num_modes, int dev_mode); + #endif /* __KERNEL__ */ #endif diff --git a/include/linux/power/sabresd_battery.h b/include/linux/power/sabresd_battery.h index c251a748a0db..463fa90afdb6 100644 --- a/include/linux/power/sabresd_battery.h +++ b/include/linux/power/sabresd_battery.h @@ -38,6 +38,7 @@ struct max8903_pdata { int flt; /* Fault output */ int dcm; /* Current-Limit Mode input (1: DC, 2: USB) */ int usus; /* USB Suspend Input (1: suspended) */ + int feature_flag;/*battery capacity feature(0:enable, 1:disable)*/ /* DCM wired to Logic High Set this true when DCM pin connect to Logic high.*/ diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index b14531157067..784b5957e37a 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2218,8 +2218,6 @@ SOC_ENUM("Capture LHPF Mode", cap_lhpf_mode), SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1, WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv), -SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME, - WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv), SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0), SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1, diff --git a/sound/soc/imx/imx-hdmi-dma.c b/sound/soc/imx/imx-hdmi-dma.c index 8ada80e0cc74..342f9c85f481 100644 --- a/sound/soc/imx/imx-hdmi-dma.c +++ b/sound/soc/imx/imx-hdmi-dma.c @@ -1116,6 +1116,8 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!check_hdmi_state()) + return 0; rtd->frame_idx = 0; if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { appl_bytes = frames_to_bytes(runtime, diff --git a/sound/soc/imx/imx-spdif.c b/sound/soc/imx/imx-spdif.c index efee7696bfbb..13c97aeb0622 100644 --- a/sound/soc/imx/imx-spdif.c +++ b/sound/soc/imx/imx-spdif.c @@ -1,7 +1,7 @@ /* * ASoC S/PDIF driver for IMX development boards * - * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. * * based on stmp3780_devb_spdif.c * @@ -119,6 +119,11 @@ static int __init imx_spdif_init(void) return -ENOMEM; } + if (machine_is_mx6sl_evk()) { + imx_spdif_dai_link.name = "HDMI-Audio"; + imx_spdif_dai_link.stream_name = "HDMI-Audio"; + } + platform_set_drvdata(imx_spdif_snd_device, &snd_soc_card_imx_spdif); ret = platform_device_add(imx_spdif_snd_device); diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h index 791f9dd27ebf..547628e97f3d 100644 --- a/tools/perf/util/include/linux/compiler.h +++ b/tools/perf/util/include/linux/compiler.h @@ -5,7 +5,9 @@ #define __always_inline inline #endif #define __user +#ifndef __attribute_const__ #define __attribute_const__ +#endif #define __used __attribute__((__unused__)) |