博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
imx6 lvds 代码分析
阅读量:4507 次
发布时间:2019-06-08

本文共 49181 字,大约阅读时间需要 163 分钟。

查看imx6 kernel中lvds设备和驱动的初始化过程。

相关文档:

  arm/arm/mach-mx6/board-mx6q_sabresd.c

  kernel/drivers/video/mxc/ldb.c

设备初始化

arm/arm/mach-mx6/board-mx6q_sabresd.cMACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")    /* Maintainer: Freescale Semiconductor, Inc. */    .boot_params = MX6_PHYS_OFFSET + 0x100,    .fixup = fixup_mxc_board,    .map_io = mx6_map_io,    .init_irq = mx6_init_irq,    .init_machine = mx6_sabresd_board_init,    ----------+    .timer = &mx6_sabresd_timer,                         |    .reserve = mx6q_sabresd_reserve,                     |MACHINE_END                                              |                                                         |// board-mx6q_sabresd.c                                  |static void __init mx6_sabresd_board_init(void)      <---+{                            ------------------------------+    ......                  /                              |    imx6q_add_ipuv3(0, &ipu_data[0]);          ---+        |   // ipu                                                  |        |    imx6q_add_ldb(&ldb_data);            ----------------------------+   //ldb    ......                                        |        |         |}                                                 |        |         |                                                  V        |         |#define imx6q_add_ipuv3(id, pdata) \                       |         |    imx_add_ipuv3(id, &imx6q_ipuv3_data[id], pdata)        |         |                                                           |         |struct platform_device *__init imx_add_ipuv3(              |         |        const int id,                                      |         |        const struct imx_ipuv3_data *data,                 |         |        struct imx_ipuv3_platform_data *pdata)             |         |{                                                          |         |    struct resource res[] = {                              |         |        {                                                  |         |            .start = data->iobase,                         |         |            .end = data->iobase + data->iosize - 1,        |         |            .flags = IORESOURCE_MEM,                       |         |        }, {                                               |         |            .start = data->irq_err,                        |         |            .end = data->irq_err,                          |         |            .flags = IORESOURCE_IRQ,                       |         |        }, {                                               |         |            .start = data->irq,                            |         |            .end = data->irq,                              |         |            .flags = IORESOURCE_IRQ,                       |         |        },                                                 |         |    };                                                     |         |                                                           |         |    pdata->init = data->init;                              |         |    pdata->pg = data->pg;                                  |         |                                                           |         |    return imx_add_platform_device_dmamask("imx-ipuv3", id,|         |            res, ARRAY_SIZE(res), pdata, sizeof(*pdata),   |         |            DMA_BIT_MASK(32));                             |         |}                                                          |         |                                                           |         |static struct imx_ipuv3_platform_data ipu_data[] = {    <--+         |    {                                                                |    .rev = 4,                                                        |    .csi_clk[0] = "clko_clk",                                        |    .bypass_reset = false,                                           |    }, {                                                             |    .rev = 4,                                                        |    .csi_clk[0] = "clko_clk",                                        |    .bypass_reset = false,                                           |    },                                                               |};                                                                   |                                                                     |#define imx6q_add_ldb(pdata) \                         <-------------+    imx_add_ldb(&imx6q_ldb_data, pdata);                             |                                                                     |struct platform_device *__init imx_add_ldb(                          |        const struct imx_ldb_data *data,                             |        struct fsl_mxc_ldb_platform_data *pdata)                     |{                                                                    |    struct resource res[] = {                                        |        {                                                            |            .start = data->iobase,                                   |            .end = data->iobase + data->iosize - 1,                  |            .flags = IORESOURCE_MEM,                                 |        },                                                           |    };                                                               |                                                                     |    return imx_add_platform_device("mxc_ldb", -1,                    |            res, ARRAY_SIZE(res), pdata, sizeof(*pdata));            |}                                                                    |                                                                     |static struct fsl_mxc_ldb_platform_data ldb_data = {          <------+    .ipu_id = 0,    .disp_id = 1,    .ext_ref = 1,    .mode = LDB_SEP1,    .sec_ipu_id = 0,    .sec_disp_id = 0,};

