summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinyu Chen <b03824@freescale.com>2011-12-29 16:39:54 +0800
committerXinyu Chen <b03824@freescale.com>2011-12-29 16:39:54 +0800
commiteb61942e81da1be65bc0c0c27f991f70054fe6ac (patch)
tree8187bb3800a80f09bcf468c7fa2bedb5605e0cda
parent5189c2bec846e6dc695ced6e13f92b9e0322d0b6 (diff)
parent042fb9ef67a1e01f8a5bcc4b377803fb2265de1f (diff)
Merge remote branch 'fsl-linux-sdk/imx_2.6.38' into imx_2.6.38_android
Conflicts: arch/arm/mach-mx6/board-mx6q_arm2.c arch/arm/mach-mx6/board-mx6q_sabrelite.c arch/arm/plat-mxc/dvfs_core.c
-rw-r--r--Documentation/arm/imx/udc.txt21
-rw-r--r--arch/arm/configs/imx6_defconfig4
-rw-r--r--arch/arm/mach-mx6/Kconfig1
-rw-r--r--arch/arm/mach-mx6/board-mx6q_arm2.c14
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabreauto.c2
-rw-r--r--arch/arm/mach-mx6/clock.c46
-rw-r--r--arch/arm/mach-mx6/cpu.c2
-rw-r--r--arch/arm/mach-mx6/cpu_regulator-mx6.c2
-rw-r--r--arch/arm/mach-mx6/crm_regs.h2
-rw-r--r--arch/arm/mach-mx6/devices-imx6q.h4
-rw-r--r--arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c6
-rw-r--r--arch/arm/mach-mx6/system.c2
-rw-r--r--arch/arm/plat-mxc/clock.c6
-rw-r--r--arch/arm/plat-mxc/devices/Kconfig3
-rw-r--r--arch/arm/plat-mxc/devices/Makefile1
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc_mlb.c71
-rw-r--r--arch/arm/plat-mxc/dvfs_core.c7
-rw-r--r--arch/arm/plat-mxc/include/mach/devices-common.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx6q.h10
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_hdmi.h34
-rw-r--r--drivers/media/video/mxc/capture/ov5642.c5
-rw-r--r--drivers/mfd/pfuze-core.c5
-rw-r--r--drivers/mmc/host/sdhci.c32
-rw-r--r--drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.c30
-rw-r--r--drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.h2
-rw-r--r--drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c9
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h4
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c45
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h6
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c55
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c60
-rw-r--r--drivers/mxc/mlb/Kconfig11
-rw-r--r--drivers/mxc/mlb/Makefile3
-rwxr-xr-xdrivers/mxc/mlb/mxc_mlb150.c2318
-rw-r--r--drivers/net/fec.c21
-rw-r--r--drivers/tty/serial/imx.c86
-rw-r--r--drivers/usb/core/hub.c6
-rw-r--r--drivers/usb/gadget/f_audio.c36
-rw-r--r--drivers/usb/gadget/u_audio.c17
-rw-r--r--drivers/usb/host/ehci-arc.c16
-rw-r--r--drivers/video/mxc_hdmi.c103
-rw-r--r--include/linux/fsl_devices.h12
-rw-r--r--include/linux/mfd/pfuze.h2
-rw-r--r--include/linux/mxc_mlb.h1
-rw-r--r--sound/soc/codecs/sgtl5000.c35
45 files changed, 2924 insertions, 236 deletions
diff --git a/Documentation/arm/imx/udc.txt b/Documentation/arm/imx/udc.txt
index fdbaa848983b..e532f310d24d 100644
--- a/Documentation/arm/imx/udc.txt
+++ b/Documentation/arm/imx/udc.txt
@@ -1,4 +1,4 @@
-How to test remote wakeup (Make sure connecting to usb host and gadget is loaded)
+* How to test remote wakeup (Make sure connecting to usb host and gadget is loaded)
1. Prepare a usb host which featured with remote wakeup
alternatively, You can use another i.mx board (like mx50 rdp, or mx6q)
2. Boot up both boards, and connect two boards with usb cable
@@ -14,3 +14,22 @@ echo 1 > /sys/devices/platform/fsl-usb2-udc/gadget/start_remote_wakeup
6. The expected behaviour is: host is waked up, and there is
not re-enumeration happens.
+* How to test usb audio gadget
+1. Test Condition
+- Host PC, only Macbook Pro (Mac OS 10.6.5+) & Ubuntu 10.10 (Linux 2.6.38+)
+are supported, Windows OS are not supported now.
+- One USB MicroAB cable and one earphone
+2. Test procedure
+- Power up the board
+- Login in rootfs, load usb audio module with below commands:
+modprobe g_audio req_count=20 audio_buf_size=8192 audio_sample_rate=44100
+- Connect board with PC using MicroAB cable
+- For Ubuntu PC, you can use aplay -l to get the sound card num for this
+usb audio gadget, usually the number is 1. For Macbook, you need to choose
+"Linux USB Audio Gadget" on the "Sound"->"Output" tab of System Preferences.
+- Choose several 44.1Khz wav file to play, you can use aplay or iTune according
+to different PCs.
+3. Constraints
+Since there is no feedback at current usb audio framework,
+it may have pop noise/no sound after play some minutes.
+
diff --git a/arch/arm/configs/imx6_defconfig b/arch/arm/configs/imx6_defconfig
index 5fc54636a1e1..42c4eeb77db4 100644
--- a/arch/arm/configs/imx6_defconfig
+++ b/arch/arm/configs/imx6_defconfig
@@ -288,6 +288,7 @@ CONFIG_IMX_HAVE_PLATFORM_IMX_PM=y
CONFIG_IMX_HAVE_PLATFORM_IMX_ASRC=y
CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_DSI=y
CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_CSI2=y
+CONFIG_IMX_HAVE_PLATFORM_MXC_MLB=y
#
# Freescale MXC Implementations
@@ -1371,6 +1372,7 @@ CONFIG_VIDEO_MXC_IPU_CAMERA=y
CONFIG_MXC_CAMERA_OV3640=m
CONFIG_MXC_CAMERA_OV5640=m
CONFIG_MXC_CAMERA_OV5640_MIPI=m
+CONFIG_MXC_CAMERA_OV8820_MIPI=m
CONFIG_MXC_CAMERA_OV5642=m
CONFIG_MXC_IPU_PRP_VF_SDC=m
CONFIG_MXC_IPU_PRP_ENC=m
@@ -1716,6 +1718,7 @@ CONFIG_USB_ARC=y
CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
# CONFIG_USB_AUDIO is not set
+CONFIG_USB_AUDIO=m
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_ETH_EEM is not set
@@ -1978,6 +1981,7 @@ CONFIG_MXC_ASRC=y
#
# MXC Media Local Bus Driver
#
+CONFIG_MXC_MLB150=m
#
# i.MX ADC support
diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig
index e28be210c654..7136e29025d2 100644
--- a/arch/arm/mach-mx6/Kconfig
+++ b/arch/arm/mach-mx6/Kconfig
@@ -55,6 +55,7 @@ config MACH_MX6Q_ARM2
select IMX_HAVE_PLATFORM_FLEXCAN
select IMX_HAVE_PLATFORM_IMX_MIPI_CSI2
select IMX_HAVE_PLATFORM_PERFMON
+ select IMX_HAVE_PLATFORM_MXC_MLB
help
Include support for i.MX 6Quad Armadillo2 platform. This includes specific
configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c
index 399d0a574903..c05d9031ce0f 100644
--- a/arch/arm/mach-mx6/board-mx6q_arm2.c
+++ b/arch/arm/mach-mx6/board-mx6q_arm2.c
@@ -279,6 +279,11 @@ static iomux_v3_cfg_t mx6q_arm2_pads[] = {
/* USBOTG ID pin */
MX6Q_PAD_GPIO_1__USBOTG_ID,
+
+ /* MLB150 */
+ MX6Q_PAD_GPIO_3__MLB_MLBCLK,
+ MX6Q_PAD_GPIO_6__MLB_MLBSIG,
+ MX6Q_PAD_GPIO_2__MLB_MLBDAT,
};
static iomux_v3_cfg_t mx6q_arm2_i2c3_pads[] = {
@@ -622,7 +627,7 @@ static int max7310_u48_setup(struct i2c_client *client,
void *context)
{
int max7310_gpio_value[] = {
- 1, 1, 1, 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 0, 0,
};
int n;
@@ -1355,6 +1360,12 @@ static int __init early_use_esai_record(char *p)
early_param("esai_record", early_use_esai_record);
+static struct mxc_mlb_platform_data mx6q_arm2_mlb150_data = {
+ .reg_nvcc = NULL,
+ .mlb_clk = "mlb150_clk",
+ .mlb_pll_clk = "pll6",
+};
+
static struct mxc_dvfs_platform_data arm2_dvfscore_data = {
.reg_id = "cpu_vddgp",
.clk1_id = "cpu_clk",
@@ -1586,6 +1597,7 @@ static void __init mx6_board_init(void)
imx6q_add_perfmon(0);
imx6q_add_perfmon(1);
imx6q_add_perfmon(2);
+ imx6q_add_mlb150(&mx6q_arm2_mlb150_data);
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
index 3dfbb39e0002..e5dde074e026 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c
@@ -748,7 +748,7 @@ static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = {
static int mx6q_sabreauto_sata_init(struct device *dev, void __iomem *addr)
{
u32 tmpdata;
- int ret = 0, iterations = 20;
+ int ret = 0;
struct clk *clk;
sata_clk = clk_get(dev, "imx_sata_clk");
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c
index cefdd850ee5f..6b1fad161b41 100644
--- a/arch/arm/mach-mx6/clock.c
+++ b/arch/arm/mach-mx6/clock.c
@@ -52,7 +52,7 @@ static struct clk pll2_pfd_400M;
static struct clk pll3_usb_otg_main_clk;
static struct clk pll4_audio_main_clk;
static struct clk pll5_video_main_clk;
-static struct clk pll6_MLB_main_clk;
+static struct clk pll6_mlb150_main_clk;
static struct clk pll7_usb_host_main_clk;
static struct clk pll8_enet_main_clk;
static struct clk apbh_dma_clk;
@@ -208,7 +208,7 @@ static inline void __iomem *_get_pll_base(struct clk *pll)
return PLL4_AUDIO_BASE_ADDR;
else if (pll == &pll5_video_main_clk)
return PLL5_VIDEO_BASE_ADDR;
- else if (pll == &pll6_MLB_main_clk)
+ else if (pll == &pll6_mlb150_main_clk)
return PLL6_MLB_BASE_ADDR;
else if (pll == &pll7_usb_host_main_clk)
return PLL7_480_USB2_BASE_ADDR;
@@ -844,10 +844,31 @@ static struct clk pll5_video_main_clk = {
.round_rate = _clk_audio_video_round_rate,
};
-static struct clk pll6_MLB_main_clk = {
- __INIT_CLK_DEBUG(pll6_MLB_main_clk)
+static int _clk_pll_mlb_main_enable(struct clk *clk)
+{
+ unsigned int reg;
+ void __iomem *pllbase;
+
+ pllbase = _get_pll_base(clk);
+
+ reg = __raw_readl(pllbase);
+ reg &= ~ANADIG_PLL_BYPASS;
+
+ reg = 0x0da20000;
+ __raw_writel(reg, pllbase);
+
+ /* Wait for PLL to lock */
+ if (!WAIT(__raw_readl(pllbase) & ANADIG_PLL_LOCK,
+ SPIN_DELAY))
+ panic("pll enable failed\n");
+
+ return 0;
+}
+
+static struct clk pll6_mlb150_main_clk = {
+ __INIT_CLK_DEBUG(pll6_mlb150_main_clk)
.parent = &osc_clk,
- .enable = _clk_pll_enable,
+ .enable = _clk_pll_mlb_main_enable,
.disable = _clk_pll_disable,
};
@@ -4520,6 +4541,16 @@ static struct clk usboh3_clk[] = {
},
};
+static struct clk mlb150_clk = {
+ __INIT_CLK_DEBUG(mlb150_clk)
+ .id = 0,
+ .parent = &ipg_clk,
+ .enable_reg = MXC_CCM_CCGR3,
+ .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET,
+ .enable = _clk_enable,
+ .disable = _clk_disable,
+};
+
static int _clk_enable1(struct clk *clk)
{
u32 reg;
@@ -4699,7 +4730,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "pll3_120M", pll3_60M),
_REGISTER_CLOCK(NULL, "pll4", pll4_audio_main_clk),
_REGISTER_CLOCK(NULL, "pll5", pll5_video_main_clk),
- _REGISTER_CLOCK(NULL, "pll4", pll6_MLB_main_clk),
+ _REGISTER_CLOCK(NULL, "pll6", pll6_mlb150_main_clk),
_REGISTER_CLOCK(NULL, "pll3", pll7_usb_host_main_clk),
_REGISTER_CLOCK(NULL, "pll4", pll8_enet_main_clk),
_REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk),
@@ -4792,6 +4823,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("mxs-perfmon.0", "perfmon", perfmon0_clk),
_REGISTER_CLOCK("mxs-perfmon.1", "perfmon", perfmon1_clk),
_REGISTER_CLOCK("mxs-perfmon.2", "perfmon", perfmon2_clk),
+ _REGISTER_CLOCK(NULL, "mlb150_clk", mlb150_clk),
};
static void clk_tree_init(void)
@@ -4849,7 +4881,7 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
#endif
pll4_audio_main_clk.disable(&pll4_audio_main_clk);
pll5_video_main_clk.disable(&pll5_video_main_clk);
- pll6_MLB_main_clk.disable(&pll6_MLB_main_clk);
+ pll6_mlb150_main_clk.disable(&pll6_mlb150_main_clk);
pll7_usb_host_main_clk.disable(&pll7_usb_host_main_clk);
pll8_enet_main_clk.disable(&pll8_enet_main_clk);
diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c
index 81f691cb35b5..da7d442eeae7 100644
--- a/arch/arm/mach-mx6/cpu.c
+++ b/arch/arm/mach-mx6/cpu.c
@@ -33,7 +33,7 @@
void *mx6_wait_in_iram_base;
-void (*mx6_wait_in_iram)();
+void (*mx6_wait_in_iram)(void);
extern void mx6_wait(void);
diff --git a/arch/arm/mach-mx6/cpu_regulator-mx6.c b/arch/arm/mach-mx6/cpu_regulator-mx6.c
index f973c5ae4f9b..779ed62eea53 100644
--- a/arch/arm/mach-mx6/cpu_regulator-mx6.c
+++ b/arch/arm/mach-mx6/cpu_regulator-mx6.c
@@ -32,6 +32,8 @@ static int cpu_op_nr;
static struct cpu_op *cpu_op_tbl;
extern struct cpu_op *(*get_cpu_op)(int *op);
+extern unsigned long loops_per_jiffy;
+
static inline unsigned long mx6_cpu_jiffies(unsigned long old, u_int div,
u_int mult)
{
diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h
index 5b80070c9fd9..7ae4396bab01 100644
--- a/arch/arm/mach-mx6/crm_regs.h
+++ b/arch/arm/mach-mx6/crm_regs.h
@@ -83,6 +83,7 @@
#define ANADIG_PLL_AV_DIV_SELECT_OFFSET (0)
/* PLL6_MLB defines. */
+#define ANADIG_PLL_MLB_LOCK (1 << 31)
#define ANADIG_PLL_MLB_FLT_RES_CFG_MASK (0x7 << 26)
#define ANADIG_PLL_MLB_FLT_RES_CFG_OFFSET (26)
#define ANADIG_PLL_MLB_RX_CLK_DELAY_CFG_MASK (0x7 << 23)
@@ -91,6 +92,7 @@
#define ANADIG_PLL_MLB_VDDD_DELAY_CFG_OFFSET (20)
#define ANADIG_PLL_MLB_VDDA_DELAY_CFG_MASK (0x7 << 17)
#define ANADIG_PLL_MLB_VDDA_DELAY_CFG_OFFSET (17)
+#define ANADIG_PLL_MLB_BYPASS (1 << 16)
/* PLL8_ENET defines. */
#define ANADIG_PLL_ENET_LOCK (1 << 31)
diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h
index e87f9c0d7e7f..ce6b50dc641f 100644
--- a/arch/arm/mach-mx6/devices-imx6q.h
+++ b/arch/arm/mach-mx6/devices-imx6q.h
@@ -194,3 +194,7 @@ extern const struct imx_perfmon_data imx6q_perfmon_data[] __initconst;
#define imx6q_add_perfmon(id) \
imx_add_perfmon(&imx6q_perfmon_data[id])
+extern const struct imx_mxc_mlb_data imx6q_mxc_mlb150_data __initconst;
+#define imx6q_add_mlb150(pdata) \
+ imx_add_mlb(pdata)
+
diff --git a/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c
index 42a6bc62f79f..ba9fb2d77c0a 100644
--- a/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c
+++ b/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c
@@ -363,7 +363,7 @@ static struct regulator_init_data vgen6_init = {
.consumer_supplies = vgen6_consumers,
};
-static struct pfuze_regulator_init_data mx6q_arm2_pfuze100_regulators[] = {
+static struct pfuze_regulator_init_data mx6q_sabreauto_pfuze100_regulators[] = {
{.id = PFUZE100_SW1A, .init_data = &sw1a_init},
{.id = PFUZE100_SW1B, .init_data = &sw1b_init},
{.id = PFUZE100_SW1C, .init_data = &sw1c_init},
@@ -384,8 +384,8 @@ static struct pfuze_regulator_init_data mx6q_arm2_pfuze100_regulators[] = {
static struct pfuze_platform_data pfuze100_plat = {
.flags = PFUZE_USE_REGULATOR,
- .num_regulators = ARRAY_SIZE(mx6q_arm2_pfuze100_regulators),
- .regulators = mx6q_arm2_pfuze100_regulators,
+ .num_regulators = ARRAY_SIZE(mx6q_sabreauto_pfuze100_regulators),
+ .regulators = mx6q_sabreauto_pfuze100_regulators,
};
static struct i2c_board_info __initdata pfuze100_i2c_device = {
diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c
index 8d8e0c747263..8ce35e0b4006 100644
--- a/arch/arm/mach-mx6/system.c
+++ b/arch/arm/mach-mx6/system.c
@@ -52,7 +52,7 @@ extern int mx6q_revision(void);
static void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR);
-extern void (*mx6_wait_in_iram)();
+extern void (*mx6_wait_in_iram)(void);
extern void mx6_wait(void);
extern void *mx6_wait_in_iram_base;
extern bool enable_wait_mode;
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 1814cdc237b9..e1923577a9f3 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -65,7 +65,11 @@ static void __clk_disable(struct clk *clk)
{
if (clk == NULL || IS_ERR(clk))
return;
- WARN_ON(!clk->usecount);
+
+ if (!clk->usecount) {
+ WARN(1, "clock enable/disable mismatch!\n");
+ return;
+ }
if (!(--clk->usecount)) {
if (clk->disable)
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index 60c42ef46d25..644515089d69 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -1,6 +1,9 @@
config IMX_HAVE_PLATFORM_DMA
bool
+config IMX_HAVE_PLATFORM_MXC_MLB
+ bool
+
config IMX_HAVE_PLATFORM_FEC
bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index aa7d7bf49303..cc1a7fedbdfe 100644
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_IMX_HAVE_PLATFORM_DMA) += platform-dma.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_MLB) += platform-mxc_mlb.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_FEC) += platform-fec.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB2_UDC) += platform-fsl-usb2-udc.o
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_mlb.c b/arch/arm/plat-mxc/devices/platform-mxc_mlb.c
new file mode 100644
index 000000000000..a1ede415ed81
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-mxc_mlb.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#ifdef CONFIG_SOC_IMX53
+struct platform_device *__init imx_add_mlb(
+ const struct mxc_mlb_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = MX53_MLB_BASE_ADDR,
+ .end = MX53_MLB_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MX53_INT_MLB,
+ .end = MX53_INT_MLB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+ return imx_add_platform_device("mxc_mlb", 0,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
+#endif /* ifdef CONFIG_SOC_IMX53 */
+
+#ifdef CONFIG_SOC_IMX6Q
+struct platform_device *__init imx_add_mlb(
+ const struct mxc_mlb_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = MLB_BASE_ADDR,
+ .end = MLB_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_MLB,
+ .end = MXC_INT_MLB,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MXC_INT_MLB_AHB0,
+ .end = MXC_INT_MLB_AHB0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MXC_INT_MLB_AHB1,
+ .end = MXC_INT_MLB_AHB1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+ return imx_add_platform_device("mxc_mlb150", 0,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
+#endif
diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c
index dca974df45be..cacd3cca7dd5 100644
--- a/arch/arm/plat-mxc/dvfs_core.c
+++ b/arch/arm/plat-mxc/dvfs_core.c
@@ -1081,13 +1081,6 @@ static int __init dvfs_init(void)
dvfs_core_is_active = 0;
printk(KERN_INFO "DVFS driver module loaded\n");
-#if 0 /* disable dvfs by default on android */
- /* Enable DVFS by default. */
- if (start_dvfs() != 0)
- printk(KERN_ERR "Failed to start DVFS\n");
- printk(KERN_INFO "DVFS driver Enabled\n");
-#endif
-
return 0;
}
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 339018118d03..903751829b60 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -51,6 +51,8 @@ struct platform_device *__init imx_add_flexcan(
const struct flexcan_platform_data *pdata);
#include <linux/fsl_devices.h>
+struct platform_device *__init imx_add_mlb(
+ const struct mxc_mlb_platform_data *pdata);
struct imx_fsl_usb2_udc_data {
resource_size_t iobase;
resource_size_t irq;
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx6q.h b/arch/arm/plat-mxc/include/mach/iomux-mx6q.h
index 9ebde65d18db..c199ad2e4249 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx6q.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx6q.h
@@ -46,6 +46,10 @@ typedef enum iomux_config {
PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS)
#define MX6Q_HIGH_DRV (PAD_CTL_DSE_120ohm)
+
+#define MX6Q_MLB150_PAD_CTRL (PAD_CTL_SPEED_LOW | \
+ PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST) \
+
#define MX6Q_UART_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \
PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS)
@@ -5915,7 +5919,7 @@ typedef enum iomux_config {
#define MX6Q_PAD_GPIO_3__USBOH3_USBH1_OC \
(_MX6Q_PAD_GPIO_3__USBOH3_USBH1_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX6Q_PAD_GPIO_3__MLB_MLBCLK \
- (_MX6Q_PAD_GPIO_3__MLB_MLBCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+ (_MX6Q_PAD_GPIO_3__MLB_MLBCLK | MUX_PAD_CTRL(MX6Q_MLB150_PAD_CTRL))
#define MX6Q_PAD_GPIO_6__ESAI1_SCKT \
(_MX6Q_PAD_GPIO_6__ESAI1_SCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
@@ -5932,7 +5936,7 @@ typedef enum iomux_config {
#define MX6Q_PAD_GPIO_6__USDHC2_LCTL \
(_MX6Q_PAD_GPIO_6__USDHC2_LCTL | MUX_PAD_CTRL(MX6Q_USDHC_PAD_CTRL))
#define MX6Q_PAD_GPIO_6__MLB_MLBSIG \
- (_MX6Q_PAD_GPIO_6__MLB_MLBSIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+ (_MX6Q_PAD_GPIO_6__MLB_MLBSIG | MUX_PAD_CTRL(MX6Q_MLB150_PAD_CTRL))
#define MX6Q_PAD_GPIO_2__ESAI1_FST \
(_MX6Q_PAD_GPIO_2__ESAI1_FST | MUX_PAD_CTRL(NO_PAD_CTRL))
@@ -5949,7 +5953,7 @@ typedef enum iomux_config {
#define MX6Q_PAD_GPIO_2__USDHC2_WP \
(_MX6Q_PAD_GPIO_2__USDHC2_WP | MUX_PAD_CTRL(MX6Q_USDHC_PAD_CTRL))
#define MX6Q_PAD_GPIO_2__MLB_MLBDAT \
- (_MX6Q_PAD_GPIO_2__MLB_MLBDAT | MUX_PAD_CTRL(NO_PAD_CTRL))
+ (_MX6Q_PAD_GPIO_2__MLB_MLBDAT | MUX_PAD_CTRL(MX6Q_MLB150_PAD_CTRL))
#define MX6Q_PAD_GPIO_4__ESAI1_HCKT \
(_MX6Q_PAD_GPIO_4__ESAI1_HCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
diff --git a/arch/arm/plat-mxc/include/mach/mxc_hdmi.h b/arch/arm/plat-mxc/include/mach/mxc_hdmi.h
index 56729b229585..02a413f2bc42 100644
--- a/arch/arm/plat-mxc/include/mach/mxc_hdmi.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_hdmi.h
@@ -787,26 +787,26 @@ enum {
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
-/* FC_AVICONF0-FC_AVICONF2 field values */
- HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x60,
+/* FC_AVICONF0-FC_AVICONF3 field values */
+ HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
- HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x20,
- HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x40,
- HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x10,
- HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x10,
+ HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
+ HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
+ HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
+ HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
- HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x40,
- HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x80,
- HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0xC0,
- HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x03,
- HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x01,
- HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x02,
+ HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
+ HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
+ HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
+ HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
+ HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
+ HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
- HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x09,
+ HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
@@ -840,10 +840,10 @@ enum {
HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
- HDMI_FC_AVICONF2_IT_CONTENT_TYPE_GRAPHICS = 0x00,
- HDMI_FC_AVICONF2_IT_CONTENT_TYPE_PHOTO = 0x01,
- HDMI_FC_AVICONF2_IT_CONTENT_TYPE_CINEMA = 0x02,
- HDMI_FC_AVICONF2_IT_CONTENT_TYPE_GAME = 0x03,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
diff --git a/drivers/media/video/mxc/capture/ov5642.c b/drivers/media/video/mxc/capture/ov5642.c
index 0a20b6f6d356..206c96b5ebc7 100644
--- a/drivers/media/video/mxc/capture/ov5642.c
+++ b/drivers/media/video/mxc/capture/ov5642.c
@@ -1881,6 +1881,7 @@ err:
}
static int ov5642_init_mode(enum ov5642_frame_rate frame_rate,
enum ov5642_mode mode);
+static int ov5642_write_snapshot_para(void);
static int ov5642_change_mode(enum ov5642_frame_rate frame_rate,
enum ov5642_mode new_mode, enum ov5642_mode orig_mode)
{
@@ -1906,10 +1907,10 @@ static int ov5642_change_mode(enum ov5642_frame_rate frame_rate,
ov5642_data.pix.height = 480;
return 0;
} else if (new_mode == ov5642_mode_QSXGA_2592_1944 && orig_mode == ov5642_mode_VGA_640_480) {
- pModeSetting = ov5642_setting_15fps_QSXGA_2592_1944;
- iModeSettingArySize = ARRAY_SIZE(ov5642_setting_15fps_QSXGA_2592_1944);
ov5642_data.pix.width = 2592;
ov5642_data.pix.height = 1944;
+ retval = ov5642_write_snapshot_para();
+ return retval;
} else if (new_mode == ov5642_mode_VGA_640_480 && orig_mode == ov5642_mode_QSXGA_2592_1944) {
pModeSetting = ov5642_setting_QSXGA_2_VGA;
iModeSettingArySize = ARRAY_SIZE(ov5642_setting_QSXGA_2_VGA);
diff --git a/drivers/mfd/pfuze-core.c b/drivers/mfd/pfuze-core.c
index ae3a37e24025..5efc5525fdc9 100644
--- a/drivers/mfd/pfuze-core.c
+++ b/drivers/mfd/pfuze-core.c
@@ -409,11 +409,6 @@ static int pfuze_add_subdevice_pdata(struct mc_pfuze *mc_pfuze,
0);
}
-static int pfuze_add_subdevice(struct mc_pfuze *mc_pfuze, const char *format)
-{
- return pfuze_add_subdevice_pdata(mc_pfuze, format, NULL, 0);
-}
-
static ssize_t pfuze_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c051ea791e95..0cdef1fb56e4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -50,14 +50,11 @@ static void sdhci_finish_command(struct sdhci_host *);
static void sdhci_clk_worker(struct work_struct *work)
{
- unsigned long flags;
struct sdhci_host *host =
container_of(work, struct sdhci_host, clk_worker.work);
- spin_lock_irqsave(&host->lock, flags);
if (host->ops->platform_clk_ctrl && host->clk_status)
host->ops->platform_clk_ctrl(host, false);
- spin_unlock_irqrestore(&host->lock, flags);
}
static inline bool sdhci_is_sdio_attached(struct sdhci_host *host)
@@ -290,16 +287,16 @@ static void sdhci_led_control(struct led_classdev *led,
struct sdhci_host *host = container_of(led, struct sdhci_host, led);
unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
sdhci_enable_clk(host);
+ spin_lock_irqsave(&host->lock, flags);
if (brightness == LED_OFF)
sdhci_deactivate_led(host);
else
sdhci_activate_led(host);
- sdhci_disable_clk(host, CLK_TIMEOUT);
spin_unlock_irqrestore(&host->lock, flags);
+ sdhci_disable_clk(host, CLK_TIMEOUT);
}
#endif
@@ -1182,6 +1179,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host = mmc_priv(mmc);
+ sdhci_enable_clk(host);
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->mrq != NULL);
@@ -1197,7 +1195,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->mrq = mrq;
- sdhci_enable_clk(host);
/* If polling, assume that the card is always present. */
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
@@ -1224,8 +1221,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
sdhci_enable_clk(host);
+ spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
@@ -1301,10 +1298,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
out:
mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+
if (ios->power_mode == MMC_POWER_OFF)
sdhci_disable_clk(host, 0);
-
- spin_unlock_irqrestore(&host->lock, flags);
}
static int sdhci_get_ro(struct mmc_host *mmc)
@@ -1315,8 +1312,8 @@ static int sdhci_get_ro(struct mmc_host *mmc)
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
sdhci_enable_clk(host);
+ spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
is_readonly = 0;
@@ -1327,6 +1324,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
& SDHCI_WRITE_PROTECT);
spin_unlock_irqrestore(&host->lock, flags);
+ sdhci_disable_clk(host, CLK_TIMEOUT);
/* This quirk needs to be replaced by a callback-function later */
return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
@@ -1340,8 +1338,8 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
sdhci_enable_clk(host);
+ spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
@@ -1450,8 +1448,8 @@ static void sdhci_tasklet_finish(unsigned long param)
#endif
mmiowb();
- sdhci_disable_clk(host, CLK_TIMEOUT);
spin_unlock_irqrestore(&host->lock, flags);
+ sdhci_disable_clk(host, CLK_TIMEOUT);
mmc_request_done(host->mmc, mrq);
}
@@ -1731,6 +1729,8 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
{
int ret;
+ mmc_claim_host(host->mmc);
+
sdhci_enable_clk(host);
sdhci_disable_card_detection(host);
@@ -1759,9 +1759,9 @@ int sdhci_resume_host(struct sdhci_host *host)
int ret;
if (host->vmmc) {
- int ret = regulator_enable(host->vmmc);
+ ret = regulator_enable(host->vmmc);
if (ret)
- return ret;
+ goto out;
}
sdhci_enable_clk(host);
@@ -1788,6 +1788,7 @@ out:
/* sync worker */
sdhci_disable_clk(host, 0);
+ mmc_release_host(host->mmc);
return ret;
}
@@ -2157,6 +2158,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
{
unsigned long flags;
+ sdhci_enable_clk(host);
+
if (dead) {
spin_lock_irqsave(&host->lock, flags);
@@ -2167,7 +2170,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
" transfer!\n", mmc_hostname(host->mmc));
host->mrq->cmd->error = -ENOMEDIUM;
- sdhci_enable_clk(host);
tasklet_schedule(&host->finish_tasklet);
}
diff --git a/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.c b/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.c
index 20c79b88806f..296b333cd763 100644
--- a/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.c
+++ b/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.c
@@ -139,21 +139,16 @@ _TimeIdleThread(
/* Cast the object. */
gckVGHARDWARE hardware = (gckVGHARDWARE) ThreadParameter;
- gcmkVERIFY_OK(gckOS_AcquireSemaphore(
- hardware->os,
- hardware->idleSemaphore));
-
while(gcvTRUE)
{
+ gcmkVERIFY_OK(gckOS_WaitSignal(hardware->os,
+ hardware->idleSignal, gcvINFINITE));
+
if (hardware->killThread)
{
break;
}
- gcmkVERIFY_OK(gckOS_AcquireSemaphore(
- hardware->os,
- hardware->idleSemaphore));
-
do
{
gcmkVERIFY_OK(gckOS_GetTicks(&currentTime));
@@ -245,8 +240,8 @@ gckVGHARDWARE_Construct(
hardware->chipMinorFeatures2 = chipMinorFeatures2;
hardware->powerMutex = gcvNULL;
- hardware->idleSemaphore = gcvNULL;
- hardware->chipPowerState = gcvPOWER_ON;
+ hardware->idleSignal = gcvNULL;
+ hardware->chipPowerState = gcvPOWER_OFF;
hardware->chipPowerStateGlobal = gcvPOWER_ON;
hardware->clockState = gcvTRUE;
hardware->powerState = gcvTRUE;
@@ -270,8 +265,7 @@ gckVGHARDWARE_Construct(
gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(hardware, -1));
gcmkERR_BREAK(gckOS_CreateMutex(Os, &hardware->powerMutex));
-
- gcmkERR_BREAK(gckOS_CreateSemaphore(Os, &hardware->idleSemaphore));
+ gcmkERR_BREAK(gckOS_CreateSignal(Os, gcvTRUE, &hardware->idleSignal));
#if gcdPOWER_MANAGEMENT
gcmkERR_BREAK(gckOS_StartThread(
hardware->os,
@@ -326,6 +320,7 @@ gckVGHARDWARE_Destroy(
#if gcdPOWER_MANAGEMENT
Hardware->killThread = gcvTRUE;
+ gcmkVERIFY_OK(gckOS_Signal(Hardware->os, Hardware->idleSignal, gcvTRUE));
gcmkVERIFY_OK(gckOS_StopThread(Hardware->os, Hardware->timeIdleThread));
#endif
/* Mark the object as unknown. */
@@ -337,10 +332,10 @@ gckVGHARDWARE_Destroy(
Hardware->os, Hardware->powerMutex));
}
- if (Hardware->idleSemaphore != gcvNULL)
+ if (Hardware->idleSignal != gcvNULL)
{
- gcmkVERIFY_OK(gckOS_DestroySemaphore(
- Hardware->os, Hardware->idleSemaphore));
+ gcmkVERIFY_OK(gckOS_DestroySignal(
+ Hardware->os, Hardware->idleSignal));
}
/* Free the object. */
@@ -1678,7 +1673,7 @@ gckVGHARDWARE_SetPowerManagementState(
if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON))
{
/* Turn on the power. */
- gcmkONERROR(gckOS_SetGPUPower(os, gcvTRUE, gcvTRUE));
+ gcmkONERROR(gckOS_SetGPUPower(os, gcvCORE_VG , gcvTRUE, gcvTRUE));
/* Mark clock and power as enabled. */
Hardware->clockState = gcvTRUE;
@@ -1749,6 +1744,7 @@ gckVGHARDWARE_SetPowerManagementState(
/* Turn off the GPU power. */
gcmkONERROR(
gckOS_SetGPUPower(os,
+ gcvCORE_VG,
(flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
: gcvTRUE,
(flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
@@ -1789,7 +1785,7 @@ gckVGHARDWARE_SetPowerManagementState(
if (State == gcvPOWER_IDLE)
{
- gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->idleSemaphore));
+ gcmkVERIFY_OK(gckOS_Signal(os, Hardware->idleSignal, gcvTRUE));
}
/* Reset power off time */
gcmkVERIFY_OK(gckOS_GetTicks(&currentTime));
diff --git a/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.h b/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.h
index a4ec3eb05afc..cff634f8bbec 100644
--- a/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.h
+++ b/drivers/mxc/gpu-viv/arch/GC350/hal/kernel/gc_hal_kernel_hardware_vg.h
@@ -57,7 +57,7 @@ struct _gckVGHARDWARE
gctBOOL clockState;
gctBOOL powerState;
gctPOINTER powerMutex;
- gctSEMAPHORE idleSemaphore;
+ gctSIGNAL idleSignal;
gctUINT32 powerProcess;
gctUINT32 powerThread;
gceCHIPPOWERSTATE chipPowerState;
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 ddf1788bb037..43cb760b3146 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
@@ -421,7 +421,7 @@ gckHARDWARE_Construct(
gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
/* Enable the GPU. */
- gcmkONERROR(gckOS_SetGPUPower(Os, gcvTRUE, gcvTRUE));
+ gcmkONERROR(gckOS_SetGPUPower(Os, Core, gcvTRUE, gcvTRUE));
gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00000, 0));
status = _ResetGPU(Os, Core);
@@ -527,7 +527,7 @@ OnError:
if (hardware != gcvNULL)
{
/* Turn off the power. */
- gcmkVERIFY_OK(gckOS_SetGPUPower(Os, gcvFALSE, gcvFALSE));
+ gcmkVERIFY_OK(gckOS_SetGPUPower(Os, hardware->core, gcvFALSE, gcvFALSE));
if (hardware->globalSemaphore != gcvNULL)
{
@@ -585,7 +585,7 @@ gckHARDWARE_Destroy(
gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
/* Turn off the power. */
- gcmkVERIFY_OK(gckOS_SetGPUPower(Hardware->os, gcvFALSE, gcvFALSE));
+ gcmkVERIFY_OK(gckOS_SetGPUPower(Hardware->os, Hardware->core, gcvFALSE, gcvFALSE));
/* Destroy the power semaphore. */
gcmkVERIFY_OK(gckOS_DestroySemaphore(Hardware->os,
@@ -3750,7 +3750,7 @@ gckHARDWARE_SetPowerManagementState(
if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON))
{
/* Turn on the power. */
- gcmkONERROR(gckOS_SetGPUPower(os, gcvTRUE, gcvTRUE));
+ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvTRUE, gcvTRUE));
/* Mark clock and power as enabled. */
Hardware->clockState = gcvTRUE;
@@ -3897,6 +3897,7 @@ gckHARDWARE_SetPowerManagementState(
/* Turn off the GPU power. */
gcmkONERROR(
gckOS_SetGPUPower(os,
+ Hardware->core,
(flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
: gcvTRUE,
(flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
index 2dfa3e74f5de..e2a6b66fa1bb 100644
--- a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
@@ -1243,6 +1243,9 @@ gckOS_BroadcastCalibrateSpeed(
** gckOS Os
** Pointer to a gckOS object.ß
**
+** gceCORE Core
+** Core type.
+**
** gctBOOL Clock
** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
**
@@ -1256,6 +1259,7 @@ gckOS_BroadcastCalibrateSpeed(
gceSTATUS
gckOS_SetGPUPower(
IN gckOS Os,
+ IN gceCORE Core,
IN gctBOOL Clock,
IN gctBOOL Power
);
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 7c0c5beae463..6d3b91bbc792 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
@@ -376,6 +376,34 @@ gckGALDEVICE_Construct(
memset(device, 0, sizeof(struct _gckGALDEVICE));
+ /*Initialize the clock structure*/
+ if (IrqLine != -1) {
+ device->clk_3d_core = clk_get(NULL, "gpu3d_clk");
+ if (!IS_ERR(device->clk_3d_core)) {
+ device->clk_3d_shader = clk_get(NULL, "gpu3d_shader_clk");
+ if (IS_ERR(device->clk_3d_shader)) {
+ IrqLine = -1;
+ clk_put(device->clk_3d_core);
+ device->clk_3d_core = NULL;
+ device->clk_3d_shader = NULL;
+ gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
+ }
+ } else {
+ IrqLine = -1;
+ device->clk_3d_core = NULL;
+ gckOS_Print("galcore: clk_get gpu3d_clk failed, disable 3d!\n");
+ }
+ }
+ if ((IrqLine2D != -1) || (IrqLineVG != -1)) {
+ device->clk_2d_core = clk_get(NULL, "gpu2d_clk");
+ if (IS_ERR(device->clk_2d_core)) {
+ IrqLine2D = -1;
+ IrqLineVG = -1;
+ device->clk_2d_core = NULL;
+ gckOS_Print("galcore: clk_get 2d clock failed, disable 2d/vg!\n");
+ }
+ }
+
if (IrqLine != -1)
{
device->requestedRegisterMemBases[gcvCORE_MAJOR] = RegisterMemBase;
@@ -941,6 +969,23 @@ gckGALDEVICE_Destroy(
}
}
+ /*Disable clock*/
+ if (Device->clk_3d_core) {
+ clk_disable(Device->clk_3d_core);
+ clk_put(Device->clk_3d_core);
+ Device->clk_3d_core = NULL;
+ }
+ if (Device->clk_3d_shader) {
+ clk_disable(Device->clk_3d_shader);
+ clk_put(Device->clk_3d_shader);
+ Device->clk_3d_shader = NULL;
+ }
+ if (Device->clk_2d_core) {
+ clk_disable(Device->clk_2d_core);
+ clk_put(Device->clk_2d_core);
+ Device->clk_2d_core = NULL;
+ }
+
/* Destroy the gckOS object. */
if (Device->os != gcvNULL)
{
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 08c5e82696ba..86333ba34732 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
@@ -82,6 +82,12 @@ typedef struct _gckGALDEVICE
/* Core mapping */
gceCORE coreMapping[8];
+ /* Clock management.*/
+ struct clk *clk_3d_core;
+ struct clk *clk_3d_shader;
+ struct clk *clk_2d_core;
+ gctBOOL clk_flag[gcdCORE_COUNT];
+
#if gcdPOWEROFF_TIMEOUT
struct task_struct *pmThreadCtxts;
gctBOOL pmThreadInitializeds;
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
index e4ef19b8c654..86ef0c67d8a7 100644
--- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
@@ -111,10 +111,6 @@ module_param(showArgs, int, 0644);
module_param(coreClock, ulong, 0644);
#endif
-static struct clk * clk_3d_core;
-static struct clk * clk_3d_shader;
-static struct clk * clk_2d_core;
-
static int drv_open(
struct inode* inode,
struct file* filp
@@ -709,38 +705,6 @@ static int drv_init(void)
#if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
gc_pwr(1);
# endif
-# else
- if (irqLine != -1) {
- clk_3d_core = clk_get(NULL, "gpu3d_clk");
- if (!IS_ERR(clk_3d_core)) {
- clk_3d_shader = clk_get(NULL, "gpu3d_shader_clk");
- if (!IS_ERR(clk_3d_shader)) {
- clk_enable(clk_3d_core);
- clk_enable(clk_3d_shader);
- } else {
- irqLine = -1;
- clk_put(clk_3d_core);
- clk_3d_core = NULL;
- clk_3d_shader = NULL;
- printk(KERN_ERR "galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
- }
- } else {
- irqLine = -1;
- clk_3d_core = NULL;
- printk(KERN_ERR "galcore: clk_get gpu3d_clk failed, disable 3d!\n");
- }
- }
- if ((irqLine2D != -1) || (irqLineVG != -1)) {
- clk_2d_core = clk_get(NULL, "gpu2d_clk");
- if (IS_ERR(clk_2d_core)) {
- irqLine2D = -1;
- irqLineVG = -1;
- clk_2d_core = NULL;
- printk(KERN_ERR "galcore: clk_get 2d clock failed, disable 2d/vg!\n");
- } else {
- clk_enable(clk_2d_core);
- }
- }
# endif
}
#endif
@@ -913,22 +877,6 @@ static void drv_exit(void)
#endif
clk = clk_get(NULL, "GCCLK");
clk_disable(clk);
-# else
- if (clk_3d_core) {
- clk_disable(clk_3d_core);
- clk_put(clk_3d_core);
- clk_3d_core = NULL;
- }
- if (clk_3d_shader) {
- clk_disable(clk_3d_shader);
- clk_put(clk_3d_shader);
- clk_3d_shader = NULL;
- }
- if (clk_2d_core) {
- clk_disable(clk_2d_core);
- clk_put(clk_2d_core);
- clk_2d_core = NULL;
- }
# endif
}
#endif
@@ -1038,7 +986,8 @@ static int __devinit gpu_suspend(struct platform_device *dev, pm_message_t state
{
status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF);
}
-
+ /*gpu clock must be turned on before power down*/
+ gckOS_SetGPUPower(device->os, i, gcvTRUE, gcvFALSE);
if (gcmIS_ERROR(status))
{
return -1;
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 eacee2791b93..619cd7685300 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
@@ -6287,6 +6287,9 @@ gckOS_GetThreadID(
** gckOS Os
** Pointer to a gckOS object.
**
+** gceCORE Core
+** Core type.
+**
** gctBOOL Clock
** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
**
@@ -6300,12 +6303,65 @@ gckOS_GetThreadID(
gceSTATUS
gckOS_SetGPUPower(
IN gckOS Os,
+ IN gceCORE Core,
IN gctBOOL Clock,
IN gctBOOL Power
)
{
- gcmkHEADER_ARG("Os=0x%X Clock=%d Power=%d", Os, Clock, Power);
-
+ struct clk *clk_3dcore = Os->device->clk_3d_core;
+ struct clk *clk_3dshader = Os->device->clk_3d_shader;
+ struct clk *clk_2dcore = Os->device->clk_2d_core;
+
+ gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
+ if (Clock == gcvTRUE) {
+ switch (Core) {
+ case gcvCORE_MAJOR:
+ if (!Os->device->clk_flag[gcvCORE_MAJOR]) {
+ clk_enable(clk_3dcore);
+ clk_enable(clk_3dshader);
+ }
+ Os->device->clk_flag[gcvCORE_MAJOR] = gcvTRUE;
+ break;
+ case gcvCORE_2D:
+ if (!(Os->device->clk_flag[gcvCORE_2D] || Os->device->clk_flag[gcvCORE_VG])) {
+ clk_enable(clk_2dcore);
+ }
+ Os->device->clk_flag[gcvCORE_2D] = gcvTRUE;
+ break;
+ case gcvCORE_VG:
+ if (!(Os->device->clk_flag[gcvCORE_2D] || Os->device->clk_flag[gcvCORE_VG])) {
+ clk_enable(clk_2dcore);
+ }
+ Os->device->clk_flag[gcvCORE_VG] = gcvTRUE;
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (Core) {
+ case gcvCORE_MAJOR:
+ if (Os->device->clk_flag[gcvCORE_MAJOR]) {
+ clk_disable(clk_3dshader);
+ clk_disable(clk_3dcore);
+ }
+ Os->device->clk_flag[gcvCORE_MAJOR] = gcvFALSE;
+ break;
+ case gcvCORE_2D:
+ if (Os->device->clk_flag[gcvCORE_2D] && (!Os->device->clk_flag[gcvCORE_VG])) {
+ clk_disable(clk_2dcore);
+ }
+ Os->device->clk_flag[gcvCORE_2D] = gcvFALSE;
+ break;
+ case gcvCORE_VG:
+ if ((!Os->device->clk_flag[gcvCORE_2D]) && Os->device->clk_flag[gcvCORE_VG]) {
+ clk_disable(clk_2dcore);
+ }
+ Os->device->clk_flag[gcvCORE_VG] = gcvFALSE;
+ break;
+ default:
+ break;
+ }
+ }
/* TODO: Put your code here. */
gcmkFOOTER_NO();
diff --git a/drivers/mxc/mlb/Kconfig b/drivers/mxc/mlb/Kconfig
index 7e3b16c2ddae..727451c1720c 100644
--- a/drivers/mxc/mlb/Kconfig
+++ b/drivers/mxc/mlb/Kconfig
@@ -5,9 +5,20 @@
menu "MXC Media Local Bus Driver"
config MXC_MLB
+ boolean
+
+config MXC_MLB50
tristate "MLB support"
depends on ARCH_MX35 || ARCH_MX53
+ select MXC_MLB
---help---
Say Y to get the MLB support.
+config MXC_MLB150
+ tristate "MLB150 support"
+ depends on ARCH_MX6Q
+ select MXC_MLB
+ ---help---
+ Say Y to get the MLB150 support.
+
endmenu
diff --git a/drivers/mxc/mlb/Makefile b/drivers/mxc/mlb/Makefile
index 60662eb1c031..d519978ffece 100644
--- a/drivers/mxc/mlb/Makefile
+++ b/drivers/mxc/mlb/Makefile
@@ -2,4 +2,5 @@
# Makefile for the kernel MLB driver
#
-obj-$(CONFIG_MXC_MLB) += mxc_mlb.o
+obj-$(CONFIG_MXC_MLB50) += mxc_mlb.o
+obj-$(CONFIG_MXC_MLB150) += mxc_mlb150.o
diff --git a/drivers/mxc/mlb/mxc_mlb150.c b/drivers/mxc/mlb/mxc_mlb150.c
new file mode 100755
index 000000000000..83f50e2eae04
--- /dev/null
+++ b/drivers/mxc/mlb/mxc_mlb150.c
@@ -0,0 +1,2318 @@
+/*
+ * Copyright (C) 2011 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/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/uaccess.h>
+#include <linux/mxc_mlb.h>
+#include <linux/iram_alloc.h>
+#include <linux/fsl_devices.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "mxc_mlb150"
+
+/*!
+ * MLB module memory map registers define
+ */
+#define MLB150_REG_MLBC0 0x0
+#define MLB150_MLBC0_MLBEN (0x1)
+#define MLB150_MLBC0_MLBCLK_MASK (0x7 << 2)
+#define MLB150_MLBC0_MLBCLK_SHIFT (2)
+#define MLB150_MLBC0_MLBPEN (0x1 << 5)
+#define MLB150_MLBC0_MLBLK (0x1 << 7)
+#define MLB150_MLBC0_ASYRETRY (0x1 << 12)
+#define MLB150_MLBC0_CTLRETRY (0x1 << 12)
+#define MLB150_MLBC0_FCNT_MASK (0x7 << 15)
+#define MLB150_MLBC0_FCNT_SHIFT (15)
+
+#define MLB150_REG_MLBPC0 0x8
+#define MLB150_MLBPC0_MCLKHYS (0x1 << 11)
+
+#define MLB150_REG_MS0 0xC
+#define MLB150_REG_MS1 0x14
+
+#define MLB150_REG_MSS 0x20
+#define MLB150_MSS_RSTSYSCMD (0x1)
+#define MLB150_MSS_LKSYSCMD (0x1 << 1)
+#define MLB150_MSS_ULKSYSCMD (0x1 << 2)
+#define MLB150_MSS_CSSYSCMD (0x1 << 3)
+#define MLB150_MSS_SWSYSCMD (0x1 << 4)
+#define MLB150_MSS_SERVREQ (0x1 << 5)
+
+#define MLB150_REG_MSD 0x24
+
+#define MLB150_REG_MIEN 0x2C
+#define MLB150_MIEN_ISOC_PE (0x1)
+#define MLB150_MIEN_ISOC_BUFO (0x1 << 1)
+#define MLB150_MIEN_SYNC_PE (0x1 << 16)
+#define MLB150_MIEN_ARX_DONE (0x1 << 17)
+#define MLB150_MIEN_ARX_PE (0x1 << 18)
+#define MLB150_MIEN_ARX_BREAK (0x1 << 19)
+#define MLB150_MIEN_ATX_DONE (0x1 << 20)
+#define MLB150_MIEN_ATX_PE (0x1 << 21)
+#define MLB150_MIEN_ATX_BREAK (0x1 << 22)
+#define MLB150_MIEN_CRX_DONE (0x1 << 24)
+#define MLB150_MIEN_CRX_PE (0x1 << 25)
+#define MLB150_MIEN_CRX_BREAK (0x1 << 26)
+#define MLB150_MIEN_CTX_DONE (0x1 << 27)
+#define MLB150_MIEN_CTX_PE (0x1 << 28)
+#define MLB150_MIEN_CTX_BREAK (0x1 << 29)
+
+#define MLB150_REG_MLBPC2 0x34
+#define MLB150_REG_MLBPC1 0x38
+#define MLB150_MLBPC1_VAL (0x00000888)
+
+#define MLB150_REG_MLBC1 0x3C
+#define MLB150_MLBC1_LOCK (0x1 << 6)
+#define MLB150_MLBC1_CLKM (0x1 << 7)
+#define MLB150_MLBC1_NDA_MASK (0xFF << 8)
+#define MLB150_MLBC1_NDA_SHIFT (8)
+
+#define MLB150_REG_HCTL 0x80
+#define MLB150_HCTL_RST0 (0x1)
+#define MLB150_HCTL_RST1 (0x1 << 1)
+#define MLB150_HCTL_EN (0x1 << 15)
+
+#define MLB150_REG_HCMR0 0x88
+#define MLB150_REG_HCMR1 0x8C
+#define MLB150_REG_HCER0 0x90
+#define MLB150_REG_HCER1 0x94
+#define MLB150_REG_HCBR0 0x98
+#define MLB150_REG_HCBR1 0x9C
+
+#define MLB150_REG_MDAT0 0xC0
+#define MLB150_REG_MDAT1 0xC4
+#define MLB150_REG_MDAT2 0xC8
+#define MLB150_REG_MDAT3 0xCC
+
+#define MLB150_REG_MDWE0 0xD0
+#define MLB150_REG_MDWE1 0xD4
+#define MLB150_REG_MDWE2 0xD8
+#define MLB150_REG_MDWE3 0xDC
+
+#define MLB150_REG_MCTL 0xE0
+#define MLB150_MCTL_XCMP (0x1)
+
+#define MLB150_REG_MADR 0xE4
+#define MLB150_MADR_WNR (0x1 << 31)
+#define MLB150_MADR_TB (0x1 << 30)
+#define MLB150_MADR_ADDR_MASK (0x7f << 8)
+#define MLB150_MADR_ADDR_SHIFT (0)
+
+#define MLB150_REG_ACTL 0x3C0
+#define MLB150_ACTL_MPB (0x1 << 4)
+#define MLB150_ACTL_DMAMODE (0x1 << 2)
+#define MLB150_ACTL_SMX (0x1 << 1)
+#define MLB150_ACTL_SCE (0x1)
+
+#define MLB150_REG_ACSR0 0x3D0
+#define MLB150_REG_ACSR1 0x3D4
+#define MLB150_REG_ACMR0 0x3D8
+#define MLB150_REG_ACMR1 0x3DC
+
+#define MLB150_REG_CAT_MDATn(ch) (MLB150_REG_MDAT0 + ((ch % 8) >> 1) * 4)
+#define MLB150_REG_CAT_MDWEn(ch) (MLB150_REG_MDWE0 + ((ch % 8) >> 1) * 4)
+
+#define MLB150_LOGIC_CH_NUM (64)
+#define MLB150_BUF_CDT_OFFSET (0x0)
+#define MLB150_BUF_ADT_OFFSET (0x40)
+#define MLB150_BUF_CAT_MLB_OFFSET (0x80)
+#define MLB150_BUF_CAT_HBI_OFFSET (0x88)
+#define MLB150_BUF_CTR_END_OFFSET (0x8F)
+
+#define MLB150_CAT_MODE_RX (0x1 << 0)
+#define MLB150_CAT_MODE_TX (0x1 << 1)
+#define MLB150_CAT_MODE_INBOUND_DMA (0x1 << 8)
+#define MLB150_CAT_MODE_OUTBOUND_DMA (0x1 << 9)
+
+
+static u32 mlb150_fs_phy_ch_num_per_frm[8] = {
+ 8, 16, 32, 58, 87, 117, 161, 215
+};
+
+#define MLB150_CH_SYNC_BUF_DEP (215 * 4 * 4)
+#define MLB150_CH_CTRL_BUF_DEP (64)
+#define MLB150_CH_ASYNC_BUF_DEP (1536)
+#define MLB150_CH_ISOC_BLK_SIZE (196)
+#define MLB150_CH_ISOC_BUF_DEP (MLB150_CH_ISOC_BLK_SIZE * 3)
+
+#define MLB150_CH_SYNC_DBR_BUF_OFFSET (0x0)
+#define MLB150_CH_CTRL_DBR_BUF_OFFSET (MLB150_CH_SYNC_DBR_BUF_OFFSET + 2 * MLB150_CH_SYNC_BUF_DEP)
+#define MLB150_CH_ASYNC_DBR_BUF_OFFSET (MLB150_CH_CTRL_DBR_BUF_OFFSET + 2 * MLB150_CH_CTRL_BUF_DEP)
+#define MLB150_CH_ISOC_DBR_BUF_OFFSET (MLB150_CH_ASYNC_DBR_BUF_OFFSET + 2 * MLB150_CH_ASYNC_BUF_DEP)
+
+static u32 mlb150_ch_packet_buf_size[4] = {
+ MLB150_CH_SYNC_BUF_DEP,
+ MLB150_CH_CTRL_BUF_DEP,
+ MLB150_CH_ASYNC_BUF_DEP,
+ MLB150_CH_ISOC_BUF_DEP
+};
+
+#define MLB150_DBR_BUF_START 0x00000
+
+#define MLB150_CDT_LEN (16)
+#define MLB150_ADT_LEN (16)
+#define MLB150_CAT_LEN (2)
+
+#define MLB150_CDT_SZ (MLB150_CDT_LEN * MLB150_LOGIC_CH_NUM)
+#define MLB150_ADT_SZ (MLB150_ADT_LEN * MLB150_LOGIC_CH_NUM)
+#define MLB150_CAT_SZ (MLB150_CAT_LEN * MLB150_LOGIC_CH_NUM * 2)
+
+#define MLB150_CDT_BASE(base) (base + MLB150_BUF_CDT_OFFSET)
+#define MLB150_ADT_BASE(base) (base + MLB150_BUF_ADT_OFFSET)
+#define MLB150_CAT_MLB_BASE(base) (base + MLB150_BUF_CAT_MLB_OFFSET)
+#define MLB150_CAT_HBI_BASE(base) (base + MLB150_BUF_CAT_HBI_OFFSET)
+
+#define MLB150_CDTn_ADDR(base, n) (base + MLB150_BUF_CDT_OFFSET + n * MLB150_CDT_LEN)
+#define MLB150_ADTn_ADDR(base, n) (base + MLB150_BUF_ADT_OFFSET + n * MLB150_ADT_LEN)
+#define MLB150_CATn_MLB_ADDR(base, n) (base + MLB150_BUF_CAT_MLB_OFFSET + n * MLB150_CAT_LEN)
+#define MLB150_CATn_HBI_ADDR(base, n) (base + MLB150_BUF_CAT_HBI_OFFSET + n * MLB150_CAT_LEN)
+
+#define CAT_CL_SHIFT (0x0)
+#define CAT_CT_SHIFT (8)
+#define CAT_CE (0x1 << 11)
+#define CAT_RNW (0x1 << 12)
+#define CAT_MT (0x1 << 13)
+#define CAT_FCE (0x1 << 14)
+#define CAT_MFE (0x1 << 14)
+
+#define CDT_WSBC_SHIFT (14)
+#define CDT_WPC_SHIFT (11)
+#define CDT_RSBC_SHIFT (30)
+#define CDT_RPC_SHIFT (27)
+#define CDT_WPC_1_SHIFT (12)
+#define CDT_RPC_1_SHIFT (28)
+#define CDT_WPTR_SHIFT (0)
+#define CDT_SYNC_WSTS_MASK (0x0000f000)
+#define CDT_SYNC_WSTS_SHIFT (12)
+#define CDT_CTRL_ASYNC_WSTS_MASK (0x0000f000)
+#define CDT_CTRL_ASYNC_WSTS_SHIFT (12)
+#define CDT_ISOC_WSTS_MASK (0x0000e000)
+#define CDT_ISOC_WSTS_SHIFT (13)
+#define CDT_RPTR_SHIFT (16)
+#define CDT_SYNC_RSTS_MASK (0xf0000000)
+#define CDT_SYNC_RSTS_SHIFT (28)
+#define CDT_CTRL_ASYNC_RSTS_MASK (0xf0000000)
+#define CDT_CTRL_ASYNC_RSTS_SHIFT (28)
+#define CDT_ISOC_RSTS_MASK (0xe0000000)
+#define CDT_ISOC_RSTS_SHIFT (29)
+#define CDT_CTRL_ASYNC_WSTS_1 (0x1 << 14)
+#define CDT_CTRL_ASYNC_RSTS_1 (0x1 << 15)
+#define CDT_BD_SHIFT (0)
+#define CDT_BA_SHIFT (16)
+#define CDT_BS_SHIFT (0)
+#define CDT_BF_SHIFT (31)
+
+#define ADT_PG (0x1 << 13)
+#define ADT_LE (0x1 << 14)
+#define ADT_CE (0x1 << 15)
+#define ADT_BD1_SHIFT (0)
+#define ADT_ERR1 (0x1 << 13)
+#define ADT_DNE1 (0x1 << 14)
+#define ADT_RDY1 (0x1 << 15)
+#define ADT_BD2_SHIFT (16)
+#define ADT_ERR2 (0x1 << 29)
+#define ADT_DNE2 (0x1 << 30)
+#define ADT_RDY2 (0x1 << 31)
+#define ADT_BA1_SHIFT (0x0)
+#define ADT_BA2_SHIFT (0x0)
+#define ADT_PS1 (0x1 << 12)
+#define ADT_PS2 (0x1 << 28)
+#define ADT_MEP1 (0x1 << 11)
+#define ADT_MEP2 (0x1 << 27)
+
+#define MLB_CONTROL_TX_CHANN (0 << 4)
+#define MLB_CONTROL_RX_CHANN (1 << 4)
+#define MLB_ASYNC_TX_CHANN (2 << 4)
+#define MLB_ASYNC_RX_CHANN (3 << 4)
+
+#define MLB_MINOR_DEVICES 4
+#define MLB_CONTROL_DEV_NAME "ctrl"
+#define MLB_ASYNC_DEV_NAME "async"
+#define MLB_SYNC_DEV_NAME "sync"
+#define MLB_ISOC_DEV_NAME "isoc"
+
+#define TX_CHANNEL 0
+#define RX_CHANNEL 1
+#define PING_BUF_MAX_SIZE (2 * 1024)
+#define PONG_BUF_MAX_SIZE (2 * 1024)
+/* max package data size */
+#define ASYNC_PACKET_SIZE 1024
+#define CTRL_PACKET_SIZE 64
+#define TRANS_RING_NODES 10
+
+#define MLB_IRAM_SIZE (MLB_MINOR_DEVICES * (PING_BUF_MAX_SIZE + PONG_BUF_MAX_SIZE) * 2)
+#define _get_txchan(dev) mlb_devinfo[dev].channels[TX_CHANNEL]
+#define _get_rxchan(dev) mlb_devinfo[dev].channels[RX_CHANNEL]
+
+enum MLB_CTYPE {
+ MLB_CTYPE_SYNC,
+ MLB_CTYPE_CTRL,
+ MLB_CTYPE_ASYNC,
+ MLB_CTYPE_ISOC,
+};
+
+enum MLB150_CLK_SPEED {
+ MLB150_CLK_256FS,
+ MLB150_CLK_512FS,
+ MLB150_CLK_1024FS,
+ MLB150_CLK_2048FS,
+ MLB150_CLK_3072FS,
+ MLB150_CLK_4096FS,
+ MLB150_CLK_6144FS,
+ MLB150_CLK_8192FS,
+};
+
+/*!
+ * Ring buffer
+ */
+#define MLB_RING_BUF_INIT(r) { \
+ r->wpos = 0; \
+ r->rpos = 0; \
+}
+
+#define MLB_RING_BUF_IS_FULL(r) (((r->wpos + 1) % TRANS_RING_NODES) == r->rpos)
+#define MLB_RING_BUF_IS_EMPTY(r) (r->rpos == r->wpos)
+#define MLB_RING_BUF_ENQUE(r, buf) { \
+ memcpy(r->node[r->wpos].data, buf, r->node.size); \
+ r->wpos = (r->wpos + 1) % TRANS_RING_NODES; \
+}
+#define MLB_RING_BUF_DEQUE(r, buf) { \
+ memcpy(buf, r->node[r->rpos].data, r->node.size); \
+ r->rpos = (r->rpos + 1) % TRANS_RING_NODES; \
+}
+
+
+struct mlb_ringnode {
+ u32 size;
+ u8 *data;
+};
+
+struct mlb_ringbuffer {
+ u32 wpos;
+ u32 rpos;
+ struct mlb_ringnode node[TRANS_RING_NODES];
+};
+
+struct mlb_channel_info {
+
+ /* channel address */
+ s32 address;
+ /* DBR buf head */
+ u32 dbr_buf_head;
+ /* ping buffer head */
+ u32 ping_buf_head;
+ /* pong buffer head */
+ u32 pong_buf_head;
+ /* ping buffer physical head */
+ u32 ping_phy_head;
+ /* pong buffer physical head */
+ u32 pong_phy_head;
+ /* channel buffer size */
+ u32 buf_size;
+ /* channel buffer current ptr */
+ u32 buf_ptr;
+ /* packet start indicator */
+ u32 ps_ind;
+ /* packet remain size */
+ u32 pkt_remain_size;
+ /* buffer spin lock */
+ rwlock_t buf_lock;
+};
+
+struct mlb_dev_info {
+
+ /* device node name */
+ const char dev_name[20];
+ /* channel type */
+ const unsigned int channel_type;
+ /* ch fps */
+ enum MLB150_CLK_SPEED fps;
+ /* channel info for tx/rx */
+ struct mlb_channel_info channels[2];
+ /* rx ring buffer */
+ struct mlb_ringnode rx_bufs[TRANS_RING_NODES];
+ /* rx ring buffer read/write ptr */
+ int rx_rdpos, rx_wtpos;
+ /* tx ring buffer */
+ struct mlb_ringnode tx_bufs[TRANS_RING_NODES];
+ /* tx ring buffer read/write ptr */
+ int tx_rdpos, tx_wtpos;
+ /* exception event */
+ unsigned long ex_event;
+ /* channel started up or not */
+ atomic_t on;
+ /* device open count */
+ atomic_t opencnt;
+ /* wait queue head for channel */
+ wait_queue_head_t rd_wq;
+ wait_queue_head_t wt_wq;
+ /* spinlock for event access */
+ spinlock_t event_lock;
+};
+
+static struct mlb_dev_info mlb_devinfo[MLB_MINOR_DEVICES] = {
+ {
+ .dev_name = MLB_SYNC_DEV_NAME,
+ .channel_type = MLB_CTYPE_SYNC,
+ .channels = {
+ [0] = {
+ .buf_size = MLB150_CH_SYNC_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_SYNC_DBR_BUF_OFFSET,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[0].channels[0].
+ buf_lock),
+ },
+ [1] = {
+ .buf_size = MLB150_CH_SYNC_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_SYNC_DBR_BUF_OFFSET
+ + MLB150_CH_SYNC_BUF_DEP,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[0].channels[1].
+ buf_lock),
+ },
+ },
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .rd_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[0].rd_wq),
+ .wt_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[0].wt_wq),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[0].event_lock),
+ },
+ {
+ .dev_name = MLB_CONTROL_DEV_NAME,
+ .channel_type = MLB_CTYPE_CTRL,
+ .channels = {
+ [0] = {
+ .buf_size = MLB150_CH_CTRL_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_CTRL_DBR_BUF_OFFSET,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[1].channels[0].
+ buf_lock),
+ },
+ [1] = {
+ .buf_size = MLB150_CH_CTRL_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_CTRL_DBR_BUF_OFFSET
+ + MLB150_CH_CTRL_BUF_DEP,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[1].channels[1].
+ buf_lock),
+ },
+ },
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .rd_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[1].rd_wq),
+ .wt_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[1].wt_wq),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[1].event_lock),
+ },
+ {
+ .dev_name = MLB_ASYNC_DEV_NAME,
+ .channel_type = MLB_CTYPE_ASYNC,
+ .channels = {
+ [0] = {
+ .buf_size = MLB150_CH_ASYNC_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_ASYNC_DBR_BUF_OFFSET,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[2].channels[0].
+ buf_lock),
+ },
+ [1] = {
+ .buf_size = MLB150_CH_ASYNC_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_ASYNC_DBR_BUF_OFFSET
+ + MLB150_CH_ASYNC_BUF_DEP,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[2].channels[1].
+ buf_lock),
+ },
+ },
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .rd_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[2].rd_wq),
+ .wt_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[2].wt_wq),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[2].event_lock),
+ },
+ {
+ .dev_name = MLB_ISOC_DEV_NAME,
+ .channel_type = MLB_CTYPE_ISOC,
+ .channels = {
+ [0] = {
+ .buf_size = MLB150_CH_ISOC_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_ISOC_DBR_BUF_OFFSET,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[3].channels[0].
+ buf_lock),
+ },
+ [1] = {
+ .buf_size = MLB150_CH_ISOC_BUF_DEP,
+ .dbr_buf_head = MLB150_CH_ISOC_DBR_BUF_OFFSET
+ + MLB150_CH_ISOC_BUF_DEP,
+ .buf_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[3].channels[1].
+ buf_lock),
+ },
+ },
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .rd_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[3].rd_wq),
+ .wt_wq = __WAIT_QUEUE_HEAD_INITIALIZER(mlb_devinfo[3].wt_wq),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[3].event_lock),
+ },
+};
+
+static struct regulator *reg_nvcc; /* NVCC_MLB regulator */
+static struct clk *mlb_clk;
+static struct clk *mlb_pll_clk;
+static dev_t dev;
+static struct class *mlb_class; /* device class */
+static struct device *class_dev;
+static u32 mlb_base; /* mlb module base address */
+static u32 ahb0_irq, ahb1_irq, mlb_irq;
+static unsigned long iram_base;
+
+DEFINE_SPINLOCK(ctr_lock);
+
+#ifdef DEBUG
+
+#define DUMP_REG(reg) pr_debug(#reg": 0x%08x\n", __raw_readl(mlb_base + reg))
+
+static void mlb150_dev_dump_reg(void)
+{
+ pr_debug("mxc_mlb150: Dump registers:\n");
+ DUMP_REG(MLB150_REG_MLBC0);
+ DUMP_REG(MLB150_REG_MLBPC0);
+ DUMP_REG(MLB150_REG_MS0);
+ DUMP_REG(MLB150_REG_MS1);
+ DUMP_REG(MLB150_REG_MSS);
+ DUMP_REG(MLB150_REG_MSD);
+ DUMP_REG(MLB150_REG_MIEN);
+ DUMP_REG(MLB150_REG_MLBPC2);
+ DUMP_REG(MLB150_REG_MLBPC1);
+ DUMP_REG(MLB150_REG_MLBC1);
+ DUMP_REG(MLB150_REG_HCTL);
+ DUMP_REG(MLB150_REG_HCMR0);
+ DUMP_REG(MLB150_REG_HCMR1);
+ DUMP_REG(MLB150_REG_HCER0);
+ DUMP_REG(MLB150_REG_HCER1);
+ DUMP_REG(MLB150_REG_HCBR0);
+ DUMP_REG(MLB150_REG_HCBR1);
+ DUMP_REG(MLB150_REG_MDAT0);
+ DUMP_REG(MLB150_REG_MDAT1);
+ DUMP_REG(MLB150_REG_MDAT2);
+ DUMP_REG(MLB150_REG_MDAT3);
+ DUMP_REG(MLB150_REG_MDWE0);
+ DUMP_REG(MLB150_REG_MDWE1);
+ DUMP_REG(MLB150_REG_MDWE2);
+ DUMP_REG(MLB150_REG_MDWE3);
+ DUMP_REG(MLB150_REG_MCTL);
+ DUMP_REG(MLB150_REG_MADR);
+ DUMP_REG(MLB150_REG_ACTL);
+ DUMP_REG(MLB150_REG_ACSR0);
+ DUMP_REG(MLB150_REG_ACSR1);
+ DUMP_REG(MLB150_REG_ACMR0);
+ DUMP_REG(MLB150_REG_ACMR1);
+}
+#endif
+
+static inline void mlb150_dev_enable_ctr_write(u32 mdat0_bits_en,
+ u32 mdat1_bits_en, u32 mdat2_bits_en, u32 mdat3_bits_en)
+{
+ __raw_writel(mdat0_bits_en, mlb_base + MLB150_REG_MDWE0);
+ __raw_writel(mdat1_bits_en, mlb_base + MLB150_REG_MDWE1);
+ __raw_writel(mdat2_bits_en, mlb_base + MLB150_REG_MDWE2);
+ __raw_writel(mdat3_bits_en, mlb_base + MLB150_REG_MDWE3);
+}
+
+static inline u8 mlb150_dev_dbr_read(u32 dbr_addr)
+{
+ s32 timeout = 1000;
+ u8 dbr_val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(MLB150_MADR_TB | dbr_addr,
+ mlb_base + MLB150_REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + MLB150_REG_MCTL)
+ & MLB150_MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (unlikely(0 == timeout))
+ return -ETIME;
+
+ dbr_val = __raw_readl(mlb_base + MLB150_REG_MDAT0) & 0x000000ff;
+
+ __raw_writel(0, mlb_base + MLB150_REG_MCTL);
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+ return dbr_val;
+}
+
+static inline s32 mlb150_dev_dbr_write(u32 dbr_addr, u32 dbr_val)
+{
+ s32 timeout = 1000;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(dbr_val, mlb_base + MLB150_REG_MDAT0);
+
+ __raw_writel(MLB150_MADR_WNR | MLB150_MADR_TB | dbr_addr,
+ mlb_base + MLB150_REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + MLB150_REG_MCTL)
+ & MLB150_MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (unlikely(timeout <= 0))
+ return -ETIME;
+
+ __raw_writel(0, mlb_base + MLB150_REG_MCTL);
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+ return 0;
+}
+
+static s32 mlb150_dev_ctr_read(u32 ctr_offset, u32 *ctr_val)
+{
+ s32 timeout = 1000;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(ctr_offset, mlb_base + MLB150_REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + MLB150_REG_MCTL)
+ & MLB150_MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (unlikely(timeout <= 0)) {
+ pr_debug("mxc_mlb150: Read CTR timeout\n");
+ return -ETIME;
+ }
+
+ ctr_val[0] = __raw_readl(mlb_base + MLB150_REG_MDAT0);
+ ctr_val[1] = __raw_readl(mlb_base + MLB150_REG_MDAT1);
+ ctr_val[2] = __raw_readl(mlb_base + MLB150_REG_MDAT2);
+ ctr_val[3] = __raw_readl(mlb_base + MLB150_REG_MDAT3);
+
+ __raw_writel(0, mlb_base + MLB150_REG_MCTL);
+
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+ return 0;
+}
+
+static s32 mlb150_dev_ctr_write(u32 ctr_offset, const u32 *ctr_val)
+{
+ s32 timeout = 1000;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+
+ __raw_writel(ctr_val[0], mlb_base + MLB150_REG_MDAT0);
+ __raw_writel(ctr_val[1], mlb_base + MLB150_REG_MDAT1);
+ __raw_writel(ctr_val[2], mlb_base + MLB150_REG_MDAT2);
+ __raw_writel(ctr_val[3], mlb_base + MLB150_REG_MDAT3);
+
+ __raw_writel(MLB150_MADR_WNR | ctr_offset,
+ mlb_base + MLB150_REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + MLB150_REG_MCTL)
+ & MLB150_MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (unlikely(timeout <= 0)) {
+ pr_debug("mxc_mlb150: Write CTR timeout\n");
+ return -ETIME;
+ }
+
+ __raw_writel(0, mlb_base + MLB150_REG_MCTL);
+
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+#ifdef DEBUG_CTR
+ {
+ u32 ctr_rd[4] = { 0 };
+
+ if (!mlb150_dev_ctr_read(ctr_offset, ctr_rd)) {
+ if (ctr_val[0] == ctr_rd[0] &&
+ ctr_val[1] == ctr_rd[1] &&
+ ctr_val[2] == ctr_rd[2] &&
+ ctr_val[3] == ctr_rd[3])
+ return 0;
+ else {
+ pr_debug("mxc_mlb150: ctr write failed\n");
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: ctr read failed\n");
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static s32 mlb150_dev_cat_write(u32 ctr_offset, u32 ch, const u16 cat_val)
+{
+ u16 ctr_val[8] = { 0 };
+
+ if (unlikely(mlb150_dev_ctr_read(ctr_offset, (u32 *)ctr_val)))
+ return -ETIME;
+
+ ctr_val[ch % 8] = cat_val;
+ if (unlikely(mlb150_dev_ctr_write(ctr_offset, (u32 *)ctr_val)))
+ return -ETIME;
+
+ return 0;
+}
+
+#define mlb150_dev_cat_mlb_write(ch, cat_val) \
+ mlb150_dev_cat_write(MLB150_BUF_CAT_MLB_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_hbi_write(ch, cat_val) \
+ mlb150_dev_cat_write(MLB150_BUF_CAT_HBI_OFFSET + (ch >> 3), ch, cat_val)
+
+#define mlb150_dev_cdt_read(ch, cdt_val) \
+ mlb150_dev_ctr_read(MLB150_BUF_CDT_OFFSET + ch, cdt_val)
+#define mlb150_dev_cdt_write(ch, cdt_val) \
+ mlb150_dev_ctr_write(MLB150_BUF_CDT_OFFSET + ch, cdt_val)
+#define mlb150_dev_adt_read(ch, adt_val) \
+ mlb150_dev_ctr_read(MLB150_BUF_ADT_OFFSET + ch, adt_val)
+#define mlb150_dev_adt_write(ch, adt_val) \
+ mlb150_dev_ctr_write(MLB150_BUF_ADT_OFFSET + ch, adt_val)
+
+#ifdef DEBUG
+static void mlb150_dev_dump_ctr_tbl(u32 ch_start, u32 ch_end)
+{
+ u32 i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ pr_debug("mxc_mlb150: CDT Table");
+ for (i = MLB150_BUF_CDT_OFFSET + ch_start;
+ i < MLB150_BUF_CDT_OFFSET + ch_end;
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+
+ pr_debug("mxc_mlb150: ADT Table");
+ for (i = MLB150_BUF_ADT_OFFSET + ch_start;
+ i < MLB150_BUF_ADT_OFFSET + ch_end;
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+
+ pr_debug("mxc_mlb150: CAT MLB Table");
+ for (i = MLB150_BUF_CAT_MLB_OFFSET + (ch_start >> 3);
+ i < MLB150_BUF_CAT_MLB_OFFSET + (ch_end >> 3);
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+
+ pr_debug("mxc_mlb150: CAT HBI Table");
+ for (i = MLB150_BUF_CAT_HBI_OFFSET + (ch_start >> 3);
+ i < MLB150_BUF_CAT_HBI_OFFSET + (ch_end >> 3);
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+}
+#endif
+
+/*!
+ * Initial the MLB module device
+ */
+static inline s32 mlb150_dev_enable_dma_irq(u32 enable)
+{
+ if (enable) {
+ __raw_writel(0xffffffff, mlb_base + MLB150_REG_ACMR0);
+ __raw_writel(0xffffffff, mlb_base + MLB150_REG_ACMR1);
+ } else {
+ __raw_writel(0x0, mlb_base + MLB150_REG_ACMR0);
+ __raw_writel(0x0, mlb_base + MLB150_REG_ACMR1);
+ }
+
+ return 0;
+}
+
+
+static s32 mlb150_dev_init_ir_amba_ahb(void)
+{
+ u32 reg = 0;
+
+ /* Step 1. Program the ACMRn registers to enable interrupts from all
+ * active DMA channels */
+ mlb150_dev_enable_dma_irq(1);
+
+ /* Step 2. Select the status clear method:
+ * ACTL.SCE = 0, hardware clears on read
+ * ACTL.SCE = 1, software writes a '1' to clear */
+ /* We only support DMA MODE 1 */
+ reg = __raw_readl(mlb_base + MLB150_REG_ACTL);
+ reg |= MLB150_ACTL_DMAMODE;
+#ifdef MLB150_MULTIPLE_PACKAGE_MODE
+ reg |= MLB150_REG_ACTL_MPB;
+#endif
+
+ /* Step 3. Select 1 or 2 interrupt signals:
+ * ACTL.SMX = 0: one interrupt for channels 0 - 31 on ahb_init[0]
+ * and another interrupt for channels 32 - 63 on ahb_init[1]
+ * ACTL.SMX = 1: singel interrupt all channels on ahb_init[0]
+ * */
+ /*
+ reg |= MLB150_ACTL_SMX;
+ */
+
+ __raw_writel(reg, mlb_base + MLB150_REG_ACTL);
+
+ return 0;
+}
+
+static inline s32 mlb150_dev_enable_ir_mlb(u32 enable)
+{
+ /* Step 1, Select the MSn to be cleared by software,
+ * writing a '0' to the appropriate bits */
+ __raw_writel(0, mlb_base + MLB150_REG_MS0);
+ __raw_writel(0, mlb_base + MLB150_REG_MS1);
+
+ /* Step 1, Program MIEN to enable protocol error
+ * interrupts for all active MLB channels */
+ if (enable)
+ __raw_writel(MLB150_MIEN_CTX_PE |
+ MLB150_MIEN_CRX_PE | MLB150_MIEN_ATX_PE |
+ MLB150_MIEN_ARX_PE | MLB150_MIEN_SYNC_PE |
+ MLB150_MIEN_ISOC_PE,
+ mlb_base + MLB150_REG_MIEN);
+ else
+ __raw_writel(0, mlb_base + MLB150_REG_MIEN);
+
+ return 0;
+}
+
+static void mlb150_dev_init(void)
+{
+ u32 c0_val, hctl_val;
+
+ /* Disable EN bits */
+ c0_val = __raw_readl(mlb_base + MLB150_REG_MLBC0);
+ c0_val &= ~MLB150_MLBC0_MLBEN;
+ __raw_writel(c0_val, mlb_base + MLB150_REG_MLBC0);
+
+ hctl_val = __raw_readl(mlb_base + MLB150_REG_HCTL);
+ hctl_val &= ~MLB150_HCTL_EN;
+ __raw_writel(hctl_val, mlb_base + MLB150_REG_HCTL);
+
+ /* Step 1, Configure the MediaLB interface */
+ /* Select pin mode and clock, 3-pin and 256fs */
+ c0_val = __raw_readl(mlb_base + MLB150_REG_MLBC0);
+ c0_val &= ~(MLB150_MLBC0_MLBPEN | MLB150_MLBC0_MLBCLK_MASK);
+ __raw_writel(c0_val, mlb_base + MLB150_REG_MLBC0);
+
+ c0_val |= MLB150_MLBC0_MLBEN;
+ __raw_writel(c0_val, mlb_base + MLB150_REG_MLBC0);
+
+ /* Step 2, Configure the HBI interface */
+ __raw_writel(0xffffffff, mlb_base + MLB150_REG_HCMR0);
+ __raw_writel(0xffffffff, mlb_base + MLB150_REG_HCMR1);
+ __raw_writel(MLB150_HCTL_EN, mlb_base + MLB150_REG_HCTL);
+
+ mlb150_dev_init_ir_amba_ahb();
+
+ mlb150_dev_enable_ir_mlb(1);
+}
+
+static s32 mlb150_dev_reset_cdt(void)
+{
+ int i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ for (i = 0; i < (MLB150_LOGIC_CH_NUM); ++i)
+ mlb150_dev_ctr_write(MLB150_BUF_CDT_OFFSET + i, ctr_val);
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_ch_cdt(u32 ch, enum MLB_CTYPE ctype, u32 ch_func)
+{
+ u32 cdt_val[4] = { 0 };
+
+ /* a. Set the 14-bit base address (BA) */
+ cdt_val[3] = (mlb_devinfo[ctype].channels[ch_func].dbr_buf_head)
+ << CDT_BA_SHIFT;
+
+ /* b. Set the 12-bit or 13-bit buffer depth (BD)
+ * BD = buffer depth in bytes - 1 */
+ switch (ctype) {
+ case MLB_CTYPE_SYNC:
+ /* For synchronous channels: (BD + 1) = 4 * m * bpf */
+ cdt_val[3] |= ((4 * mlb150_fs_phy_ch_num_per_frm[mlb_devinfo[0].fps] * 4) - 1)
+ << CDT_BD_SHIFT;
+ break;
+ case MLB_CTYPE_CTRL:
+ /* For control channels: (BD + 1) >= max packet length (64) */
+ /* BD */
+ cdt_val[3] |= ((MLB150_CH_CTRL_BUF_DEP - 1) << CDT_BD_SHIFT);
+ break;
+ case MLB_CTYPE_ASYNC:
+ /* For asynchronous channels: (BD + 1) >= max packet length
+ * 1024 for a MOST Data packet (MDP);
+ * 1536 for a MOST Ethernet Packet (MEP) */
+ cdt_val[3] |= ((MLB150_CH_ASYNC_BUF_DEP - 1) << CDT_BD_SHIFT);
+ break;
+ case MLB_CTYPE_ISOC:
+ /* For isochronous channels: (BD + 1) mod (BS + 1) = 0 */
+ /* BS */
+ cdt_val[1] |= (MLB150_CH_ISOC_BLK_SIZE - 1);
+ /* BD */
+ cdt_val[3] |= (MLB150_CH_ISOC_BUF_DEP - 1)
+ << CDT_BD_SHIFT;
+ break;
+ default:
+ break;
+ }
+
+ pr_debug("mxc_mlb150: Set CDT val of channel %d, type: %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ch, ctype, cdt_val[3], cdt_val[2], cdt_val[1], cdt_val[0]);
+
+ if (unlikely(mlb150_dev_cdt_write(ch, cdt_val)))
+ return -ETIME;
+
+#ifdef DEBUG_CTR
+ {
+ u32 cdt_rd[4] = { 0 };
+ if (likely(!mlb150_dev_cdt_read(ch, cdt_rd))) {
+ pr_debug("mxc_mlb150: CDT val of channel %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ch, cdt_rd[3], cdt_rd[2], cdt_rd[1], cdt_rd[0]);
+ if (cdt_rd[3] == cdt_val[3] &&
+ cdt_rd[2] == cdt_val[2] &&
+ cdt_rd[1] == cdt_val[1] &&
+ cdt_rd[0] == cdt_val[0]) {
+ pr_debug("mxc_mlb150: set cdt succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set cdt failed!\n");
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: Read CDT val of channel %d failed\n",
+ ch);
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_ch_cat(u32 ch, u32 cat_mode, enum MLB_CTYPE ctype)
+{
+ u16 cat_val = 0;
+#ifdef DEBUG_CTR
+ u16 cat_rd = 0;
+#endif
+
+ cat_val = CAT_CE | (ctype << CAT_CT_SHIFT) | ch;
+
+ if (cat_mode & MLB150_CAT_MODE_OUTBOUND_DMA)
+ cat_val |= CAT_RNW;
+
+ if (MLB_CTYPE_SYNC == ctype)
+ cat_val |= CAT_MT;
+
+ switch (cat_mode) {
+ case MLB150_CAT_MODE_RX | MLB150_CAT_MODE_INBOUND_DMA:
+ case MLB150_CAT_MODE_TX | MLB150_CAT_MODE_OUTBOUND_DMA:
+ if (unlikely(mlb150_dev_cat_mlb_write(ch, cat_val)))
+ return -ETIME;
+#ifdef DEBUG_CTR
+ if (likely(!mlb150_dev_cat_mlb_read(ch, &cat_rd)))
+ pr_debug("mxc_mlb150: CAT val of mlb channel %d: 0x%04x",
+ ch, cat_rd);
+ else {
+ pr_debug("mxc_mlb150: Read CAT of mlb channel %d failed\n",
+ ch);
+ return -EBADE;
+ }
+#endif
+ break;
+ case MLB150_CAT_MODE_TX | MLB150_CAT_MODE_INBOUND_DMA:
+ case MLB150_CAT_MODE_RX | MLB150_CAT_MODE_OUTBOUND_DMA:
+ if (unlikely(mlb150_dev_cat_hbi_write(ch, cat_val)))
+ return -ETIME;
+#ifdef DEBUG_CTR
+ if (likely(!mlb150_dev_cat_hbi_read(ch, &cat_rd)))
+ pr_debug("mxc_mlb150: CAT val of hbi channel %d: 0x%04x",
+ ch, cat_rd);
+ else {
+ pr_debug("mxc_mlb150: Read CAT of hbi channel %d failed\n",
+ ch);
+ return -EBADE;
+ }
+#endif
+ break;
+ default:
+ return EBADRQC;
+ }
+
+#ifdef DEBUG_CTR
+ {
+ if (cat_val == cat_rd) {
+ pr_debug("mxc_mlb150: set cat succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set cat failed!\n");
+ return -EBADE;
+ }
+ }
+#endif
+ return 0;
+}
+
+static s32 mlb150_dev_reset_cat(void)
+{
+ int i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ for (i = 0; i < (MLB150_LOGIC_CH_NUM >> 3); ++i) {
+ mlb150_dev_ctr_write(MLB150_BUF_CAT_MLB_OFFSET + i, ctr_val);
+ mlb150_dev_ctr_write(MLB150_BUF_CAT_HBI_OFFSET + i, ctr_val);
+ }
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_rfb(u32 rx_ch, u32 tx_ch, enum MLB_CTYPE ctype)
+{
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+
+ /* Step 1, Initialize all bits of CAT to '0' */
+ mlb150_dev_reset_cat();
+ mlb150_dev_reset_cdt();
+
+ /* Step 2, Initialize logical channel */
+ /* Step 3, Program the CDT for channel N */
+ mlb150_dev_init_ch_cdt(rx_ch, ctype, RX_CHANNEL);
+ mlb150_dev_init_ch_cdt(tx_ch, ctype, TX_CHANNEL);
+
+ /* Step 4&5, Program the CAT for the inbound and outbound DMA */
+ mlb150_dev_init_ch_cat(rx_ch,
+ MLB150_CAT_MODE_RX | MLB150_CAT_MODE_INBOUND_DMA,
+ ctype);
+ mlb150_dev_init_ch_cat(rx_ch,
+ MLB150_CAT_MODE_RX | MLB150_CAT_MODE_OUTBOUND_DMA,
+ ctype);
+ mlb150_dev_init_ch_cat(tx_ch,
+ MLB150_CAT_MODE_TX | MLB150_CAT_MODE_INBOUND_DMA,
+ ctype);
+ mlb150_dev_init_ch_cat(tx_ch,
+ MLB150_CAT_MODE_TX | MLB150_CAT_MODE_OUTBOUND_DMA,
+ ctype);
+
+ return 0;
+}
+
+static s32 mlb150_dev_reset_adt(void)
+{
+ int i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ for (i = 0; i < (MLB150_LOGIC_CH_NUM); ++i)
+ mlb150_dev_ctr_write(MLB150_BUF_ADT_OFFSET + i, ctr_val);
+
+ return 0;
+}
+
+static s32 mlb150_dev_set_ch_amba_ahb(u32 ch, enum MLB_CTYPE ctype, u32 dne_sts)
+{
+ /* Only set MDAT1 in this function */
+ /* In MDWE, only MDWE1 should be enabled */
+ u32 ctr_val[4] = { 0 };
+
+ if (MLB_CTYPE_ASYNC == ctype ||
+ MLB_CTYPE_CTRL == ctype) {
+ ctr_val[1] |= ADT_PS1;
+ ctr_val[1] |= ADT_PS2;
+ }
+
+ /* Clear DNE1 and ERR1 */
+ /* Set the page ready bit (RDY1) */
+ if (dne_sts & ADT_DNE1)
+ ctr_val[1] |= ADT_RDY2;
+ else
+ ctr_val[1] |= ADT_RDY1;
+
+#ifdef DEBUG_ADT
+ pr_debug("mxc_mlb150: Set ADT val of channel %d, ctype: %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ch, ctype, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+#endif
+
+ if (unlikely(mlb150_dev_adt_write(ch, ctr_val)))
+ return -ETIME;
+
+#ifdef DEBUG_ADT
+ {
+ u32 ctr_rd[4] = { 0 };
+ if (likely(!mlb150_dev_adt_read(ch, ctr_rd))) {
+ if (ctr_rd[3] == ctr_val[3] &&
+ ctr_rd[2] == ctr_val[2] &&
+ ctr_rd[1] == ctr_val[1] &&
+ ctr_rd[0] == ctr_val[0]) {
+ pr_debug("mxc_mlb150: set adt succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set adt failed!\n");
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: Read ADT val of channel %d failed\n",
+ ch);
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_ch_amba_ahb(struct mlb_channel_info *chinfo,
+ enum MLB_CTYPE ctype)
+{
+ u32 ctr_val[4] = { 0 };
+
+ /* a. Set the 32-bit base address (BA1) */
+ ctr_val[3] = chinfo->pong_phy_head;
+ ctr_val[2] = chinfo->ping_phy_head;
+ ctr_val[1] = (chinfo->buf_size - 1) << ADT_BD1_SHIFT;
+ ctr_val[1] |= (chinfo->buf_size - 1) << ADT_BD2_SHIFT;
+ if (MLB_CTYPE_ASYNC == ctype ||
+ MLB_CTYPE_CTRL == ctype) {
+ ctr_val[1] |= ADT_PS1;
+ ctr_val[1] |= ADT_PS2;
+ }
+
+ ctr_val[0] |= (ADT_LE | ADT_CE);
+
+ if (unlikely(mlb150_dev_adt_write(chinfo->address, ctr_val)))
+ return -ETIME;
+
+#ifdef DEBUG_CTR
+ {
+ u32 ctr_rd[4] = { 0 };
+ if (likely(!mlb150_dev_adt_read(chinfo->address, ctr_rd))) {
+ pr_debug("mxc_mlb150: ADT val of channel %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ chinfo->address, ctr_rd[3], ctr_rd[2],
+ ctr_rd[1], ctr_rd[0]);
+ if (ctr_rd[3] == ctr_val[3] &&
+ ctr_rd[2] == ctr_val[2] &&
+ ctr_rd[1] == ctr_val[1] &&
+ ctr_rd[0] == ctr_val[0]) {
+ pr_debug("mxc_mlb150: set adt succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set adt failed!\n");
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: Read ADT val of channel %d failed\n",
+ chinfo->address);
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_amba_ahb(struct mlb_channel_info *rx_chinfo,
+ struct mlb_channel_info *tx_chinfo, enum MLB_CTYPE ctype)
+{
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+
+ /* Step 1, Initialize all bits of the ADT to '0' */
+ mlb150_dev_reset_adt();
+
+ /* Step 2, Select a logic channel */
+ /* Step 3, Program the AMBA AHB block ping page for channel N */
+ /* Step 4, Program the AMBA AHB block pong page for channel N */
+ mlb150_dev_init_ch_amba_ahb(rx_chinfo, ctype);
+ mlb150_dev_init_ch_amba_ahb(tx_chinfo, ctype);
+
+ return 0;
+}
+
+static s32 mlb150_dev_unmute_syn_ch(u32 rx_ch, u32 tx_ch)
+{
+ u32 timeout = 10000;
+
+ /* Check that MediaLB clock is running (MLBC1.CLKM = 0)
+ * If MLBC1.CLKM = 1, clear the register bit, wait one
+ * APB or I/O clock cycle and repeat the check */
+ while ((__raw_readl(mlb_base + MLB150_REG_MLBC1) & MLB150_MLBC1_CLKM)
+ || timeout--)
+ __raw_writel(~MLB150_MLBC1_CLKM, mlb_base + MLB150_REG_MLBC1);
+
+ if (unlikely(0 == timeout))
+ return -ETIME;
+
+ timeout = 10000;
+ /* Poll for MLB lock (MLBC0.MLBLK = 1) */
+ while (!(__raw_readl(mlb_base + MLB150_REG_MLBC0) & MLB150_MLBC0_MLBLK)
+ || timeout--)
+ ;
+
+ if (unlikely(0 == timeout))
+ return -ETIME;
+
+ /* Unmute synchronous channel(s) */
+ mlb150_dev_cat_mlb_write(rx_ch, CAT_CE | rx_ch);
+ mlb150_dev_cat_mlb_write(tx_ch,
+ CAT_CE | tx_ch | CAT_RNW);
+ mlb150_dev_cat_hbi_write(rx_ch,
+ CAT_CE | rx_ch | CAT_RNW);
+ mlb150_dev_cat_hbi_write(tx_ch, CAT_CE | tx_ch);
+
+ return 0;
+}
+
+static void mlb150_dev_exit(void)
+{
+ mlb150_dev_enable_dma_irq(0);
+ mlb150_dev_enable_ir_mlb(0);
+
+ __raw_writel(0, mlb_base + MLB150_REG_HCTL);
+ __raw_writel(0, mlb_base + MLB150_REG_MLBC0);
+}
+
+/*!
+ * MLB receive start function
+ *
+ * load phy_head to next buf register to start next rx
+ * here use single-packet buffer, set start=end
+ */
+static void mlb_start_rx(int cdev_id, u32 dne_sts)
+{
+ struct mlb_channel_info *chinfo = &_get_rxchan(cdev_id);
+ unsigned int ctype = mlb_devinfo[cdev_id].channel_type;
+
+ /* Set ADT for RX */
+ mlb150_dev_set_ch_amba_ahb(chinfo->address, ctype, dne_sts);
+}
+
+/*!
+ * MLB transmit start function
+ * make sure aquiring the rw buf_lock, when calling this
+ */
+static void mlb_start_tx(int cdev_id, u32 dne_sts)
+{
+ struct mlb_channel_info *chinfo = &_get_txchan(cdev_id);
+ unsigned int ctype = mlb_devinfo[cdev_id].channel_type;
+
+ /* Set ADT for TX */
+ mlb150_dev_set_ch_amba_ahb(chinfo->address, ctype, dne_sts);
+}
+
+/*!
+ * Enable the MLB channel
+ */
+static void mlb_channel_enable(int chan_dev_id, int on)
+{
+ u32 c0_val = 0;
+ /*!
+ * setup the direction, enable, channel type,
+ * mode select, channel address and mask buf start
+ */
+ if (on) {
+ u32 ctype = mlb_devinfo[chan_dev_id].channel_type;
+ struct mlb_channel_info *tx_chinfo = &_get_txchan(chan_dev_id);
+ struct mlb_channel_info *rx_chinfo = &_get_rxchan(chan_dev_id);
+ u32 tx_ch = tx_chinfo->address;
+ u32 rx_ch = rx_chinfo->address;
+
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+ mlb150_dev_init_rfb(rx_ch, tx_ch, ctype);
+
+ mlb150_dev_init_amba_ahb(rx_chinfo, tx_chinfo, ctype);
+
+ /* Synchronize and unmute synchrouous channel */
+ if (MLB_CTYPE_SYNC == ctype)
+ mlb150_dev_unmute_syn_ch(rx_ch, tx_ch);
+
+ mlb150_dev_enable_ctr_write(0x0, ADT_RDY1 | ADT_DNE1 |
+ ADT_ERR1 | ADT_PS1 |
+ ADT_MEP1 | ADT_RDY2 | ADT_DNE2 | ADT_ERR2 |
+ ADT_PS2 | ADT_MEP2,
+ 0x0, 0x0);
+
+ if (mlb_devinfo[chan_dev_id].fps >= MLB150_CLK_2048FS) {
+ c0_val = __raw_readl(mlb_base + MLB150_REG_MLBC0);
+
+ __raw_writel(MLB150_MLBPC1_VAL,
+ mlb_base + MLB150_REG_MLBPC1);
+
+ if (c0_val & MLB150_MLBC0_MLBPEN) {
+ c0_val &= ~MLB150_MLBC0_MLBPEN;
+ __raw_writel(c0_val,
+ mlb_base + MLB150_REG_MLBC0);
+ }
+
+ c0_val |= MLB150_MLBC0_MLBPEN;
+ __raw_writel(c0_val, mlb_base + MLB150_REG_MLBC0);
+
+ clk_enable(mlb_pll_clk);
+ }
+
+ atomic_set(&mlb_devinfo[chan_dev_id].on, 1);
+
+ mlb_start_rx(chan_dev_id, ADT_DNE2);
+ } else {
+ mlb150_dev_enable_dma_irq(0);
+ mlb150_dev_enable_ir_mlb(0);
+
+ mlb150_dev_reset_cat();
+
+ atomic_set(&mlb_devinfo[chan_dev_id].on, 0);
+
+ if (mlb_devinfo[chan_dev_id].fps >= MLB150_CLK_2048FS) {
+ c0_val = __raw_readl(mlb_base + MLB150_REG_MLBC0);
+
+ __raw_writel(0x0, mlb_base + MLB150_REG_MLBPC1);
+
+ c0_val &= ~MLB150_MLBC0_MLBPEN;
+ __raw_writel(c0_val, mlb_base + MLB150_REG_MLBC0);
+
+ clk_disable(mlb_pll_clk);
+ }
+ }
+}
+
+/*!
+ * MLB interrupt handler
+ */
+static void mlb_tx_isr(int minor)
+{
+ struct mlb_channel_info *pchinfo = &_get_txchan(minor);
+ u32 adt_val[4] = { 0 };
+
+ mlb150_dev_adt_read(pchinfo->address, adt_val);
+
+ /* Select another buffer to tx */
+ if (adt_val[1] & ADT_DNE1)
+ pchinfo->buf_ptr = pchinfo->pong_buf_head;
+ else if (adt_val[1] & ADT_DNE2)
+ pchinfo->buf_ptr = pchinfo->ping_buf_head;
+ else {
+ panic("No DNE bit detected!\n");
+ return;
+ }
+
+ wake_up_interruptible(&mlb_devinfo[minor].wt_wq);
+}
+
+static void mlb_rx_isr(int minor)
+{
+ struct mlb_channel_info *pchinfo = &_get_rxchan(minor);
+ struct mlb_dev_info *pdevinfo = &mlb_devinfo[minor];
+ u32 len;
+ u32 adt_val[4] = { 0 };
+ s32 wpos, rpos;
+ u8 *adt_buf_ptr = (u8 *)pchinfo->buf_ptr;
+
+ mlb150_dev_adt_read(pchinfo->address, adt_val);
+ /* Decide which buffer to copy data from.
+ * Not setting ahb */
+ if (adt_val[1] & ADT_DNE1)
+ adt_buf_ptr = (u8 *)pchinfo->ping_buf_head;
+ else if (adt_val[1] & ADT_DNE2)
+ adt_buf_ptr = (u8 *)pchinfo->pong_buf_head;
+ else {
+ panic("No DNE bit detected!\n");
+ return;
+ }
+
+ rpos = pdevinfo->rx_rdpos;
+ wpos = pdevinfo->rx_wtpos;
+
+ len = pchinfo->buf_size;
+
+ /*!
+ * Copy packet from IRAM buf to ring buf.
+ * if the wpos++ == rpos, drop this packet
+ */
+ if (((wpos + 1) % TRANS_RING_NODES) != rpos) {
+ u8 *rx_ring_buf = pdevinfo->rx_bufs[wpos].data;
+#ifdef DEBUG_RX
+ if (len > mlb150_ch_packet_buf_size[pdevinfo->channel_type])
+ pr_debug("mxc_mlb150: packet overflow, "
+ "packet type: %d\n", pdevinfo->channel_type);
+#endif
+
+ memcpy(rx_ring_buf, (const void *)adt_buf_ptr, len);
+
+ pdevinfo->rx_bufs[wpos].size = len;
+
+ /* update the ring wpos */
+ pdevinfo->rx_wtpos = (wpos + 1) % TRANS_RING_NODES;
+
+ /* wake up the reader */
+ wake_up_interruptible(&pdevinfo->rd_wq);
+
+#ifdef DEBUG_RX
+ pr_debug("recv package, len:%d, rx_rdpos: %d, rx_wtpos: %d\n",
+ len, rpos, pdevinfo->rx_wtpos);
+#endif
+ } else {
+ pr_debug
+ ("drop package, due to no space, (%d,%d)\n",
+ rpos, pdevinfo->rx_wtpos);
+ }
+
+ /* start next rx */
+ mlb_start_rx(minor, adt_val[1]);
+}
+
+static irqreturn_t mlb_ahb_isr(int irq, void *dev_id)
+{
+ u32 rx_int_sts, tx_int_sts, acsr0,
+ acsr1, rx_err, tx_err, hcer0, hcer1;
+ struct mlb_dev_info *pdev = NULL;
+ struct mlb_channel_info *ptxchinfo = NULL, *prxchinfo = NULL;
+ int minor;
+
+ /* Step 5, Read the ACSRn registers to determine which channel or
+ * channels are causing the interrupt */
+ acsr0 = __raw_readl(mlb_base + MLB150_REG_ACSR0);
+ acsr1 = __raw_readl(mlb_base + MLB150_REG_ACSR1);
+
+ hcer0 = __raw_readl(mlb_base + MLB150_REG_HCER0);
+ hcer1 = __raw_readl(mlb_base + MLB150_REG_HCER1);
+
+ pr_debug("mlb_ahb_isr: acsr0: 0x%08x, acsr1: 0x%08x\n", acsr0, acsr1);
+
+ /* Step 6, If ACTL.SCE = 1, write the result of step 5 back to ACSR0
+ * and ACSR1 to clear the interrupt */
+ if (MLB150_ACTL_SCE & __raw_readl(mlb_base + MLB150_REG_ACTL)) {
+ __raw_writel(acsr0, mlb_base + MLB150_REG_ACSR0);
+ __raw_writel(acsr1, mlb_base + MLB150_REG_ACSR1);
+ }
+
+ for (minor = 0; minor < MLB_MINOR_DEVICES; minor++) {
+ pdev = &mlb_devinfo[minor];
+ prxchinfo = &_get_rxchan(minor);
+ ptxchinfo = &_get_txchan(minor);
+
+ rx_int_sts = (prxchinfo->address < 31) ? acsr0 : acsr1;
+ tx_int_sts = (ptxchinfo->address < 31) ? acsr0 : acsr1;
+ rx_err = (prxchinfo->address < 31) ? hcer0 : hcer1;
+ tx_err = (ptxchinfo->address < 31) ? hcer0 : hcer1;
+
+ /* get tx channel interrupt status */
+ if (tx_int_sts & (1 << (ptxchinfo->address % 32))) {
+ if (!(tx_err & (1 << (ptxchinfo->address % 32))))
+ mlb_tx_isr(minor);
+ else {
+ pr_debug("tx channel %d encountered an AHB error!\n",
+ ptxchinfo->address);
+ }
+ }
+
+ /* get rx channel interrupt status */
+ if (rx_int_sts & (1 << (prxchinfo->address % 32))) {
+ if (!(rx_err & (1 << (prxchinfo->address % 32))))
+ mlb_rx_isr(minor);
+ else {
+ pr_debug("rx channel %d encountered an AHB error!\n",
+ prxchinfo->address);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mlb_isr(int irq, void *dev_id)
+{
+ u32 rx_int_sts, tx_int_sts, ms0,
+ ms1, tx_cis, rx_cis, ctype;
+ struct mlb_dev_info *pdev;
+ int minor;
+ u32 cdt_val[4] = { 0 };
+
+ /* Step 4, Read the MSn register to determine which channel(s)
+ * are causing the interrupt */
+ ms0 = __raw_readl(mlb_base + MLB150_REG_MS0);
+ ms1 = __raw_readl(mlb_base + MLB150_REG_MS1);
+ pr_debug("mxc_mlb150: mlb interrupt:0x%08x 0x%08x\n",
+ (u32)ms0, (u32)ms1);
+
+ for (minor = 0; minor < MLB_MINOR_DEVICES; minor++) {
+ pdev = &mlb_devinfo[minor];
+ tx_cis = rx_cis = 0;
+
+ ctype = pdev->channel_type;
+ rx_int_sts = (_get_rxchan(minor).address < 31) ? ms0 : ms1;
+ tx_int_sts = (_get_txchan(minor).address < 31) ? ms0 : ms1;
+
+ /* Get tx channel interrupt status */
+ if (tx_int_sts & (1 << (_get_txchan(minor).address % 32))) {
+ mlb150_dev_cdt_read(_get_txchan(minor).address,
+ cdt_val);
+ pr_debug("mxc_mlb150: cdt_val[3]: 0x%08x, "
+ "cdt_val[2]: 0x%08x, "
+ "cdt_val[1]: 0x%08x, "
+ "cdt_val[0]: 0x%08x\n",
+ cdt_val[3], cdt_val[2],
+ cdt_val[1], cdt_val[0]);
+ switch (ctype) {
+ case MLB_CTYPE_SYNC:
+ tx_cis = (cdt_val[2] & ~CDT_SYNC_WSTS_MASK)
+ >> CDT_SYNC_WSTS_SHIFT;
+ /* Clear RSTS/WSTS errors to resume
+ * channel operation */
+ /* a. For synchronous channels: WSTS[3] = 0 */
+ cdt_val[2] &= ~(0x8 << CDT_SYNC_WSTS_SHIFT);
+ break;
+ case MLB_CTYPE_CTRL:
+ case MLB_CTYPE_ASYNC:
+ tx_cis =
+ (cdt_val[2] & ~CDT_CTRL_ASYNC_WSTS_MASK)
+ >> CDT_CTRL_ASYNC_WSTS_SHIFT;
+ tx_cis = (cdt_val[3] & CDT_CTRL_ASYNC_WSTS_1) ?
+ (tx_cis | (0x1 << 4)) : tx_cis;
+ /* b. For async and ctrl channels:
+ * RSTS[4]/WSTS[4] = 0
+ * and RSTS[2]/WSTS[2] = 0 */
+ cdt_val[3] &= ~CDT_CTRL_ASYNC_WSTS_1;
+ cdt_val[2] &=
+ ~(0x4 << CDT_CTRL_ASYNC_WSTS_SHIFT);
+ break;
+ case MLB_CTYPE_ISOC:
+ tx_cis = (cdt_val[2] & ~CDT_ISOC_WSTS_MASK)
+ >> CDT_ISOC_WSTS_SHIFT;
+ /* c. For isoc channels: WSTS[2:1] = 0x00 */
+ cdt_val[2] &= ~(0x6 << CDT_ISOC_WSTS_SHIFT);
+ break;
+ default:
+ break;
+ }
+ mlb150_dev_cdt_write(_get_txchan(minor).address,
+ cdt_val);
+ }
+
+ /* Get rx channel interrupt status */
+ if (rx_int_sts & (1 << (_get_rxchan(minor).address % 32))) {
+ mlb150_dev_cdt_read(_get_rxchan(minor).address,
+ cdt_val);
+ switch (ctype) {
+ case MLB_CTYPE_SYNC:
+ tx_cis = (cdt_val[2] & ~CDT_SYNC_RSTS_MASK)
+ >> CDT_SYNC_RSTS_SHIFT;
+ cdt_val[2] &= ~(0x8 << CDT_SYNC_WSTS_SHIFT);
+ break;
+ case MLB_CTYPE_CTRL:
+ case MLB_CTYPE_ASYNC:
+ tx_cis = (cdt_val[2] &
+ ~CDT_CTRL_ASYNC_RSTS_MASK)
+ >> CDT_CTRL_ASYNC_RSTS_SHIFT;
+ tx_cis = (cdt_val[3] & CDT_CTRL_ASYNC_RSTS_1) ?
+ (tx_cis | (0x1 << 4)) : tx_cis;
+ cdt_val[3] &= ~CDT_CTRL_ASYNC_RSTS_1;
+ cdt_val[2] &=
+ ~(0x4 << CDT_CTRL_ASYNC_RSTS_SHIFT);
+ break;
+ case MLB_CTYPE_ISOC:
+ tx_cis = (cdt_val[2] & ~CDT_ISOC_RSTS_MASK)
+ >> CDT_ISOC_RSTS_SHIFT;
+ cdt_val[2] &= ~(0x6 << CDT_ISOC_WSTS_SHIFT);
+ break;
+ default:
+ break;
+ }
+ mlb150_dev_cdt_write(_get_rxchan(minor).address,
+ cdt_val);
+ }
+
+ if (!tx_cis && !rx_cis)
+ continue;
+
+ /* fill exception event */
+ spin_lock(&pdev->event_lock);
+ pdev->ex_event |= (rx_cis << 16) | tx_cis;
+ spin_unlock(&pdev->event_lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mxc_mlb150_open(struct inode *inode, struct file *filp)
+{
+ int minor;
+ struct mxc_mlb_platform_data *plat_data;
+
+ plat_data = container_of(inode->i_cdev, struct mxc_mlb_platform_data,
+ cdev);
+ filp->private_data = plat_data;
+
+ minor = MINOR(inode->i_rdev);
+
+ if (unlikely(minor < 0 || minor >= MLB_MINOR_DEVICES))
+ return -ENODEV;
+
+ /* open for each channel device */
+ if (unlikely(atomic_cmpxchg(&mlb_devinfo[minor].opencnt, 0, 1) != 0))
+ return -EBUSY;
+
+ /* reset the buffer read/write ptr */
+ _get_txchan(minor).buf_ptr = _get_txchan(minor).ping_buf_head;
+ _get_rxchan(minor).buf_ptr = _get_rxchan(minor).ping_buf_head;
+ mlb_devinfo[minor].rx_rdpos = mlb_devinfo[minor].rx_wtpos = 0;
+ mlb_devinfo[minor].tx_rdpos = mlb_devinfo[minor].tx_wtpos = 0;
+ mlb_devinfo[minor].ex_event = 0;
+
+ return 0;
+}
+
+static int mxc_mlb150_release(struct inode *inode, struct file *filp)
+{
+ int minor;
+
+ minor = MINOR(inode->i_rdev);
+
+ /* clear channel settings and info */
+ mlb_channel_enable(minor, 0);
+
+ /* decrease the open count */
+ atomic_set(&mlb_devinfo[minor].opencnt, 0);
+
+ return 0;
+}
+
+static long mxc_mlb150_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ void __user *argp = (void __user *)arg;
+ unsigned long flags, event;
+ int minor;
+ struct mxc_mlb_platform_data *plat_data = filp->private_data;
+
+ minor = MINOR(inode->i_rdev);
+
+ pr_debug("mxc_mlb150: minor: %d\n", minor);
+
+ switch (cmd) {
+ case MLB_CHAN_SETADDR:
+ {
+ unsigned int caddr;
+ /* get channel address from user space */
+ if (copy_from_user(&caddr, argp, sizeof(caddr))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+ _get_txchan(minor).address = (caddr >> 16) & 0xFFFF;
+ _get_rxchan(minor).address = caddr & 0xFFFF;
+ pr_debug("mxc_mlb150: set ch addr, tx: %d, rx: %d\n",
+ _get_txchan(minor).address,
+ _get_rxchan(minor).address);
+ break;
+ }
+
+ case MLB_CHAN_STARTUP:
+ if (unlikely(atomic_read(&mlb_devinfo[minor].on))) {
+ pr_debug("mxc_mlb150: channel areadly startup\n");
+ break;
+ }
+ pr_debug("mxc_mlb150: start channel\n");
+ mlb_channel_enable(minor, 1);
+ break;
+ case MLB_CHAN_SHUTDOWN:
+ if (unlikely(atomic_read(&mlb_devinfo[minor].on) == 0)) {
+ pr_debug("mxc_mlb150: channel areadly shutdown\n");
+ break;
+ }
+ pr_debug("mxc_mlb150: shutdown channel\n");
+ mlb_channel_enable(minor, 0);
+ break;
+ case MLB_CHAN_GETEVENT:
+ /* get and clear the ex_event */
+ spin_lock_irqsave(&mlb_devinfo[minor].event_lock, flags);
+ event = mlb_devinfo[minor].ex_event;
+ mlb_devinfo[minor].ex_event = 0;
+ spin_unlock_irqrestore(&mlb_devinfo[minor].event_lock, flags);
+
+ pr_debug("mxc_mlb150: get event\n");
+ if (event) {
+ if (copy_to_user(argp, &event, sizeof(event))) {
+ pr_err("mxc_mlb150: copy to user failed\n");
+ return -EFAULT;
+ }
+ } else {
+ pr_debug("mxc_mlb150: no exception event now\n");
+ return -EAGAIN;
+ }
+ break;
+ case MLB_SET_FPS:
+ {
+ u32 fps, c0_val;
+
+ /* get fps from user space */
+ if (unlikely(copy_from_user(&fps, argp, sizeof(fps)))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+
+ if (plat_data->fps_sel)
+ plat_data->fps_sel(fps);
+
+ c0_val = __raw_readl(mlb_base + MLB150_REG_MLBC0);
+ c0_val &= ~MLB150_MLBC0_MLBCLK_MASK;
+
+ /* check fps value */
+ switch (fps) {
+ case 256:
+ case 512:
+ case 1024:
+ mlb_devinfo[minor].fps = fps >> 9;
+ c0_val &= ~MLB150_MLBC0_MLBPEN;
+ c0_val |= (fps >> 9)
+ << MLB150_MLBC0_MLBCLK_SHIFT;
+ break;
+ case 2048:
+ case 3072:
+ case 4096:
+ mlb_devinfo[minor].fps = (fps >> 10) + 1;
+ c0_val |= ((fps >> 10) + 1)
+ << MLB150_MLBC0_MLBCLK_SHIFT;
+ break;
+ case 6144:
+ mlb_devinfo[minor].fps = fps >> 10;
+ c0_val |= ((fps >> 10) + 1)
+ << MLB150_MLBC0_MLBCLK_SHIFT;
+ break;
+ case 8192:
+ mlb_devinfo[minor].fps = (fps >> 10) - 1;
+ c0_val |= ((fps >> 10) - 1)
+ << MLB150_MLBC0_MLBCLK_SHIFT;
+ break;
+ default:
+ pr_debug("mxc_mlb150: invalid fps argument: %d\n",
+ fps);
+ return -EINVAL;
+ }
+
+ __raw_writel(c0_val, mlb_base + MLB150_REG_MLBC0);
+
+ pr_debug("mxc_mlb150: set fps to %d, MLBC0: 0x%08x\n",
+ fps,
+ (u32)__raw_readl(mlb_base + MLB150_REG_MLBC0));
+
+ break;
+ }
+
+ case MLB_GET_VER:
+ {
+ u32 version;
+
+ /* get MLB device module version */
+ version = 0x03030003;
+
+ pr_debug("mxc_mlb150: get version: 0x%08x\n",
+ version);
+
+ if (copy_to_user(argp, &version, sizeof(version))) {
+ pr_err("mxc_mlb150: copy to user failed\n");
+ return -EFAULT;
+ }
+ break;
+ }
+
+ case MLB_SET_DEVADDR:
+ {
+ u32 c1_val;
+ u8 devaddr;
+
+ /* get MLB device address from user space */
+ if (unlikely(copy_from_user
+ (&devaddr, argp, sizeof(unsigned char)))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+
+ c1_val = __raw_readl(mlb_base + MLB150_REG_MLBC1);
+ c1_val &= ~MLB150_MLBC1_NDA_MASK;
+ c1_val |= devaddr << MLB150_MLBC1_NDA_SHIFT;
+ __raw_writel(c1_val, mlb_base + MLB150_REG_MLBC1);
+ pr_debug("mxc_mlb150: set dev addr, dev addr: %d, "
+ "MLBC1: 0x%08x\n", devaddr,
+ (u32)__raw_readl(mlb_base + MLB150_REG_MLBC1));
+
+ break;
+ }
+ default:
+ pr_info("mxc_mlb150: Invalid ioctl command\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*!
+ * MLB read routine
+ *
+ * Read the current received data from queued buffer,
+ * and free this buffer for hw to fill ingress data.
+ */
+static ssize_t mxc_mlb150_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ int minor, ret;
+ int size, rdpos;
+ struct mlb_ringnode *rxbuf = NULL;
+
+#ifdef DEBUG_RX
+ pr_debug("mxc_mlb150: mxc_mlb150_read\n");
+#endif
+
+ minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+
+ rdpos = mlb_devinfo[minor].rx_rdpos;
+ rxbuf = mlb_devinfo[minor].rx_bufs;
+
+ /* check the current rx buffer is available or not */
+ if (rdpos == mlb_devinfo[minor].rx_wtpos) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ /* if !O_NONBLOCK, we wait for recv packet */
+ ret = wait_event_interruptible(mlb_devinfo[minor].rd_wq,
+ (mlb_devinfo[minor].rx_wtpos !=
+ rdpos));
+ if (ret < 0)
+ return ret;
+ }
+
+ size = rxbuf[rdpos].size;
+ if (unlikely(size > count)) {
+ /* the user buffer is too small */
+ pr_warning
+ ("mxc_mlb150: received data size is bigger than count\n");
+ return -EINVAL;
+ }
+
+ /* copy rx buffer data to user buffer */
+ if (unlikely(copy_to_user(buf, rxbuf[rdpos].data, size))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+
+ /* update the read ptr */
+ mlb_devinfo[minor].rx_rdpos = (rdpos + 1) % TRANS_RING_NODES;
+
+ *f_pos = 0;
+
+ return size;
+}
+
+/*!
+ * MLB write routine
+ *
+ * Copy the user data to tx channel buffer,
+ * and prepare the channel current/next buffer ptr.
+ */
+static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ s32 minor = 0, ret = 0;
+ struct mlb_channel_info *pchinfo = NULL;
+ struct mlb_dev_info *pdevinfo = NULL;
+ u32 adt_val[4] = { 0 };
+
+ minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ pchinfo = &_get_txchan(minor);
+ pdevinfo = &mlb_devinfo[minor];
+
+ if (unlikely(count > pchinfo->buf_size)) {
+ /* too many data to write */
+ pr_warning("mxc_mlb150: overflow write data\n");
+ return -EFBIG;
+ }
+
+ *f_pos = 0;
+
+ memcpy((void *)pchinfo->buf_ptr, buf, count);
+
+ mlb150_dev_adt_read(pchinfo->address, adt_val);
+ mlb_start_tx(minor, adt_val[1]);
+
+ ret = count;
+
+ return ret;
+}
+
+static unsigned int mxc_mlb150_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ int minor;
+ unsigned int ret = 0;
+
+ minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+
+ poll_wait(filp, &mlb_devinfo[minor].rd_wq, wait);
+ poll_wait(filp, &mlb_devinfo[minor].wt_wq, wait);
+
+ /* check the tx buffer is avaiable or not */
+ if (mlb_devinfo[minor].tx_rdpos != mlb_devinfo[minor].tx_wtpos)
+ ret |= POLLOUT | POLLWRNORM;
+
+ /* check the rx buffer filled or not */
+ if (mlb_devinfo[minor].rx_rdpos != mlb_devinfo[minor].rx_wtpos)
+ ret |= POLLIN | POLLRDNORM;
+
+ /* check the exception event */
+ if (mlb_devinfo[minor].ex_event)
+ ret |= POLLIN | POLLRDNORM;
+
+ return ret;
+}
+
+/*!
+ * char dev file operations structure
+ */
+static const struct file_operations mxc_mlb150_fops = {
+
+ .owner = THIS_MODULE,
+ .open = mxc_mlb150_open,
+ .release = mxc_mlb150_release,
+ .unlocked_ioctl = mxc_mlb150_ioctl,
+ .poll = mxc_mlb150_poll,
+ .read = mxc_mlb150_read,
+ .write = mxc_mlb150_write,
+};
+
+/*!
+ * This function is called whenever the MLB device is detected.
+ */
+static int __devinit mxc_mlb150_probe(struct platform_device *pdev)
+{
+ int ret, mlb_major, i, j;
+ struct mxc_mlb_platform_data *plat_data;
+ struct resource *res;
+ void __iomem *base, *bufaddr;
+ unsigned long phyaddr;
+
+ plat_data = (struct mxc_mlb_platform_data *)pdev->dev.platform_data;
+ plat_data->dev = &pdev->dev;
+
+ /* malloc the Rx ring buffer firstly */
+ for (i = 0; i < MLB_MINOR_DEVICES; ++i) {
+ char *buf;
+ int bufsize;
+
+ bufsize =
+ mlb150_ch_packet_buf_size[mlb_devinfo[i].channel_type];
+ buf = kmalloc(bufsize * TRANS_RING_NODES * 2, GFP_KERNEL);
+ if (unlikely(buf == NULL)) {
+ ret = -ENOMEM;
+ dev_err(plat_data->dev, "can not alloc rx buffers\n");
+ goto err3;
+ }
+
+ dev_dbg(plat_data->dev, "ch_type: %d, ring buf base: 0x%08x\n",
+ mlb_devinfo[i].channel_type, (u32)buf);
+
+ for (j = 0; j < TRANS_RING_NODES; ++j) {
+ mlb_devinfo[i].rx_bufs[j].data = buf;
+ buf += bufsize;
+ }
+
+ for (j = 0; j < TRANS_RING_NODES; ++j) {
+ mlb_devinfo[i].tx_bufs[j].data = buf;
+ buf += bufsize;
+ }
+ }
+
+ /**
+ * Register MLB lld as four character devices
+ */
+ ret = alloc_chrdev_region(&dev, 0, MLB_MINOR_DEVICES, "mxc_mlb150");
+ mlb_major = MAJOR(dev);
+ dev_dbg(plat_data->dev, "MLB device major: %d\n", mlb_major);
+
+ if (unlikely(ret < 0)) {
+ dev_err(plat_data->dev, "can't get major %d\n", mlb_major);
+ goto err2;
+ }
+
+ cdev_init(&plat_data->cdev, &mxc_mlb150_fops);
+ plat_data->cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&plat_data->cdev, dev, MLB_MINOR_DEVICES);
+ if (unlikely(ret)) {
+ dev_err(plat_data->dev, "can't add cdev\n");
+ goto err2;
+ }
+
+ /* create class and device for udev information */
+ mlb_class = class_create(THIS_MODULE, "mlb150");
+ if (unlikely(IS_ERR(mlb_class))) {
+ dev_err(plat_data->dev, "failed to create mlb150 class\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ for (i = 0; i < MLB_MINOR_DEVICES; i++) {
+ class_dev = device_create(mlb_class, NULL, MKDEV(mlb_major, i),
+ NULL, mlb_devinfo[i].dev_name);
+ if (unlikely(IS_ERR(class_dev))) {
+ dev_err(plat_data->dev, "failed to create mlb150 %s"
+ " class device\n", mlb_devinfo[i].dev_name);
+ ret = -ENOMEM;
+ goto err1;
+ }
+ }
+
+ /* get irq line */
+ /* AHB0 IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (unlikely(res == NULL)) {
+ dev_err(plat_data->dev, "No mlb150 ahb0 irq line provided\n");
+ goto err0;
+ }
+
+ ahb0_irq = res->start;
+ dev_dbg(plat_data->dev, "ahb0_irq: %d\n", ahb0_irq);
+ if (request_irq(ahb0_irq, mlb_ahb_isr, 0, "mlb_ahb0", NULL)) {
+ dev_err(plat_data->dev, "failed to request irq\n");
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ /* AHB1 IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+ if (unlikely(res == NULL)) {
+ dev_err(plat_data->dev, "No mlb150 ahb0 irq line provided\n");
+ goto err0;
+ }
+
+ ahb1_irq = res->start;
+ dev_dbg(plat_data->dev, "ahb1_irq: %d\n", ahb1_irq);
+ if (request_irq(ahb1_irq, mlb_ahb_isr, 0, "mlb_ahb1", NULL)) {
+ dev_err(plat_data->dev, "failed to request irq\n");
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ /* MLB IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(plat_data->dev, "No mlb150 irq line provided\n");
+ goto err0;
+ }
+
+ mlb_irq = res->start;
+ dev_dbg(plat_data->dev, "mlb_irq: %d\n", mlb_irq);
+ if (request_irq(mlb_irq, mlb_isr, 0, "mlb", NULL)) {
+ dev_err(plat_data->dev, "failed to request irq\n");
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ /* ioremap from phy mlb to kernel space */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(res == NULL)) {
+ dev_err(plat_data->dev, "No mlb150 base address provided\n");
+ goto err0;
+ }
+
+ base = ioremap(res->start, res->end - res->start);
+ dev_dbg(plat_data->dev, "mapped mlb150 base address: 0x%08x\n",
+ (u32)base);
+
+ if (unlikely(base == NULL)) {
+ dev_err(plat_data->dev,
+ "failed to do ioremap with mlb150 base\n");
+ goto err0;
+ }
+ mlb_base = (u32)base;
+
+ dev_dbg(plat_data->dev, "mlb reg base: 0x%08x\n", mlb_base);
+
+ /*!
+ * get rx/tx buffer address from platform data
+ * make sure the buf_address is 4bytes aligned
+ *
+ * ------------------- <-- plat_data->buf_address
+ * | minor 0 tx buf |
+ * -----------------
+ * | minor 0 rx buf |
+ * -----------------
+ * | .... |
+ * -----------------
+ * | minor n tx buf |
+ * -----------------
+ * | minor n rx buf |
+ * -------------------
+ */
+ bufaddr = iram_alloc(MLB_IRAM_SIZE, &iram_base);
+ plat_data->buf_addr = (u32)bufaddr;
+ plat_data->phy_addr = phyaddr = iram_base;
+
+ dev_dbg(plat_data->dev, "iram buf base: 0x%08x, phy base: 0x%08x\n",
+ plat_data->buf_addr, plat_data->phy_addr);
+
+ for (i = 0; i < MLB_MINOR_DEVICES; i++) {
+ /* set the virtual and physical buf head address */
+ _get_txchan(i).ping_buf_head = (u32)bufaddr;
+ _get_txchan(i).ping_phy_head = phyaddr;
+
+ bufaddr += PING_BUF_MAX_SIZE;
+ phyaddr += PING_BUF_MAX_SIZE;
+
+ _get_rxchan(i).ping_buf_head = (u32)bufaddr;
+ _get_rxchan(i).ping_phy_head = phyaddr;
+
+ bufaddr += PING_BUF_MAX_SIZE;
+ phyaddr += PING_BUF_MAX_SIZE;
+
+ _get_txchan(i).pong_buf_head = (u32)bufaddr;
+ _get_txchan(i).pong_phy_head = phyaddr;
+
+ bufaddr += PONG_BUF_MAX_SIZE;
+ phyaddr += PONG_BUF_MAX_SIZE;
+
+ _get_rxchan(i).pong_buf_head = (u32)bufaddr;
+ _get_rxchan(i).pong_phy_head = phyaddr;
+
+ bufaddr += PONG_BUF_MAX_SIZE;
+ phyaddr += PONG_BUF_MAX_SIZE;
+
+ dev_dbg(plat_data->dev, "ctype: %d, tx phy_head: ping(0x%08x), "
+ "pong(0x%08x)\n",
+ i,
+ (u32)_get_txchan(i).ping_phy_head,
+ (u32)_get_txchan(i).pong_phy_head);
+ dev_dbg(plat_data->dev, "ctype: %d, tx buf_head: ping(0x%08x), "
+ "pong(0x%08x)\n",
+ i,
+ (u32)_get_txchan(i).ping_buf_head,
+ (u32)_get_txchan(i).pong_buf_head);
+ dev_dbg(plat_data->dev, "ctype: %d, rx phy_head: ping(0x%08x), "
+ "pong(0x%08x)\n",
+ i,
+ (u32)_get_rxchan(i).ping_phy_head,
+ (u32)_get_rxchan(i).pong_phy_head);
+ dev_dbg(plat_data->dev, "ctype: %d, rx buf_head: ping(0x%08x), "
+ "pong(0x%08x)\n",
+ i,
+ (u32)_get_rxchan(i).ping_buf_head,
+ (u32)_get_rxchan(i).pong_buf_head);
+ }
+
+ if (plat_data->reg_nvcc) {
+ /* power on MLB */
+ reg_nvcc = regulator_get(plat_data->dev, plat_data->reg_nvcc);
+ if (unlikely(!IS_ERR(reg_nvcc))) {
+ /* set MAX LDO6 for NVCC to 2.5V */
+ regulator_set_voltage(reg_nvcc, 2500000, 2500000);
+ regulator_enable(reg_nvcc);
+ }
+ }
+
+ /* enable clock */
+ if (likely(plat_data->mlb_clk)) {
+ mlb_clk = clk_get(plat_data->dev, plat_data->mlb_clk);
+ if (unlikely(IS_ERR(mlb_clk))) {
+ dev_err(&pdev->dev, "unable to get mlb clock\n");
+ ret = PTR_ERR(mlb_clk);
+ goto err0;
+ }
+ clk_enable(mlb_clk);
+ }
+
+ if (likely(plat_data->mlb_pll_clk)) {
+ mlb_pll_clk = clk_get(plat_data->dev, plat_data->mlb_pll_clk);
+ if (unlikely(IS_ERR(mlb_pll_clk))) {
+ dev_err(&pdev->dev, "unable to get mlb pll clock\n");
+ ret = PTR_ERR(mlb_pll_clk);
+ goto err0;
+ }
+ }
+
+ /* initial MLB module */
+ mlb150_dev_init();
+
+ return 0;
+
+err0:
+ if (likely(ahb0_irq)) {
+ free_irq(ahb0_irq, NULL);
+ ahb0_irq = 0;
+ }
+ if (likely(ahb1_irq)) {
+ free_irq(ahb1_irq, NULL);
+ ahb1_irq = 0;
+ }
+ if (likely(mlb_irq)) {
+ free_irq(mlb_irq, NULL);
+ mlb_irq = 0;
+ }
+err1:
+ for (--i; i >= 0; i--)
+ device_destroy(mlb_class, MKDEV(mlb_major, i));
+
+ class_destroy(mlb_class);
+err2:
+ unregister_chrdev_region(dev, MLB_MINOR_DEVICES);
+err3:
+ for (i = 0; i < MLB_MINOR_DEVICES; i++)
+ kfree(mlb_devinfo[i].rx_bufs[0].data);
+
+ return ret;
+}
+
+static int __devexit mxc_mlb150_remove(struct platform_device *pdev)
+{
+ int i;
+ struct mxc_mlb_platform_data *plat_data;
+
+ plat_data = (struct mxc_mlb_platform_data *)pdev->dev.platform_data;
+
+ mlb150_dev_exit();
+
+ /* disable mlb clock */
+ if (plat_data->mlb_clk) {
+ clk_disable(mlb_clk);
+ clk_put(mlb_clk);
+ }
+
+ if (plat_data->mlb_pll_clk)
+ clk_put(mlb_pll_clk);
+
+ /* disable mlb power */
+ if (plat_data->reg_nvcc) {
+ regulator_disable(reg_nvcc);
+ regulator_put(reg_nvcc);
+ }
+
+ /* inactive GPIO */
+ gpio_mlb_inactive();
+
+ if (iram_base) {
+ iram_free(iram_base, MLB_IRAM_SIZE);
+ iram_base = 0;
+ }
+
+ /* iounmap */
+ if (mlb_base) {
+ iounmap((void *)mlb_base);
+ mlb_base = 0;
+ }
+
+ if (ahb0_irq)
+ free_irq(ahb0_irq, NULL);
+ if (ahb1_irq)
+ free_irq(ahb1_irq, NULL);
+ if (mlb_irq)
+ free_irq(mlb_irq, NULL);
+ ahb0_irq = ahb1_irq = mlb_irq = 0;
+
+ /* destroy mlb device class */
+ for (i = MLB_MINOR_DEVICES - 1; i >= 0; i--)
+ device_destroy(mlb_class, MKDEV(MAJOR(dev), i));
+ class_destroy(mlb_class);
+
+ /* Unregister the two MLB devices */
+ unregister_chrdev_region(dev, MLB_MINOR_DEVICES);
+
+ for (i = 0; i < MLB_MINOR_DEVICES; i++)
+ kfree(mlb_devinfo[i].rx_bufs[0].data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxc_mlb150_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+static int mxc_mlb150_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#else
+#define mxc_mlb150_suspend NULL
+#define mxc_mlb150_resume NULL
+#endif
+
+/*!
+ * platform driver structure for MLB
+ */
+static struct platform_driver mxc_mlb150_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = mxc_mlb150_probe,
+ .remove = __devexit_p(mxc_mlb150_remove),
+ .suspend = mxc_mlb150_suspend,
+ .resume = mxc_mlb150_resume,
+};
+
+static int __init mxc_mlb150_init(void)
+{
+ return platform_driver_register(&mxc_mlb150_driver);
+}
+
+static void __exit mxc_mlb150_exit(void)
+{
+ platform_driver_unregister(&mxc_mlb150_driver);
+}
+
+module_init(mxc_mlb150_init);
+module_exit(mxc_mlb150_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MLB150 low level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 3ca487da1272..bf6c10055607 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -246,7 +246,7 @@ static void fec_stop(struct net_device *dev);
#define FEC_MMFR_TA (2 << 16)
#define FEC_MMFR_DATA(v) (v & 0xffff)
-#define FEC_MII_TIMEOUT 2000 /* us */
+#define FEC_MII_TIMEOUT 30 /* ms */
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
@@ -444,7 +444,9 @@ fec_enet_tx(struct net_device *dev)
if (bdp == fep->cur_tx && fep->tx_full == 0)
break;
- dma_unmap_single(&dev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
+ if (bdp->cbd_bufaddr)
+ dma_unmap_single(&dev->dev, bdp->cbd_bufaddr,
+ FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
bdp->cbd_bufaddr = 0;
skb = fep->tx_skbuff[fep->skb_dirty];
@@ -584,8 +586,9 @@ fec_enet_rx(struct net_device *dev)
dev->stats.rx_bytes += pkt_len;
data = (__u8*)__va(bdp->cbd_bufaddr);
- dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
- DMA_FROM_DEVICE);
+ if (bdp->cbd_bufaddr)
+ dma_unmap_single(&dev->dev, bdp->cbd_bufaddr,
+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, pkt_len);
@@ -612,8 +615,8 @@ fec_enet_rx(struct net_device *dev)
netif_rx(skb);
}
- bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen,
- DMA_FROM_DEVICE);
+ bdp->cbd_bufaddr = dma_map_single(&dev->dev, data,
+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
rx_processing_done:
/* Clear the status flags for this buffer */
status &= ~BD_ENET_RX_STATS;
@@ -756,7 +759,7 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
/* wait for end of transfer */
time_left = wait_for_completion_timeout(&fep->mdio_done,
- usecs_to_jiffies(FEC_MII_TIMEOUT));
+ msecs_to_jiffies(FEC_MII_TIMEOUT));
if (time_left == 0) {
fep->mii_timeout = 1;
printk(KERN_ERR "FEC: MDIO read timeout, mii_id=%d\n", mii_id);
@@ -784,7 +787,7 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
/* wait for end of transfer */
time_left = wait_for_completion_timeout(&fep->mdio_done,
- usecs_to_jiffies(FEC_MII_TIMEOUT));
+ msecs_to_jiffies(FEC_MII_TIMEOUT));
if (time_left == 0) {
fep->mii_timeout = 1;
printk(KERN_ERR "FEC: MDIO write timeout, mii_id=%d\n", mii_id);
@@ -1096,7 +1099,6 @@ fec_enet_open(struct net_device *dev)
/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/
-
if (!clk_get_usecount(fep->clk))
clk_enable(fep->clk);
ret = fec_enet_alloc_buffers(dev);
@@ -1296,6 +1298,7 @@ static int fec_enet_init(struct net_device *dev)
/* Initialize the BD for every fragment in the page. */
bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
bdp++;
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 8ebe2e81b332..4f6edd9b8718 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -138,7 +138,6 @@
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
-#define UFCR_RXTL_MASK 0x3f /* RX FIFO is 6 bits wide */
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
@@ -191,8 +190,6 @@
#define UART_NR 8
-#define UART_RX_SIZE (16)
-
struct imx_port {
struct uart_port port;
struct timer_list timer;
@@ -216,6 +213,7 @@ struct imx_port {
struct work_struct tsk_dma_rx, tsk_dma_tx;
unsigned int dma_tx_nents;
bool dma_is_rxing;
+ wait_queue_head_t dma_wait;
};
#ifdef CONFIG_IRDA
@@ -331,6 +329,13 @@ static void imx_stop_rx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
+ /*
+ * We are in SMP now, so if the DMA RX thread is running,
+ * we have to wait for it to finish.
+ */
+ if (sport->enable_dma && sport->dma_is_rxing)
+ return;
+
temp = readl(sport->port.membase + UCR2);
writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
}
@@ -601,12 +606,6 @@ static void imx_dma_rxint(struct imx_port *sport)
if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
sport->dma_is_rxing = true;
- /* increase the RX FIFO threthold. */
- temp = readl(sport->port.membase + UFCR);
- temp &= ~(UFCR_RXTL_MASK << UFCR_RXTL_SHF);
- temp |= UART_RX_SIZE;
- writel(temp, sport->port.membase + UFCR);
-
/* disable the `Recerver Ready Interrrupt` */
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_RRDYEN);
@@ -757,10 +756,28 @@ static void dma_rx_work(struct work_struct *w)
start_rx_dma(sport);
}
+static void imx_finish_dma(struct imx_port *sport)
+{
+ unsigned long temp;
+
+ /* Enable the interrupt when the RXFIFO is not empty. */
+ temp = readl(sport->port.membase + UCR1);
+ temp |= UCR1_RRDYEN;
+ writel(temp, sport->port.membase + UCR1);
+
+ sport->dma_is_rxing = false;
+ if (waitqueue_active(&sport->dma_wait))
+ wake_up(&sport->dma_wait);
+}
+
/*
- * There are two kinds RX DMA interrupts:
+ * There are three kinds of RX DMA interrupts:
* [1] the RX DMA buffer is full.
- * [2] the Aging timer reached its final value(enabled the UCR4_IDDMAEN).
+ * [2] the Aging timer expires(wait for 8 bytes long)
+ * [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *
+ * The [2] and [3] are similar, but [3] is better.
+ * [3] can wait for 32 bytes long, so we do not use [2].
*/
static void dma_rx_callback(void *data)
{
@@ -778,27 +795,20 @@ static void dma_rx_callback(void *data)
/* unmap it first */
dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
+ /* If we have finish the reading. we will not accept any more data. */
+ if (tty->closing) {
+ imx_finish_dma(sport);
+ return;
+ }
+
status = chan->device->device_tx_status(chan,
(dma_cookie_t)NULL, &state);
count = RX_BUF_SIZE - state.residue;
if (count) {
sport->rx_bytes = count;
schedule_work(&sport->tsk_dma_rx);
- } else {
- unsigned long temp;
-
- /* Enable the interrupt when the RXFIFO is not empty. */
- temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_RRDYEN;
- writel(temp, sport->port.membase + UCR1);
- sport->dma_is_rxing = false;
-
- /* decrease the RX FIFO threthold. */
- temp = readl(sport->port.membase + UFCR);
- temp &= ~(UFCR_RXTL_MASK << UFCR_RXTL_SHF);
- temp |= RXTL;
- writel(temp, sport->port.membase + UFCR);
- }
+ } else
+ imx_finish_dma(sport);
}
static int start_rx_dma(struct imx_port *sport)
@@ -869,7 +879,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
slave_config.direction = DMA_FROM_DEVICE;
slave_config.src_addr = sport->port.mapbase + URXD0;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config.src_maxburst = UART_RX_SIZE;
+ slave_config.src_maxburst = RXTL; /* fix me */
ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
if (ret) {
pr_err("error in RX dma configuration.\n");
@@ -993,6 +1003,7 @@ static int imx_startup(struct uart_port *port)
sport->port.flags |= UPF_LOW_LATENCY;
INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);
+ init_waitqueue_head(&sport->dma_wait);
}
spin_lock_irqsave(&sport->port.lock, flags);
@@ -1004,7 +1015,7 @@ static int imx_startup(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
if (sport->enable_dma) {
- temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
+ temp |= UCR1_RDMAEN | UCR1_TDMAEN;
/* ICD, wait for more than 32 frames, but it still to short. */
temp |= UCR1_ICD_REG(3);
}
@@ -1093,6 +1104,13 @@ static void imx_shutdown(struct uart_port *port)
unsigned long temp;
unsigned long flags;
+ if (sport->enable_dma) {
+ /* We have to wait for the DMA to finish. */
+ wait_event(sport->dma_wait, !sport->dma_is_rxing);
+ imx_stop_rx(port);
+ imx_uart_dma_exit(sport);
+ }
+
spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
@@ -1131,12 +1149,16 @@ static void imx_shutdown(struct uart_port *port)
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
if (USE_IRDA(sport))
temp &= ~(UCR1_IREN);
-
+ if (sport->enable_dma)
+ temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN);
writel(temp, sport->port.membase + UCR1);
- spin_unlock_irqrestore(&sport->port.lock, flags);
- if (sport->enable_dma)
- imx_uart_dma_exit(sport);
+ if (sport->enable_dma) {
+ temp = readl(sport->port.membase + UCR4);
+ temp &= ~UCR4_IDDMAEN;
+ writel(temp, sport->port.membase + UCR4);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b883c701aeb8..d21948396595 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2892,7 +2892,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
#ifdef MX6_USB_HOST_HACK
{ /*Must enable HOSTDISCONDETECT after second reset*/
- if (port1 == 1) {
+ if ((port1 == 1) && (udev->level == 1)) {
if (udev->speed == USB_SPEED_HIGH) {
struct device *dev = hcd->self.controller;
struct fsl_usb2_platform_data *pdata;
@@ -3046,11 +3046,11 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
struct fsl_usb2_platform_data *pdata;
pdata = (struct fsl_usb2_platform_data *)dev->platform_data;
- if (dev->parent && dev->type) {
+ if (dev->parent && (hdev->level == 0) && dev->type) {
if (port1 == 1 && pdata->init)
pdata->init(NULL);
}
- if (port1 == 1) {
+ if ((port1 == 1) && (hdev->level == 0)) {
if (!(portstatus&USB_PORT_STAT_CONNECTION)) {
/* Must clear HOSTDISCONDETECT when disconnect*/
fsl_platform_set_usb_phy_dis(pdata, 0);
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 3af0895469f3..2d285ec6e8bc 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -29,9 +29,16 @@ static int audio_buf_size = 48000;
module_param(audio_buf_size, int, S_IRUGO);
MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
+/* The first usb audio buf to alsa playback */
+static int first_audio_buf_size = 65500;
+module_param(first_audio_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(first_audio_buf_size, "First Audio buffer size");
+
static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
+/* Flag to use buffer with first_audio_buf_size to asla */
+static int first_copy_audio_buffer = 1;
/*
* DESCRIPTORS ... most are static, but strings and full
* configuration descriptors are built on demand.
@@ -329,13 +336,27 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
if (!copy_buf)
return -EINVAL;
+ if (!first_copy_audio_buffer) {
/* Copy buffer is full, add it to the play_queue */
- if (audio_buf_size - copy_buf->actual < req->actual) {
- list_add_tail(&copy_buf->list, &audio->play_queue);
- schedule_work(&audio->playback_work);
- copy_buf = f_audio_buffer_alloc(audio_buf_size);
- if (IS_ERR(copy_buf))
- return -ENOMEM;
+ if (audio_buf_size - copy_buf->actual < req->actual) {
+ list_add_tail(&copy_buf->list, &audio->play_queue);
+ schedule_work(&audio->playback_work);
+ copy_buf = f_audio_buffer_alloc(audio_buf_size);
+
+ if (IS_ERR(copy_buf))
+ return -ENOMEM;
+ }
+ } else {
+ if (first_audio_buf_size - copy_buf->actual < req->actual) {
+ list_add_tail(&copy_buf->list, &audio->play_queue);
+ schedule_work(&audio->playback_work);
+ copy_buf = f_audio_buffer_alloc(audio_buf_size);
+
+ if (IS_ERR(copy_buf))
+ return -ENOMEM;
+
+ first_copy_audio_buffer = 0;
+ }
}
memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
@@ -577,7 +598,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt == 1) {
usb_ep_enable(out_ep, audio->out_desc);
out_ep->driver_data = audio;
- audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
+ audio->copy_buf = f_audio_buffer_alloc(first_audio_buf_size);
if (IS_ERR(audio->copy_buf))
return -ENOMEM;
@@ -614,6 +635,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
&audio->play_queue);
schedule_work(&audio->playback_work);
}
+ first_copy_audio_buffer = 1;
}
}
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_audio.c
index 59ffe1ecf1c9..c72aeca692ed 100644
--- a/drivers/usb/gadget/u_audio.c
+++ b/drivers/usb/gadget/u_audio.c
@@ -39,6 +39,10 @@ static char *fn_cntl = FILE_CONTROL;
module_param(fn_cntl, charp, S_IRUGO);
MODULE_PARM_DESC(fn_cntl, "Control device file name");
+static int audio_sample_rate = 48000;
+module_param(audio_sample_rate, int, S_IRUGO);
+MODULE_PARM_DESC(audio_sample_rate, "Audio Sample Rate");
+
/*-------------------------------------------------------------------------*/
/**
@@ -122,13 +126,23 @@ static int playback_default_hw_params(struct gaudio_snd_dev *snd)
snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
snd->format = SNDRV_PCM_FORMAT_S16_LE;
snd->channels = 2;
- snd->rate = 48000;
+ if (audio_sample_rate == 44100)
+ snd->rate = 44100;
+ else if (audio_sample_rate == 48000)
+ snd->rate = 48000;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
_snd_pcm_hw_params_any(params);
+
+ if (audio_sample_rate == 44100) {
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, \
+ 2*1024, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, \
+ 16*1024, 0);
+ }
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
snd->access, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
@@ -193,6 +207,7 @@ try_again:
set_fs(KERNEL_DS);
result = snd_pcm_lib_write(snd->substream, buf, frames);
if (result != frames) {
+ msleep_interruptible(2);
ERROR(card, "Playback error: %d\n", (int)result);
set_fs(old_fs);
goto try_again;
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c
index 5ccfdf8e7b2e..4e6674a684df 100644
--- a/drivers/usb/host/ehci-arc.c
+++ b/drivers/usb/host/ehci-arc.c
@@ -28,6 +28,7 @@
#include "../core/usb.h"
#include "ehci-fsl.h"
#include <mach/fsl_usb.h>
+
extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
static void fsl_usb_lowpower_mode(struct fsl_usb2_platform_data *pdata, bool enable)
{
@@ -123,7 +124,7 @@ void fsl_usb_recover_hcd(struct platform_device *pdev)
* CMDRUN bit in 20ms to keep port status.
*/
cmd = ehci_readl(ehci, &ehci->regs->command);
- if (!(cmd & CMD_RUN)) {
+ if (!(cmd & CMD_RUN) || (hcd->state == HC_STATE_SUSPENDED)) {
ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* Resume root hub here? */
usb_hcd_resume_root_hub(hcd);
@@ -410,6 +411,7 @@ static int ehci_fsl_bus_suspend(struct usb_hcd *hcd)
{
int ret = 0;
struct fsl_usb2_platform_data *pdata;
+ u32 tmp, portsc, cmd;
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
@@ -421,13 +423,23 @@ static int ehci_fsl_bus_suspend(struct usb_hcd *hcd)
return 0;
}
+ portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
ret = ehci_bus_suspend(hcd);
if (ret != 0)
return ret;
+ cmd = ehci_readl(ehci, &ehci->regs->command);
+ if ((portsc & PORT_CONNECT) && ((cmd & CMD_RUN) == 0)) {
+ tmp = ehci_readl(ehci, &ehci->regs->command);
+ tmp |= CMD_RUN;
+ ehci_writel(ehci, tmp, &ehci->regs->command);
+ /* on MX6Q, it need a short delay between set RUNSTOP
+ * and set PHCD
+ */
+ udelay(100);
+ }
if (pdata->platform_suspend)
pdata->platform_suspend(pdata);
-
usb_host_set_wakeup(hcd->self.controller, true);
spin_lock_irqsave(&ehci->lock, flags);
fsl_usb_lowpower_mode(pdata, true);
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c
index 0bdf6b0469ee..46d93efb631e 100644
--- a/drivers/video/mxc_hdmi.c
+++ b/drivers/video/mxc_hdmi.c
@@ -75,7 +75,7 @@
#define YCBCR444 1
#define YCBCR422_16BITS 2
#define YCBCR422_8BITS 3
-#define XVYCC444 4
+#define XVYCC444 4
/*
* We follow a flowchart which is in the "Synopsys DesignWare Courses
@@ -96,6 +96,19 @@ static const struct fb_videomode vga_mode = {
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
};
+static const struct fb_videomode xga_mode = {
+ /* 13 1024x768-60 VESA */
+ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA
+};
+
+static const struct fb_videomode sxga_mode = {
+ /* 20 1280x1024-60 VESA */
+ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA
+};
+
enum hdmi_datamap {
RGB444_8B = 0x01,
RGB444_10B = 0x03,
@@ -251,7 +264,7 @@ static void hdmi_video_sample(struct mxc_hdmi *hdmi)
color_format = 0x07;
else
return;
- } else if (hdmi->hdmi_data.enc_in_format == XVYCC444) {
+ } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
if (hdmi->hdmi_data.enc_color_depth == 8)
color_format = 0x09;
else if (hdmi->hdmi_data.enc_color_depth == 10)
@@ -301,14 +314,14 @@ static int isColorSpaceDecimation(struct mxc_hdmi *hdmi)
{
return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) &&
(hdmi->hdmi_data.enc_in_format == RGB ||
- hdmi->hdmi_data.enc_in_format == XVYCC444));
+ hdmi->hdmi_data.enc_in_format == YCBCR444));
}
static int isColorSpaceInterpolation(struct mxc_hdmi *hdmi)
{
return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) &&
(hdmi->hdmi_data.enc_out_format == RGB
- || hdmi->hdmi_data.enc_out_format == XVYCC444));
+ || hdmi->hdmi_data.enc_out_format == YCBCR444));
}
/*!
@@ -489,7 +502,7 @@ static void hdmi_video_csc(struct mxc_hdmi *hdmi)
if (isColorSpaceInterpolation(hdmi))
interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
else if (isColorSpaceDecimation(hdmi))
- decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1;
+ decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
if (hdmi->hdmi_data.enc_color_depth == 8)
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
@@ -813,7 +826,7 @@ static void mxc_hdmi_phy_sel_interface_control(u8 enable)
static int hdmi_phy_configure(struct mxc_hdmi *hdmi, unsigned char pRep,
unsigned char cRes, int cscOn)
{
- u8 val;
+ u8 val, clkdis;
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
@@ -833,6 +846,13 @@ static int hdmi_phy_configure(struct mxc_hdmi *hdmi, unsigned char pRep,
hdmi_writeb(val, HDMI_MC_FLOWCTRL);
+ /* Enable csc path */
+ if (cscOn) {
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+ }
+
/* gen2 tx power off */
mxc_hdmi_phy_gen2_txpwron(0);
@@ -1057,9 +1077,14 @@ static int hdmi_phy_configure(struct mxc_hdmi *hdmi, unsigned char pRep,
static void mxc_hdmi_phy_init(struct mxc_hdmi *hdmi)
{
int i;
+ bool cscon = false;
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+ /*check csc whether needed activated in HDMI mode */
+ cscon = (isColorSpaceConversion(hdmi) &&
+ !hdmi->hdmi_data.video_mode.mDVI);
+
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0 ; i < 2 ; i++) {
mxc_hdmi_phy_sel_data_en_pol(1);
@@ -1067,8 +1092,8 @@ static void mxc_hdmi_phy_init(struct mxc_hdmi *hdmi)
mxc_hdmi_phy_enable_tmds(0);
mxc_hdmi_phy_enable_power(0);
- /* TODO: Enable CSC */
- hdmi_phy_configure(hdmi, 0, 8, false);
+ /* Enable CSC */
+ hdmi_phy_configure(hdmi, 0, 8, cscon);
}
hdmi->phy_enabled = true;
@@ -1104,6 +1129,7 @@ static void hdmi_config_AVI(struct mxc_hdmi *hdmi)
{
u8 val;
u8 pix_fmt;
+ u8 under_scan;
u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
struct fb_videomode mode;
const struct fb_videomode *edid_mode;
@@ -1125,21 +1151,25 @@ static void hdmi_config_AVI(struct mxc_hdmi *hdmi)
/********************************************
* AVI Data Byte 1
********************************************/
- if (hdmi->edid_cfg.cea_ycbcr444)
+ if (hdmi->hdmi_data.enc_out_format == YCBCR444)
pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
- else if (hdmi->edid_cfg.cea_ycbcr422)
+ else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
else
pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+ if (hdmi->edid_cfg.cea_underscan)
+ under_scan = HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN;
+ else
+ under_scan = HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
/*
* Active format identification data is present in the AVI InfoFrame.
- * No scan info, no bar data
+ * Under scan info, no bar data
*/
- val = pix_fmt |
+ val = pix_fmt | under_scan |
HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
- HDMI_FC_AVICONF0_BAR_DATA_NO_DATA |
- HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+ HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
hdmi_writeb(val, HDMI_FC_AVICONF0);
@@ -1207,7 +1237,7 @@ static void hdmi_config_AVI(struct mxc_hdmi *hdmi)
hdmi_writeb(val, HDMI_FC_PRCONF);
/* IT Content and quantization range = don't care */
- val = HDMI_FC_AVICONF2_IT_CONTENT_TYPE_GRAPHICS |
+ val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
hdmi_writeb(val, HDMI_FC_AVICONF3);
@@ -1513,10 +1543,12 @@ static void mxc_hdmi_edid_rebuild_modelist(struct mxc_hdmi *hdmi)
FB_VMODE_INTERLACED)) {
dev_dbg(&hdmi->pdev->dev, "Added mode %d:", i);
dev_dbg(&hdmi->pdev->dev,
- "xres = %d, yres = %d, freq = %d\n",
+ "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n",
hdmi->fbi->monspecs.modedb[i].xres,
hdmi->fbi->monspecs.modedb[i].yres,
- hdmi->fbi->monspecs.modedb[i].refresh);
+ hdmi->fbi->monspecs.modedb[i].refresh,
+ hdmi->fbi->monspecs.modedb[i].vmode,
+ hdmi->fbi->monspecs.modedb[i].flag);
fb_add_videomode(&hdmi->fbi->monspecs.modedb[i],
&hdmi->fbi->modelist);
@@ -1553,11 +1585,13 @@ static void mxc_hdmi_default_modelist(struct mxc_hdmi *hdmi)
{
u32 i;
const struct fb_videomode *mode;
+ struct fb_videomode m;
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
/* If not EDID data read, set up default modelist */
dev_info(&hdmi->pdev->dev, "No modes read from edid\n");
+ dev_info(&hdmi->pdev->dev, "create default modelist\n");
/* Set the default mode only once. */
if (!hdmi->dft_mode_set) {
@@ -1577,17 +1611,30 @@ static void mxc_hdmi_default_modelist(struct mxc_hdmi *hdmi)
fb_destroy_modelist(&hdmi->fbi->modelist);
+ /*Add all no interlaced CEA mode to default modelist */
for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
mode = &mxc_cea_mode[i];
- if ((mode->xres == hdmi->fbi->var.xres) &&
- (mode->yres == hdmi->fbi->var.yres) &&
- !(mode->vmode & FB_VMODE_INTERLACED))
+ if (!(mode->vmode & FB_VMODE_INTERLACED) && (mode->xres != 0))
fb_add_videomode(mode, &hdmi->fbi->modelist);
}
+ /*Add XGA and SXGA to default modelist */
+ fb_add_videomode(&xga_mode, &hdmi->fbi->modelist);
+ fb_add_videomode(&sxga_mode, &hdmi->fbi->modelist);
+
console_unlock();
- mxc_hdmi_notify_fb(hdmi);
+ fb_var_to_videomode(&m, &hdmi->fbi->var);
+ dump_fb_videomode(&m);
+ mode = fb_find_nearest_mode(&m, &hdmi->fbi->modelist);
+ if (mode) {
+ fb_videomode_to_var(&hdmi->fbi->var, mode);
+ dump_fb_videomode((struct fb_videomode *)mode);
+ dev_warn(&hdmi->pdev->dev,
+ "Default modelist,the video mode may not support by monitor.\n");
+ mxc_hdmi_notify_fb(hdmi);
+ } else
+ pr_err("%s: could not find mode in default modelist\n", __func__);
}
static void mxc_hdmi_set_mode_to_vga_dvi(struct mxc_hdmi *hdmi)
@@ -1886,12 +1933,14 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi)
hdmi->hdmi_data.enc_in_format = RGB;
hdmi->hdmi_data.enc_out_format = RGB;
- if (hdmi->edid_cfg.hdmi_cap) {
- if (hdmi->edid_cfg.cea_ycbcr444)
- hdmi->hdmi_data.enc_out_format = YCBCR444;
- else if (hdmi->edid_cfg.cea_ycbcr422)
- hdmi->hdmi_data.enc_out_format = YCBCR422_8BITS;
- }
+ /*DVI mode not support non-RGB */
+ if (!hdmi->hdmi_data.video_mode.mDVI)
+ if (hdmi->edid_cfg.hdmi_cap) {
+ if (hdmi->edid_cfg.cea_ycbcr444)
+ hdmi->hdmi_data.enc_out_format = YCBCR444;
+ else if (hdmi->edid_cfg.cea_ycbcr422)
+ hdmi->hdmi_data.enc_out_format = YCBCR422_8BITS;
+ }
hdmi->hdmi_data.enc_color_depth = 8;
hdmi->hdmi_data.pix_repet_factor = 0;
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 0bb6c7eedb3e..2bc0ecff686d 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -18,6 +18,7 @@
#define _FSL_DEVICE_H_
#include <linux/types.h>
+#include <linux/cdev.h>
/*
* Some conventions on how we handle peripherals on Freescale chips
@@ -163,6 +164,17 @@ struct fsl_usb2_wakeup_platform_data {
#define FLS_USB2_WORKAROUND_ENGCM09152 (1 << 0)
+struct mxc_mlb_platform_data {
+ struct device *dev;
+ u32 buf_addr;
+ u32 phy_addr;
+ char *reg_nvcc;
+ char *mlb_clk;
+ char *mlb_pll_clk;
+ void (*fps_sel)(int mlbfs);
+ struct cdev cdev;
+};
+
struct spi_device;
struct fsl_spi_platform_data {
diff --git a/include/linux/mfd/pfuze.h b/include/linux/mfd/pfuze.h
index a4c51c5c43a9..42976420203d 100644
--- a/include/linux/mfd/pfuze.h
+++ b/include/linux/mfd/pfuze.h
@@ -105,6 +105,6 @@ struct pfuze_platform_data {
#define PFUZE_USE_REGULATOR (1 << 0)
unsigned int flags;
int num_regulators;
- struct fuze_regulator_init_data *regulators;
+ struct pfuze_regulator_init_data *regulators;
};
#endif
diff --git a/include/linux/mxc_mlb.h b/include/linux/mxc_mlb.h
index 7c8afea2f64d..7ac953c84dd3 100644
--- a/include/linux/mxc_mlb.h
+++ b/include/linux/mxc_mlb.h
@@ -17,6 +17,7 @@
#define _MXC_MLB_H
/* define IOCTL command */
+#define MLB_DBG_RUNTIME _IO('S', 0x09)
#define MLB_SET_FPS _IOW('S', 0x10, unsigned int)
#define MLB_GET_VER _IOR('S', 0x11, unsigned long)
#define MLB_SET_DEVADDR _IOR('S', 0x12, unsigned char)
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 8cf6761b66b6..00fa1c5612c4 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -105,9 +105,6 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_MASK,
SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
-
- snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -118,9 +115,6 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_MASK,
SGTL5000_BIAS_R_off << SGTL5000_BIAS_R_SHIFT);
-
- snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_VAG_POWERUP, 0);
break;
}
return 0;
@@ -136,14 +130,9 @@ static int small_pop_event(struct snd_soc_dapm_widget *w,
{
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_VAG_POWERUP, 0);
- msleep(400);
break;
default:
break;
@@ -1098,9 +1087,24 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
int ret;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ if (codec->dapm.bias_level == level)
+ return 0;
+
switch (level) {
case SND_SOC_BIAS_ON:
+
+ ret = snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
+ if (ret)
+ msleep(400);
+ break;
+
case SND_SOC_BIAS_PREPARE:
+ ret = snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, 0);
+ if (ret)
+ msleep(600);
+
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
@@ -1112,8 +1116,17 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
udelay(10);
}
+ ret = snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, 0);
+ if (ret)
+ msleep(600);
break;
case SND_SOC_BIAS_OFF:
+ ret = snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, 0);
+ if (ret)
+ msleep(600);
+
regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
break;