#include <linux/spinlock.h>
#include <linux/of_device.h>
#include <linux/mod_devicetable.h>
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
#include "mxc_dispdrv.h"
#define DISPDRV_LDB "ldb"
static struct fb_videomode ldb_modedb[] = {
{
- "LDB-WXGA", 60, 1280, 800, 14065,
- 40, 40,
- 10, 3,
- 80, 10,
- 0,
- FB_VMODE_NONINTERLACED,
- FB_MODE_IS_DETAILED,},
+ "LDB-WXGA", 60, 1280, 800, 14065,
+ 40, 40,
+ 10, 3,
+ 80, 10,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,
+ },
+ {
+ "LDB-XGA", 60, 1024, 768, 15385,
+ 220, 40,
+ 21, 7,
+ 60, 10,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,
+ },
{
- "LDB-XGA", 60, 1024, 768, 15385,
- 220, 40,
- 21, 7,
- 60, 10,
- 0,
- FB_VMODE_NONINTERLACED,
- FB_MODE_IS_DETAILED,},
+ "LDB-1080P60", 60, 1920, 1080, 7692,
+ 100, 40,
+ 30, 3,
+ 10, 2,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,
+ },
+ {
+ "LDB-NL12880BC20", 60, 1280, 800, KHZ2PICOS(71000),
+ 50, 50,
+ 5, 5,
+ 60, 13,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,
+ },
{
- "LDB-1080P60", 60, 1920, 1080, 7692,
- 100, 40,
- 30, 3,
- 10, 2,
- 0,
- FB_VMODE_NONINTERLACED,
- FB_MODE_IS_DETAILED,},
+ "LDB-VGA", 60, 640, 480, KHZ2PICOS(25200),
+ 48, 16,
+ 31, 12,
+ 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_DETAILED,
+ },
};
static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);
* "ldb=sin0/1" -- single mode on LVDS0/1
* "ldb=sep0/1" -- separate mode begin from LVDS0/1
*
- * there are two LVDS channels(LVDS0 and LVDS1) which can transfer video
- * datas, there two channels can be used as split/dual/single/separate mode.
+ * There are two LVDS channels (LVDS0 and LVDS1) which can transfer video
+ * data. These two channels can be used as split/dual/single/separate mode.
*
- * split mode means display data from DI0 or DI1 will send to both channels
+ * split mode means display data from DI0 or DI1 will be sent to both channels
* LVDS0+LVDS1.
* dual mode means display data from DI0 or DI1 will be duplicated on LVDS0
- * and LVDS1, it said, LVDS0 and LVDS1 has the same content.
+ * and LVDS1, i.e. LVDS0 and LVDS1 has the same content.
* single mode means only work for DI0/DI1->LVDS0 or DI0/DI1->LVDS1.
* separate mode means you can make DI0/DI1->LVDS0 and DI0/DI1->LVDS1 work
* at the same time.
char id[16];
int i;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < ARRAY_SIZE(id_di); 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]));
+ strlcpy(id, id_di[ldb->setting[i].di], sizeof(id));
id[4] += ldb->setting[i].ipu;
if (!strcmp(id, fbi->fix.id))
return i;
val = readl(ldb->control_reg);
val |= ldb->setting[setting_idx].ch_val;
writel(val, ldb->control_reg);
- dev_dbg(&ldb->pdev->dev, "LDB setup, control reg:0x%x\n",
+ dev_dbg(&ldb->pdev->dev, "LDB setup, control reg: 0x%08x\n",
readl(ldb->control_reg));
/* vsync setup */
data &= ~ldb->setting[index].ch_mask;
writel(data, ldb->control_reg);
dev_dbg(&ldb->pdev->dev,
- "LDB blank, control reg:0x%x\n",
+ "LDB blank, control reg: 0x%08x\n",
readl(ldb->control_reg));
}
}
(ROUTE_IPU_DI(ipu, di) << LVDS1_MUX_CTL_OFFS);
dev_dbg(&ldb->pdev->dev,
"Dual/Split mode both channels route to IPU%d-DI%d\n",
- ipu, di);
+ ipu + 1, di);
} else if ((mode == LDB_SIN0) || (mode == LDB_SIN1)) {
reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
channel = mode - LDB_SIN0;
reg |= ROUTE_IPU_DI(ipu, di) << shift;
dev_dbg(&ldb->pdev->dev,
"Single mode channel %d route to IPU%d-DI%d\n",
- channel, ipu, di);
+ channel, ipu + 1, di);
} else {
static bool first = true;
dev_dbg(&ldb->pdev->dev,
"Separate mode channel %d route to IPU%d-DI%d\n",
- channel, ipu, di);
+ channel, ipu + 1, di);
}
writel(reg, ldb->gpr3_reg);
/* 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");
+ dev_warn(&ldb->pdev->dev, "Input pixel format not valid use default RGB666\n");
setting->if_fmt = IPU_PIX_FMT_RGB666;
}
reg = readl(ldb->control_reg);
- /* refrence resistor select */
+ /* reference resistor select */
reg &= ~LDB_BGREF_RMODE_MASK;
if (plat_data->ext_ref)
reg |= LDB_BGREF_RMODE_EXT;
ret = ldb->mode - LDB_SIN0;
if (plat_data->disp_id != ret) {
dev_warn(&ldb->pdev->dev,
- "change IPU DI%d to IPU DI%d for LDB "
- "channel%d.\n",
+ "change IPU DI%d to IPU DI%d for LDB channel%d.\n",
plat_data->disp_id, ret, ret);
plat_data->disp_id = ret;
}
} else if (((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))
&& is_imx6_ldb(plat_data)) {
- if (plat_data->disp_id == plat_data->sec_disp_id) {
+ if (plat_data->ipu_id == plat_data->sec_ipu_id &&
+ plat_data->disp_id == plat_data->sec_disp_id) {
dev_err(&ldb->pdev->dev,
- "For LVDS separate mode,"
- "two DIs should be different!\n");
+ "For LVDS separate mode, two DIs should be different!\n");
return -EINVAL;
}
- if (((!plat_data->disp_id) && (ldb->mode == LDB_SEP1))
- || ((plat_data->disp_id) &&
- (ldb->mode == LDB_SEP0))) {
+ if ((!plat_data->disp_id && ldb->mode == LDB_SEP1) ||
+ (plat_data->disp_id && ldb->mode == LDB_SEP0)) {
dev_dbg(&ldb->pdev->dev,
- "LVDS separate mode:"
- "swap DI configuration!\n");
+ "LVDS separate mode: swap DI configuration!\n");
ipu_id = plat_data->ipu_id;
disp_id = plat_data->disp_id;
plat_data->ipu_id = plat_data->sec_ipu_id;
reg |= LDB_CH1_MODE_EN_TO_DI1;
ch_mask = LDB_CH1_MODE_MASK;
ch_val = reg & LDB_CH1_MODE_MASK;
- } else { /* separate mode*/
+ } else { /* separate mode */
setting->disp_id = plat_data->disp_id;
/* first output is LVDS0 or LVDS1 */
(ldb->mode == LDB_DUL_DI1) ||
(ldb->mode == LDB_SIN0) ||
(ldb->mode == LDB_SIN1)) {
- dev_err(&ldb->pdev->dev, "for second ldb disp"
- "ldb mode should in separate mode\n");
+ dev_err(&ldb->pdev->dev, "for second ldb disp ldb mode should be in separate mode\n");
return -EINVAL;
}
setting->dev_id = plat_data->ipu_id;
setting->disp_id = !plat_data->disp_id;
}
- if (setting->disp_id == ldb->setting[0].di) {
- dev_err(&ldb->pdev->dev, "Err: for second ldb disp in"
- "separate mode, DI should be different!\n");
+ if (setting->dev_id == ldb->setting[0].ipu &&
+ setting->disp_id == ldb->setting[0].di) {
+ dev_err(&ldb->pdev->dev, "Err: for second ldb disp in separate mode, DI should be different!\n");
return -EINVAL;
}
ldb->setting[setting_idx].ldb_di_clk = clk_get(&ldb->pdev->dev,
ldb_clk);
if (IS_ERR(ldb->setting[setting_idx].ldb_di_clk)) {
- dev_err(&ldb->pdev->dev, "get ldb clk failed\n");
+ dev_err(&ldb->pdev->dev, "Failed to get %s clk: %ld\n",
+ ldb_clk, PTR_ERR(ldb->setting[setting_idx].ldb_di_clk));
return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk);
}
ldb->setting[setting_idx].div_3_5_clk = clk_get(&ldb->pdev->dev,
div_3_5_clk);
if (IS_ERR(ldb->setting[setting_idx].div_3_5_clk)) {
- dev_err(&ldb->pdev->dev, "get div 3.5 clk failed\n");
+ dev_err(&ldb->pdev->dev, "Failed to get %s clk: %ld\n",
+ div_3_5_clk, PTR_ERR(ldb->setting[setting_idx].div_3_5_clk));
return PTR_ERR(ldb->setting[setting_idx].div_3_5_clk);
}
ldb->setting[setting_idx].div_7_clk = clk_get(&ldb->pdev->dev,
div_7_clk);
if (IS_ERR(ldb->setting[setting_idx].div_7_clk)) {
- dev_err(&ldb->pdev->dev, "get div 7 clk failed\n");
+ dev_err(&ldb->pdev->dev, "Failed to get %s clk: %ld\n",
+ div_7_clk, PTR_ERR(ldb->setting[setting_idx].div_7_clk));
return PTR_ERR(ldb->setting[setting_idx].div_7_clk);
}
ldb->setting[setting_idx].div_sel_clk = clk_get(&ldb->pdev->dev,
div_sel_clk);
if (IS_ERR(ldb->setting[setting_idx].div_sel_clk)) {
- dev_err(&ldb->pdev->dev, "get div sel clk failed\n");
+ dev_err(&ldb->pdev->dev, "Failed to get %s clk: %ld\n",
+ div_sel_clk, PTR_ERR(ldb->setting[setting_idx].div_sel_clk));
return PTR_ERR(ldb->setting[setting_idx].div_sel_clk);
}
ldb->setting[setting_idx].di_clk = clk_get(&ldb->pdev->dev,
di_clk);
if (IS_ERR(ldb->setting[setting_idx].di_clk)) {
- dev_err(&ldb->pdev->dev, "get di clk failed\n");
+ dev_err(&ldb->pdev->dev, "Failed to get %s clk: %ld\n",
+ di_clk, PTR_ERR(ldb->setting[setting_idx].di_clk));
return PTR_ERR(ldb->setting[setting_idx].di_clk);
}
if (is_imx6_ldb(plat_data))
ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb);
+ if (setting->fbmode) {
+ ldb_modedb[0] = *setting->fbmode;
+ ldb_modedb_sz = 1;
+ }
+
/* 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);
ret = clk_set_parent(ldb->setting[setting_idx].di_clk,
ldb->setting[setting_idx].ldb_di_clk);
if (ret) {
- dev_err(&ldb->pdev->dev, "fail to set ldb_di clk as"
- "the parent of ipu_di clk\n");
+ dev_err(&ldb->pdev->dev, "fail to set ldb_di clk as the parent of ipu_di clk\n");
return ret;
}
ret = clk_set_parent(ldb->setting[setting_idx].div_sel_clk,
ldb->setting[setting_idx].div_3_5_clk);
if (ret) {
- dev_err(&ldb->pdev->dev, "fail to set div 3.5 clk as"
- "the parent of div sel clk\n");
+ dev_err(&ldb->pdev->dev, "fail to set div 3.5 clk as the parent of div sel clk\n");
return ret;
}
} else {
ret = clk_set_parent(ldb->setting[setting_idx].div_sel_clk,
ldb->setting[setting_idx].div_7_clk);
if (ret) {
- dev_err(&ldb->pdev->dev, "fail to set div 7 clk as"
- "the parent of div sel clk\n");
+ dev_err(&ldb->pdev->dev, "fail to set div 7 clk as the parent of div sel clk\n");
return ret;
}
}
}
static struct mxc_dispdrv_driver ldb_drv = {
- .name = DISPDRV_LDB,
- .init = ldb_disp_init,
+ .name = DISPDRV_LDB,
+ .init = ldb_disp_init,
.post_init = ldb_post_disp_init,
.deinit = ldb_disp_deinit,
.setup = ldb_disp_setup,
}
static struct platform_device_id imx_ldb_devtype[] = {
- {
- .name = "ldb-imx6",
- .driver_data = LDB_IMX6,
- }, {
- /* sentinel */
- }
+ { "ldb-imx6", LDB_IMX6, },
+ { /* sentinel */ }
};
static const struct of_device_id imx_ldb_dt_ids[] = {