驱动初始化

kernel/drivers/video/mxc/ldb.cstatic int __init ldb_init(void){    return platform_driver_register(&mxcldb_driver);      -----+}                                                              |                                                               |static struct platform_driver mxcldb_driver = {            <---+    .driver = {           .name = "mxc_ldb",           },    .probe = ldb_probe,                              -----+    .remove = ldb_remove,                                 |    .suspend = ldb_suspend,                               |    .resume = ldb_resume,                                 |};                                                        |                                                          |static int ldb_probe(struct platform_device *pdev)    <---+{    int ret = 0;    struct ldb_data *ldb;    ldb = kzalloc(sizeof(struct ldb_data), GFP_KERNEL);    if (!ldb) {        ret = -ENOMEM;        goto alloc_failed;    }                                              +------------------+    ldb->pdev = pdev;                         |                  |    ldb->disp_ldb = mxc_dispdrv_register(&ldb_drv);              |    mxc_dispdrv_setdata(ldb->disp_ldb, ldb);                     |                                                                 |    dev_set_drvdata(&pdev->dev, ldb);                            |                                                                 |    /*                                                           |     * Disable HannStar touch panel CABC function,               |     * this function turns the panel's backlight automatically   |     * according to the content shown on the panel which         |     * may cause annoying unstable backlight issue.              |     *                                                           |     */                                                          |                                                                 |alloc_failed:                                                    |    return ret;                                                  |}                                                                |                                                                 |                                                                 |static struct mxc_dispdrv_driver ldb_drv = {             <-------+    .name     = DISPDRV_LDB,    .init     = ldb_disp_init,           ----------------------+    .deinit    = ldb_disp_deinit,                              |    .setup = ldb_disp_setup,             ----------------------------------------------+};                                                             |                       |                                                               |                       |static int ldb_disp_init(struct mxc_dispdrv_handle *disp,   <--+                       |    struct mxc_dispdrv_setting *setting)                                               |{                                                                                      |    int ret = 0, i;                                                                    |    struct ldb_data *ldb = mxc_dispdrv_getdata(disp);                                  |    struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data;        |    struct i2c_client *i2c_dev;                                                        |    struct resource *res;                                                              |    uint32_t base_addr;                                                                |    uint32_t reg, setting_idx;                                                         |    uint32_t ch_mask = 0, ch_val = 0;                                                  |    int lvds_channel = 0;                                                              |    uint32_t ipu_id, disp_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) {                                                                |        char di_clk[] = "ipu1_di0_clk";                                                |        char ldb_clk[] = "ldb_di0_clk";                                                |                                                                                       |        setting_idx = 0;                                                               |        res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0);                     |        if (IS_ERR(res))                                                               |            return -ENOMEM;                                                            |                                                                                       |        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);                                        |        }                                                                              |                                                                                       |        /* ipu selected by platform data setting */                                    |        setting->dev_id = plat_data->ipu_id;                                           |                                                                                       |        reg = readl(ldb->control_reg);                                                 |        //ldb参考电阻选择                                                              |        /* refrence resistor select */                                                 |        reg &= ~LDB_BGREF_RMODE_MASK;                                                  |        if (plat_data->ext_ref)                                                        |            reg |= LDB_BGREF_RMODE_EXT;                                                |        else                                                                           |            reg |= LDB_BGREF_RMODE_INT;                                                |        //使用SPWG标准对数据进行映射                                                   |        /* 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);                   |        //指定数据宽度,24bit或者18bit                                                 |        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;                                               |        //single mode                                                                  |        if ((ldb->mode == LDB_SIN0) || (ldb->mode == LDB_SIN1)) {                      |            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",                                                    |                    plat_data->disp_id, ret, ret);                                     |                plat_data->disp_id = ret;                                              |            }                                                                          |        // separate mode                                                               |        } else if (((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))                |                && (cpu_is_mx6q() || cpu_is_mx6dl())) {                                |            if (plat_data->disp_id == plat_data->sec_disp_id) {                        |                dev_err(&ldb->pdev->dev,                                               |                    "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))) {                                        |                dev_dbg(&ldb->pdev->dev,                                               |                    "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;                             |                plat_data->disp_id = plat_data->sec_disp_id;                           |                plat_data->sec_ipu_id = ipu_id;                                        |                plat_data->sec_disp_id = disp_id;                                      |            }                                                                          |        }                                                                              |        // split 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_SIN0) {                                            |            reg &= ~LDB_SPLIT_MODE_EN;                                                 |            setting->disp_id = plat_data->disp_id;                                     |            if (setting->disp_id == 0)                                                 |                reg |= LDB_CH0_MODE_EN_TO_DI0;                                         |            else                                                                       |                reg |= LDB_CH0_MODE_EN_TO_DI1;                                         |            ch_mask = LDB_CH0_MODE_MASK;                                               |            ch_val = reg & LDB_CH0_MODE_MASK;                                          |        } else if (ldb->mode == LDB_SIN1) {                                            |            reg &= ~LDB_SPLIT_MODE_EN;                                                 |            setting->disp_id = plat_data->disp_id;                                     |            if (setting->disp_id == 0)                                                 |                reg |= LDB_CH1_MODE_EN_TO_DI0;                                         |            else                                                                       |                reg |= LDB_CH1_MODE_EN_TO_DI1;                                         |            ch_mask = LDB_CH1_MODE_MASK;                                               |            ch_val = reg & LDB_CH1_MODE_MASK;                                          |        } else { /* separate mode*/                                                    |        // dual mode                                                                   |            setting->disp_id = plat_data->disp_id;                                     |                                                                                       |            /* first output is LVDS0 or LVDS1 */                                       |            if (ldb->mode == LDB_SEP0)                                                 |                lvds_channel = 0;                                                      |            else                                                                       |                lvds_channel = 1;                                                      |                                                                                       |            reg &= ~LDB_SPLIT_MODE_EN;                                                 |                                                                                       |            if ((lvds_channel == 0) && (setting->disp_id == 0))                        |                reg |= LDB_CH0_MODE_EN_TO_DI0;                                         |            else if ((lvds_channel == 0) && (setting->disp_id == 1))                   |                reg |= LDB_CH0_MODE_EN_TO_DI1;                                         |            else if ((lvds_channel == 1) && (setting->disp_id == 0))                   |                reg |= LDB_CH1_MODE_EN_TO_DI0;                                         |            else                                                                       |                reg |= LDB_CH1_MODE_EN_TO_DI1;                                         |            ch_mask = lvds_channel ? LDB_CH1_MODE_MASK :                               |                    LDB_CH0_MODE_MASK;                                                 |            ch_val = reg & ch_mask;                                                    |                                                                                       |            if (bits_per_pixel(setting->if_fmt) == 24) {                               |                if (lvds_channel == 0)                                                 |                    reg &= ~LDB_DATA_WIDTH_CH1_24;                                     |                else                                                                   |                    reg &= ~LDB_DATA_WIDTH_CH0_24;                                     |            } else {                                                                   |                if (lvds_channel == 0)                                                 |                    reg &= ~LDB_DATA_WIDTH_CH1_18;                                     |                else                                                                   |                    reg &= ~LDB_DATA_WIDTH_CH0_18;                                     |            }                                                                          |        }                                                                              |                                                                                       |        writel(reg, ldb->control_reg);                                                 |        if (ldb->mode <  LDB_SIN0) {                                                   |            ch_mask = LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK;                           |            ch_val = reg & (LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);                    |        }                                                                              |                                                                                       |        /* clock setting */                                                            |        if ((cpu_is_mx6q() || cpu_is_mx6dl()) &&                                       |            ((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1)))                      |            ldb_clk[6] += lvds_channel;                                                |        else                                                                           |            ldb_clk[6] += setting->disp_id;                                            |        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 clk0 failed\n");                         |            iounmap(ldb->reg);                                                         |            return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk);                      |        }                                                                              |        di_clk[3] += setting->dev_id;                                                  |        di_clk[7] += setting->disp_id;                                                 |        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 clk0 failed\n");                          |            iounmap(ldb->reg);                                                         |            return PTR_ERR(ldb->setting[setting_idx].di_clk);                          |        }                                                                              |                                                                                       |        dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk);    |                                                                                       |        /* fb notifier for clk setting */                                              |        ldb->nb.notifier_call = ldb_fb_event,                                          |        ret = fb_register_client(&ldb->nb);                                            |        if (ret < 0) {                                                                 |            iounmap(ldb->reg);                                                         |            return ret;                                                                |        }                                                                              |                                                                                       |        ldb->inited = true;                                                            |                                                                                       |        i2c_dev = ldb_i2c_client[lvds_channel];                                        |                                                                                       |    } else { /* second time for separate mode */                                       |        char di_clk[] = "ipu1_di0_clk";                                                |        char ldb_clk[] = "ldb_di0_clk";                                                |                                                                                       |        if ((ldb->mode == LDB_SPL_DI0) ||                                              |            (ldb->mode == LDB_SPL_DI1) ||                                              |            (ldb->mode == LDB_DUL_DI0) ||                                              |            (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");                             |            return -EINVAL;                                                            |        }                                                                              |                                                                                       |        setting_idx = 1;                                                               |        if (cpu_is_mx6q() || cpu_is_mx6dl()) {                                         |            setting->dev_id = plat_data->sec_ipu_id;                                   |            setting->disp_id = plat_data->sec_disp_id;                                 |        } else {                                                                       |            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");                           |            return -EINVAL;                                                            |        }                                                                              |                                                                                       |        /* second output is LVDS0 or LVDS1 */                                          |        if (ldb->mode == LDB_SEP0)                                                     |            lvds_channel = 1;                                                          |        else                                                                           |            lvds_channel = 0;                                                          |                                                                                       |        reg = readl(ldb->control_reg);                                                 |        if ((lvds_channel == 0) && (setting->disp_id == 0))                            |            reg |= LDB_CH0_MODE_EN_TO_DI0;                                             |        else if ((lvds_channel == 0) && (setting->disp_id == 1))                       |            reg |= LDB_CH0_MODE_EN_TO_DI1;                                             |        else if ((lvds_channel == 1) && (setting->disp_id == 0))                       |            reg |= LDB_CH1_MODE_EN_TO_DI0;                                             |        else                                                                           |            reg |= LDB_CH1_MODE_EN_TO_DI1;                                             |        ch_mask = lvds_channel ?  LDB_CH1_MODE_MASK :                                  |                LDB_CH0_MODE_MASK;                                                     |        ch_val = reg & ch_mask;                                                        |                                                                                       |        if (bits_per_pixel(setting->if_fmt) == 24) {                                   |            if (lvds_channel == 0)                                                     |                reg |= LDB_DATA_WIDTH_CH0_24;                                          |            else                                                                       |                reg |= LDB_DATA_WIDTH_CH1_24;                                          |        } else {                                                                       |            if (lvds_channel == 0)                                                     |                reg |= LDB_DATA_WIDTH_CH0_18;                                          |            else                                                                       |                reg |= LDB_DATA_WIDTH_CH1_18;                                          |        }                                                                              |        writel(reg, ldb->control_reg);                                                 |                                                                                       |        /* clock setting */                                                            |        if (cpu_is_mx6q() || cpu_is_mx6dl())                                           |            ldb_clk[6] += lvds_channel;                                                |        else                                                                           |            ldb_clk[6] += setting->disp_id;                                            |        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 clk1 failed\n");                         |            return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk);                      |        }                                                                              |        di_clk[3] += setting->dev_id;                                                  |        di_clk[7] += setting->disp_id;                                                 |        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 clk1 failed\n");                          |            return PTR_ERR(ldb->setting[setting_idx].di_clk);                          |        }                                                                              |                                                                                       |        i2c_dev = ldb_i2c_client[lvds_channel];                                        |                                                                                       |        dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk);    |    }                                                                                  |                                                                                       |    if (i2c_dev)                                                                       |        mxc_dispdrv_setdev(ldb->disp_ldb, &i2c_dev->dev);                              |    else                                                                               |        mxc_dispdrv_setdev(ldb->disp_ldb, NULL);                                       |                                                                                       |    ldb->setting[setting_idx].ch_mask = ch_mask;                                       |    ldb->setting[setting_idx].ch_val = ch_val;                                         |                                                                                       |    if (cpu_is_mx6q() || cpu_is_mx6dl())                                               |        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->setting[setting_idx].di_clk,                                   |     |            ldb->setting[setting_idx].ldb_di_clk);                                     |     |                                                                                       |     |    /* 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;                                                                     |     |        }                                                                              |     |    }                                                                                  |     |                                                                                       |     |    /* get screen size in edid */                                                      |     |    if (i2c_dev) {                                                                     |     |        ret = mxc_ldb_edidread(i2c_dev);                                               |     |        if (ret > 0) {                                                                 |     |            fb_edid_to_monspecs(&g_edid[lvds_channel][0],                              |     |                        &setting->fbi->monspecs);                                      |     |            /* centimeter to millimeter */                                             |     |            setting->fbi->var.width =                                                  |     |                    setting->fbi->monspecs.max_x * 10;                                 |     |            setting->fbi->var.height =                                                 |     |                    setting->fbi->monspecs.max_y * 10;                                 |     |        } else {                                                                       |     |            /* ignore i2c access failure */                                            |     |            ret = 0;                                                                   |     |        }                                                                              |     |    }                                                                                  |     |                                                                                       |     |    /* 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 ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)   <----+     |{                                                                                            |    uint32_t reg, val;                                                                       |    uint32_t pixel_clk, rounded_pixel_clk;                                                   |    struct clk *ldb_clk_parent;                                                              |    struct ldb_data *ldb = mxc_dispdrv_getdata(disp);                                        |    int setting_idx, di;                                                                     |                                                                                             |    setting_idx = find_ldb_setting(ldb, fbi);                                                |    if (setting_idx < 0)                                                                     |        return setting_idx;                                                                  |                                                                                             |    di = ldb->setting[setting_idx].di;                                                       |                                                                                             |    /* restore channel mode setting */                                                       |    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",                                |            readl(ldb->control_reg));                                                        |    //设置vsync信号的极性    /* vsync setup */                                                                        |    reg = readl(ldb->control_reg);                                                           |    if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) {                                             |        if (di == 0)                                                                         |            reg = (reg & ~LDB_DI0_VS_POL_MASK)                                               |                | LDB_DI0_VS_POL_ACT_HIGH;                                                   |        else                                                                                 |            reg = (reg & ~LDB_DI1_VS_POL_MASK)                                               |                | LDB_DI1_VS_POL_ACT_HIGH;                                                   |    } else {                                                                                 |        if (di == 0)                                                                         |            reg = (reg & ~LDB_DI0_VS_POL_MASK)                                               |                | LDB_DI0_VS_POL_ACT_LOW;                                                    |        else                                                                                 |            reg = (reg & ~LDB_DI1_VS_POL_MASK)                                               |                | LDB_DI1_VS_POL_ACT_LOW;                                                    |    }                                                                                        |    writel(reg, ldb->control_reg);                                                           |                                                                                             |    /* clk setup */                                                                          |    //时钟关闭                                                                               |    if (ldb->setting[setting_idx].clk_en)                                                    |        clk_disable(ldb->setting[setting_idx].ldb_di_clk);                                   |    pixel_clk = (PICOS2KHZ(fbi->var.pixclock)) * 1000UL;                                     |    ldb_clk_parent = clk_get_parent(ldb->setting[setting_idx].ldb_di_clk);                   |    if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1))                            |        clk_set_rate(ldb_clk_parent, pixel_clk * 7 / 2);                                     |    else                                                                                     |        clk_set_rate(ldb_clk_parent, pixel_clk * 7);                                         |    rounded_pixel_clk = clk_round_rate(ldb->setting[setting_idx].ldb_di_clk,                 |            pixel_clk);                                                                      |    clk_set_rate(ldb->setting[setting_idx].ldb_di_clk, rounded_pixel_clk);                   |    //时钟使能                                                                               |    clk_enable(ldb->setting[setting_idx].ldb_di_clk);                                        |    if (!ldb->setting[setting_idx].clk_en)                                                   |        ldb->setting[setting_idx].clk_en = true;                                             |                                                                                             |    return 0;                                                                                |}                                                                                            |                                                                                             |#define LVDS_MUX_CTL_WIDTH    2                                                              |#define LVDS_MUX_CTL_MASK    3                                                               |#define LVDS0_MUX_CTL_OFFS    6                                                              |#define LVDS1_MUX_CTL_OFFS    8                                                              |#define LVDS0_MUX_CTL_MASK    (LVDS_MUX_CTL_MASK << 6)                                       |#define LVDS1_MUX_CTL_MASK    (LVDS_MUX_CTL_MASK << 8)                                       |#define ROUTE_IPU_DI(ipu, di)    (((ipu << 1) | di) & LVDS_MUX_CTL_MASK)                     |static int ldb_ipu_ldb_route(int ipu, int di, struct ldb_data *ldb)              <-----------+{    uint32_t reg;    int channel;    int shift;    int mode = ldb->mode;    //IOMUXC_GPR3    reg = readl(ldb->gpr3_reg);    if (mode < LDB_SIN0) {        reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);        reg |= (ROUTE_IPU_DI(ipu, di) << LVDS0_MUX_CTL_OFFS) |            (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);    } else if ((mode == LDB_SIN0) || (mode == LDB_SIN1)) {        reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);      //选择lvds源        channel = mode - LDB_SIN0;        shift = LVDS0_MUX_CTL_OFFS + channel * LVDS_MUX_CTL_WIDTH;        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);    } else {        static bool first = true;        if (first) {            if (mode == LDB_SEP0) {                reg &= ~LVDS0_MUX_CTL_MASK;                channel = 0;            } else {                reg &= ~LVDS1_MUX_CTL_MASK;                channel = 1;            }            first = false;        } else {            if (mode == LDB_SEP0) {                reg &= ~LVDS1_MUX_CTL_MASK;                channel = 1;            } else {                reg &= ~LVDS0_MUX_CTL_MASK;                channel = 0;            }        }        shift = LVDS0_MUX_CTL_OFFS + channel * LVDS_MUX_CTL_WIDTH;        reg |= ROUTE_IPU_DI(ipu, di) << shift;        dev_dbg(&ldb->pdev->dev,            "Separate mode channel %d route to IPU%d-DI%d\n",            channel, ipu, di);    }    writel(reg, ldb->gpr3_reg);    return 0;}

