summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJason Chen <b02280@freescale.com>2011-07-13 12:18:38 +0800
committerJason Chen <b02280@freescale.com>2011-07-13 12:18:38 +0800
commit907ae6b664973daac1464cdc4c629394e3e019b6 (patch)
treec74118859c2c55c3a8d796856d938f817440acff /drivers
parent88ef6a58453bd224dbdce546ecb357d4adabb18f (diff)
ENGR00152845-8 mxc_dispdrv: add support for mxc_dispdrv.
add dispdrv support. add dispdrv sub-driver ldb/lcdif/tve support. change ipuv3 fb driver for new ipu and dispdrv framework. Signed-off-by: Jason Chen <jason.chen@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/mxc/Kconfig2
-rw-r--r--drivers/video/mxc/Makefile4
-rw-r--r--drivers/video/mxc/ldb.c1705
-rw-r--r--drivers/video/mxc/mxc_dispdrv.c152
-rw-r--r--drivers/video/mxc/mxc_dispdrv.h43
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c1052
-rw-r--r--drivers/video/mxc/mxc_lcdif.c144
-rw-r--r--drivers/video/mxc/tve.c1025
8 files changed, 1755 insertions, 2372 deletions
diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig
index e2b79faeaf35..cec114a602d1 100644
--- a/drivers/video/mxc/Kconfig
+++ b/drivers/video/mxc/Kconfig
@@ -27,7 +27,7 @@ config FB_MXC_EPSON_VGA_SYNC_PANEL
config FB_MXC_TVOUT_TVE
tristate "MXC TVE TV Out Encoder"
depends on FB_MXC_SYNC_PANEL
- depends on MXC_IPU_V3
+ depends on MXC_IPU_V3 && !ARCH_MX6Q
config FB_MXC_LDB
tristate "MXC LDB"
diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile
index 723001a166a1..501107974b60 100644
--- a/drivers/video/mxc/Makefile
+++ b/drivers/video/mxc/Makefile
@@ -1,7 +1,7 @@
obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o
obj-$(CONFIG_FB_MXC_SII902X) += mxcfb_sii902x.o
obj-$(CONFIG_FB_MXC_LDB) += ldb.o
-obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o
+#obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o
ifeq ($(CONFIG_ARCH_MX21)$(CONFIG_ARCH_MX27)$(CONFIG_ARCH_MX25),y)
obj-$(CONFIG_FB_MXC_TVOUT) += fs453.o
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mx2fb.o mxcfb_modedb.o
@@ -10,7 +10,7 @@ else
ifeq ($(CONFIG_MXC_IPU_V1),y)
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxcfb.o mxcfb_modedb.o
else
- obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_ipuv3_fb.o
+ obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o
endif
obj-$(CONFIG_FB_MXC_EPSON_PANEL) += mxcfb_epson.o
obj-$(CONFIG_FB_MXC_EPSON_QVGA_PANEL) += mxcfb_epson_qvga.o
diff --git a/drivers/video/mxc/ldb.c b/drivers/video/mxc/ldb.c
index 24ad8e617138..07f2519d71f3 100644
--- a/drivers/video/mxc/ldb.c
+++ b/drivers/video/mxc/ldb.c
@@ -24,7 +24,6 @@
* @brief This file contains the LDB driver device interface and fops
* functions.
*/
-
#include <linux/types.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -33,14 +32,15 @@
#include <linux/console.h>
#include <linux/io.h>
#include <linux/ipu.h>
-#include <linux/ldb.h>
#include <linux/mxcfb.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
-#include <linux/uaccess.h>
#include <linux/fsl_devices.h>
#include <mach/hardware.h>
#include <mach/clock.h>
+#include "mxc_dispdrv.h"
+
+#define DISPDRV_LDB "ldb"
#define LDB_BGREF_RMODE_MASK 0x00008000
#define LDB_BGREF_RMODE_INT 0x00008000
@@ -78,61 +78,47 @@
#define LDB_SPLIT_MODE_EN 0x00000010
-enum ldb_chan_mode_opt {
- LDB_SIN_DI0 = 0,
- LDB_SIN_DI1 = 1,
- LDB_SEP = 2,
- LDB_DUL_DI0 = 3,
- LDB_DUL_DI1 = 4,
- LDB_SPL_DI0 = 5,
- LDB_SPL_DI1 = 6,
- LDB_NO_MODE = 7,
-};
-
-static struct ldb_data {
- struct fb_info *fbi[2];
- bool ch_working[2];
- int blank[2];
- uint32_t chan_mode_opt;
- uint32_t chan_bit_map[2];
- uint32_t bgref_rmode;
- uint32_t base_addr;
+struct ldb_data {
+ struct platform_device *pdev;
+ struct mxc_dispdrv_entry *disp_ldb;
+ uint32_t *reg;
uint32_t *control_reg;
- struct clk *ldb_di_clk[2];
+ uint32_t *gpr3_reg;
struct regulator *lvds_bg_reg;
-} ldb;
-
-static struct device *g_ldb_dev;
-static u32 *ldb_reg;
-static int g_chan_mode_opt = LDB_NO_MODE;
-static int g_chan_bit_map[2];
-#define MXC_ENABLE 1
-#define MXC_DISABLE 2
-static int g_enable_ldb;
-static bool g_di0_used;
-static bool g_di1_used;
+ int mode;
+ bool inited;
+ struct clk *di_clk[2];
+ struct clk *ldb_di_clk[2];
+ struct ldb_setting {
+ bool active;
+ bool clk_en;
+ int ipu;
+ int di;
+ } setting[2];
+ struct notifier_block nb;
+};
-DEFINE_SPINLOCK(ldb_lock);
+static int g_ldb_mode;
-struct fb_videomode mxcfb_ldb_modedb[] = {
+static struct fb_videomode ldb_modedb[] = {
{
- "1080P60", 60, 1920, 1080, 7692,
- 100, 40,
- 30, 3,
- 10, 2,
+ "LDB-XGA", 60, 1024, 768, 15385,
+ 220, 40,
+ 21, 7,
+ 60, 10,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
{
- "XGA", 60, 1024, 768, 15385,
- 220, 40,
- 21, 7,
- 60, 10,
+ "LDB-1080P60", 60, 1920, 1080, 7692,
+ 100, 40,
+ 30, 3,
+ 10, 2,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
};
-int mxcfb_ldb_modedb_sz = ARRAY_SIZE(mxcfb_ldb_modedb);
+static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);
static int bits_per_pixel(int pixel_fmt)
{
@@ -161,1070 +147,448 @@ static int valid_mode(int pixel_fmt)
(pixel_fmt == IPU_PIX_FMT_BGR666));
}
-static void ldb_disable(int ipu_di)
-{
- uint32_t reg;
- int i = 0;
-
- spin_lock(&ldb_lock);
-
- switch (ldb.chan_mode_opt) {
- case LDB_SIN_DI0:
- if (ipu_di != 0 || !ldb.ch_working[0]) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_DISABLE,
- ldb.control_reg);
-
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[0]) != 0)
- clk_disable(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[0]);
-
- ldb.ch_working[0] = false;
- break;
- case LDB_SIN_DI1:
- if (ipu_di != 1 || !ldb.ch_working[1]) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_DISABLE,
- ldb.control_reg);
-
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[1]) != 0)
- clk_disable(ldb.ldb_di_clk[1]);
- clk_put(ldb.ldb_di_clk[1]);
-
- ldb.ch_working[1] = false;
- break;
- case LDB_SPL_DI0:
- case LDB_DUL_DI0:
- if (ipu_di != 0) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- for (i = 0; i < 2; i++) {
- if (ldb.ch_working[i]) {
- reg = __raw_readl(ldb.control_reg);
- if (i == 0)
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_DISABLE,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH1_MODE_DISABLE,
- ldb.control_reg);
-
- if (ldb.chan_mode_opt == LDB_SPL_DI0) {
- reg = __raw_readl(ldb.control_reg);
- __raw_writel(reg & ~LDB_SPLIT_MODE_EN,
- ldb.control_reg);
- }
-
- ldb.ldb_di_clk[i] = clk_get(g_ldb_dev, i ?
- "ldb_di1_clk" :
- "ldb_di0_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[i]) != 0)
- clk_disable(ldb.ldb_di_clk[i]);
- clk_put(ldb.ldb_di_clk[i]);
-
- ldb.ch_working[i] = false;
- }
- }
- break;
- case LDB_SPL_DI1:
- case LDB_DUL_DI1:
- if (ipu_di != 1) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- for (i = 0; i < 2; i++) {
- if (ldb.ch_working[i]) {
- reg = __raw_readl(ldb.control_reg);
- if (i == 0)
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_DISABLE,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH1_MODE_DISABLE,
- ldb.control_reg);
-
- if (ldb.chan_mode_opt == LDB_SPL_DI1) {
- reg = __raw_readl(ldb.control_reg);
- __raw_writel(reg & ~LDB_SPLIT_MODE_EN,
- ldb.control_reg);
- }
-
- ldb.ldb_di_clk[i] = clk_get(g_ldb_dev, i ?
- "ldb_di1_clk" :
- "ldb_di0_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[i]) != 0)
- clk_disable(ldb.ldb_di_clk[i]);
- clk_put(ldb.ldb_di_clk[i]);
-
- ldb.ch_working[i] = false;
- }
- }
- break;
- case LDB_SEP:
- if (ldb.ch_working[ipu_di]) {
- reg = __raw_readl(ldb.control_reg);
- if (ipu_di == 0)
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_DISABLE,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_DISABLE,
- ldb.control_reg);
-
- ldb.ldb_di_clk[ipu_di] = clk_get(g_ldb_dev, ipu_di ?
- "ldb_di1_clk" :
- "ldb_di0_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[ipu_di]) != 0)
- clk_disable(ldb.ldb_di_clk[ipu_di]);
- clk_put(ldb.ldb_di_clk[ipu_di]);
-
- ldb.ch_working[ipu_di] = false;
- }
- break;
- default:
- break;
- }
-
- spin_unlock(&ldb_lock);
- return;
-}
-
-static void ldb_enable(int ipu_di)
+static int __init ldb_setup(char *options)
{
- uint32_t reg;
-
- spin_lock(&ldb_lock);
-
- reg = __raw_readl(ldb.control_reg);
- switch (ldb.chan_mode_opt) {
- case LDB_SIN_DI0:
- if (ldb.ch_working[0] || ipu_di != 0) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[0]);
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_EN_TO_DI0, ldb.control_reg);
- ldb.ch_working[0] = true;
- break;
- case LDB_SIN_DI1:
- if (ldb.ch_working[1] || ipu_di != 1) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- clk_put(ldb.ldb_di_clk[1]);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
- ldb.ch_working[1] = true;
- break;
- case LDB_SEP:
- if (ldb.ch_working[ipu_di]) {
- spin_unlock(&ldb_lock);
- return;
- }
+ if (!strcmp(options, "spl0"))
+ g_ldb_mode = LDB_SPL_DI0;
+ else if (!strcmp(options, "spl1"))
+ g_ldb_mode = LDB_SPL_DI1;
+ else if (!strcmp(options, "dul0"))
+ g_ldb_mode = LDB_DUL_DI0;
+ else if (!strcmp(options, "dul1"))
+ g_ldb_mode = LDB_DUL_DI1;
+ else if (!strcmp(options, "sin0"))
+ g_ldb_mode = LDB_SIN_DI0;
+ else if (!strcmp(options, "sin1"))
+ g_ldb_mode = LDB_SIN_DI1;
+ else if (!strcmp(options, "sep"))
+ g_ldb_mode = LDB_SEP;
- if (ipu_di == 0) {
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[0]);
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_EN_TO_DI0,
- ldb.control_reg);
- ldb.ch_working[0] = true;
- } else {
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- clk_put(ldb.ldb_di_clk[1]);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_EN_TO_DI1,
- ldb.control_reg);
- ldb.ch_working[1] = true;
- }
- break;
- case LDB_DUL_DI0:
- case LDB_SPL_DI0:
- if (ipu_di != 0)
- return;
- else
- goto proc;
- case LDB_DUL_DI1:
- case LDB_SPL_DI1:
- if (ipu_di != 1)
- return;
-proc:
- if (ldb.ch_working[0] || ldb.ch_working[1]) {
- spin_unlock(&ldb_lock);
- return;
- }
-
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- clk_put(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[1]);
-
- if (ldb.chan_mode_opt == LDB_DUL_DI0 ||
- ldb.chan_mode_opt == LDB_SPL_DI0) {
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_EN_TO_DI0,
- ldb.control_reg);
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_EN_TO_DI0,
- ldb.control_reg);
- } else if (ldb.chan_mode_opt == LDB_DUL_DI1 ||
- ldb.chan_mode_opt == LDB_SPL_DI1) {
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_EN_TO_DI1,
- ldb.control_reg);
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_EN_TO_DI1,
- ldb.control_reg);
- }
- if (ldb.chan_mode_opt == LDB_SPL_DI0 ||
- ldb.chan_mode_opt == LDB_SPL_DI1) {
- reg = __raw_readl(ldb.control_reg);
- __raw_writel(reg | LDB_SPLIT_MODE_EN,
- ldb.control_reg);
- }
- ldb.ch_working[0] = true;
- ldb.ch_working[1] = true;
- break;
- default:
- break;
- }
- spin_unlock(&ldb_lock);
- return;
+ return 1;
}
+__setup("ldb=", ldb_setup);
-static int ldb_fb_pre_setup(struct fb_info *fbi)
+static int find_ldb_setting(struct ldb_data *ldb, struct fb_info *fbi)
{
- int ipu_di = 0;
- struct clk *di_clk, *ldb_clk_parent;
- unsigned long ldb_clk_prate = 455000000;
-
- fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
- &fbi->modelist);
- if (!fbi->mode) {
- dev_warn(g_ldb_dev, "can not find mode for xres=%d, yres=%d\n",
- fbi->var.xres, fbi->var.yres);
- return 0;
- }
-
- if (fbi->fbops->fb_ioctl) {
- mm_segment_t old_fs;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi,
- MXCFB_GET_FB_IPU_DI,
- (unsigned long)&ipu_di);
- fbi->fbops->fb_ioctl(fbi,
- MXCFB_GET_FB_BLANK,
- (unsigned int)(&ldb.blank[ipu_di]));
- set_fs(old_fs);
-
- /*
- * Default ldb mode:
- * 1080p: DI0 split, SPWG or DI1 split, SPWG
- * others: single, SPWG
- */
- if (ldb.chan_mode_opt == LDB_NO_MODE) {
- if (fb_mode_is_equal(fbi->mode, &mxcfb_ldb_modedb[0])) {
- if (ipu_di == 0) {
- ldb.chan_mode_opt = LDB_SPL_DI0;
- dev_warn(g_ldb_dev,
- "default di0 split mode\n");
- } else {
- ldb.chan_mode_opt = LDB_SPL_DI1;
- dev_warn(g_ldb_dev,
- "default di1 split mode\n");
- }
- ldb.chan_bit_map[0] = LDB_BIT_MAP_SPWG;
- ldb.chan_bit_map[1] = LDB_BIT_MAP_SPWG;
- } else if (fb_mode_is_equal(fbi->mode, &mxcfb_ldb_modedb[1])) {
- if (ipu_di == 0) {
- ldb.chan_mode_opt = LDB_SIN_DI0;
- ldb.chan_bit_map[0] = LDB_BIT_MAP_SPWG;
- dev_warn(g_ldb_dev,
- "default di0 single mode\n");
- } else {
- ldb.chan_mode_opt = LDB_SIN_DI1;
- ldb.chan_bit_map[1] = LDB_BIT_MAP_SPWG;
- dev_warn(g_ldb_dev,
- "default di1 single mode\n");
- }
- }
- }
-
- /* TODO:Set the correct pll4 rate for all situations */
- if (ipu_di == 1) {
- ldb.ldb_di_clk[1] =
- clk_get(g_ldb_dev, "ldb_di1_clk");
- di_clk = clk_get(g_ldb_dev, "ipu_di1_clk");
- ldb_clk_parent =
- clk_get_parent(ldb.ldb_di_clk[1]);
- clk_set_rate(ldb_clk_parent, ldb_clk_prate);
- clk_set_parent(di_clk, ldb.ldb_di_clk[1]);
- clk_put(di_clk);
- clk_put(ldb.ldb_di_clk[1]);
- } else {
- ldb.ldb_di_clk[0] =
- clk_get(g_ldb_dev, "ldb_di0_clk");
- di_clk = clk_get(g_ldb_dev, "ipu_di0_clk");
- ldb_clk_parent =
- clk_get_parent(ldb.ldb_di_clk[0]);
- clk_set_rate(ldb_clk_parent, ldb_clk_prate);
- clk_set_parent(di_clk, ldb.ldb_di_clk[0]);
- clk_put(di_clk);
- clk_put(ldb.ldb_di_clk[0]);
- }
+ char *id_di[] = {
+ "DISP3 BG",
+ "DISP3 BG - DI1",
+ };
+ char id[16];
+ int i;
- switch (ldb.chan_mode_opt) {
- case LDB_SIN_DI0:
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
- if (ldb.blank[0] == FB_BLANK_UNBLANK &&
- clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[0]);
- break;
- case LDB_SIN_DI1:
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
- if (ldb.blank[1] == FB_BLANK_UNBLANK &&
- clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- clk_put(ldb.ldb_di_clk[1]);
- break;
- case LDB_SEP:
- if (ipu_di == 0) {
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
- if (ldb.blank[0] == FB_BLANK_UNBLANK &&
- clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[0]);
- } else {
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
- if (ldb.blank[1] == FB_BLANK_UNBLANK &&
- clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- clk_put(ldb.ldb_di_clk[1]);
- }
- break;
- case LDB_DUL_DI0:
- case LDB_SPL_DI0:
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (ldb.chan_mode_opt == LDB_DUL_DI0) {
- clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
- } else {
- clk_set_rate(ldb.ldb_di_clk[0], 2*ldb_clk_prate/7);
- clk_set_rate(ldb.ldb_di_clk[1], 2*ldb_clk_prate/7);
- }
- if (ldb.blank[0] == FB_BLANK_UNBLANK) {
- if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- }
- clk_put(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[1]);
- break;
- case LDB_DUL_DI1:
- case LDB_SPL_DI1:
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (ldb.chan_mode_opt == LDB_DUL_DI1) {
- clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
- } else {
- clk_set_rate(ldb.ldb_di_clk[0], 2*ldb_clk_prate/7);
- clk_set_rate(ldb.ldb_di_clk[1], 2*ldb_clk_prate/7);
- }
- if (ldb.blank[1] == FB_BLANK_UNBLANK) {
- if (clk_get_usecount(ldb.ldb_di_clk[0]) == 0)
- clk_enable(ldb.ldb_di_clk[0]);
- if (clk_get_usecount(ldb.ldb_di_clk[1]) == 0)
- clk_enable(ldb.ldb_di_clk[1]);
- }
- clk_put(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[1]);
- break;
- default:
- break;
+ for (i = 0; i < 2; i++) {
+ if (ldb->setting[i].active) {
+ memset(id, 0, 16);
+ memcpy(id, id_di[ldb->setting[i].di],
+ strlen(id_di[ldb->setting[i].di]));
+ id[4] += ldb->setting[i].ipu;
+ if (!strcmp(id, fbi->fix.id))
+ return i;
}
-
- if (ldb.blank[ipu_di] == FB_BLANK_UNBLANK)
- ldb_enable(ipu_di);
}
-
- return 0;
+ return -EINVAL;
}
int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
{
+ struct ldb_data *ldb = container_of(nb, struct ldb_data, nb);
struct fb_event *event = v;
struct fb_info *fbi = event->info;
- mm_segment_t old_fs;
- int ipu_di = 0;
-
- /* Get rid of impact from FG fb */
- if (strcmp(fbi->fix.id, "DISP3 FG") == 0)
- return 0;
+ int setting_idx, di;
- if (fbi->fbops->fb_ioctl) {
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi,
- MXCFB_GET_FB_IPU_DI,
- (unsigned long)&ipu_di);
- set_fs(old_fs);
- } else
- return 0;
-
- if ((ipu_di == 0 && !g_di0_used) ||
- (ipu_di == 1 && !g_di1_used) ||
- ipu_di > 1)
+ setting_idx = find_ldb_setting(ldb, fbi);
+ if (setting_idx < 0)
return 0;
fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
&fbi->modelist);
if (!fbi->mode) {
- dev_warn(g_ldb_dev, "can not find mode for xres=%d, yres=%d\n",
+ dev_warn(&ldb->pdev->dev,
+ "LDB: can not find mode for xres=%d, yres=%d\n",
fbi->var.xres, fbi->var.yres);
+ if (ldb->setting[setting_idx].clk_en) {
+ clk_disable(ldb->ldb_di_clk[di]);
+ ldb->setting[setting_idx].clk_en = false;
+ }
return 0;
}
+ di = ldb->setting[setting_idx].di;
+
switch (val) {
- case FB_EVENT_MODE_CHANGE: {
- int ipu_di_pix_fmt;
+ case FB_EVENT_PREMODE_CHANGE:
+ {
uint32_t reg;
+ uint32_t pixel_clk, rounded_pixel_clk;
- if ((ldb.fbi[0] != NULL && ldb.chan_mode_opt != LDB_SEP) ||
- ldb.fbi[1] != NULL)
- return 0;
-
- /*
- * We cannot support two LVDS panels with different
- * pixel clock rates except that one's pixel clock rate
- * is two times of the others'.
- */
- if (ldb.fbi[0]) {
- if (ldb.fbi[0]->var.pixclock == fbi->var.pixclock ||
- ldb.fbi[0]->var.pixclock ==
- 2 * fbi->var.pixclock ||
- fbi->var.pixclock == 2 * ldb.fbi[0]->var.pixclock)
- ldb.fbi[1] = fbi;
- else
- return 0;
- } else
- ldb.fbi[0] = fbi;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi, MXCFB_GET_DIFMT,
- (unsigned long)&ipu_di_pix_fmt);
- set_fs(old_fs);
-
- if (!valid_mode(ipu_di_pix_fmt)) {
- dev_err(g_ldb_dev, "Unsupport pixel format "
- "for ldb input\n");
- return 0;
- }
-
- reg = __raw_readl(ldb.control_reg);
+ /* vsync setup */
+ reg = readl(ldb->control_reg);
if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) {
- if (ipu_di == 0)
- __raw_writel((reg &
- ~LDB_DI0_VS_POL_MASK) |
- LDB_DI0_VS_POL_ACT_HIGH,
- ldb.control_reg);
+ if (di == 0)
+ reg = (reg & ~LDB_DI0_VS_POL_MASK)
+ | LDB_DI0_VS_POL_ACT_HIGH;
else
- __raw_writel((reg &
- ~LDB_DI1_VS_POL_MASK) |
- LDB_DI1_VS_POL_ACT_HIGH,
- ldb.control_reg);
+ reg = (reg & ~LDB_DI1_VS_POL_MASK)
+ | LDB_DI1_VS_POL_ACT_HIGH;
} else {
- if (ipu_di == 0)
- __raw_writel((reg &
- ~LDB_DI0_VS_POL_MASK) |
- LDB_DI0_VS_POL_ACT_LOW,
- ldb.control_reg);
+ if (di == 0)
+ reg = (reg & ~LDB_DI0_VS_POL_MASK)
+ | LDB_DI0_VS_POL_ACT_LOW;
else
- __raw_writel((reg &
- ~LDB_DI1_VS_POL_MASK) |
- LDB_DI1_VS_POL_ACT_LOW,
- ldb.control_reg);
+ reg = (reg & ~LDB_DI1_VS_POL_MASK)
+ | LDB_DI1_VS_POL_ACT_LOW;
}
+ writel(reg, ldb->control_reg);
- switch (ldb.chan_mode_opt) {
- case LDB_SIN_DI0:
- reg = __raw_readl(ldb.control_reg);
- if (bits_per_pixel(ipu_di_pix_fmt) == 24)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH0_24,
- ldb.control_reg);
- else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH0_18,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_JEIDA,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_EN_TO_DI0, ldb.control_reg);
- if (ldb.blank[0] == FB_BLANK_UNBLANK)
- ldb.ch_working[0] = true;
- break;
- case LDB_SIN_DI1:
- reg = __raw_readl(ldb.control_reg);
- if (bits_per_pixel(ipu_di_pix_fmt) == 24)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
- LDB_DATA_WIDTH_CH1_24,
- ldb.control_reg);
- else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
- LDB_DATA_WIDTH_CH1_18,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_JEIDA,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
- if (ldb.blank[1] == FB_BLANK_UNBLANK)
- ldb.ch_working[1] = true;
- break;
- case LDB_SEP:
- reg = __raw_readl(ldb.control_reg);
- if (ipu_di == 0) {
- if (bits_per_pixel(ipu_di_pix_fmt) == 24)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH0_24,
- ldb.control_reg);
- else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH0_18,
- ldb.control_reg);
- } else {
- if (bits_per_pixel(ipu_di_pix_fmt) == 24)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
- LDB_DATA_WIDTH_CH1_24,
- ldb.control_reg);
- else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
- LDB_DATA_WIDTH_CH1_18,
- ldb.control_reg);
- }
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_JEIDA,
- ldb.control_reg);
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_JEIDA,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~(LDB_CH0_MODE_MASK |
- LDB_CH1_MODE_MASK)) |
- LDB_CH0_MODE_EN_TO_DI0 |
- LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
- if (ldb.blank[0] == FB_BLANK_UNBLANK)
- ldb.ch_working[0] = true;
- if (ldb.blank[1] == FB_BLANK_UNBLANK)
- ldb.ch_working[1] = true;
- break;
- case LDB_DUL_DI0:
- case LDB_SPL_DI0:
- reg = __raw_readl(ldb.control_reg);
- if (bits_per_pixel(ipu_di_pix_fmt) == 24)
- __raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
- LDB_DATA_WIDTH_CH1_MASK)) |
- LDB_DATA_WIDTH_CH0_24 |
- LDB_DATA_WIDTH_CH1_24,
- ldb.control_reg);
- else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
- __raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
- LDB_DATA_WIDTH_CH1_MASK)) |
- LDB_DATA_WIDTH_CH0_18 |
- LDB_DATA_WIDTH_CH1_18,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_JEIDA,
- ldb.control_reg);
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_JEIDA,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_mode_opt == LDB_SPL_DI0)
- __raw_writel(reg | LDB_SPLIT_MODE_EN,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~(LDB_CH0_MODE_MASK |
- LDB_CH1_MODE_MASK)) |
- LDB_CH0_MODE_EN_TO_DI0 |
- LDB_CH1_MODE_EN_TO_DI0, ldb.control_reg);
- if (ldb.blank[0] == FB_BLANK_UNBLANK) {
- ldb.ch_working[0] = true;
- ldb.ch_working[1] = true;
+ /* clk setup */
+ pixel_clk = (PICOS2KHZ(fbi->var.pixclock)) * 1000UL;
+ rounded_pixel_clk = clk_round_rate(ldb->ldb_di_clk[di],
+ pixel_clk);
+ clk_set_rate(ldb->ldb_di_clk[di], rounded_pixel_clk);
+ clk_enable(ldb->ldb_di_clk[di]);
+ ldb->setting[setting_idx].clk_en = true;
+ break;
+ }
+ case FB_EVENT_BLANK:
+ {
+ if (*((int *)event->data) == FB_BLANK_UNBLANK) {
+ if (!ldb->setting[setting_idx].clk_en) {
+ clk_enable(ldb->ldb_di_clk[di]);
+ ldb->setting[setting_idx].clk_en = true;
}
- break;
- case LDB_DUL_DI1:
- case LDB_SPL_DI1:
- reg = __raw_readl(ldb.control_reg);
- if (bits_per_pixel(ipu_di_pix_fmt) == 24)
- __raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
- LDB_DATA_WIDTH_CH1_MASK)) |
- LDB_DATA_WIDTH_CH0_24 |
- LDB_DATA_WIDTH_CH1_24,
- ldb.control_reg);
- else if (bits_per_pixel(ipu_di_pix_fmt) == 18)
- __raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
- LDB_DATA_WIDTH_CH1_MASK)) |
- LDB_DATA_WIDTH_CH0_18 |
- LDB_DATA_WIDTH_CH1_18,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_JEIDA,
- ldb.control_reg);
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
- LDB_BIT_MAP_CH1_JEIDA,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.chan_mode_opt == LDB_SPL_DI1)
- __raw_writel(reg | LDB_SPLIT_MODE_EN,
- ldb.control_reg);
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~(LDB_CH0_MODE_MASK |
- LDB_CH1_MODE_MASK)) |
- LDB_CH0_MODE_EN_TO_DI1 |
- LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
- if (ldb.blank[1] == FB_BLANK_UNBLANK) {
- ldb.ch_working[0] = true;
- ldb.ch_working[1] = true;
+ } else {
+ if (ldb->setting[setting_idx].clk_en) {
+ clk_disable(ldb->ldb_di_clk[di]);
+ ldb->setting[setting_idx].clk_en = false;
}
- break;
- default:
- break;
}
+ }
+ default:
break;
}
- case FB_EVENT_BLANK: {
- if (ldb.fbi[0] != fbi && ldb.fbi[1] != fbi)
- return 0;
-
- if (*((int *)event->data) == ldb.blank[ipu_di])
- return 0;
+ return 0;
+}
- if (*((int *)event->data) == FB_BLANK_UNBLANK)
- ldb_enable(ipu_di);
+#define LVDS0_MUX_CTL_MASK (3 << 6)
+#define LVDS1_MUX_CTL_MASK (3 << 8)
+#define LVDS0_MUX_CTL_OFFS 6
+#define LVDS1_MUX_CTL_OFFS 8
+#define ROUTE_IPU0_DI0 0
+#define ROUTE_IPU0_DI1 1
+#define ROUTE_IPU1_DI0 2
+#define ROUTE_IPU1_DI1 3
+static int ldb_ipu_ldb_route(int ipu, int di, struct ldb_data *ldb)
+{
+ uint32_t reg;
+ int mode = ldb->mode;
+
+ reg = readl(ldb->gpr3_reg);
+ if ((mode == LDB_SPL_DI0) || (mode == LDB_DUL_DI0)) {
+ reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ if (ipu == 0)
+ reg |= (ROUTE_IPU0_DI0 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU0_DI0 << LVDS1_MUX_CTL_OFFS);
+ else
+ reg |= (ROUTE_IPU1_DI0 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU1_DI0 << LVDS1_MUX_CTL_OFFS);
+ dev_dbg(&ldb->pdev->dev,
+ "Dual/Split mode both channels route to IPU%d-DI0\n", ipu);
+ } else if ((mode == LDB_SPL_DI1) || (mode == LDB_DUL_DI1)) {
+ reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
+ if (ipu == 0)
+ reg |= (ROUTE_IPU0_DI1 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU0_DI1 << LVDS1_MUX_CTL_OFFS);
+ else
+ reg |= (ROUTE_IPU1_DI1 << LVDS0_MUX_CTL_OFFS) |
+ (ROUTE_IPU1_DI1 << LVDS1_MUX_CTL_OFFS);
+ dev_dbg(&ldb->pdev->dev,
+ "Dual/Split mode both channels route to IPU%d-DI1\n", ipu);
+ } else if (mode == LDB_SIN_DI0) {
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ if (ipu == 0)
+ reg |= ROUTE_IPU0_DI0 << LVDS0_MUX_CTL_OFFS;
else
- ldb_disable(ipu_di);
+ reg |= ROUTE_IPU1_DI0 << LVDS0_MUX_CTL_OFFS;
+ dev_dbg(&ldb->pdev->dev,
+ "Single mode channel 0 route to IPU%d-DI0\n", ipu);
+ } else if (mode == LDB_SIN_DI1) {
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ if (ipu == 0)
+ reg |= ROUTE_IPU0_DI1 << LVDS1_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU1_DI1 << LVDS1_MUX_CTL_OFFS;
+ dev_dbg(&ldb->pdev->dev,
+ "Single mode channel 1 route to IPU%d-DI1\n", ipu);
+ } else if (mode == LDB_SEP) {
+ if (di == 0)
+ reg &= ~LVDS0_MUX_CTL_MASK;
+ else
+ reg &= ~LVDS1_MUX_CTL_MASK;
+ if ((ipu == 0) && (di == 0))
+ reg |= ROUTE_IPU0_DI0 << LVDS0_MUX_CTL_OFFS;
+ else if ((ipu == 0) && (di == 1))
+ reg |= ROUTE_IPU0_DI1 << LVDS1_MUX_CTL_OFFS;
+ else if ((ipu == 1) && (di == 0))
+ reg |= ROUTE_IPU1_DI0 << LVDS0_MUX_CTL_OFFS;
+ else
+ reg |= ROUTE_IPU1_DI1 << LVDS1_MUX_CTL_OFFS;
- ldb.blank[ipu_di] = *((int *)event->data);
- break;
- }
- default:
- break;
+ dev_dbg(&ldb->pdev->dev,
+ "Separate mode channel %d route to IPU%d-DI%d\n", di, ipu, di);
}
+ writel(reg, ldb->gpr3_reg);
+
return 0;
}
-static struct notifier_block nb = {
- .notifier_call = ldb_fb_event,
-};
-
-static long mxc_ldb_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+static int ldb_disp_init(struct mxc_dispdrv_entry *disp)
{
- int ret = 0;
- uint32_t reg;
+ int ret = 0, i;
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ struct mxc_dispdrv_setting *setting = mxc_dispdrv_getsetting(disp);
+ struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data;
+ struct resource *res;
+ uint32_t base_addr;
+ uint32_t reg, setting_idx;
- switch (cmd) {
- case LDB_BGREF_RMODE:
- {
- ldb_bgref_parm parm;
-
- if (copy_from_user(&parm, (ldb_bgref_parm *) arg,
- sizeof(ldb_bgref_parm)))
- return -EFAULT;
-
- spin_lock(&ldb_lock);
- reg = __raw_readl(ldb.control_reg);
- if (parm.bgref_mode == LDB_EXT_REF)
- __raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
- LDB_BGREF_RMODE_EXT, ldb.control_reg);
- else if (parm.bgref_mode == LDB_INT_REF)
- __raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
- LDB_BGREF_RMODE_INT, ldb.control_reg);
- spin_unlock(&ldb_lock);
- break;
- }
- case LDB_VSYNC_POL:
- {
- ldb_vsync_parm parm;
-
- if (copy_from_user(&parm, (ldb_vsync_parm *) arg,
- sizeof(ldb_vsync_parm)))
- return -EFAULT;
-
- spin_lock(&ldb_lock);
- reg = __raw_readl(ldb.control_reg);
- if (parm.vsync_mode == LDB_VS_ACT_H) {
- if (parm.di == 0)
- __raw_writel((reg &
- ~LDB_DI0_VS_POL_MASK) |
- LDB_DI0_VS_POL_ACT_HIGH,
- ldb.control_reg);
- else
- __raw_writel((reg &
- ~LDB_DI1_VS_POL_MASK) |
- LDB_DI1_VS_POL_ACT_HIGH,
- ldb.control_reg);
- } else if (parm.vsync_mode == LDB_VS_ACT_L) {
- if (parm.di == 0)
- __raw_writel((reg &
- ~LDB_DI0_VS_POL_MASK) |
- LDB_DI0_VS_POL_ACT_LOW,
- ldb.control_reg);
- else
- __raw_writel((reg &
- ~LDB_DI1_VS_POL_MASK) |
- LDB_DI1_VS_POL_ACT_LOW,
- ldb.control_reg);
+ /* ipu selected by platform data setting */
+ setting->dev_id = plat_data->ipu_id;
+
+ /* if input format not valid, make RGB666 as default*/
+ if (!valid_mode(setting->if_fmt)) {
+ dev_warn(&ldb->pdev->dev, "Input pixel format not valid"
+ "use default RGB666\n");
+ setting->if_fmt = IPU_PIX_FMT_RGB666;
+ }
+
+ if (!ldb->inited) {
+ struct clk *ldb_clk_parent;
+ char di0_clk[] = "ipu1_di0_clk";
+ char di1_clk[] = "ipu1_di1_clk";
+ unsigned long ldb_clk_prate = 455000000;
+ ldb->ldb_di_clk[0] = clk_get(&ldb->pdev->dev, "ldb_di0_clk");
+ if (IS_ERR(ldb->ldb_di_clk[0])) {
+ dev_err(&ldb->pdev->dev, "get ldb clk0 failed\n");
+ return PTR_ERR(ldb->ldb_di_clk[0]);
}
- spin_unlock(&ldb_lock);
- break;
+ ldb->ldb_di_clk[1] = clk_get(&ldb->pdev->dev, "ldb_di1_clk");
+ if (IS_ERR(ldb->ldb_di_clk[1])) {
+ dev_err(&ldb->pdev->dev, "get ldb clk1 failed\n");
+ return PTR_ERR(ldb->ldb_di_clk[1]);
}
- case LDB_BIT_MAP:
- {
- ldb_bitmap_parm parm;
-
- if (copy_from_user(&parm, (ldb_bitmap_parm *) arg,
- sizeof(ldb_bitmap_parm)))
- return -EFAULT;
-
- spin_lock(&ldb_lock);
- reg = __raw_readl(ldb.control_reg);
- if (parm.bitmap_mode == LDB_BIT_MAP_SPWG) {
- if (parm.channel == 0)
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_SPWG,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH1_SPWG,
- ldb.control_reg);
- } else if (parm.bitmap_mode == LDB_BIT_MAP_JEIDA) {
- if (parm.channel == 0)
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH0_JEIDA,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
- LDB_BIT_MAP_CH1_JEIDA,
- ldb.control_reg);
+ di0_clk[3] += plat_data->ipu_id;
+ di1_clk[3] += plat_data->ipu_id;
+
+ ldb->di_clk[0] = clk_get(&ldb->pdev->dev, di0_clk);
+ if (IS_ERR(ldb->di_clk[0])) {
+ dev_err(&ldb->pdev->dev, "get di clk0 failed\n");
+ return PTR_ERR(ldb->di_clk[0]);
}
- spin_unlock(&ldb_lock);
- break;
+ ldb->di_clk[1] = clk_get(&ldb->pdev->dev, di1_clk);
+ if (IS_ERR(ldb->di_clk[1])) {
+ dev_err(&ldb->pdev->dev, "get di clk1 failed\n");
+ return PTR_ERR(ldb->di_clk[1]);
}
- case LDB_DATA_WIDTH:
- {
- ldb_data_width_parm parm;
-
- if (copy_from_user(&parm, (ldb_data_width_parm *) arg,
- sizeof(ldb_data_width_parm)))
- return -EFAULT;
-
- spin_lock(&ldb_lock);
- reg = __raw_readl(ldb.control_reg);
- if (parm.data_width == 24) {
- if (parm.channel == 0)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH0_24,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH1_24,
- ldb.control_reg);
- } else if (parm.data_width == 18) {
- if (parm.channel == 0)
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH0_18,
- ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
- LDB_DATA_WIDTH_CH1_18,
- ldb.control_reg);
+
+ /* FIXME: set ldb_di_clk parent to 455M to fit both XGA/1080P mode*/
+ ldb_clk_parent =
+ clk_get_parent(ldb->ldb_di_clk[0]);
+ clk_set_rate(ldb_clk_parent, ldb_clk_prate);
+ ldb_clk_parent =
+ clk_get_parent(ldb->ldb_di_clk[1]);
+ clk_set_rate(ldb_clk_parent, ldb_clk_prate);
+
+ res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0);
+ if (IS_ERR(res)) {
+ ret = -ENOMEM;
+ goto get_res_failed;
}
- spin_unlock(&ldb_lock);
- break;
+
+ base_addr = res->start;
+ ldb->reg = ioremap(base_addr, res->end - res->start + 1);
+ ldb->control_reg = ldb->reg + 2;
+ ldb->gpr3_reg = ldb->reg + 3;
+
+ ldb->lvds_bg_reg = regulator_get(&ldb->pdev->dev, plat_data->lvds_bg_reg);
+ if (!IS_ERR(ldb->lvds_bg_reg)) {
+ regulator_set_voltage(ldb->lvds_bg_reg, 2500000, 2500000);
+ regulator_enable(ldb->lvds_bg_reg);
}
- case LDB_CHAN_MODE:
- {
- ldb_chan_mode_parm parm;
- struct clk *pll4_clk;
- unsigned long pll4_rate = 0;
-
- if (copy_from_user(&parm, (ldb_chan_mode_parm *) arg,
- sizeof(ldb_chan_mode_parm)))
- return -EFAULT;
-
- spin_lock(&ldb_lock);
-
- /* TODO:Set the correct pll4 rate for all situations */
- pll4_clk = clk_get(g_ldb_dev, "pll4");
- pll4_rate = clk_get_rate(pll4_clk);
- pll4_rate = 455000000;
- clk_set_rate(pll4_clk, pll4_rate);
- clk_put(pll4_clk);
-
- reg = __raw_readl(ldb.control_reg);
- switch (parm.channel_mode) {
- case LDB_CHAN_MODE_SIN:
- if (parm.di == 0) {
- ldb.chan_mode_opt = LDB_SIN_DI0;
-
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev,
- "ldb_di0_clk");
- clk_set_rate(ldb.ldb_di_clk[0], pll4_rate/7);
- clk_put(ldb.ldb_di_clk[0]);
-
- __raw_writel((reg & ~LDB_CH0_MODE_MASK) |
- LDB_CH0_MODE_EN_TO_DI0,
- ldb.control_reg);
- } else {
- ldb.chan_mode_opt = LDB_SIN_DI1;
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev,
- "ldb_di1_clk");
- clk_set_rate(ldb.ldb_di_clk[1], pll4_rate/7);
- clk_put(ldb.ldb_di_clk[1]);
+ reg = readl(ldb->control_reg);
- __raw_writel((reg & ~LDB_CH1_MODE_MASK) |
- LDB_CH1_MODE_EN_TO_DI1,
- ldb.control_reg);
- }
- break;
- case LDB_CHAN_MODE_SEP:
- ldb.chan_mode_opt = LDB_SEP;
-
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- clk_set_rate(ldb.ldb_di_clk[0], pll4_rate/7);
- clk_put(ldb.ldb_di_clk[0]);
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- clk_set_rate(ldb.ldb_di_clk[1], pll4_rate/7);
- clk_put(ldb.ldb_di_clk[1]);
-
- __raw_writel((reg & ~(LDB_CH0_MODE_MASK |
- LDB_CH1_MODE_MASK)) |
- LDB_CH0_MODE_EN_TO_DI0 |
- LDB_CH1_MODE_EN_TO_DI1,
- ldb.control_reg);
- break;
- case LDB_CHAN_MODE_DUL:
- case LDB_CHAN_MODE_SPL:
- ldb.ldb_di_clk[0] = clk_get(g_ldb_dev, "ldb_di0_clk");
- ldb.ldb_di_clk[1] = clk_get(g_ldb_dev, "ldb_di1_clk");
- if (parm.di == 0) {
- if (parm.channel_mode == LDB_CHAN_MODE_DUL) {
- ldb.chan_mode_opt = LDB_DUL_DI0;
- clk_set_rate(ldb.ldb_di_clk[0],
- pll4_rate/7);
- } else {
- ldb.chan_mode_opt = LDB_SPL_DI0;
- clk_set_rate(ldb.ldb_di_clk[0],
- 2*pll4_rate/7);
- clk_set_rate(ldb.ldb_di_clk[1],
- 2*pll4_rate/7);
- reg = __raw_readl(ldb.control_reg);
- __raw_writel(reg | LDB_SPLIT_MODE_EN,
- ldb.control_reg);
- }
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~(LDB_CH0_MODE_MASK |
- LDB_CH1_MODE_MASK)) |
- LDB_CH0_MODE_EN_TO_DI0 |
- LDB_CH1_MODE_EN_TO_DI0,
- ldb.control_reg);
+ /* refrence resistor select */
+ reg &= ~LDB_BGREF_RMODE_MASK;
+ if (plat_data->ext_ref)
+ reg |= LDB_BGREF_RMODE_EXT;
+ else
+ reg |= LDB_BGREF_RMODE_INT;
+
+ /* TODO: now only use SPWG data mapping for both channel */
+ reg &= ~(LDB_BIT_MAP_CH0_MASK | LDB_BIT_MAP_CH1_MASK);
+ reg |= LDB_BIT_MAP_CH0_SPWG | LDB_BIT_MAP_CH1_SPWG;
+
+ /* channel mode setting */
+ reg &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
+ reg &= ~(LDB_DATA_WIDTH_CH0_MASK | LDB_DATA_WIDTH_CH1_MASK);
+
+ if (bits_per_pixel(setting->if_fmt) == 24)
+ reg |= LDB_DATA_WIDTH_CH0_24 | LDB_DATA_WIDTH_CH1_24;
+ else
+ reg |= LDB_DATA_WIDTH_CH0_18 | LDB_DATA_WIDTH_CH1_18;
+
+ if (g_ldb_mode)
+ ldb->mode = g_ldb_mode;
+ else
+ ldb->mode = plat_data->mode;
+
+ if (ldb->mode == LDB_SPL_DI0) {
+ reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI0
+ | LDB_CH1_MODE_EN_TO_DI0;
+ setting->disp_id = 0;
+ } else if (ldb->mode == LDB_SPL_DI1) {
+ reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI1
+ | LDB_CH1_MODE_EN_TO_DI1;
+ setting->disp_id = 1;
+ } else if (ldb->mode == LDB_DUL_DI0) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0;
+ setting->disp_id = 0;
+ } else if (ldb->mode == LDB_DUL_DI1) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1;
+ setting->disp_id = 1;
+ } else if (ldb->mode == LDB_SIN_DI0) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH0_MODE_EN_TO_DI0;
+ setting->disp_id = 0;
+ } else if (ldb->mode == LDB_SIN_DI1) {
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH1_MODE_EN_TO_DI1;
+ setting->disp_id = 1;
+ } else { /* separate mode*/
+ reg &= ~LDB_SPLIT_MODE_EN;
+ reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI1;
+ setting->disp_id = plat_data->disp_id;
+ if (bits_per_pixel(setting->if_fmt) == 24) {
+ if (setting->disp_id == 0)
+ reg &= ~LDB_DATA_WIDTH_CH1_24;
+ else
+ reg &= ~LDB_DATA_WIDTH_CH0_24;
} else {
- if (parm.channel_mode == LDB_CHAN_MODE_DUL) {
- ldb.chan_mode_opt = LDB_DUL_DI1;
- clk_set_rate(ldb.ldb_di_clk[1],
- pll4_rate/7);
- } else {
- ldb.chan_mode_opt = LDB_SPL_DI1;
- clk_set_rate(ldb.ldb_di_clk[0],
- 2*pll4_rate/7);
- clk_set_rate(ldb.ldb_di_clk[1],
- 2*pll4_rate/7);
- reg = __raw_readl(ldb.control_reg);
- __raw_writel(reg | LDB_SPLIT_MODE_EN,
- ldb.control_reg);
- }
-
- reg = __raw_readl(ldb.control_reg);
- __raw_writel((reg & ~(LDB_CH0_MODE_MASK |
- LDB_CH1_MODE_MASK)) |
- LDB_CH0_MODE_EN_TO_DI1 |
- LDB_CH1_MODE_EN_TO_DI1,
- ldb.control_reg);
+ if (setting->disp_id == 0)
+ reg &= ~LDB_DATA_WIDTH_CH1_18;
+ else
+ reg &= ~LDB_DATA_WIDTH_CH0_18;
}
- clk_put(ldb.ldb_di_clk[0]);
- clk_put(ldb.ldb_di_clk[1]);
- break;
- default:
- ret = -EINVAL;
- break;
}
- spin_unlock(&ldb_lock);
- break;
- }
- case LDB_ENABLE:
- {
- int ipu_di;
- if (copy_from_user(&ipu_di, (int *) arg, sizeof(int)))
- return -EFAULT;
+ writel(reg, ldb->control_reg);
- ldb_enable(ipu_di);
- break;
+ /* fb notifier for clk setting */
+ ldb->nb.notifier_call = ldb_fb_event,
+ ret = fb_register_client(&ldb->nb);
+ if (ret < 0)
+ goto fb_register_nb_failed;
+
+ setting_idx = 0;
+ ldb->inited = true;
+ } else { /* second time for separate mode */
+ int disp_id;
+
+ if ((ldb->mode == LDB_SPL_DI0) ||
+ (ldb->mode == LDB_SPL_DI1) ||
+ (ldb->mode == LDB_DUL_DI0) ||
+ (ldb->mode == LDB_DUL_DI1) ||
+ (ldb->mode == LDB_SIN_DI0) ||
+ (ldb->mode == LDB_SIN_DI1)) {
+ dev_err(&ldb->pdev->dev, "for second ldb disp"
+ "ldb mode should in separate mode\n");
+ return -EINVAL;
}
- case LDB_DISABLE:
- {
- int ipu_di;
- if (copy_from_user(&ipu_di, (int *) arg, sizeof(int)))
- return -EFAULT;
+ disp_id = setting->disp_id = !plat_data->disp_id;
- ldb_disable(ipu_di);
- break;
+ reg = readl(ldb->control_reg);
+ if (bits_per_pixel(setting->if_fmt) == 24) {
+ if (disp_id == 0)
+ reg |= LDB_DATA_WIDTH_CH0_24;
+ else
+ reg |= LDB_DATA_WIDTH_CH1_24;
+ } else {
+ if (disp_id == 0)
+ reg |= LDB_DATA_WIDTH_CH0_18;
+ else
+ reg |= LDB_DATA_WIDTH_CH1_18;
+ }
+ writel(reg, ldb->control_reg);
+ setting_idx = 1;
+ }
+
+ if (cpu_is_mx6q())
+ ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb);
+
+ /*
+ * ldb_di0_clk -> ipux_di0_clk
+ * ldb_di1_clk -> ipux_di1_clk
+ */
+ clk_set_parent(ldb->di_clk[setting->disp_id],
+ ldb->ldb_di_clk[setting->disp_id]);
+
+ /* must use spec video mode defined by driver */
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp);
+ if (ret != 1)
+ fb_videomode_to_var(&setting->fbi->var, &ldb_modedb[0]);
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < ldb_modedb_sz; i++) {
+ struct fb_videomode m;
+ fb_var_to_videomode(&m, &setting->fbi->var);
+ if (fb_mode_is_equal(&m, &ldb_modedb[i])) {
+ fb_add_videomode(&ldb_modedb[i],
+ &setting->fbi->modelist);
+ break;
}
- default:
- ret = -EINVAL;
- break;
}
+ /* save current ldb setting for fb notifier */
+ ldb->setting[setting_idx].active = true;
+ ldb->setting[setting_idx].ipu = setting->dev_id;
+ ldb->setting[setting_idx].di = setting->disp_id;
+
return ret;
-}
-static int mxc_ldb_open(struct inode *inode, struct file *file)
-{
- return 0;
+fb_register_nb_failed:
+ iounmap(ldb->reg);
+get_res_failed:
+ return ret;
}
-static int mxc_ldb_release(struct inode *inode, struct file *file)
+static void ldb_disp_deinit(struct mxc_dispdrv_entry *disp)
{
- return 0;
-}
+ struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
+ int i;
-static int mxc_ldb_mmap(struct file *file, struct vm_area_struct *vma)
-{
- return 0;
+ writel(0, ldb->control_reg);
+
+ for (i = 0; i < 2; i++) {
+ clk_disable(ldb->ldb_di_clk[i]);
+ clk_put(ldb->ldb_di_clk[i]);
+ }
+
+ fb_unregister_client(&ldb->nb);
+
+ iounmap(ldb->reg);
}
-static const struct file_operations mxc_ldb_fops = {
- .owner = THIS_MODULE,
- .open = mxc_ldb_open,
- .mmap = mxc_ldb_mmap,
- .release = mxc_ldb_release,
- .unlocked_ioctl = mxc_ldb_ioctl
+static struct mxc_dispdrv_driver ldb_drv = {
+ .name = DISPDRV_LDB,
+ .init = ldb_disp_init,
+ .deinit = ldb_disp_deinit,
};
/*!
@@ -1239,186 +603,30 @@ static const struct file_operations mxc_ldb_fops = {
static int ldb_probe(struct platform_device *pdev)
{
int ret = 0;
- struct resource *res;
- struct fsl_mxc_ldb_platform_data *plat_data = pdev->dev.platform_data;
- uint32_t reg;
- struct device *temp;
- int mxc_ldb_major;
- struct class *mxc_ldb_class;
-
- if ((plat_data->boot_enable & (MXC_LDBDI0 | MXC_LDBDI1))
- && !g_enable_ldb) {
- g_enable_ldb = MXC_ENABLE;
- if (plat_data->boot_enable & MXC_LDBDI0)
- g_di0_used = true;
- if (plat_data->boot_enable & MXC_LDBDI1)
- g_di1_used = true;
- }
-
- if (!g_enable_ldb)
- g_enable_ldb = MXC_DISABLE;
-
- if (g_enable_ldb == MXC_DISABLE) {
- printk(KERN_WARNING "By setting, LDB driver will not be enabled\n");
- return 0;
- }
-
- spin_lock_init(&ldb_lock);
-
- g_ldb_dev = &pdev->dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (IS_ERR(res))
- return -ENODEV;
-
- memset(&ldb, 0, sizeof(struct ldb_data));
- ldb.chan_mode_opt = g_chan_mode_opt;
- ldb.chan_bit_map[0] = g_chan_bit_map[0];
- ldb.chan_bit_map[1] = g_chan_bit_map[1];
-
- ldb.base_addr = res->start;
- ldb_reg = ioremap(ldb.base_addr, res->end - res->start + 1);
- ldb.control_reg = ldb_reg + 2;
-
- ldb.bgref_rmode = plat_data->ext_ref;
- ldb.lvds_bg_reg = regulator_get(&pdev->dev, plat_data->lvds_bg_reg);
- if (!IS_ERR(ldb.lvds_bg_reg)) {
- regulator_set_voltage(ldb.lvds_bg_reg, 2500000, 2500000);
- regulator_enable(ldb.lvds_bg_reg);
- }
-
- reg = __raw_readl(ldb.control_reg);
- if (ldb.bgref_rmode == LDB_EXT_REF)
- __raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
- LDB_BGREF_RMODE_EXT, ldb.control_reg);
- else
- __raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
- LDB_BGREF_RMODE_INT, ldb.control_reg);
-
- mxc_ldb_major = register_chrdev(0, "mxc_ldb", &mxc_ldb_fops);
- if (mxc_ldb_major < 0) {
- dev_err(g_ldb_dev, "Unable to register MXC LDB as a char "
- "device\n");
- ret = mxc_ldb_major;
- goto err0;
- }
-
- mxc_ldb_class = class_create(THIS_MODULE, "mxc_ldb");
- if (IS_ERR(mxc_ldb_class)) {
- dev_err(g_ldb_dev, "Unable to create class for MXC LDB\n");
- ret = PTR_ERR(mxc_ldb_class);
- goto err1;
- }
+ struct ldb_data *ldb;
- temp = device_create(mxc_ldb_class, NULL, MKDEV(mxc_ldb_major, 0),
- NULL, "mxc_ldb");
- if (IS_ERR(temp)) {
- dev_err(g_ldb_dev, "Unable to create class device for "
- "MXC LDB\n");
- ret = PTR_ERR(temp);
- goto err2;
+ ldb = kzalloc(sizeof(struct ldb_data), GFP_KERNEL);
+ if (!ldb) {
+ ret = -ENOMEM;
+ goto alloc_failed;
}
- if (g_di0_used) {
- mxcfb_register_mode(0, mxcfb_ldb_modedb,
- mxcfb_ldb_modedb_sz,
- MXC_DISP_SPEC_DEV);
- mxcfb_register_presetup(0, ldb_fb_pre_setup);
- }
- if (g_di1_used) {
- mxcfb_register_mode(1, mxcfb_ldb_modedb,
- mxcfb_ldb_modedb_sz,
- MXC_DISP_SPEC_DEV);
- mxcfb_register_presetup(1, ldb_fb_pre_setup);
- }
+ ldb->pdev = pdev;
+ ldb->disp_ldb = mxc_dispdrv_register(&ldb_drv);
+ mxc_dispdrv_setdata(ldb->disp_ldb, ldb);
- ret = fb_register_client(&nb);
- if (ret < 0)
- goto err2;
+ dev_set_drvdata(&pdev->dev, ldb);
- ldb.blank[0] = ldb.blank[1] = -1;
-
- return ret;
-err2:
- class_destroy(mxc_ldb_class);
-err1:
- unregister_chrdev(mxc_ldb_major, "mxc_ldb");
-err0:
- iounmap(ldb_reg);
+alloc_failed:
return ret;
}
static int ldb_remove(struct platform_device *pdev)
{
- int i;
-
- __raw_writel(0, ldb.control_reg);
+ struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
- for (i = 0; i < 2; i++) {
- if (ldb.ch_working[i]) {
- ldb.ldb_di_clk[i] = clk_get(g_ldb_dev,
- i ? "ldb_di1_clk" : "ldb_di0_clk");
- clk_disable(ldb.ldb_di_clk[i]);
- clk_put(ldb.ldb_di_clk[i]);
- ldb.ch_working[i] = false;
- }
- }
-
- fb_unregister_client(&nb);
- return 0;
-}
-
-static int ldb_suspend(struct platform_device *pdev, pm_message_t state)
-{
- switch (ldb.chan_mode_opt) {
- case LDB_SIN_DI0:
- case LDB_DUL_DI0:
- case LDB_SPL_DI0:
- if (ldb.blank[0] != FB_BLANK_UNBLANK)
- ldb_disable(0);
- break;
- case LDB_SIN_DI1:
- case LDB_DUL_DI1:
- case LDB_SPL_DI1:
- if (ldb.blank[1] != FB_BLANK_UNBLANK)
- ldb_disable(1);
- break;
- case LDB_SEP:
- if (ldb.blank[0] != FB_BLANK_UNBLANK)
- ldb_disable(0);
- if (ldb.blank[1] != FB_BLANK_UNBLANK)
- ldb_disable(1);
- break;
- default:
- break;
- }
- return 0;
-}
-
-static int ldb_resume(struct platform_device *pdev)
-{
- switch (ldb.chan_mode_opt) {
- case LDB_SIN_DI0:
- case LDB_DUL_DI0:
- case LDB_SPL_DI0:
- if (ldb.blank[0] == FB_BLANK_UNBLANK)
- ldb_enable(0);
- break;
- case LDB_SIN_DI1:
- case LDB_DUL_DI1:
- case LDB_SPL_DI1:
- if (ldb.blank[1] == FB_BLANK_UNBLANK)
- ldb_enable(1);
- break;
- case LDB_SEP:
- if (ldb.blank[0] == FB_BLANK_UNBLANK)
- ldb_enable(0);
- if (ldb.blank[1] == FB_BLANK_UNBLANK)
- ldb_enable(1);
- break;
- default:
- break;
- }
+ mxc_dispdrv_unregister(ldb->disp_ldb);
+ kfree(ldb);
return 0;
}
@@ -1428,102 +636,11 @@ static struct platform_driver mxcldb_driver = {
},
.probe = ldb_probe,
.remove = ldb_remove,
- .suspend = ldb_suspend,
- .resume = ldb_resume,
};
-/*
- * Parse user specified options (`ldb=')
- * example:
- * ldb=single(separate, dual or split),(di=0 or di=1),
- * ch0_map=SPWG or JEIDA,ch1_map=SPWG or JEIDA
- *
- */
-static int __init ldb_setup(char *options)
-{
- if (!strcmp(options, "=off")) {
- g_enable_ldb = MXC_DISABLE;
- return 1;
- } else
- g_enable_ldb = MXC_ENABLE;
-
- if (!strlen(options))
- return 1;
- else if (!strsep(&options, "="))
- return 1;
-
- if (!strncmp(options, "di0", 3))
- g_di0_used = true;
-
- if (!strncmp(options, "di1", 3))
- g_di1_used = true;
-
- if (!strncmp(options, "single", 6)) {
- strsep(&options, ",");
- if (!strncmp(options, "di=0", 4)) {
- g_chan_mode_opt = LDB_SIN_DI0;
- g_di0_used = true;
- } else {
- g_chan_mode_opt = LDB_SIN_DI1;
- g_di1_used = true;
- }
- } else if (!strncmp(options, "separate", 8)) {
- g_chan_mode_opt = LDB_SEP;
- g_di0_used = true;
- g_di1_used = true;
- } else if (!strncmp(options, "dual", 4)) {
- strsep(&options, ",");
- if (!strncmp(options, "di=", 3)) {
- if (simple_strtoul(options + 3, NULL, 0) == 0) {
- g_chan_mode_opt = LDB_DUL_DI0;
- g_di0_used = true;
- } else {
- g_chan_mode_opt = LDB_DUL_DI1;
- g_di1_used = true;
- }
- }
- } else if (!strncmp(options, "split", 5)) {
- strsep(&options, ",");
- if (!strncmp(options, "di=", 3)) {
- if (simple_strtoul(options + 3, NULL, 0) == 0) {
- g_chan_mode_opt = LDB_SPL_DI0;
- g_di0_used = true;
- } else {
- g_chan_mode_opt = LDB_SPL_DI1;
- g_di1_used = true;
- }
- }
- } else
- return 1;
-
- if ((strsep(&options, ",") != NULL) &&
- !strncmp(options, "ch0_map=", 8)) {
- if (!strncmp(options + 8, "SPWG", 4))
- g_chan_bit_map[0] = LDB_BIT_MAP_SPWG;
- else
- g_chan_bit_map[0] = LDB_BIT_MAP_JEIDA;
- }
-
- if (!(g_chan_mode_opt == LDB_SIN_DI0 ||
- g_chan_mode_opt == LDB_SIN_DI1) &&
- (strsep(&options, ",") != NULL) &&
- !strncmp(options, "ch1_map=", 8)) {
- if (!strncmp(options + 8, "SPWG", 4))
- g_chan_bit_map[1] = LDB_BIT_MAP_SPWG;
- else
- g_chan_bit_map[1] = LDB_BIT_MAP_JEIDA;
- }
-
- return 1;
-}
-__setup("ldb", ldb_setup);
-
static int __init ldb_init(void)
{
- int ret;
-
- ret = platform_driver_register(&mxcldb_driver);
- return 0;
+ return platform_driver_register(&mxcldb_driver);
}
static void __exit ldb_uninit(void)
diff --git a/drivers/video/mxc/mxc_dispdrv.c b/drivers/video/mxc/mxc_dispdrv.c
new file mode 100644
index 000000000000..06b7af944f5b
--- /dev/null
+++ b/drivers/video/mxc/mxc_dispdrv.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_dispdrv.c
+ * @brief mxc display driver framework.
+ *
+ * A display device driver could call mxc_dispdrv_register(drv) in its dev_probe() function.
+ * Move all dev_probe() things into mxc_dispdrv_driver->init(), init() function should init
+ * and feedback setting;
+ * Move all dev_remove() things into mxc_dispdrv_driver->deinit();
+ * Move all dev_suspend() things into fb_notifier for SUSPEND, if there is;
+ * Move all dev_resume() things into fb_notifier for RESUME, if there is;
+ *
+ * ipuv3 fb driver could call mxc_dispdrv_init(setting) before a fb need be added, with fbi param
+ * passing by setting, after mxc_dispdrv_init() return, FB driver should get the basic setting
+ * about fbi info and ipuv3-hw (ipu_id and disp_id).
+ *
+ * @ingroup Framebuffer
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include "mxc_dispdrv.h"
+
+static LIST_HEAD(dispdrv_list);
+static DEFINE_MUTEX(dispdrv_lock);
+
+struct mxc_dispdrv_entry {
+ const char *name;
+ struct list_head list;
+ int (*init) (struct mxc_dispdrv_entry *);
+ void (*deinit) (struct mxc_dispdrv_entry *);
+ bool active;
+ struct mxc_dispdrv_setting setting;
+ void *priv;
+};
+
+struct mxc_dispdrv_entry *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv)
+{
+ struct mxc_dispdrv_entry *new;
+
+ mutex_lock(&dispdrv_lock);
+
+ new = kzalloc(sizeof(struct mxc_dispdrv_entry), GFP_KERNEL);
+ if (!new) {
+ mutex_unlock(&dispdrv_lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ new->name = drv->name;
+ new->init = drv->init;
+ new->deinit = drv->deinit;
+
+ list_add_tail(&new->list, &dispdrv_list);
+ mutex_unlock(&dispdrv_lock);
+
+ return new;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_register);
+
+int mxc_dispdrv_unregister(struct mxc_dispdrv_entry *entry)
+{
+ if (entry) {
+ mutex_lock(&dispdrv_lock);
+ if (entry->active && entry->deinit)
+ entry->deinit(entry);
+ list_del(&entry->list);
+ mutex_unlock(&dispdrv_lock);
+ kfree(entry);
+ return 0;
+ } else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_unregister);
+
+int mxc_dispdrv_init(char *name, struct mxc_dispdrv_setting *setting)
+{
+ int ret = 0, found = 0;
+ struct mxc_dispdrv_entry *disp;
+
+ mutex_lock(&dispdrv_lock);
+ list_for_each_entry(disp, &dispdrv_list, list) {
+ if (!strcmp(disp->name, name)) {
+ if (disp->init) {
+ memcpy(&disp->setting, setting,
+ sizeof(struct mxc_dispdrv_setting));
+ ret = disp->init(disp);
+ if (ret >= 0) {
+ disp->active = true;
+ /* setting may need fix-up */
+ memcpy(setting, &disp->setting,
+ sizeof(struct mxc_dispdrv_setting));
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found)
+ ret = -EINVAL;
+
+ mutex_unlock(&dispdrv_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_init);
+
+int mxc_dispdrv_setdata(struct mxc_dispdrv_entry *entry, void *data)
+{
+ if (entry) {
+ entry->priv = data;
+ return 0;
+ } else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_setdata);
+
+void *mxc_dispdrv_getdata(struct mxc_dispdrv_entry *entry)
+{
+ if (entry) {
+ return entry->priv;
+ } else
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_getdata);
+
+struct mxc_dispdrv_setting
+ *mxc_dispdrv_getsetting(struct mxc_dispdrv_entry *entry)
+{
+ if (entry) {
+ return &entry->setting;
+ } else
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_getsetting);
diff --git a/drivers/video/mxc/mxc_dispdrv.h b/drivers/video/mxc/mxc_dispdrv.h
new file mode 100644
index 000000000000..f5f62a2c3cb3
--- /dev/null
+++ b/drivers/video/mxc/mxc_dispdrv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MXC_DISPDRV_H__
+#define __MXC_DISPDRV_H__
+
+struct mxc_dispdrv_entry;
+
+struct mxc_dispdrv_driver {
+ const char *name;
+ int (*init) (struct mxc_dispdrv_entry *);
+ void (*deinit) (struct mxc_dispdrv_entry *);
+};
+
+struct mxc_dispdrv_setting {
+ /*input-feedback parameter*/
+ struct fb_info *fbi;
+ int if_fmt;
+ int default_bpp;
+ char *dft_mode_str;
+
+ /*feedback parameter*/
+ int dev_id;
+ int disp_id;
+};
+
+struct mxc_dispdrv_entry *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv);
+int mxc_dispdrv_unregister(struct mxc_dispdrv_entry *entry);
+int mxc_dispdrv_init(char *name, struct mxc_dispdrv_setting *setting);
+int mxc_dispdrv_setdata(struct mxc_dispdrv_entry *entry, void *data);
+void *mxc_dispdrv_getdata(struct mxc_dispdrv_entry *entry);
+struct mxc_dispdrv_setting
+ *mxc_dispdrv_getsetting(struct mxc_dispdrv_entry *entry);
+#endif
diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c
index efdb664a1d7b..a27815096415 100644
--- a/drivers/video/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/mxc/mxc_ipuv3_fb.c
@@ -48,6 +48,7 @@
#include <linux/fsl_devices.h>
#include <asm/mach-types.h>
#include <mach/ipu-v3.h>
+#include "mxc_dispdrv.h"
/*
* Driver name
@@ -60,11 +61,11 @@
* Structure containing the MXC specific framebuffer information.
*/
struct mxcfb_info {
- char *fb_mode_str;
int default_bpp;
int cur_blank;
int next_blank;
ipu_channel_t ipu_ch;
+ int ipu_id;
int ipu_di;
u32 ipu_di_pix_fmt;
bool ipu_int_clk;
@@ -82,16 +83,14 @@ struct mxcfb_info {
u32 pseudo_palette[16];
+ bool mode_found;
bool wait4vsync;
struct semaphore flip_sem;
struct semaphore alpha_flip_sem;
struct completion vsync_complete;
-};
-struct mxcfb_mode {
- int dev_mode;
- int num_modes;
- struct fb_videomode *mode;
+ void *ipu;
+ struct fb_info *ovfbi;
};
struct mxcfb_alloc_list {
@@ -108,72 +107,8 @@ enum {
BOTH_OFF
};
-static bool g_dp_in_use;
+static bool g_dp_in_use[2];
LIST_HEAD(fb_alloc_list);
-static struct fb_info *mxcfb_info[3];
-static __initdata struct mxcfb_mode mxc_disp_mode[MXCFB_PORT_NUM];
-static __initdata int (*mxcfb_pre_setup[MXCFB_PORT_NUM])(struct fb_info *info);
-
-/*
- * register pre-setup callback for some display
- * driver which need prepare clk etc.
- */
-void mxcfb_register_presetup(int disp_port,
- int (*pre_setup)(struct fb_info *info))
-{
- if (pre_setup)
- mxcfb_pre_setup[disp_port] = pre_setup;
-}
-EXPORT_SYMBOL(mxcfb_register_presetup);
-
-/*
- * mode register from each display driver before
- * primary fb setting.
- */
-void mxcfb_register_mode(int disp_port,
- const struct fb_videomode *modedb,
- int num_modes, int dev_mode)
-{
- struct fb_videomode *mode;
- int mode_sum;
-
- if (disp_port > MXCFB_PORT_NUM)
- return;
-
- /*
- * if there is new DDC device, overwrite old modes.
- * if there is old DDC device while new device is not DDC,
- * just keep old DDC modes.
- */
- if (dev_mode & MXC_DISP_DDC_DEV) {
- if (mxc_disp_mode[disp_port].num_modes) {
- kfree(mxc_disp_mode[disp_port].mode);
- mxc_disp_mode[disp_port].num_modes = 0;
- }
- } else if (mxc_disp_mode[disp_port].dev_mode & MXC_DISP_DDC_DEV)
- return;
-
- mode_sum = mxc_disp_mode[disp_port].num_modes + num_modes;
- mode = kzalloc(mode_sum * sizeof(struct fb_videomode), GFP_KERNEL);
-
- if (mxc_disp_mode[disp_port].num_modes)
- memcpy(mode, mxc_disp_mode[disp_port].mode,
- mxc_disp_mode[disp_port].num_modes
- * sizeof(struct fb_videomode));
- if (modedb)
- memcpy(mode + mxc_disp_mode[disp_port].num_modes,
- modedb, num_modes * sizeof(struct fb_videomode));
-
- if (mxc_disp_mode[disp_port].num_modes)
- kfree(mxc_disp_mode[disp_port].mode);
-
- mxc_disp_mode[disp_port].mode = mode;
- mxc_disp_mode[disp_port].num_modes += num_modes;
- mxc_disp_mode[disp_port].dev_mode = dev_mode;
-
- return;
-}
-EXPORT_SYMBOL(mxcfb_register_mode);
static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
{
@@ -196,11 +131,29 @@ static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
return pixfmt;
}
+static struct fb_info *found_registered_fb(ipu_channel_t ipu_ch, int ipu_id)
+{
+ int i;
+ struct mxcfb_info *mxc_fbi;
+ struct fb_info *fbi = NULL;
+
+ for (i = 0; i < num_registered_fb; i++) {
+ mxc_fbi =
+ ((struct mxcfb_info *)(registered_fb[i]->par));
+
+ if ((mxc_fbi->ipu_ch == ipu_ch) &&
+ (mxc_fbi->ipu_id == ipu_id)) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+ return fbi;
+}
+
static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id);
static int mxcfb_blank(int blank, struct fb_info *info);
static int mxcfb_map_video_memory(struct fb_info *fbi);
static int mxcfb_unmap_video_memory(struct fb_info *fbi);
-static int mxcfb_option_setup(struct fb_info *info, char *options);
/*
* Set fixed framebuffer parameters based on variable settings.
@@ -230,56 +183,23 @@ static int _setup_disp_channel1(struct fb_info *fbi)
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
memset(&params, 0, sizeof(params));
- params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
- /*
- * Assuming interlaced means yuv output, below setting also
- * valid for mem_dc_sync. FG should have the same vmode as BG.
- */
- if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
- struct mxcfb_info *mxc_fbi_tmp;
- int i;
-
- for (i = 0; i < num_registered_fb; i++) {
- mxc_fbi_tmp = (struct mxcfb_info *)
- (registered_fb[i]->par);
- if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) {
- fbi->var.vmode =
- registered_fb[i]->var.vmode;
- mxc_fbi->ipu_di_pix_fmt =
- mxc_fbi_tmp->ipu_di_pix_fmt;
- break;
- }
- }
- }
if (mxc_fbi->ipu_ch == MEM_DC_SYNC) {
- if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ params.mem_dc_sync.di = mxc_fbi->ipu_di;
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
params.mem_dc_sync.interlaced = true;
- params.mem_dc_sync.out_pixel_fmt =
- IPU_PIX_FMT_YUV444;
- } else {
- if (mxc_fbi->ipu_di_pix_fmt)
- params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
- else
- params.mem_dc_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
- }
+ params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
params.mem_dc_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
} else {
- if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
params.mem_dp_bg_sync.interlaced = true;
- params.mem_dp_bg_sync.out_pixel_fmt =
- IPU_PIX_FMT_YUV444;
- } else {
- if (mxc_fbi->ipu_di_pix_fmt)
- params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
- else
- params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
- }
+ params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
if (mxc_fbi->alpha_chan_en)
params.mem_dp_bg_sync.alpha_chan_en = true;
}
- ipu_init_channel(mxc_fbi->ipu_ch, &params);
+ ipu_init_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, &params);
return 0;
}
@@ -316,7 +236,8 @@ static int _setup_disp_channel2(struct fb_info *fbi)
base = (fbi->var.bits_per_pixel) * base / 8;
base += fbi->fix.smem_start;
- retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ retval = ipu_init_channel_buffer(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
bpp_to_pixfmt(fbi),
fbi->var.xres, fbi->var.yres,
fb_stride,
@@ -332,7 +253,8 @@ static int _setup_disp_channel2(struct fb_info *fbi)
}
if (mxc_fbi->alpha_chan_en) {
- retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch,
+ retval = ipu_init_channel_buffer(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
IPU_PIX_FMT_GENERIC,
fbi->var.xres, fbi->var.yres,
@@ -366,10 +288,10 @@ static int mxcfb_set_par(struct fb_info *fbi)
dev_dbg(fbi->device, "Reconfiguring framebuffer\n");
- ipu_disable_irq(mxc_fbi->ipu_ch_irq);
- ipu_disable_channel(mxc_fbi->ipu_ch, true);
- ipu_uninit_channel(mxc_fbi->ipu_ch);
- ipu_clear_irq(mxc_fbi->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_disable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
+ ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
mxcfb_set_fix(fbi);
mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
@@ -380,6 +302,7 @@ static int mxcfb_set_par(struct fb_info *fbi)
if (mxcfb_map_video_memory(fbi) < 0)
return -ENOMEM;
}
+
if (mxc_fbi->alpha_chan_en) {
alpha_mem_len = fbi->var.xres * fbi->var.yres;
if ((!mxc_fbi->alpha_phy_addr0 && !mxc_fbi->alpha_phy_addr1) ||
@@ -435,15 +358,9 @@ static int mxcfb_set_par(struct fb_info *fbi)
uint32_t out_pixel_fmt;
memset(&sig_cfg, 0, sizeof(sig_cfg));
- if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
sig_cfg.interlaced = true;
- out_pixel_fmt = IPU_PIX_FMT_YUV444;
- } else {
- if (mxc_fbi->ipu_di_pix_fmt)
- out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
- else
- out_pixel_fmt = IPU_PIX_FMT_RGB666;
- }
+ out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
sig_cfg.odd_field_first = true;
if (mxc_fbi->ipu_int_clk)
@@ -464,7 +381,7 @@ static int mxcfb_set_par(struct fb_info *fbi)
dev_dbg(fbi->device, "pixclock = %ul Hz\n",
(u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
- if (ipu_init_sync_panel(mxc_fbi->ipu_di,
+ if (ipu_init_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di,
(PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
fbi->var.xres, fbi->var.yres,
out_pixel_fmt,
@@ -484,29 +401,30 @@ static int mxcfb_set_par(struct fb_info *fbi)
(struct fb_videomode *)fb_match_mode(&fbi->var,
&fbi->modelist);
- ipu_disp_set_window_pos(mxc_fbi->ipu_ch, 0, 0);
+ ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, 0, 0);
}
retval = _setup_disp_channel2(fbi);
if (retval)
return retval;
- ipu_enable_channel(mxc_fbi->ipu_ch);
+ ipu_enable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
return retval;
}
-static int _swap_channels(struct fb_info *fbi,
+static int _swap_channels(struct fb_info *fbi_from,
struct fb_info *fbi_to, bool both_on)
{
int retval, tmp;
ipu_channel_t old_ch;
- struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par;
+ struct fb_info *ovfbi;
+ struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi_from->par;
struct mxcfb_info *mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;
if (both_on) {
- ipu_disable_channel(mxc_fbi_to->ipu_ch, true);
- ipu_uninit_channel(mxc_fbi_to->ipu_ch);
+ ipu_disable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch, true);
+ ipu_uninit_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
}
/* switch the mxc fbi parameters */
@@ -516,33 +434,36 @@ static int _swap_channels(struct fb_info *fbi,
tmp = mxc_fbi_from->ipu_ch_irq;
mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
mxc_fbi_to->ipu_ch_irq = tmp;
+ ovfbi = mxc_fbi_from->ovfbi;
+ mxc_fbi_from->ovfbi = mxc_fbi_to->ovfbi;
+ mxc_fbi_to->ovfbi = ovfbi;
- _setup_disp_channel1(fbi);
- retval = _setup_disp_channel2(fbi);
+ _setup_disp_channel1(fbi_from);
+ retval = _setup_disp_channel2(fbi_from);
if (retval)
return retval;
/* switch between dp and dc, disable old idmac, enable new idmac */
- retval = ipu_swap_channel(old_ch, mxc_fbi_from->ipu_ch);
- ipu_uninit_channel(old_ch);
+ retval = ipu_swap_channel(mxc_fbi_from->ipu, old_ch, mxc_fbi_from->ipu_ch);
+ ipu_uninit_channel(mxc_fbi_from->ipu, old_ch);
if (both_on) {
_setup_disp_channel1(fbi_to);
retval = _setup_disp_channel2(fbi_to);
if (retval)
return retval;
- ipu_enable_channel(mxc_fbi_to->ipu_ch);
+ ipu_enable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
}
return retval;
}
-static int swap_channels(struct fb_info *fbi)
+static int swap_channels(struct fb_info *fbi_from)
{
int i;
int swap_mode;
ipu_channel_t ch_to;
- struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par;
+ struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi_from->par;
struct fb_info *fbi_to = NULL;
struct mxcfb_info *mxc_fbi_to;
@@ -552,21 +473,15 @@ static int swap_channels(struct fb_info *fbi)
else
ch_to = MEM_BG_SYNC;
- for (i = 0; i < num_registered_fb; i++) {
- mxc_fbi_to =
- (struct mxcfb_info *)mxcfb_info[i]->par;
- if (mxc_fbi_to->ipu_ch == ch_to) {
- fbi_to = mxcfb_info[i];
- break;
- }
- }
- if (fbi_to == NULL)
+ fbi_to = found_registered_fb(ch_to, mxc_fbi_from->ipu_id);
+ if (!fbi_to)
return -1;
+ mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;
- ipu_clear_irq(mxc_fbi_from->ipu_ch_irq);
- ipu_clear_irq(mxc_fbi_to->ipu_ch_irq);
- ipu_free_irq(mxc_fbi_from->ipu_ch_irq, fbi);
- ipu_free_irq(mxc_fbi_to->ipu_ch_irq, fbi_to);
+ ipu_clear_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq);
+ ipu_free_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq, fbi_from);
+ ipu_free_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq, fbi_to);
if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) {
if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
@@ -580,31 +495,18 @@ static int swap_channels(struct fb_info *fbi)
swap_mode = BOTH_OFF;
}
- /* tvout di-1: for DC use UYVY, for DP use RGB */
- if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_DC_SYNC) {
- fbi->var.bits_per_pixel = 16;
- fbi->var.nonstd = IPU_PIX_FMT_UYVY;
- } else if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_BG_SYNC) {
- fbi->var.nonstd = 0;
- } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_DC_SYNC) {
- fbi_to->var.nonstd = 0;
- } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_BG_SYNC) {
- fbi->var.bits_per_pixel = 16;
- fbi->var.nonstd = IPU_PIX_FMT_UYVY;
- }
-
switch (swap_mode) {
case BOTH_ON:
/* disable target->switch src->enable target */
- _swap_channels(fbi, fbi_to, true);
+ _swap_channels(fbi_from, fbi_to, true);
break;
case SRC_ON:
/* just switch src */
- _swap_channels(fbi, fbi_to, false);
+ _swap_channels(fbi_from, fbi_to, false);
break;
case TGT_ON:
/* just switch target */
- _swap_channels(fbi_to, fbi, false);
+ _swap_channels(fbi_to, fbi_from, false);
break;
case BOTH_OFF:
/* switch directly, no more need to do */
@@ -618,20 +520,20 @@ static int swap_channels(struct fb_info *fbi)
break;
}
- if (ipu_request_irq(mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0,
- MXCFB_NAME, fbi) != 0) {
- dev_err(fbi->device, "Error registering irq %d\n",
+ if (ipu_request_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0,
+ MXCFB_NAME, fbi_from) != 0) {
+ dev_err(fbi_from->device, "Error registering irq %d\n",
mxc_fbi_from->ipu_ch_irq);
return -EBUSY;
}
- ipu_disable_irq(mxc_fbi_from->ipu_ch_irq);
- if (ipu_request_irq(mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0,
+ ipu_disable_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq);
+ if (ipu_request_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0,
MXCFB_NAME, fbi_to) != 0) {
dev_err(fbi_to->device, "Error registering irq %d\n",
mxc_fbi_to->ipu_ch_irq);
return -EBUSY;
}
- ipu_disable_irq(mxc_fbi_to->ipu_ch_irq);
+ ipu_disable_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq);
return 0;
}
@@ -652,25 +554,19 @@ static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
/* fg should not bigger than bg */
if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
struct fb_info *fbi_tmp;
- struct mxcfb_info *mxc_fbi_tmp;
- int i, bg_xres, bg_yres;
+ int bg_xres = 0, bg_yres = 0;
int16_t pos_x, pos_y;
bg_xres = var->xres;
bg_yres = var->yres;
- for (i = 0; i < num_registered_fb; i++) {
- fbi_tmp = registered_fb[i];
- mxc_fbi_tmp = (struct mxcfb_info *)
- (fbi_tmp->par);
- if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) {
- bg_xres = fbi_tmp->var.xres;
- bg_yres = fbi_tmp->var.yres;
- break;
- }
+ fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (fbi_tmp) {
+ bg_xres = fbi_tmp->var.xres;
+ bg_yres = fbi_tmp->var.yres;
}
- ipu_disp_get_window_pos(mxc_fbi->ipu_ch, &pos_x, &pos_y);
+ ipu_disp_get_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, &pos_x, &pos_y);
if ((var->xres + pos_x) > bg_xres)
var->xres = bg_xres - pos_x;
@@ -855,7 +751,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch,
+ if (ipu_disp_set_global_alpha(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
(bool)ga.enable,
ga.alpha)) {
retval = -EINVAL;
@@ -874,35 +771,36 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case MXCFB_SET_LOC_ALPHA:
{
struct mxcfb_loc_alpha la;
- int i;
- char *video_plane_idstr = "";
if (copy_from_user(&la, (void *)arg, sizeof(la))) {
retval = -EFAULT;
break;
}
- if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch,
+ if (ipu_disp_set_global_alpha(mxc_fbi->ipu, mxc_fbi->ipu_ch,
!(bool)la.enable, 0)) {
retval = -EINVAL;
break;
}
if (la.enable && !la.alpha_in_pixel) {
+ struct fb_info *fbi_tmp;
+ ipu_channel_t ipu_ch;
+
mxc_fbi->alpha_chan_en = true;
if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
- video_plane_idstr = "DISP3 BG";
+ ipu_ch = MEM_BG_SYNC;
else if (mxc_fbi->ipu_ch == MEM_BG_SYNC)
- video_plane_idstr = "DISP3 FG";
-
- for (i = 0; i < num_registered_fb; i++) {
- char *idstr = registered_fb[i]->fix.id;
- if (strcmp(idstr, video_plane_idstr) == 0) {
- ((struct mxcfb_info *)(registered_fb[i]->par))->alpha_chan_en = false;
- break;
- }
+ ipu_ch = MEM_FG_SYNC;
+ else {
+ retval = -EINVAL;
+ break;
}
+
+ fbi_tmp = found_registered_fb(ipu_ch, mxc_fbi->ipu_id);
+ if (fbi_tmp)
+ ((struct mxcfb_info *)(fbi_tmp->par))->alpha_chan_en = false;
} else
mxc_fbi->alpha_chan_en = false;
@@ -956,16 +854,16 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
mxc_fbi->cur_ipu_alpha_buf =
!mxc_fbi->cur_ipu_alpha_buf;
- if (ipu_update_channel_buffer(mxc_fbi->ipu_ch,
+ if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
mxc_fbi->
cur_ipu_alpha_buf,
base) == 0) {
- ipu_select_buffer(mxc_fbi->ipu_ch,
+ ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
mxc_fbi->cur_ipu_alpha_buf);
- ipu_clear_irq(ipu_alp_ch_irq);
- ipu_enable_irq(ipu_alp_ch_irq);
+ ipu_clear_irq(mxc_fbi->ipu, ipu_alp_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, ipu_alp_ch_irq);
} else {
dev_err(fbi->device,
"Error updating %s SDC alpha buf %d "
@@ -982,7 +880,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- retval = ipu_disp_set_color_key(mxc_fbi->ipu_ch,
+ retval = ipu_disp_set_color_key(mxc_fbi->ipu, mxc_fbi->ipu_ch,
key.enable,
key.color_key);
dev_dbg(fbi->device, "Set color key to 0x%08X\n",
@@ -996,7 +894,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu_ch,
+ retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
gamma.enable,
gamma.constk,
gamma.slopek);
@@ -1005,14 +904,17 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case MXCFB_WAIT_FOR_VSYNC:
{
if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
+ /* BG should poweron */
struct mxcfb_info *bg_mxcfbi = NULL;
- int i;
- for (i = 0; i < num_registered_fb; i++) {
- bg_mxcfbi =
- ((struct mxcfb_info *)(registered_fb[i]->par));
+ struct fb_info *fbi_tmp;
+
+ fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (fbi_tmp)
+ bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
- if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC)
- break;
+ if (!bg_mxcfbi) {
+ retval = -EINVAL;
+ break;
}
if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK) {
retval = -EINVAL;
@@ -1026,9 +928,9 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
init_completion(&mxc_fbi->vsync_complete);
- ipu_clear_irq(mxc_fbi->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
mxc_fbi->wait4vsync = 1;
- ipu_enable_irq(mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
retval = wait_for_completion_interruptible_timeout(
&mxc_fbi->vsync_complete, 1 * HZ);
if (retval == 0) {
@@ -1103,7 +1005,6 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct mxcfb_pos pos;
struct fb_info *bg_fbi = NULL;
struct mxcfb_info *bg_mxcfbi = NULL;
- int i;
if (mxc_fbi->ipu_ch != MEM_FG_SYNC) {
dev_err(fbi->device, "Should use the overlay "
@@ -1118,15 +1019,9 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- for (i = 0; i < num_registered_fb; i++) {
- bg_mxcfbi =
- ((struct mxcfb_info *)(registered_fb[i]->par));
-
- if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC) {
- bg_fbi = registered_fb[i];
- break;
- }
- }
+ bg_fbi = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (bg_fbi)
+ bg_mxcfbi = ((struct mxcfb_info *)(bg_fbi->par));
if (bg_fbi == NULL) {
dev_err(fbi->device, "Cannot find the "
@@ -1148,7 +1043,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
pos.y = bg_fbi->var.yres - fbi->var.yres;
}
- retval = ipu_disp_set_window_pos(mxc_fbi->ipu_ch,
+ retval = ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch,
pos.x, pos.y);
if (copy_to_user((void *)arg, &pos, sizeof(pos))) {
@@ -1229,9 +1124,10 @@ static int mxcfb_blank(int blank, struct fb_info *info)
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_NORMAL:
- ipu_disable_channel(mxc_fbi->ipu_ch, true);
- ipu_uninit_sync_panel(mxc_fbi->ipu_di);
- ipu_uninit_channel(mxc_fbi->ipu_ch);
+ ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
+ if (mxc_fbi->ipu_di >= 0)
+ ipu_uninit_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di);
+ ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
break;
case FB_BLANK_UNBLANK:
mxcfb_set_par(info);
@@ -1257,7 +1153,7 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
u_int y_bottom;
unsigned long base, active_alpha_phy_addr = 0;
bool loc_alpha_en = false;
- int i = 0;
+ int i;
if (info->var.yoffset == var->yoffset)
return 0; /* No change, do nothing */
@@ -1265,14 +1161,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
/* no pan display during fb blank */
if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
struct mxcfb_info *bg_mxcfbi = NULL;
- int j;
- for (j = 0; j < num_registered_fb; j++) {
- bg_mxcfbi =
- ((struct mxcfb_info *)(registered_fb[j]->par));
+ struct fb_info *fbi_tmp;
- if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC)
- break;
- }
+ fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (fbi_tmp)
+ bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
+ if (!bg_mxcfbi)
+ return -EINVAL;
if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK)
return -EINVAL;
}
@@ -1294,9 +1189,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
/* Check if DP local alpha is enabled and find the graphic fb */
if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) {
for (i = 0; i < num_registered_fb; i++) {
+ char *bg_id = "DISP3 BG";
+ char *fg_id = "DISP3 FG";
char *idstr = registered_fb[i]->fix.id;
- if ((strcmp(idstr, "DISP3 BG") == 0 ||
- strcmp(idstr, "DISP3 FG") == 0) &&
+ bg_id[4] += mxc_fbi->ipu_id;
+ fg_id[4] += mxc_fbi->ipu_id;
+ if ((strcmp(idstr, bg_id) == 0 ||
+ strcmp(idstr, fg_id) == 0) &&
((struct mxcfb_info *)
(registered_fb[i]->par))->alpha_chan_en) {
loc_alpha_en = true;
@@ -1323,41 +1222,41 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
info->fix.id, mxc_fbi->cur_ipu_buf, base);
- if (ipu_update_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
mxc_fbi->cur_ipu_buf, base) == 0) {
/* Update the DP local alpha buffer only for graphic plane */
if (loc_alpha_en && mxc_graphic_fbi == mxc_fbi &&
- ipu_update_channel_buffer(mxc_graphic_fbi->ipu_ch,
+ ipu_update_channel_buffer(mxc_graphic_fbi->ipu, mxc_graphic_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
mxc_fbi->cur_ipu_alpha_buf,
active_alpha_phy_addr) == 0) {
- ipu_select_buffer(mxc_graphic_fbi->ipu_ch,
+ ipu_select_buffer(mxc_graphic_fbi->ipu, mxc_graphic_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
mxc_fbi->cur_ipu_alpha_buf);
}
- ipu_select_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
mxc_fbi->cur_ipu_buf);
- ipu_clear_irq(mxc_fbi->ipu_ch_irq);
- ipu_enable_irq(mxc_fbi->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
} else {
dev_err(info->device,
"Error updating SDC buf %d to address=0x%08lX, "
"current buf %d, buf0 ready %d, buf1 ready %d, "
"buf2 ready %d\n", mxc_fbi->cur_ipu_buf, base,
- ipu_get_cur_buffer_idx(mxc_fbi->ipu_ch,
+ ipu_get_cur_buffer_idx(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_INPUT_BUFFER),
- ipu_check_buffer_ready(mxc_fbi->ipu_ch,
+ ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_INPUT_BUFFER, 0),
- ipu_check_buffer_ready(mxc_fbi->ipu_ch,
+ ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_INPUT_BUFFER, 1),
- ipu_check_buffer_ready(mxc_fbi->ipu_ch,
+ ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
IPU_INPUT_BUFFER, 2));
mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3;
mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3;
mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
- ipu_clear_irq(mxc_fbi->ipu_ch_irq);
- ipu_enable_irq(mxc_fbi->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
return -EBUSY;
}
@@ -1448,11 +1347,11 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
if (mxc_fbi->wait4vsync) {
complete(&mxc_fbi->vsync_complete);
- ipu_disable_irq(irq);
+ ipu_disable_irq(mxc_fbi->ipu, irq);
mxc_fbi->wait4vsync = 0;
} else {
up(&mxc_fbi->flip_sem);
- ipu_disable_irq(irq);
+ ipu_disable_irq(mxc_fbi->ipu, irq);
}
return IRQ_HANDLED;
}
@@ -1463,7 +1362,7 @@ static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
struct mxcfb_info *mxc_fbi = fbi->par;
up(&mxc_fbi->alpha_flip_sem);
- ipu_disable_irq(irq);
+ ipu_disable_irq(mxc_fbi->ipu, irq);
return IRQ_HANDLED;
}
@@ -1479,6 +1378,18 @@ static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
void *fbmem;
#endif
+ if (mxc_fbi->ovfbi) {
+ struct mxcfb_info *mxc_fbi_fg =
+ (struct mxcfb_info *)mxc_fbi->ovfbi->par;
+
+ console_lock();
+ fb_set_suspend(mxc_fbi->ovfbi, 1);
+ saved_blank = mxc_fbi_fg->cur_blank;
+ mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
+ mxc_fbi_fg->next_blank = saved_blank;
+ console_unlock();
+ }
+
console_lock();
fb_set_suspend(fbi, 1);
saved_blank = mxc_fbi->cur_blank;
@@ -1502,6 +1413,15 @@ static int mxcfb_resume(struct platform_device *pdev)
fb_set_suspend(fbi, 0);
console_unlock();
+ if (mxc_fbi->ovfbi) {
+ struct mxcfb_info *mxc_fbi_fg =
+ (struct mxcfb_info *)mxc_fbi->ovfbi->par;
+ console_lock();
+ mxcfb_blank(mxc_fbi_fg->next_blank, mxc_fbi->ovfbi);
+ fb_set_suspend(mxc_fbi->ovfbi, 0);
+ console_unlock();
+ }
+
return 0;
}
@@ -1631,16 +1551,12 @@ static ssize_t swap_disp_chan(struct device *dev,
(strstr(buf, "1-layer-fb") != NULL)) ||
((mxcfbi->ipu_ch == MEM_DC_SYNC) &&
(strstr(buf, "2-layer-fb-bg") != NULL))) {
- int i;
+ struct fb_info *fbi_fg;
+
+ fbi_fg = found_registered_fb(MEM_FG_SYNC, mxcfbi->ipu_id);
+ if (fbi_fg)
+ fg_mxcfbi = (struct mxcfb_info *)fbi_fg->par;
- for (i = 0; i < num_registered_fb; i++) {
- fg_mxcfbi =
- (struct mxcfb_info *)mxcfb_info[i]->par;
- if (fg_mxcfbi->ipu_ch == MEM_FG_SYNC)
- break;
- else
- fg_mxcfbi = NULL;
- }
if (!fg_mxcfbi ||
fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {
dev_err(dev,
@@ -1658,151 +1574,183 @@ static ssize_t swap_disp_chan(struct device *dev,
}
DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan);
-static int mxcfb_setup(struct fb_info *fbi, struct platform_device *pdev)
+static int mxcfb_dispdrv_init(struct platform_device *pdev,
+ struct fb_info *fbi)
{
- struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
+ struct mxc_dispdrv_setting setting;
+ char disp_dev[32], *default_dev = "lcd";
int ret = 0;
- /* Need dummy values until real panel is configured */
- fbi->var.xres = 240;
- fbi->var.yres = 320;
-
- if (!mxcfbi->default_bpp)
- mxcfbi->default_bpp = 16;
-
- if (plat_data && !mxcfbi->ipu_di_pix_fmt)
- mxcfbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
-
- if (!mxcfbi->fb_mode_str && plat_data && plat_data->mode_str)
- mxcfbi->fb_mode_str = plat_data->mode_str;
-
- if (mxcfbi->fb_mode_str) {
- if (mxcfbi->ipu_di >= 0) {
- const struct fb_videomode *mode = NULL;
- struct fb_videomode m;
- int num = 0, found = 0;
-
- dev_dbg(fbi->device, "Config display port %d\n",
- mxcfbi->ipu_di);
-
- INIT_LIST_HEAD(&fbi->modelist);
-
- if (mxc_disp_mode[mxcfbi->ipu_di].num_modes) {
- int i;
- mode = mxc_disp_mode[mxcfbi->ipu_di].mode;
- num = mxc_disp_mode[mxcfbi->ipu_di].num_modes;
-
- for (i = 0; i < num; i++) {
- /*
- * FIXME now we do not support interlaced
- * mode for ddc mode
- */
- if ((mxc_disp_mode[mxcfbi->ipu_di].dev_mode
- & MXC_DISP_DDC_DEV) &&
- (mode[i].vmode & FB_VMODE_INTERLACED))
- continue;
- else
- fb_add_videomode(&mode[i], &fbi->modelist);
- }
- }
+ setting.if_fmt = plat_data->interface_pix_fmt;
+ setting.dft_mode_str = plat_data->mode_str;
+ setting.default_bpp = plat_data->default_bpp;
+ if (!setting.default_bpp)
+ setting.default_bpp = 16;
+ setting.fbi = fbi;
+ if (!strlen(plat_data->disp_dev)) {
+ memcpy(disp_dev, default_dev, strlen(default_dev));
+ disp_dev[strlen(default_dev)] = '\0';
+ } else {
+ memcpy(disp_dev, plat_data->disp_dev,
+ strlen(plat_data->disp_dev));
+ disp_dev[strlen(plat_data->disp_dev)] = '\0';
+ }
- if ((mxc_disp_mode[mxcfbi->ipu_di].dev_mode
- & MXC_DISP_DDC_DEV) &&
- !list_empty(&fbi->modelist)) {
- dev_dbg(fbi->device,
- "Look for video mode %s in ddc modelist\n",
- mxcfbi->fb_mode_str);
- /*
- * For DDC mode, try to get compatible mode first.
- * If get one, try to find nearest mode, otherwise,
- * use first mode provide by DDC.
- */
- ret = fb_find_mode(&fbi->var, fbi,
- mxcfbi->fb_mode_str, NULL, 0,
- NULL, mxcfbi->default_bpp);
- if (ret) {
- fb_var_to_videomode(&m, &fbi->var);
- mode = fb_find_nearest_mode(&m,
- &fbi->modelist);
- fb_videomode_to_var(&fbi->var, mode);
- } else {
- struct list_head *pos, *head;
- struct fb_modelist *modelist;
-
- head = &fbi->modelist;
- list_for_each(pos, head) {
- modelist = list_entry(pos,
- struct fb_modelist, list);
- m = modelist->mode;
- if (m.flag & FB_MODE_IS_FIRST)
- break;
- }
- /* if no first mode, use last one */
- mode = &m;
- fb_videomode_to_var(&fbi->var, mode);
- }
- found = 1;
- } else if (!list_empty(&fbi->modelist)) {
- dev_dbg(fbi->device,
- "Look for video mode %s in spec modelist\n",
- mxcfbi->fb_mode_str);
- /*
- * For specific mode, try to get specified mode
- * from fbi modelist.
- */
- ret = fb_find_mode(&fbi->var, fbi,
- mxcfbi->fb_mode_str, mode, num,
- NULL, mxcfbi->default_bpp);
- if (ret == 1)
- found = 1;
+ dev_info(&pdev->dev, "register mxc display driver %s\n", disp_dev);
+
+ ret = mxc_dispdrv_init(disp_dev, &setting);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "register mxc display driver failed with %d\n", ret);
+ } else {
+ /* fix-up */
+ mxcfbi->ipu_di_pix_fmt = setting.if_fmt;
+ mxcfbi->default_bpp = setting.default_bpp;
+
+ /* setting */
+ mxcfbi->ipu_id = setting.dev_id;
+ mxcfbi->ipu_di = setting.disp_id;
+ }
+
+ return ret;
+}
+
+/*
+ * Parse user specified options (`video=trident:')
+ * example:
+ * video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,bpp=16,noaccel
+ */
+static int mxcfb_option_setup(struct platform_device *pdev)
+{
+ struct ipuv3_fb_platform_data *pdata = pdev->dev.platform_data;
+ char *options, *opt, *fb_mode_str = NULL;
+ char name[] = "mxcfb0";
+
+ name[5] += pdev->id;
+ fb_get_options(name, &options);
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "dev=", 4)) {
+ memcpy(pdata->disp_dev, opt + 4, strlen(opt) - 4);
+ continue;
+ }
+ if (!strncmp(opt, "if=", 3)) {
+ if (!strncmp(opt+3, "RGB24", 5)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB24;
+ continue;
+ } else if (!strncmp(opt+6, "BGR24", 5)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_BGR24;
+ continue;
}
- /*
- * if no DDC mode and spec mode found,
- * try plat_data mode.
- */
- if (!found) {
- dev_dbg(fbi->device,
- "Look for video mode %s in plat modelist\n",
- mxcfbi->fb_mode_str);
- if (plat_data && plat_data->modes
- && plat_data->num_modes)
- ret = fb_find_mode(&fbi->var, fbi,
- mxcfbi->fb_mode_str,
- plat_data->modes,
- plat_data->num_modes,
- NULL,
- mxcfbi->default_bpp);
- else
- ret = fb_find_mode(&fbi->var, fbi,
- mxcfbi->fb_mode_str, NULL, 0,
- NULL, mxcfbi->default_bpp);
- if (ret)
- found = 1;
+ if (!strncmp(opt+3, "GBR24", 5)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_GBR24;
+ continue;
}
-
- if (!found) {
- dev_err(fbi->device,
- "Not found any valid video mode");
- ret = -EINVAL;
- goto done;
+ if (!strncmp(opt+3, "RGB565", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB565;
+ continue;
+ }
+ if (!strncmp(opt+3, "RGB666", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB666;
+ continue;
+ }
+ if (!strncmp(opt+3, "YUV444", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YUV444;
+ continue;
+ }
+ if (!strncmp(opt+3, "LVDS666", 7)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
+ continue;
+ }
+ if (!strncmp(opt+3, "YUYV16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YUYV;
+ continue;
+ }
+ if (!strncmp(opt+3, "UYVY16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_UYVY;
+ continue;
+ }
+ if (!strncmp(opt+3, "YVYU16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YVYU;
+ continue;
+ }
+ if (!strncmp(opt+3, "VYUY16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_VYUY;
+ continue;
}
-
- /*added found mode to fbi modelist*/
- fb_var_to_videomode(&m, &fbi->var);
- fb_add_videomode(&m, &fbi->modelist);
}
+ if (!strncmp(opt, "int_clk", 7)) {
+ pdata->int_clk = true;
+ continue;
+ }
+ if (!strncmp(opt, "bpp=", 4))
+ pdata->default_bpp =
+ simple_strtoul(opt + 4, NULL, 0);
+ else
+ fb_mode_str = opt;
+ }
+
+ if (fb_mode_str)
+ pdata->mode_str = fb_mode_str;
+
+ return 0;
+}
+
+static int mxcfb_register(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
+ struct fb_videomode m;
+ int ret = 0;
+ char bg0_id[] = "DISP3 BG";
+ char bg1_id[] = "DISP3 BG - DI1";
+ char fg_id[] = "DISP3 FG";
+
+ if (mxcfbi->ipu_di == 0) {
+ bg0_id[4] += mxcfbi->ipu_id;
+ strcpy(fbi->fix.id, bg0_id);
+ } else if (mxcfbi->ipu_di == 1) {
+ bg1_id[4] += mxcfbi->ipu_id;
+ strcpy(fbi->fix.id, bg1_id);
+ } else { /* Overlay */
+ fg_id[4] += mxcfbi->ipu_id;
+ strcpy(fbi->fix.id, fg_id);
}
+ if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, mxcfb_irq_handler, 0,
+ MXCFB_NAME, fbi) != 0) {
+ dev_err(fbi->device, "Error registering BG irq handler.\n");
+ ret = -EBUSY;
+ goto err0;
+ }
+ ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq);
+
+ if (mxcfbi->ipu_alp_ch_irq != -1)
+ if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq,
+ mxcfb_alpha_irq_handler, 0,
+ MXCFB_NAME, fbi) != 0) {
+ dev_err(fbi->device, "Error registering alpha irq "
+ "handler.\n");
+ ret = -EBUSY;
+ goto err1;
+ }
+
mxcfb_check_var(&fbi->var, fbi);
mxcfb_set_fix(fbi);
- /* setup display */
- if (mxcfbi->ipu_di >= 0)
- if (mxcfb_pre_setup[mxcfbi->ipu_di])
- (mxcfb_pre_setup[mxcfbi->ipu_di])(fbi);
+ /*added first mode to fbi modelist*/
+ if (!fbi->modelist.next || !fbi->modelist.prev)
+ INIT_LIST_HEAD(&fbi->modelist);
+ fb_var_to_videomode(&m, &fbi->var);
+ fb_add_videomode(&m, &fbi->modelist);
fbi->var.activate |= FB_ACTIVATE_FORCE;
console_lock();
@@ -1810,10 +1758,109 @@ static int mxcfb_setup(struct fb_info *fbi, struct platform_device *pdev)
ret = fb_set_var(fbi, &fbi->var);
fbi->flags &= ~FBINFO_MISC_USEREVENT;
console_unlock();
-done:
+
+ ret = register_framebuffer(fbi);
+ if (ret < 0)
+ goto err2;
+
+ return ret;
+err2:
+ if (mxcfbi->ipu_alp_ch_irq != -1)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
+err1:
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
+err0:
return ret;
}
+static void mxcfb_unregister(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
+
+ if (mxcfbi->ipu_alp_ch_irq != -1)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
+ if (mxcfbi->ipu_ch_irq)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
+
+ unregister_framebuffer(fbi);
+}
+
+static int mxcfb_setup_overlay(struct platform_device *pdev,
+ struct fb_info *fbi_bg)
+{
+ struct fb_info *ovfbi;
+ struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
+ struct mxcfb_info *mxcfbi_fg;
+ int ret = 0;
+
+ ovfbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
+ if (!ovfbi) {
+ ret = -ENOMEM;
+ goto init_ovfbinfo_failed;
+ }
+ mxcfbi_fg = (struct mxcfb_info *)ovfbi->par;
+
+ mxcfbi_fg->ipu = ipu_get_soc(mxcfbi_bg->ipu_id);
+ if (IS_ERR(mxcfbi_fg->ipu)) {
+ ret = -ENODEV;
+ goto get_ipu_failed;
+ }
+ mxcfbi_fg->ipu_id = mxcfbi_bg->ipu_id;
+ mxcfbi_fg->ipu_ch_irq = IPU_IRQ_FG_SYNC_EOF;
+ mxcfbi_fg->ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
+ mxcfbi_fg->ipu_ch = MEM_FG_SYNC;
+ mxcfbi_fg->ipu_di = -1;
+ mxcfbi_fg->ipu_di_pix_fmt = mxcfbi_bg->ipu_di_pix_fmt;
+ mxcfbi_fg->overlay = true;
+ mxcfbi_fg->cur_blank = mxcfbi_fg->next_blank = FB_BLANK_POWERDOWN;
+
+ /* Need dummy values until real panel is configured */
+ ovfbi->var.xres = 240;
+ ovfbi->var.yres = 320;
+
+ ret = mxcfb_register(ovfbi);
+ if (ret < 0)
+ goto register_ov_failed;
+
+ mxcfbi_bg->ovfbi = ovfbi;
+
+ return ret;
+
+register_ov_failed:
+get_ipu_failed:
+ fb_dealloc_cmap(&ovfbi->cmap);
+ framebuffer_release(ovfbi);
+init_ovfbinfo_failed:
+ return ret;
+}
+
+static void mxcfb_unsetup_overlay(struct fb_info *fbi_bg)
+{
+ struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
+ struct fb_info *ovfbi = mxcfbi_bg->ovfbi;
+
+ mxcfb_unregister(ovfbi);
+
+ if (&ovfbi->cmap)
+ fb_dealloc_cmap(&ovfbi->cmap);
+ framebuffer_release(ovfbi);
+}
+
+static bool ipu_usage[2][2];
+static int ipu_test_set_usage(int ipu, int di)
+{
+ if (ipu_usage[ipu][di])
+ return -EBUSY;
+ else
+ ipu_usage[ipu][di] = true;
+ return 0;
+}
+
+static void ipu_clear_usage(int ipu, int di)
+{
+ ipu_usage[ipu][di] = false;
+}
+
/*!
* Probe routine for the framebuffer driver. It is called during the
* driver binding process. The following functions are performed in
@@ -1824,11 +1871,10 @@ done:
*/
static int mxcfb_probe(struct platform_device *pdev)
{
+ struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
struct fb_info *fbi;
struct mxcfb_info *mxcfbi;
struct resource *res;
- char *options;
- char name[] = "mxcdi0fb";
int ret = 0;
/*
@@ -1837,91 +1883,68 @@ static int mxcfb_probe(struct platform_device *pdev)
fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
if (!fbi) {
ret = -ENOMEM;
- goto err0;
+ goto init_fbinfo_failed;
}
+
+ mxcfb_option_setup(pdev);
+
mxcfbi = (struct mxcfb_info *)fbi->par;
+ mxcfbi->ipu_int_clk = plat_data->int_clk;
+ ret = mxcfb_dispdrv_init(pdev, fbi);
+ if (ret < 0)
+ goto init_dispdrv_failed;
- name[5] += pdev->id;
- if (fb_get_options(name, &options)) {
- ret = -ENODEV;
- goto err1;
+ ret = ipu_test_set_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "ipu%d-di%d already in use\n",
+ mxcfbi->ipu_id, mxcfbi->ipu_di);
+ goto ipu_in_busy;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res && res->end) {
+ fbi->fix.smem_len = res->end - res->start + 1;
+ fbi->fix.smem_start = res->start;
+ fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
}
- if (options)
- mxcfb_option_setup(fbi, options);
+ mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);
+ if (IS_ERR(mxcfbi->ipu)) {
+ ret = -ENODEV;
+ goto get_ipu_failed;
+ }
- if (!g_dp_in_use) {
+ /* first user uses DP with alpha feature */
+ if (!g_dp_in_use[mxcfbi->ipu_id]) {
mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF;
+ mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
mxcfbi->ipu_ch = MEM_BG_SYNC;
mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;
- } else {
- mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;
- mxcfbi->ipu_ch = MEM_DC_SYNC;
- mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
- }
-
- mxcfbi->ipu_di = pdev->id;
- mxcfbi->ipu_alp_ch_irq = -1;
-
- if (pdev->id == 0) {
- ipu_disp_set_global_alpha(mxcfbi->ipu_ch, true, 0x80);
- ipu_disp_set_color_key(mxcfbi->ipu_ch, false, 0);
- strcpy(fbi->fix.id, "DISP3 BG");
-
- if (!g_dp_in_use)
- mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
- g_dp_in_use = true;
- } else if (pdev->id == 1) {
- strcpy(fbi->fix.id, "DISP3 BG - DI1");
-
- if (!g_dp_in_use)
- mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
- g_dp_in_use = true;
- } else if (pdev->id == 2) { /* Overlay */
- mxcfbi->ipu_ch_irq = IPU_IRQ_FG_SYNC_EOF;
- mxcfbi->ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
- mxcfbi->ipu_ch = MEM_FG_SYNC;
- mxcfbi->ipu_di = -1;
- mxcfbi->overlay = true;
- mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
-
- strcpy(fbi->fix.id, "DISP3 FG");
- }
- mxcfb_info[pdev->id] = fbi;
+ ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch, true, 0x80);
+ ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);
- if (ipu_request_irq(mxcfbi->ipu_ch_irq, mxcfb_irq_handler, 0,
- MXCFB_NAME, fbi) != 0) {
- dev_err(&pdev->dev, "Error registering BG irq handler.\n");
- ret = -EBUSY;
- goto err1;
- }
- ipu_disable_irq(mxcfbi->ipu_ch_irq);
+ ret = mxcfb_register(fbi);
+ if (ret < 0)
+ goto mxcfb_register_failed;
- if (mxcfbi->ipu_alp_ch_irq != -1)
- if (ipu_request_irq(mxcfbi->ipu_alp_ch_irq,
- mxcfb_alpha_irq_handler, 0,
- MXCFB_NAME, fbi) != 0) {
- dev_err(&pdev->dev, "Error registering alpha irq "
- "handler.\n");
- ret = -EBUSY;
- goto err2;
+ ret = mxcfb_setup_overlay(pdev, fbi);
+ if (ret < 0) {
+ mxcfb_unregister(fbi);
+ goto mxcfb_setupoverlay_failed;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res && res->end) {
- fbi->fix.smem_len = res->end - res->start + 1;
- fbi->fix.smem_start = res->start;
- fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
- }
-
- ret = mxcfb_setup(fbi, pdev);
- if (ret < 0)
- goto err3;
+ g_dp_in_use[mxcfbi->ipu_id] = true;
+ } else {
+ mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;
+ mxcfbi->ipu_alp_ch_irq = -1;
+ mxcfbi->ipu_ch = MEM_DC_SYNC;
+ mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
- ret = register_framebuffer(fbi);
- if (ret < 0)
- goto err3;
+ ret = mxcfb_register(fbi);
+ if (ret < 0)
+ goto mxcfb_register_failed;
+ }
platform_set_drvdata(pdev, fbi);
@@ -1935,15 +1958,16 @@ static int mxcfb_probe(struct platform_device *pdev)
#endif
return 0;
-err3:
- if (mxcfbi->ipu_alp_ch_irq != -1)
- ipu_free_irq(mxcfbi->ipu_alp_ch_irq, fbi);
-err2:
- ipu_free_irq(mxcfbi->ipu_ch_irq, fbi);
-err1:
+
+mxcfb_setupoverlay_failed:
+mxcfb_register_failed:
+get_ipu_failed:
+ ipu_clear_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
+ipu_in_busy:
+init_dispdrv_failed:
fb_dealloc_cmap(&fbi->cmap);
framebuffer_release(fbi);
-err0:
+init_fbinfo_failed:
return ret;
}
@@ -1956,13 +1980,18 @@ static int mxcfb_remove(struct platform_device *pdev)
return 0;
mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
- ipu_free_irq(mxc_fbi->ipu_ch_irq, fbi);
+ mxcfb_unregister(fbi);
mxcfb_unmap_video_memory(fbi);
+ if (mxc_fbi->ovfbi) {
+ mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
+ mxcfb_unsetup_overlay(fbi);
+ mxcfb_unmap_video_memory(mxc_fbi->ovfbi);
+ }
+
+ ipu_clear_usage(mxc_fbi->ipu_id, mxc_fbi->ipu_di);
if (&fbi->cmap)
fb_dealloc_cmap(&fbi->cmap);
-
- unregister_framebuffer(fbi);
framebuffer_release(fbi);
return 0;
}
@@ -1980,81 +2009,6 @@ static struct platform_driver mxcfb_driver = {
.resume = mxcfb_resume,
};
-/*
- * Parse user specified options (`video=trident:')
- * example:
- * video=mxcdi0fb:RGB24, 1024x768M-16@60,bpp=16,noaccel
- */
-static int mxcfb_option_setup(struct fb_info *info, char *options)
-{
- struct mxcfb_info *mxcfbi = info->par;
- char *opt;
-
- if (!options || !*options)
- return 0;
-
- while ((opt = strsep(&options, ",")) != NULL) {
- if (!*opt)
- continue;
-
- if (!strncmp(opt, "RGB24", 5)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB24;
- continue;
- }
- if (!strncmp(opt, "BGR24", 5)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_BGR24;
- continue;
- }
- if (!strncmp(opt, "GBR24", 5)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_GBR24;
- continue;
- }
- if (!strncmp(opt, "RGB565", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB565;
- continue;
- }
- if (!strncmp(opt, "RGB666", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB666;
- continue;
- }
- if (!strncmp(opt, "YUV444", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YUV444;
- continue;
- }
- if (!strncmp(opt, "LVDS666", 7)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_LVDS666;
- continue;
- }
- if (!strncmp(opt, "YUYV16", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YUYV;
- continue;
- }
- if (!strncmp(opt, "UYVY16", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_UYVY;
- continue;
- }
- if (!strncmp(opt, "YVYU16", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YVYU;
- continue;
- }
- if (!strncmp(opt, "VYUY16", 6)) {
- mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_VYUY;
- continue;
- }
- if (!strncmp(opt, "int_clk", 7)) {
- mxcfbi->ipu_int_clk = true;
- continue;
- }
- if (!strncmp(opt, "bpp=", 4))
- mxcfbi->default_bpp =
- simple_strtoul(opt + 4, NULL, 0);
- else
- mxcfbi->fb_mode_str = opt;
- }
-
- return 0;
-}
-
/*!
* Main entry function for the framebuffer. The function registers the power
* management callback functions with the kernel and also registers the MXCFB
diff --git a/drivers/video/mxc/mxc_lcdif.c b/drivers/video/mxc/mxc_lcdif.c
new file mode 100644
index 000000000000..d9d7fa306a83
--- /dev/null
+++ b/drivers/video/mxc/mxc_lcdif.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mxcfb.h>
+#include <linux/fsl_devices.h>
+#include "mxc_dispdrv.h"
+
+struct mxc_lcdif_data {
+ struct platform_device *pdev;
+ struct mxc_dispdrv_entry *disp_lcdif;
+};
+
+#define DISPDRV_LCD "lcd"
+
+static struct fb_videomode lcdif_modedb[] = {
+ {
+ /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
+ "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+ {
+ /* 800x480 @ 60 Hz , pixel clk @ 32MHz */
+ "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+};
+static int lcdif_modedb_sz = ARRAY_SIZE(lcdif_modedb);
+
+static int lcdif_init(struct mxc_dispdrv_entry *disp)
+{
+ int ret, i;
+ struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp);
+ struct mxc_dispdrv_setting *setting = mxc_dispdrv_getsetting(disp);
+ struct fsl_mxc_lcd_platform_data *plat_data
+ = lcdif->pdev->dev.platform_data;
+ struct fb_videomode *modedb = lcdif_modedb;
+ int modedb_sz = lcdif_modedb_sz;
+
+ /* use platform defined ipu/di */
+ setting->dev_id = plat_data->ipu_id;
+ setting->disp_id = plat_data->disp_id;
+
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ modedb, modedb_sz, NULL, setting->default_bpp);
+ if (!ret) {
+ fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
+ setting->if_fmt = plat_data->default_ifmt;
+ }
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < modedb_sz; i++) {
+ struct fb_videomode m;
+ fb_var_to_videomode(&m, &setting->fbi->var);
+ if (fb_mode_is_equal(&m, &modedb[i])) {
+ fb_add_videomode(&modedb[i],
+ &setting->fbi->modelist);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void lcdif_deinit(struct mxc_dispdrv_entry *disp)
+{
+ /*TODO*/
+}
+
+static struct mxc_dispdrv_driver lcdif_drv = {
+ .name = DISPDRV_LCD,
+ .init = lcdif_init,
+ .deinit = lcdif_deinit,
+};
+
+static int mxc_lcdif_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mxc_lcdif_data *lcdif;
+
+ lcdif = kzalloc(sizeof(struct mxc_lcdif_data), GFP_KERNEL);
+ if (!lcdif) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ lcdif->pdev = pdev;
+ lcdif->disp_lcdif = mxc_dispdrv_register(&lcdif_drv);
+ mxc_dispdrv_setdata(lcdif->disp_lcdif, lcdif);
+
+ dev_set_drvdata(&pdev->dev, lcdif);
+
+alloc_failed:
+ return ret;
+}
+
+static int mxc_lcdif_remove(struct platform_device *pdev)
+{
+ struct mxc_lcdif_data *lcdif = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_unregister(lcdif->disp_lcdif);
+ kfree(lcdif);
+ return 0;
+}
+
+static struct platform_driver mxc_lcdif_driver = {
+ .driver = {
+ .name = "mxc_lcdif",
+ },
+ .probe = mxc_lcdif_probe,
+ .remove = mxc_lcdif_remove,
+};
+
+static int __init mxc_lcdif_init(void)
+{
+ return platform_driver_register(&mxc_lcdif_driver);
+}
+
+static void __exit mxc_lcdif_exit(void)
+{
+ platform_driver_unregister(&mxc_lcdif_driver);
+}
+
+module_init(mxc_lcdif_init);
+module_exit(mxc_lcdif_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX ipuv3 LCD extern port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mxc/tve.c b/drivers/video/mxc/tve.c
index 8e01f0531e98..04d380bd226f 100644
--- a/drivers/video/mxc/tve.c
+++ b/drivers/video/mxc/tve.c
@@ -38,6 +38,7 @@
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <mach/hardware.h>
+#include "mxc_dispdrv.h"
#define TVE_ENABLE (1UL)
#define TVE_DAC_FULL_RATE (0UL<<1)
@@ -98,16 +99,8 @@
#define TVOUT_FMT_VGA_SXGA 12
#define TVOUT_FMT_VGA_WSXGA 13
-#define IPU_DISP_PORT 1
-
-static int enabled; /* enable power on or not */
-DEFINE_SPINLOCK(tve_lock);
-
-static struct fb_info *tve_fbi;
-#define MXC_ENABLE 1
-#define MXC_DISABLE 2
-static int g_enable_tve;
-static int g_enable_vga;
+#define DISPDRV_VGA "vga"
+#define DISPDRV_TVE "tve"
struct tve_data {
struct platform_device *pdev;
@@ -116,14 +109,21 @@ struct tve_data {
int output_mode;
int detect;
void *base;
+ spinlock_t tve_lock;
+ bool inited;
+ int enabled;
int irq;
- int blank;
struct clk *clk;
struct clk *di_clk;
struct regulator *dac_reg;
struct regulator *dig_reg;
struct delayed_work cd_work;
-} tve;
+ struct tve_reg_mapping *regs;
+ struct tve_reg_fields_mapping *reg_fields;
+ struct mxc_dispdrv_entry *disp_tve;
+ struct mxc_dispdrv_entry *disp_vga;
+ struct notifier_block nb;
+};
struct tve_reg_mapping {
u32 tve_com_conf_reg;
@@ -165,11 +165,7 @@ static struct tve_reg_fields_mapping tve_reg_fields_v2 = {
1, 2, 1, 2, 4, 0x01000000, 0x700000, 0x7000, 20, 12, 16
};
-
-struct tve_reg_mapping *tve_regs;
-struct tve_reg_fields_mapping *tve_reg_fields;
-
-static struct fb_videomode video_modes[] = {
+static struct fb_videomode video_modes_tve[] = {
{
/* NTSC TV output */
"TV-NTSC", 60, 720, 480, 74074,
@@ -252,6 +248,7 @@ static struct fb_videomode video_modes[] = {
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
};
+static int tve_modedb_sz = ARRAY_SIZE(video_modes_tve);
static struct fb_videomode video_modes_vga[] = {
{
@@ -291,6 +288,7 @@ static struct fb_videomode video_modes_vga[] = {
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
};
+static int vga_modedb_sz = ARRAY_SIZE(video_modes_vga);
enum tvout_mode {
TV_OFF,
@@ -314,30 +312,30 @@ static unsigned short tvout_mode_to_channel_map[8] = {
7 /* TVRGB */
};
-static void tve_dump_regs(void)
+static void tve_dump_regs(struct tve_data *tve)
{
- dev_dbg(&tve.pdev->dev, "tve_com_conf_reg 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_com_conf_reg));
- dev_dbg(&tve.pdev->dev, "tve_cd_cont_reg 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_cd_cont_reg));
- dev_dbg(&tve.pdev->dev, "tve_int_cont_reg 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_int_cont_reg));
- dev_dbg(&tve.pdev->dev, "tve_tst_mode_reg 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_tst_mode_reg));
- dev_dbg(&tve.pdev->dev, "tve_tvdac_cont_reg0 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_tvdac_cont_reg));
- dev_dbg(&tve.pdev->dev, "tve_tvdac_cont_reg1 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_tvdac_cont_reg + 4));
- dev_dbg(&tve.pdev->dev, "tve_tvdac_cont_reg2 0x%x\n",
- __raw_readl(tve.base + tve_regs->tve_tvdac_cont_reg + 8));
+ dev_dbg(&tve->pdev->dev, "tve_com_conf_reg 0x%x\n",
+ readl(tve->base + tve->regs->tve_com_conf_reg));
+ dev_dbg(&tve->pdev->dev, "tve_cd_cont_reg 0x%x\n",
+ readl(tve->base + tve->regs->tve_cd_cont_reg));
+ dev_dbg(&tve->pdev->dev, "tve_int_cont_reg 0x%x\n",
+ readl(tve->base + tve->regs->tve_int_cont_reg));
+ dev_dbg(&tve->pdev->dev, "tve_tst_mode_reg 0x%x\n",
+ readl(tve->base + tve->regs->tve_tst_mode_reg));
+ dev_dbg(&tve->pdev->dev, "tve_tvdac_cont_reg0 0x%x\n",
+ readl(tve->base + tve->regs->tve_tvdac_cont_reg));
+ dev_dbg(&tve->pdev->dev, "tve_tvdac_cont_reg1 0x%x\n",
+ readl(tve->base + tve->regs->tve_tvdac_cont_reg + 4));
+ dev_dbg(&tve->pdev->dev, "tve_tvdac_cont_reg2 0x%x\n",
+ readl(tve->base + tve->regs->tve_tvdac_cont_reg + 8));
}
-static int is_vga_enabled(void)
+static int is_vga_enabled(struct tve_data *tve)
{
u32 reg;
- if (tve.revision == 2) {
- reg = __raw_readl(tve.base + tve_regs->tve_tst_mode_reg);
+ if (tve->revision == 2) {
+ reg = readl(tve->base + tve->regs->tve_tst_mode_reg);
if (reg & TVEV2_DAC_TEST_MODE_MASK)
return 1;
else
@@ -368,78 +366,64 @@ static inline int valid_mode(int mode)
|| (mode == TVOUT_FMT_1080P30));
}
-static int get_video_mode(struct fb_info *fbi, int *fmt)
+static int get_video_mode(struct fb_info *fbi)
{
int mode;
- if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ if (fb_mode_is_equal(fbi->mode, &video_modes_tve[0])) {
mode = TVOUT_FMT_NTSC;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[1])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[1])) {
mode = TVOUT_FMT_PAL;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[2])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[2])) {
mode = TVOUT_FMT_720P60;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[3])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[3])) {
mode = TVOUT_FMT_720P30;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[4])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[4])) {
mode = TVOUT_FMT_1080I60;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[5])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[5])) {
mode = TVOUT_FMT_1080I50;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[6])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[6])) {
mode = TVOUT_FMT_1080P30;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[7])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[7])) {
mode = TVOUT_FMT_1080P25;
- } else if (fb_mode_is_equal(fbi->mode, &video_modes[8])) {
- *fmt = IPU_PIX_FMT_YUV444;
+ } else if (fb_mode_is_equal(fbi->mode, &video_modes_tve[8])) {
mode = TVOUT_FMT_1080P24;
} else if (fb_mode_is_equal(fbi->mode, &video_modes_vga[0])) {
- *fmt = IPU_PIX_FMT_GBR24;
mode = TVOUT_FMT_VGA_SVGA;
} else if (fb_mode_is_equal(fbi->mode, &video_modes_vga[1])) {
- *fmt = IPU_PIX_FMT_GBR24;
mode = TVOUT_FMT_VGA_XGA;
} else if (fb_mode_is_equal(fbi->mode, &video_modes_vga[2])) {
- *fmt = IPU_PIX_FMT_GBR24;
mode = TVOUT_FMT_VGA_SXGA;
} else if (fb_mode_is_equal(fbi->mode, &video_modes_vga[3])) {
- *fmt = IPU_PIX_FMT_GBR24;
mode = TVOUT_FMT_VGA_WSXGA;
} else {
- *fmt = IPU_PIX_FMT_YUV444;
mode = TVOUT_FMT_OFF;
}
return mode;
}
-static void tve_disable_vga_mode(void)
+static void tve_disable_vga_mode(struct tve_data *tve)
{
- if (tve.revision == 2) {
+ if (tve->revision == 2) {
u32 reg;
/* disable test mode */
- reg = __raw_readl(tve.base + tve_regs->tve_tst_mode_reg);
+ reg = readl(tve->base + tve->regs->tve_tst_mode_reg);
reg = reg & ~TVEV2_DAC_TEST_MODE_MASK;
- __raw_writel(reg, tve.base + tve_regs->tve_tst_mode_reg);
+ writel(reg, tve->base + tve->regs->tve_tst_mode_reg);
}
}
-static void tve_set_tvout_mode(int mode)
+static void tve_set_tvout_mode(struct tve_data *tve, int mode)
{
u32 conf_reg;
/* clear sync_ch and tvout_mode fields */
- conf_reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
- conf_reg &= ~(tve_reg_fields->sync_ch_mask |
- tve_reg_fields->tvout_mode_mask);
+ conf_reg = readl(tve->base + tve->regs->tve_com_conf_reg);
+ conf_reg &= ~(tve->reg_fields->sync_ch_mask |
+ tve->reg_fields->tvout_mode_mask);
conf_reg = conf_reg & ~TVE_DAC_SAMPRATE_MASK;
- if (tve.revision == 2) {
+ if (tve->revision == 2) {
conf_reg = (conf_reg & ~TVEV2_DATA_SRC_MASK) |
TVEV2_DATA_SRC_BUS_1;
conf_reg = conf_reg & ~TVEV2_INP_VIDEO_FORM;
@@ -447,18 +431,18 @@ static void tve_set_tvout_mode(int mode)
}
conf_reg |=
- mode << tve_reg_fields->
+ mode << tve->reg_fields->
tvout_mode_offset | tvout_mode_to_channel_map[mode] <<
- tve_reg_fields->sync_ch_offset;
- __raw_writel(conf_reg, tve.base + tve_regs->tve_com_conf_reg);
+ tve->reg_fields->sync_ch_offset;
+ writel(conf_reg, tve->base + tve->regs->tve_com_conf_reg);
}
-static int _is_tvout_mode_hd_compatible(void)
+static int _is_tvout_mode_hd_compatible(struct tve_data *tve)
{
u32 conf_reg, mode;
- conf_reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
- mode = (conf_reg >> tve_reg_fields->tvout_mode_offset) & 7;
+ conf_reg = readl(tve->base + tve->regs->tve_com_conf_reg);
+ mode = (conf_reg >> tve->reg_fields->tvout_mode_offset) & 7;
if (mode == YPBPR || mode == TVRGB) {
return 1;
} else {
@@ -466,37 +450,37 @@ static int _is_tvout_mode_hd_compatible(void)
}
}
-static int tve_setup_vga(void)
+static int tve_setup_vga(struct tve_data *tve)
{
u32 reg;
- if (tve.revision == 2) {
+ if (tve->revision == 2) {
/* set gain */
- reg = __raw_readl(tve.base + tve_regs->tve_tvdac_cont_reg);
+ reg = readl(tve->base + tve->regs->tve_tvdac_cont_reg);
reg = (reg & ~TVEV2_DAC_GAIN_MASK) | 0;
- __raw_writel(reg, tve.base + tve_regs->tve_tvdac_cont_reg);
- reg = __raw_readl(tve.base + tve_regs->tve_tvdac_cont_reg + 4);
+ writel(reg, tve->base + tve->regs->tve_tvdac_cont_reg);
+ reg = readl(tve->base + tve->regs->tve_tvdac_cont_reg + 4);
reg = (reg & ~TVEV2_DAC_GAIN_MASK) | 0;
- __raw_writel(reg, tve.base + tve_regs->tve_tvdac_cont_reg + 4);
- reg = __raw_readl(tve.base + tve_regs->tve_tvdac_cont_reg + 8);
+ writel(reg, tve->base + tve->regs->tve_tvdac_cont_reg + 4);
+ reg = readl(tve->base + tve->regs->tve_tvdac_cont_reg + 8);
reg = (reg & ~TVEV2_DAC_GAIN_MASK) | 0;
- __raw_writel(reg, tve.base + tve_regs->tve_tvdac_cont_reg + 8);
+ writel(reg, tve->base + tve->regs->tve_tvdac_cont_reg + 8);
/* set tve_com_conf_reg */
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_DAC_SAMPRATE_MASK) | TVE_DAC_DIV2_RATE;
reg = (reg & ~TVEV2_DATA_SRC_MASK) | TVEV2_DATA_SRC_BUS_2;
reg = reg | TVEV2_INP_VIDEO_FORM;
reg = reg & ~TVEV2_P2I_CONV_EN;
reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P30_STAND;
- reg |= TVRGB << tve_reg_fields->tvout_mode_offset |
- 1 << tve_reg_fields->sync_ch_offset;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
+ reg |= TVRGB << tve->reg_fields->tvout_mode_offset |
+ 1 << tve->reg_fields->sync_ch_offset;
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
/* set test mode */
- reg = __raw_readl(tve.base + tve_regs->tve_tst_mode_reg);
+ reg = readl(tve->base + tve->regs->tve_tst_mode_reg);
reg = (reg & ~TVEV2_DAC_TEST_MODE_MASK) | 1;
- __raw_writel(reg, tve.base + tve_regs->tve_tst_mode_reg);
+ writel(reg, tve->base + tve->regs->tve_tst_mode_reg);
}
return 0;
@@ -511,7 +495,7 @@ static int tve_setup_vga(void)
* 0 successful
* otherwise failed
*/
-static int tve_setup(int mode)
+static int tve_setup(struct tve_data *tve, int mode)
{
u32 reg;
struct clk *tve_parent_clk;
@@ -519,10 +503,10 @@ static int tve_setup(int mode)
unsigned long tve_clock_rate = 216000000;
unsigned long lock_flags;
- if (tve.cur_mode == mode)
+ if (tve->cur_mode == mode)
return 0;
- spin_lock_irqsave(&tve_lock, lock_flags);
+ spin_lock_irqsave(&tve->tve_lock, lock_flags);
switch (mode) {
case TVOUT_FMT_PAL:
@@ -562,122 +546,122 @@ static int tve_setup(int mode)
di1_clock_rate = 147140000;
break;
}
- if (enabled)
- clk_disable(tve.clk);
+ if (tve->enabled)
+ clk_disable(tve->clk);
- tve_parent_clk = clk_get_parent(tve.clk);
+ tve_parent_clk = clk_get_parent(tve->clk);
clk_set_rate(tve_parent_clk, parent_clock_rate);
- tve_clock_rate = clk_round_rate(tve.clk, tve_clock_rate);
- clk_set_rate(tve.clk, tve_clock_rate);
+ tve_clock_rate = clk_round_rate(tve->clk, tve_clock_rate);
+ clk_set_rate(tve->clk, tve_clock_rate);
- clk_enable(tve.clk);
- di1_clock_rate = clk_round_rate(tve.di_clk, di1_clock_rate);
- clk_set_rate(tve.di_clk, di1_clock_rate);
+ clk_enable(tve->clk);
+ di1_clock_rate = clk_round_rate(tve->di_clk, di1_clock_rate);
+ clk_set_rate(tve->di_clk, di1_clock_rate);
- tve.cur_mode = mode;
+ tve->cur_mode = mode;
/* select output video format */
if (mode == TVOUT_FMT_PAL) {
- tve_disable_vga_mode();
- tve_set_tvout_mode(YPBPR);
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ tve_disable_vga_mode(tve);
+ tve_set_tvout_mode(tve, YPBPR);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_PAL_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to PAL video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to PAL video\n");
} else if (mode == TVOUT_FMT_NTSC) {
- tve_disable_vga_mode();
- tve_set_tvout_mode(YPBPR);
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ tve_disable_vga_mode(tve);
+ tve_set_tvout_mode(tve, YPBPR);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_NTSC_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to NTSC video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to NTSC video\n");
} else if (mode == TVOUT_FMT_720P60) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD720P60_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 720P60 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 720P60 video\n");
} else if (mode == TVOUT_FMT_720P30) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD720P30_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 720P30 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 720P30 video\n");
} else if (mode == TVOUT_FMT_1080I60) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080I60_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 1080I60 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 1080I60 video\n");
} else if (mode == TVOUT_FMT_1080I50) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080I50_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 1080I50 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 1080I50 video\n");
} else if (mode == TVOUT_FMT_1080P30) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P30_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 1080P30 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 1080P30 video\n");
} else if (mode == TVOUT_FMT_1080P25) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P25_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 1080P25 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 1080P25 video\n");
} else if (mode == TVOUT_FMT_1080P24) {
- tve_disable_vga_mode();
- if (!_is_tvout_mode_hd_compatible()) {
- tve_set_tvout_mode(YPBPR);
- pr_debug("The TV out mode is HD incompatible. Setting to YPBPR.");
+ tve_disable_vga_mode(tve);
+ if (!_is_tvout_mode_hd_compatible(tve)) {
+ tve_set_tvout_mode(tve, YPBPR);
+ dev_dbg(&tve->pdev->dev, "The TV out mode is HD incompatible. Setting to YPBPR.");
}
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
reg = (reg & ~TVE_STAND_MASK) | TVE_HD1080P24_STAND;
- __raw_writel(reg, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to 1080P24 video\n");
+ writel(reg, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to 1080P24 video\n");
} else if (is_vga_mode(mode)) {
/* do not need cable detect */
- tve_setup_vga();
- pr_debug("TVE: change to VGA video\n");
+ tve_setup_vga(tve);
+ dev_dbg(&tve->pdev->dev, "TVE: change to VGA video\n");
} else if (mode == TVOUT_FMT_OFF) {
- __raw_writel(0x0, tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE: change to OFF video\n");
+ writel(0x0, tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE: change to OFF video\n");
} else {
- pr_debug("TVE: no such video format.\n");
+ dev_dbg(&tve->pdev->dev, "TVE: no such video format.\n");
}
- if (!enabled)
- clk_disable(tve.clk);
+ if (!tve->enabled)
+ clk_disable(tve->clk);
- spin_unlock_irqrestore(&tve_lock, lock_flags);
+ spin_unlock_irqrestore(&tve->tve_lock, lock_flags);
return 0;
}
@@ -685,63 +669,63 @@ static int tve_setup(int mode)
* tve_enable
* Enable the tve Power to begin TV encoder
*/
-static void tve_enable(void)
+static void tve_enable(struct tve_data *tve)
{
u32 reg;
unsigned long lock_flags;
- spin_lock_irqsave(&tve_lock, lock_flags);
- if (!enabled) {
- enabled = 1;
- clk_enable(tve.clk);
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
- __raw_writel(reg | TVE_IPU_CLK_ENABLE | TVE_ENABLE,
- tve.base + tve_regs->tve_com_conf_reg);
- pr_debug("TVE power on.\n");
+ spin_lock_irqsave(&tve->tve_lock, lock_flags);
+ if (!tve->enabled) {
+ tve->enabled = 1;
+ clk_enable(tve->clk);
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
+ writel(reg | TVE_IPU_CLK_ENABLE | TVE_ENABLE,
+ tve->base + tve->regs->tve_com_conf_reg);
+ dev_dbg(&tve->pdev->dev, "TVE power on.\n");
}
- if (is_vga_enabled()) {
+ if (is_vga_enabled(tve)) {
/* disable interrupt */
- pr_debug("TVE VGA disable cable detect.\n");
- __raw_writel(0xffffffff, tve.base + tve_regs->tve_stat_reg);
- __raw_writel(0, tve.base + tve_regs->tve_int_cont_reg);
+ dev_dbg(&tve->pdev->dev, "TVE VGA disable cable detect.\n");
+ writel(0xffffffff, tve->base + tve->regs->tve_stat_reg);
+ writel(0, tve->base + tve->regs->tve_int_cont_reg);
} else {
/* enable interrupt */
- pr_debug("TVE TVE enable cable detect.\n");
- __raw_writel(0xffffffff, tve.base + tve_regs->tve_stat_reg);
- __raw_writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT,
- tve.base + tve_regs->tve_int_cont_reg);
+ dev_dbg(&tve->pdev->dev, "TVE TVE enable cable detect.\n");
+ writel(0xffffffff, tve->base + tve->regs->tve_stat_reg);
+ writel(CD_SM_INT | CD_LM_INT | CD_MON_END_INT,
+ tve->base + tve->regs->tve_int_cont_reg);
}
- spin_unlock_irqrestore(&tve_lock, lock_flags);
+ spin_unlock_irqrestore(&tve->tve_lock, lock_flags);
- tve_dump_regs();
+ tve_dump_regs(tve);
}
/**
* tve_disable
* Disable the tve Power to stop TV encoder
*/
-static void tve_disable(void)
+static void tve_disable(struct tve_data *tve)
{
u32 reg;
unsigned long lock_flags;
- spin_lock_irqsave(&tve_lock, lock_flags);
- if (enabled) {
- enabled = 0;
- reg = __raw_readl(tve.base + tve_regs->tve_com_conf_reg);
- __raw_writel(reg & ~TVE_ENABLE & ~TVE_IPU_CLK_ENABLE,
- tve.base + tve_regs->tve_com_conf_reg);
- clk_disable(tve.clk);
- pr_debug("TVE power off.\n");
+ spin_lock_irqsave(&tve->tve_lock, lock_flags);
+ if (tve->enabled) {
+ tve->enabled = 0;
+ reg = readl(tve->base + tve->regs->tve_com_conf_reg);
+ writel(reg & ~TVE_ENABLE & ~TVE_IPU_CLK_ENABLE,
+ tve->base + tve->regs->tve_com_conf_reg);
+ clk_disable(tve->clk);
+ dev_dbg(&tve->pdev->dev, "TVE power off.\n");
}
- spin_unlock_irqrestore(&tve_lock, lock_flags);
+ spin_unlock_irqrestore(&tve->tve_lock, lock_flags);
}
-static int tve_update_detect_status(void)
+static int tve_update_detect_status(struct tve_data *tve)
{
- int old_detect = tve.detect;
+ int old_detect = tve->detect;
u32 stat_lm, stat_sm, stat;
u32 int_ctl;
u32 cd_cont_reg;
@@ -750,244 +734,201 @@ static int tve_update_detect_status(void)
char event_string[16];
char *envp[] = { event_string, NULL };
- spin_lock_irqsave(&tve_lock, lock_flags);
+ spin_lock_irqsave(&tve->tve_lock, lock_flags);
- if (!enabled) {
- pr_warning("Warning: update tve status while it disabled!\n");
- tve.detect = 0;
+ if (!tve->enabled) {
+ dev_warn(&tve->pdev->dev, "Warning: update tve status while it disabled!\n");
+ tve->detect = 0;
goto done;
}
- int_ctl = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
- cd_cont_reg = __raw_readl(tve.base + tve_regs->tve_cd_cont_reg);
+ int_ctl = readl(tve->base + tve->regs->tve_int_cont_reg);
+ cd_cont_reg = readl(tve->base + tve->regs->tve_cd_cont_reg);
if ((cd_cont_reg & 0x1) == 0) {
- pr_warning("Warning: pls enable TVE CD first!\n");
+ dev_warn(&tve->pdev->dev, "Warning: pls enable TVE CD first!\n");
goto done;
}
- stat = __raw_readl(tve.base + tve_regs->tve_stat_reg);
+ stat = readl(tve->base + tve->regs->tve_stat_reg);
while (((stat & CD_MON_END_INT) == 0) && (timeout > 0)) {
- spin_unlock_irqrestore(&tve_lock, lock_flags);
+ spin_unlock_irqrestore(&tve->tve_lock, lock_flags);
msleep(2);
- spin_lock_irqsave(&tve_lock, lock_flags);
+ spin_lock_irqsave(&tve->tve_lock, lock_flags);
timeout -= 2;
- if (!enabled) {
- pr_warning("Warning: update tve status while it disabled!\n");
- tve.detect = 0;
+ if (!tve->enabled) {
+ dev_warn(&tve->pdev->dev, "Warning: update tve status while it disabled!\n");
+ tve->detect = 0;
goto done;
} else
- stat = __raw_readl(tve.base + tve_regs->tve_stat_reg);
+ stat = readl(tve->base + tve->regs->tve_stat_reg);
}
if (((stat & CD_MON_END_INT) == 0) && (timeout <= 0)) {
- pr_warning("Warning: get detect result without CD_MON_END_INT!\n");
+ dev_warn(&tve->pdev->dev, "Warning: get detect result without CD_MON_END_INT!\n");
goto done;
}
- stat = stat >> tve_reg_fields->cd_ch_stat_offset;
+ stat = stat >> tve->reg_fields->cd_ch_stat_offset;
stat_lm = stat & (CD_CH_0_LM_ST | CD_CH_1_LM_ST | CD_CH_2_LM_ST);
if ((stat_lm == (CD_CH_0_LM_ST | CD_CH_1_LM_ST | CD_CH_2_LM_ST)) &&
((stat & (CD_CH_0_SM_ST | CD_CH_1_SM_ST | CD_CH_2_SM_ST)) == 0)
) {
- tve.detect = 3;
- tve.output_mode = YPBPR;
+ tve->detect = 3;
+ tve->output_mode = YPBPR;
} else if ((stat_lm == (CD_CH_0_LM_ST | CD_CH_1_LM_ST)) &&
((stat & (CD_CH_0_SM_ST | CD_CH_1_SM_ST)) == 0)) {
- tve.detect = 4;
- tve.output_mode = SVIDEO;
+ tve->detect = 4;
+ tve->output_mode = SVIDEO;
} else if (stat_lm == CD_CH_0_LM_ST) {
stat_sm = stat & CD_CH_0_SM_ST;
if (stat_sm != 0) {
/* headset */
- tve.detect = 2;
- tve.output_mode = TV_OFF;
+ tve->detect = 2;
+ tve->output_mode = TV_OFF;
} else {
- tve.detect = 1;
- tve.output_mode = CVBS0;
+ tve->detect = 1;
+ tve->output_mode = CVBS0;
}
} else if (stat_lm == CD_CH_2_LM_ST) {
stat_sm = stat & CD_CH_2_SM_ST;
if (stat_sm != 0) {
/* headset */
- tve.detect = 2;
- tve.output_mode = TV_OFF;
+ tve->detect = 2;
+ tve->output_mode = TV_OFF;
} else {
- tve.detect = 1;
- tve.output_mode = CVBS2;
+ tve->detect = 1;
+ tve->output_mode = CVBS2;
}
} else {
/* none */
- tve.detect = 0;
- tve.output_mode = TV_OFF;
+ tve->detect = 0;
+ tve->output_mode = TV_OFF;
}
- tve_set_tvout_mode(tve.output_mode);
+ tve_set_tvout_mode(tve, tve->output_mode);
/* clear interrupt */
- __raw_writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
- tve.base + tve_regs->tve_stat_reg);
+ writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
+ tve->base + tve->regs->tve_stat_reg);
- __raw_writel(int_ctl | CD_SM_INT | CD_LM_INT,
- tve.base + tve_regs->tve_int_cont_reg);
+ writel(int_ctl | CD_SM_INT | CD_LM_INT,
+ tve->base + tve->regs->tve_int_cont_reg);
done:
- spin_unlock_irqrestore(&tve_lock, lock_flags);
+ spin_unlock_irqrestore(&tve->tve_lock, lock_flags);
- if (old_detect != tve.detect) {
- sysfs_notify(&tve.pdev->dev.kobj, NULL, "headphone");
- if (tve.detect == 1)
+ if (old_detect != tve->detect) {
+ sysfs_notify(&tve->pdev->dev.kobj, NULL, "headphone");
+ if (tve->detect == 1)
sprintf(event_string, "EVENT=CVBS0");
- else if (tve.detect == 3)
+ else if (tve->detect == 3)
sprintf(event_string, "EVENT=YPBPR");
- else if (tve.detect == 4)
+ else if (tve->detect == 4)
sprintf(event_string, "EVENT=SVIDEO");
else
sprintf(event_string, "EVENT=NONE");
- kobject_uevent_env(&tve.pdev->dev.kobj, KOBJ_CHANGE, envp);
+ kobject_uevent_env(&tve->pdev->dev.kobj, KOBJ_CHANGE, envp);
}
- dev_dbg(&tve.pdev->dev, "detect = %d mode = %d\n",
- tve.detect, tve.output_mode);
- return tve.detect;
+ dev_dbg(&tve->pdev->dev, "detect = %d mode = %d\n",
+ tve->detect, tve->output_mode);
+ return tve->detect;
}
static void cd_work_func(struct work_struct *work)
{
- tve_update_detect_status();
-}
-#if 0
-static int tve_man_detect(void)
-{
- u32 cd_cont;
- u32 int_cont;
-
- if (!enabled)
- return -1;
-
- int_cont = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
- __raw_writel(int_cont &
- ~(tve_reg_fields->cd_sm_int | tve_reg_fields->cd_lm_int),
- tve.base + tve_regs->tve_int_cont_reg);
-
- cd_cont = __raw_readl(tve.base + tve_regs->tve_cd_cont_reg);
- __raw_writel(cd_cont | tve_reg_fields->cd_trig_mode,
- tve.base + tve_regs->tve_cd_cont_reg);
-
- __raw_writel(tve_reg_fields->cd_sm_int | tve_reg_fields->
- cd_lm_int | tve_reg_fields->
- cd_mon_end_int | tve_reg_fields->cd_man_trig,
- tve.base + tve_regs->tve_stat_reg);
-
- while ((__raw_readl(tve.base + tve_regs->tve_stat_reg)
- & tve_reg_fields->cd_mon_end_int) == 0)
- msleep(5);
-
- tve_update_detect_status();
+ struct delayed_work *delay_work = to_delayed_work(work);
+ struct tve_data *tve =
+ container_of(delay_work, struct tve_data, cd_work);
- __raw_writel(cd_cont, tve.base + tve_regs->tve_cd_cont_reg);
- __raw_writel(int_cont, tve.base + tve_regs->tve_int_cont_reg);
-
- return tve.detect;
+ tve_update_detect_status(tve);
}
-#endif
static irqreturn_t tve_detect_handler(int irq, void *data)
{
- u32 int_ctl = __raw_readl(tve.base + tve_regs->tve_int_cont_reg);
+ struct tve_data *tve = data;
+
+ u32 int_ctl = readl(tve->base + tve->regs->tve_int_cont_reg);
/* disable INT first */
int_ctl &= ~(CD_SM_INT | CD_LM_INT | CD_MON_END_INT);
- __raw_writel(int_ctl, tve.base + tve_regs->tve_int_cont_reg);
+ writel(int_ctl, tve->base + tve->regs->tve_int_cont_reg);
- __raw_writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
- tve.base + tve_regs->tve_stat_reg);
+ writel(CD_MON_END_INT | CD_LM_INT | CD_SM_INT,
+ tve->base + tve->regs->tve_stat_reg);
- schedule_delayed_work(&tve.cd_work, msecs_to_jiffies(1000));
+ schedule_delayed_work(&tve->cd_work, msecs_to_jiffies(1000));
return IRQ_HANDLED;
}
-static inline void tve_set_di_fmt(struct fb_info *fbi, unsigned int fmt)
-{
- mm_segment_t old_fs;
-
- if (fbi->fbops->fb_ioctl) {
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi, MXCFB_SET_DIFMT, (unsigned long)&fmt);
- set_fs(old_fs);
- }
-}
-
/*!
* FB suspend/resume routing
*/
-static int tve_suspend(void)
+static int tve_suspend(struct tve_data *tve)
{
- if (enabled) {
- __raw_writel(0, tve.base + tve_regs->tve_int_cont_reg);
- __raw_writel(0, tve.base + tve_regs->tve_cd_cont_reg);
- __raw_writel(0, tve.base + tve_regs->tve_com_conf_reg);
- clk_disable(tve.clk);
+ if (tve->enabled) {
+ writel(0, tve->base + tve->regs->tve_int_cont_reg);
+ writel(0, tve->base + tve->regs->tve_cd_cont_reg);
+ writel(0, tve->base + tve->regs->tve_com_conf_reg);
+ clk_disable(tve->clk);
}
return 0;
}
-static int tve_resume(struct fb_info *fbi)
+static int tve_resume(struct tve_data *tve, struct fb_info *fbi)
{
int mode;
- if (enabled) {
- clk_enable(tve.clk);
+ if (tve->enabled) {
+ clk_enable(tve->clk);
/* Setup cable detect */
- if (tve.revision == 1)
- __raw_writel(0x01067701,
- tve.base + tve_regs->tve_cd_cont_reg);
+ if (tve->revision == 1)
+ writel(0x01067701,
+ tve->base + tve->regs->tve_cd_cont_reg);
else
- __raw_writel(0x00770601,
- tve.base + tve_regs->tve_cd_cont_reg);
-
- if (valid_mode(tve.cur_mode)) {
- mode = tve.cur_mode;
- tve_disable();
- tve.cur_mode = TVOUT_FMT_OFF;
- tve_setup(mode);
+ writel(0x00770601,
+ tve->base + tve->regs->tve_cd_cont_reg);
+
+ if (valid_mode(tve->cur_mode)) {
+ mode = tve->cur_mode;
+ tve_disable(tve);
+ tve->cur_mode = TVOUT_FMT_OFF;
+ tve_setup(tve, mode);
}
- tve_enable();
+ tve_enable(tve);
}
return 0;
}
-int tve_fb_setup(struct fb_info *fbi)
+int tve_fb_setup(struct tve_data *tve, struct fb_info *fbi)
{
- int mode, fmt;
+ int mode;
fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
&fbi->modelist);
if (!fbi->mode) {
- pr_warning("TVE: can not find mode for xres=%d, yres=%d\n",
+ dev_warn(&tve->pdev->dev, "TVE: can not find mode for xres=%d, yres=%d\n",
fbi->var.xres, fbi->var.yres);
- tve_disable();
- tve.cur_mode = TVOUT_FMT_OFF;
+ tve_disable(tve);
+ tve->cur_mode = TVOUT_FMT_OFF;
return 0;
}
- pr_debug("TVE: fb mode change event: xres=%d, yres=%d\n",
+ dev_dbg(&tve->pdev->dev, "TVE: fb mode change event: xres=%d, yres=%d\n",
fbi->mode->xres, fbi->mode->yres);
- mode = get_video_mode(fbi, &fmt);
+ mode = get_video_mode(fbi);
if (mode != TVOUT_FMT_OFF) {
- tve_set_di_fmt(fbi, fmt);
- tve_disable();
- tve_setup(mode);
- if (tve.blank == FB_BLANK_UNBLANK)
- tve_enable();
+ tve_disable(tve);
+ tve_setup(tve, mode);
+ tve_enable(tve);
} else {
- tve_disable();
- tve_setup(mode);
+ tve_disable(tve);
+ tve_setup(tve, mode);
}
return 0;
@@ -995,78 +936,62 @@ int tve_fb_setup(struct fb_info *fbi)
int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
{
+ struct tve_data *tve = container_of(nb, struct tve_data, nb);
struct fb_event *event = v;
struct fb_info *fbi = event->info;
+ /* only work for ipu0 di1*/
if (strcmp(fbi->fix.id, "DISP3 BG - DI1"))
return 0;
switch (val) {
- case FB_EVENT_FB_REGISTERED:
- pr_debug("TVE: fb registered event\n");
- if (tve_fbi != NULL)
- break;
-
- tve_fbi = fbi;
- break;
- case FB_EVENT_MODE_CHANGE:
+ case FB_EVENT_PREMODE_CHANGE:
{
- if (tve_fbi != fbi)
- break;
-
- tve_fb_setup(fbi);
+ tve_fb_setup(tve, fbi);
break;
}
case FB_EVENT_BLANK:
- if ((tve_fbi != fbi) || (fbi->mode == NULL))
+ if (fbi->mode == NULL)
return 0;
- pr_debug("TVE: fb blank event\n");
+ dev_dbg(&tve->pdev->dev, "TVE: fb blank event\n");
if (*((int *)event->data) == FB_BLANK_UNBLANK) {
- if (tve.blank != FB_BLANK_UNBLANK) {
- int mode, fmt;
- mode = get_video_mode(fbi, &fmt);
- if (mode != TVOUT_FMT_OFF) {
- if (tve.cur_mode != mode) {
- tve_disable();
- tve_setup(mode);
- }
- tve_enable();
- } else
- tve_setup(mode);
- tve.blank = FB_BLANK_UNBLANK;
- }
- } else {
- tve_disable();
- tve.blank = FB_BLANK_POWERDOWN;
- }
+ int mode;
+ mode = get_video_mode(fbi);
+ if (mode != TVOUT_FMT_OFF) {
+ if (tve->cur_mode != mode) {
+ tve_disable(tve);
+ tve_setup(tve, mode);
+ }
+ tve_enable(tve);
+ } else
+ tve_setup(tve, mode);
+ } else
+ tve_disable(tve);
break;
case FB_EVENT_SUSPEND:
- tve_suspend();
+ tve_suspend(tve);
break;
case FB_EVENT_RESUME:
- tve_resume(fbi);
+ tve_resume(tve, fbi);
break;
}
return 0;
}
-static struct notifier_block nb = {
- .notifier_call = tve_fb_event,
-};
-
static ssize_t show_headphone(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ struct tve_data *tve = dev_get_drvdata(dev);
int detect;
- if (!enabled) {
+ if (!tve->enabled) {
strcpy(buf, "tve power off\n");
return strlen(buf);
}
- detect = tve_update_detect_status();
+ detect = tve_update_detect_status(tve);
if (detect == 0)
strcpy(buf, "none\n");
@@ -1084,14 +1009,14 @@ static ssize_t show_headphone(struct device *dev,
static DEVICE_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL);
-static int _tve_get_revision(void)
+static int _tve_get_revision(struct tve_data *tve)
{
u32 conf_reg;
u32 rev = 0;
/* find out TVE rev based on the base addr default value
* can be used at the init/probe ONLY */
- conf_reg = __raw_readl(tve.base);
+ conf_reg = readl(tve->base);
switch (conf_reg) {
case 0x00842000:
rev = 1;
@@ -1103,180 +1028,250 @@ static int _tve_get_revision(void)
return rev;
}
-int tve_fb_pre_setup(struct fb_info *fbi)
-{
- if (fbi->fbops->fb_ioctl) {
- mm_segment_t old_fs;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi,
- MXCFB_GET_FB_BLANK,
- (unsigned int)(&tve.blank));
- set_fs(old_fs);
- }
- return tve_fb_setup(fbi);
-}
-
-static int tve_probe(struct platform_device *pdev)
+static int tve_drv_init(struct mxc_dispdrv_entry *disp, bool vga)
{
int ret;
+ struct tve_data *tve = mxc_dispdrv_getdata(disp);
+ struct mxc_dispdrv_setting *setting = mxc_dispdrv_getsetting(disp);
+ struct fsl_mxc_tve_platform_data *plat_data
+ = tve->pdev->dev.platform_data;
struct resource *res;
- struct fsl_mxc_tve_platform_data *plat_data = pdev->dev.platform_data;
+ struct fb_videomode *modedb;
+ int modedb_sz;
u32 conf_reg;
- /*
- * tve/vga can be enabled by platform data when there is
- * no setting from cmdline setup
- */
- if ((plat_data->boot_enable & MXC_TVE_TVOUT)
- && !g_enable_tve)
- g_enable_tve = MXC_ENABLE;
- if (!g_enable_tve)
- g_enable_tve = MXC_DISABLE;
-
- if ((plat_data->boot_enable & MXC_TVE_VGA) &&
- !g_enable_vga)
- g_enable_vga = MXC_ENABLE;
- if (!g_enable_vga)
- g_enable_vga = MXC_DISABLE;
-
- if (g_enable_tve == MXC_DISABLE &&
- g_enable_vga == MXC_DISABLE) {
- printk(KERN_WARNING "By setting, TVE driver will not be enabled\n");
- return 0;
- }
+ if (tve->inited == true)
+ return -ENODEV;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL)
- return -ENOMEM;
+ /*tve&vga only use ipu0 and di1*/
+ setting->dev_id = 0;
+ setting->disp_id = 1;
- tve.pdev = pdev;
- tve.base = ioremap(res->start, res->end - res->start);
+ res = platform_get_resource(tve->pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ ret = -ENOMEM;
+ goto get_res_failed;
+ }
- tve.irq = platform_get_irq(pdev, 0);
- if (tve.irq < 0) {
- ret = tve.irq;
- goto err0;
+ tve->irq = platform_get_irq(tve->pdev, 0);
+ if (tve->irq < 0) {
+ ret = tve->irq;
+ goto get_irq_failed;
}
- ret = request_irq(tve.irq, tve_detect_handler, 0, pdev->name, pdev);
- if (ret < 0)
- goto err0;
+ tve->base = ioremap(res->start, res->end - res->start);
+ if (!tve->base) {
+ ret = -ENOMEM;
+ goto ioremap_failed;
+ }
- ret = device_create_file(&pdev->dev, &dev_attr_headphone);
+ ret = device_create_file(&tve->pdev->dev, &dev_attr_headphone);
if (ret < 0)
- goto err1;
+ goto dev_file_create_failed;
- tve.dac_reg = regulator_get(&pdev->dev, plat_data->dac_reg);
- if (!IS_ERR(tve.dac_reg)) {
- regulator_set_voltage(tve.dac_reg, 2750000, 2750000);
- regulator_enable(tve.dac_reg);
+ tve->dac_reg = regulator_get(&tve->pdev->dev, plat_data->dac_reg);
+ if (!IS_ERR(tve->dac_reg)) {
+ regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
+ regulator_enable(tve->dac_reg);
}
-
- tve.dig_reg = regulator_get(&pdev->dev, plat_data->dig_reg);
- if (!IS_ERR(tve.dig_reg)) {
- regulator_set_voltage(tve.dig_reg, 1250000, 1250000);
- regulator_enable(tve.dig_reg);
+ tve->dig_reg = regulator_get(&tve->pdev->dev, plat_data->dig_reg);
+ if (!IS_ERR(tve->dig_reg)) {
+ regulator_set_voltage(tve->dig_reg, 1250000, 1250000);
+ regulator_enable(tve->dig_reg);
}
- tve.clk = clk_get(&pdev->dev, "tve_clk");
- if (IS_ERR(tve.clk)) {
- ret = PTR_ERR(tve.clk);
- goto err2;
+ tve->clk = clk_get(&tve->pdev->dev, "tve_clk");
+ if (IS_ERR(tve->clk)) {
+ ret = PTR_ERR(tve->clk);
+ goto get_tveclk_failed;
}
- tve.di_clk = clk_get(NULL, "ipu_di1_clk");
- if (IS_ERR(tve.di_clk)) {
- ret = PTR_ERR(tve.di_clk);
- goto err2;
+ tve->di_clk = clk_get(NULL, "ipu1_di1_clk");
+ if (IS_ERR(tve->di_clk)) {
+ ret = PTR_ERR(tve->di_clk);
+ goto get_diclk_failed;
}
- clk_set_rate(tve.clk, 216000000);
- clk_set_parent(tve.di_clk, tve.clk);
- clk_enable(tve.clk);
-
- tve.revision = _tve_get_revision();
- if (tve.revision == 1) {
- tve_regs = &tve_regs_v1;
- tve_reg_fields = &tve_reg_fields_v1;
+
+ clk_set_rate(tve->clk, 216000000);
+ clk_set_parent(tve->di_clk, tve->clk);
+ clk_enable(tve->clk);
+
+ tve->revision = _tve_get_revision(tve);
+ if (tve->revision == 1) {
+ tve->regs = &tve_regs_v1;
+ tve->reg_fields = &tve_reg_fields_v1;
} else {
- tve_regs = &tve_regs_v2;
- tve_reg_fields = &tve_reg_fields_v2;
+ tve->regs = &tve_regs_v2;
+ tve->reg_fields = &tve_reg_fields_v2;
}
- /*[> adjust video mode for mx37 <]
+ /* adjust video mode for mx37 */
if (cpu_is_mx37()) {
- video_modes[0].left_margin = 121;
- video_modes[0].right_margin = 16;
- video_modes[0].upper_margin = 17;
- video_modes[0].lower_margin = 5;
- video_modes[1].left_margin = 131;
- video_modes[1].right_margin = 12;
- video_modes[1].upper_margin = 21;
- video_modes[1].lower_margin = 3;
- }*/
-
- /* TVE is on disp port 1 */
- if (tve.revision == 1) {
- if (g_enable_tve == MXC_ENABLE)
- mxcfb_register_mode(IPU_DISP_PORT, video_modes,
- 3, MXC_DISP_SPEC_DEV);
+ video_modes_tve[0].left_margin = 121;
+ video_modes_tve[0].right_margin = 16;
+ video_modes_tve[0].upper_margin = 17;
+ video_modes_tve[0].lower_margin = 5;
+ video_modes_tve[1].left_margin = 131;
+ video_modes_tve[1].right_margin = 12;
+ video_modes_tve[1].upper_margin = 21;
+ video_modes_tve[1].lower_margin = 3;
+ }
+
+ if (vga && cpu_is_mx53()) {
+ setting->if_fmt = IPU_PIX_FMT_GBR24;
+ modedb = video_modes_vga;
+ modedb_sz = vga_modedb_sz;
} else {
- if (g_enable_tve == MXC_ENABLE)
- mxcfb_register_mode(IPU_DISP_PORT, video_modes,
- ARRAY_SIZE(video_modes),
- MXC_DISP_SPEC_DEV);
-
- if (cpu_is_mx53() && (g_enable_vga == MXC_ENABLE))
- mxcfb_register_mode(IPU_DISP_PORT, video_modes_vga,
- ARRAY_SIZE(video_modes_vga),
- MXC_DISP_SPEC_DEV);
+ setting->if_fmt = IPU_PIX_FMT_YUV444;
+ if (tve->revision == 1) {
+ modedb = video_modes_tve;
+ modedb_sz = 3;
+ } else {
+ modedb = video_modes_tve;
+ modedb_sz = tve_modedb_sz;
+ }
}
- mxcfb_register_presetup(IPU_DISP_PORT, tve_fb_pre_setup);
+
+ fb_videomode_to_modelist(modedb, modedb_sz, &setting->fbi->modelist);
+
+ /* must use spec video mode defined by driver */
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ modedb, modedb_sz, NULL, setting->default_bpp);
+ if (ret != 1)
+ fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
+
+ ret = request_irq(tve->irq, tve_detect_handler, 0, tve->pdev->name, tve);
+ if (ret < 0)
+ goto req_irq_failed;
/* Setup cable detect, for YPrPb mode, default use channel#-1 for Y */
- INIT_DELAYED_WORK(&tve.cd_work, cd_work_func);
- if (tve.revision == 1)
- __raw_writel(0x01067701, tve.base + tve_regs->tve_cd_cont_reg);
+ INIT_DELAYED_WORK(&tve->cd_work, cd_work_func);
+ if (tve->revision == 1)
+ writel(0x01067701, tve->base + tve->regs->tve_cd_cont_reg);
else
- __raw_writel(0x00770601, tve.base + tve_regs->tve_cd_cont_reg);
+ writel(0x00770601, tve->base + tve->regs->tve_cd_cont_reg);
conf_reg = 0;
- __raw_writel(conf_reg, tve.base + tve_regs->tve_com_conf_reg);
+ writel(conf_reg, tve->base + tve->regs->tve_com_conf_reg);
+
+ writel(0x00000000, tve->base + tve->regs->tve_mv_cont_reg - 4 * 5);
+ writel(0x00000000, tve->base + tve->regs->tve_mv_cont_reg - 4 * 4);
+ writel(0x00000000, tve->base + tve->regs->tve_mv_cont_reg - 4 * 3);
+ writel(0x00000000, tve->base + tve->regs->tve_mv_cont_reg - 4 * 2);
+ writel(0x00000000, tve->base + tve->regs->tve_mv_cont_reg - 4);
+ writel(0x00000000, tve->base + tve->regs->tve_mv_cont_reg);
- __raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 5);
- __raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 4);
- __raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 3);
- __raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4 * 2);
- __raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg - 4);
- __raw_writel(0x00000000, tve.base + tve_regs->tve_mv_cont_reg);
+ clk_disable(tve->clk);
- clk_disable(tve.clk);
+ tve->nb.notifier_call = tve_fb_event;
+ ret = fb_register_client(&tve->nb);
+ if (ret < 0)
+ goto reg_fbclient_failed;
+
+ dev_set_drvdata(&tve->pdev->dev, tve);
+
+ spin_lock_init(&tve->tve_lock);
+
+ tve->inited = true;
+
+ return 0;
+
+reg_fbclient_failed:
+ free_irq(tve->irq, tve->pdev);
+req_irq_failed:
+get_diclk_failed:
+get_tveclk_failed:
+ device_remove_file(&tve->pdev->dev, &dev_attr_headphone);
+dev_file_create_failed:
+ iounmap(tve->base);
+ioremap_failed:
+get_irq_failed:
+get_res_failed:
+ return ret;
+
+}
+
+static int tvout_init(struct mxc_dispdrv_entry *disp)
+{
+ return tve_drv_init(disp, 0);
+}
- ret = fb_register_client(&nb);
+static int vga_init(struct mxc_dispdrv_entry *disp)
+{
+ return tve_drv_init(disp, 1);
+}
+
+void tvout_deinit(struct mxc_dispdrv_entry *disp)
+{
+ struct tve_data *tve = mxc_dispdrv_getdata(disp);
+
+ if (tve->enabled)
+ clk_disable(tve->clk);
+
+ fb_unregister_client(&tve->nb);
+ free_irq(tve->irq, tve->pdev);
+ device_remove_file(&tve->pdev->dev, &dev_attr_headphone);
+ iounmap(tve->base);
+}
+
+static struct mxc_dispdrv_driver tve_drv = {
+ .name = DISPDRV_TVE,
+ .init = tvout_init,
+ .deinit = tvout_deinit,
+};
+
+static struct mxc_dispdrv_driver vga_drv = {
+ .name = DISPDRV_VGA,
+ .init = vga_init,
+ .deinit = tvout_deinit,
+};
+
+static int tve_dispdrv_init(struct tve_data *tve)
+{
+ tve->disp_tve = mxc_dispdrv_register(&tve_drv);
+ mxc_dispdrv_setdata(tve->disp_tve, tve);
+ tve->disp_vga = mxc_dispdrv_register(&vga_drv);
+ mxc_dispdrv_setdata(tve->disp_vga, tve);
+ return 0;
+}
+
+static void tve_dispdrv_deinit(struct tve_data *tve)
+{
+ mxc_dispdrv_unregister(tve->disp_tve);
+ mxc_dispdrv_unregister(tve->disp_vga);
+}
+
+static int tve_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct tve_data *tve;
+
+ tve = kzalloc(sizeof(struct tve_data), GFP_KERNEL);
+ if (!tve) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ tve->pdev = pdev;
+ ret = tve_dispdrv_init(tve);
if (ret < 0)
- goto err2;
+ goto dispdrv_init_failed;
- tve.blank = -1;
+ dev_set_drvdata(&pdev->dev, tve);
return 0;
-err2:
- device_remove_file(&pdev->dev, &dev_attr_headphone);
-err1:
- free_irq(tve.irq, pdev);
-err0:
- iounmap(tve.base);
+
+dispdrv_init_failed:
+ kfree(tve);
+alloc_failed:
return ret;
}
static int tve_remove(struct platform_device *pdev)
{
- if (enabled) {
- clk_disable(tve.clk);
- enabled = 0;
- }
- free_irq(tve.irq, pdev);
- device_remove_file(&pdev->dev, &dev_attr_headphone);
- fb_unregister_client(&nb);
+ struct tve_data *tve = dev_get_drvdata(&pdev->dev);
+
+ tve_dispdrv_deinit(tve);
+ kfree(tve);
return 0;
}
@@ -1288,28 +1283,6 @@ static struct platform_driver tve_driver = {
.remove = tve_remove,
};
-static int __init enable_tve_setup(char *options)
-{
- if (!strcmp(options, "=off"))
- g_enable_tve = MXC_DISABLE;
- else
- g_enable_tve = MXC_ENABLE;
-
- return 1;
-}
-__setup("tve", enable_tve_setup);
-
-static int __init enable_vga_setup(char *options)
-{
- if (!strcmp(options, "=off"))
- g_enable_vga = MXC_DISABLE;
- else
- g_enable_vga = MXC_ENABLE;
-
- return 1;
-}
-__setup("vga", enable_vga_setup);
-
static int __init tve_init(void)
{
return platform_driver_register(&tve_driver);