Author

Tony Liu

2016-8-31, Shenzhen

转载于:https://www.cnblogs.com/helloworldtoyou/p/5824691.html

你可能感兴趣的文章
dll注入到指定进程
查看>>
[知识梳理]课本1&2.1-2.5
查看>>
LeetCode 21. 合并两个有序链表(Merge Two Sorted Lists)
查看>>
STM32—LAN8720学习
查看>>
如何用Python做自动化特征工程
查看>>
C++线程同步之事件
查看>>
给毕业4年的待业者——要将学习继续下去
查看>>
XP下搭建 iphone 开发环境
查看>>
tomcat7的配置
查看>>
MFC之HTTP客户端应用程序
查看>>
Oracle 数据库监听配置
查看>>
php标题 栏目不显示<title>,DEDECMS专题列表页不显示title的解决方法
查看>>
matlab实现tophat,[问题] 多尺度tophat的实现问题
查看>>
java多线程发布订阅,多线程实现发布订阅升级版---遗留问题
查看>>
php think命令用不了,自定义 PHP think 命令无法在命令类文件里面使用 Db 类
查看>>
java注释跳转方法,Java自定义注解实现Router跳转
查看>>
499php,一笔画仙路 [499]第499章 神器的威力 最新章节无弹窗全文免费阅读 乐文阅读官网...
查看>>
zend怎么保存php,Zend Framework页面缓存实例
查看>>
oracle 并接去掉字符串,ORACLE删除字符-TRIM字符截取-substr查找字符-instr
查看>>
linux webrtc浏览器,WebRTC 浏览器支持
查看>>