• imx6 framebuffer 分析


    分析imx6 framebuffer设备和驱动的注册过程。

                              Tony Liu, 2016-8-31, Shenzhen

    相关文件:

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

      kernel/video/mxc/mxc_ipuv3_fb.c

      mm/memblock.c |

      drivers/video/fbmem.c |

    设备注册

    MACHINE_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,                    --------------+        //读取uboot bootargs中关于framebufer的参数
        .map_io = mx6_map_io,                                      |
        .init_irq = mx6_init_irq,                                  |
        .init_machine = mx6_sabresd_board_init,      ---------------------------------------------+     //设备初始化
        .timer = &mx6_sabresd_timer,                               |                              |
        .reserve = mx6q_sabresd_reserve,             -----------------------------------+         |     //framebuffer内存保留
    MACHINE_END                                                    |                    |         |
                                                                   |                    |         |
    //读取bootargs中的参数                                         V                    |         |
    static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,     |         |
                       char **cmdline, struct meminfo *mi)                              |         |
    {                                                                                   |         |
        char *str;                                                                      |         |
        struct tag *t;                                                                  |         |
        int i = 0;                                                                      |         |
        struct ipuv3_fb_platform_data *pdata_fb = sabresd_fb_data;                      |         |
                                                                                        |         |
        for_each_tag(t, tags) {                                                         |         |
            if (t->hdr.tag == ATAG_CMDLINE) {                                           |         |
                str = t->u.cmdline.cmdline;                                             |         |
                str = strstr(str, "fbmem=");                                            |         |
                if (str != NULL) {                                                      |         |
                    str += 6;                                                           |         |
                    pdata_fb[i++].res_size[0] = memparse(str, &str);                    |         |
                    while (*str == ',' &&                                               |         |
                        i < ARRAY_SIZE(sabresd_fb_data)) {                              |         |
                        str++;                                                          |         |
                        pdata_fb[i++].res_size[0] = memparse(str, &str);                |         |
                    }                                                                   |         |
                }                                                                       |         |
                /* ION reserved memory */                                               |         |
                str = t->u.cmdline.cmdline;                                             |         |
                str = strstr(str, "ionmem=");                                           |         |
                if (str != NULL) {                                                      |         |
                    str += 7;                                                           |         |
                    imx_ion_data.heaps[0].size = memparse(str, &str);                   |         |
                }                                                                       |         |
                /* Primary framebuffer base address */                                  |         |
                str = t->u.cmdline.cmdline;                                             |         |
                str = strstr(str, "fb0base=");                                          |         |
                if (str != NULL) {                                                      |         |
                    str += 8;                                                           |         |
                    pdata_fb[0].res_base[0] =                                           |         |
                            simple_strtol(str, &str, 16);                               |         |
                }                                                                       |         |
                /* GPU reserved memory */                                               |         |
                str = t->u.cmdline.cmdline;                                             |         |
                str = strstr(str, "gpumem=");                                           |         |
                if (str != NULL) {                                                      |         |
                    str += 7;                                                           |         |
                    imx6q_gpu_pdata.reserved_mem_size = memparse(str, &str);            |         |
                }                                                                       |         |
                break;                                                                  |         |
            }                                                                           |         |
        }                                                                               |         |
    }                                                                                   |         |
                                                                                        |         |
    static void __init mx6q_sabresd_reserve(void)                        <------------- +         |
    {                                                                                             |
        phys_addr_t phys;                                                                         |
        int i, fb0_reserved = 0, fb_array_size;                                                   |
                                                                                                  |
        /*                                                                                        |
         * Reserve primary framebuffer memory if its base address                                 |
         * is set by kernel command line.                                                         |
         */                                                                                       |
        // fb0                                                                                    |
        fb_array_size = ARRAY_SIZE(sabresd_fb_data);                                              |
        if (fb_array_size > 0 && sabresd_fb_data[0].res_base[0] &&                                |
            sabresd_fb_data[0].res_size[0]) {                                                     |
            //将framebuffer的数据保留,放在memblock.reverse中
            memblock_reserve(sabresd_fb_data[0].res_base[0],                                      |
                     sabresd_fb_data[0].res_size[0]);                                             |
            //将原来的内存中memblock.memory中删除
            memblock_remove(sabresd_fb_data[0].res_base[0],                                       |
                    sabresd_fb_data[0].res_size[0]);                                              |
            sabresd_fb_data[0].late_init = true;                                                  |
            ipu_data[ldb_data.ipu_id].bypass_reset = true;                                        |
            fb0_reserved = 1;                                                                     |
        }                                                                                         |
        // 对于fb_arrary剩下的元素
        for (i = fb0_reserved; i < fb_array_size; i++)                                            |
            if (sabresd_fb_data[i].res_size[0]) {                                                 |
                /* Reserve for other background buffer. */                                        |
                //申请空间,保留到memblock.reverse中
                phys = memblock_alloc(sabresd_fb_data[i].res_size[0],                             |
                            SZ_4K);                                                               |
                //将memblock.memory中一块大小的空间删除,因为已经申请,并放入memblock.reverse中
                memblock_remove(phys, sabresd_fb_data[i].res_size[0]);                            |
                sabresd_fb_data[i].res_base[0] = phys;                      --------------+       |
            }                                                                             |       |
                                                                                          |       |
    #ifdef CONFIG_ANDROID_RAM_CONSOLE                                                     |       |
        //保留128K的内存到memblock.reserve,4K对齐                                        |       |
        phys = memblock_alloc_base(SZ_128K, SZ_4K, SZ_1G);                                |       |
        memblock_remove(phys, SZ_128K);                                                   |       |
        memblock_free(phys, SZ_128K);                                                     |       |
        ram_console_resource.start = phys;                                                |       |
        ram_console_resource.end   = phys + SZ_128K - 1;                                  |       |
    #endif                                                                                |       |
                                                                                          |       |
    #if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE)                 |       |
        //保留  内存到memblock.reserve,4K对齐
        if (imx6q_gpu_pdata.reserved_mem_size) {                                          |       |
            phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size,                 |       |
                           SZ_4K, SZ_1G);                                                 |       |
            memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size);                     |       |
            imx6q_gpu_pdata.reserved_mem_base = phys;                                     |       |
        }                                                                                 |       |
    #endif                                                                                |       |
                                                                                          |       |
    #if defined(CONFIG_ION)                                                               |       |
        if (imx_ion_data.heaps[0].size) {                                                 |       |
            phys = memblock_alloc(imx_ion_data.heaps[0].size, SZ_4K);                     |       |
            memblock_remove(phys, imx_ion_data.heaps[0].size);                            |       |
            imx_ion_data.heaps[0].base = phys;                                            |       |
        }                                                                                 |       |
    #endif                                                                                |       |
    }                                                                                     |       |
                                                                                          |       |
    //#define IPU_PIX_FMT_BIT24                                                           |       |
    static struct ipuv3_fb_platform_data sabresd_fb_data[] = {                   <--------+       |
        { /*fb0*/                                                                                 |
        .disp_dev = "ldb",                                                                        |
    #ifdef IPU_PIX_FMT_BIT24                                                                      |
        .interface_pix_fmt = IPU_PIX_FMT_RGB24,                                                   |
        .default_bpp = 24,                                                                        |
    #else                                                                                         |
        .interface_pix_fmt = IPU_PIX_FMT_RGB666,                                                  |
        .default_bpp = 16,                                                                        |
    #endif                                                                                        |
        .mode_str = "LDB-XGA",                                                                    |
        .int_clk = false,                                                                         |
        .late_init = false,                                                                       |
        },                                                                                        |
        {                                                                                         |
        .disp_dev = "hdmi",                                                                       |
        .interface_pix_fmt = IPU_PIX_FMT_RGB24,                                                   |
        .mode_str = "1920x1080M@60",                                                              |
        .default_bpp = 32,                                                                        |
        .int_clk = false,                                                                         |
        .late_init = false,                                                                       |
        },                                                                                        |
        {                                                                                         |
        .disp_dev = "ldb",                                                                        |
    #ifdef IPU_PIX_FMT_BIT24                                                                      |
        .interface_pix_fmt = IPU_PIX_FMT_RGB24,                                                   |
        .default_bpp = 24,                                                                        |
    #else                                                                                         |
        .interface_pix_fmt = IPU_PIX_FMT_RGB666,                                                  |
        .default_bpp = 16,                                                                        |
    #endif                                                                                        |
        .mode_str = "LDB-XGA",                                                                    |
        .int_clk = false,                                                                         |
        .late_init = false,                                                                       |
        },                                                                                        |
    };                                                                                            |
                                                                                                  |
    mm/memblock.c                                                                                 |
    long __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)                     |
    {                                                                                             |
        struct memblock_type *_rgn = &memblock.reserved;                                          |
                                                                                                  |
        BUG_ON(0 == size);                                                                        |
                                                                                                  |
        return memblock_add_region(_rgn, base, size);                                             |
    }                                                                                             |
                                                                                                  |
    long __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)                      |
    {                                                                                             |
        return __memblock_remove(&memblock.memory, base, size);                                   |
    }                                                                                             |
                                                                                                  |
    phys_addr_t __init memblock_alloc(phys_addr_t size, phys_addr_t align)                        |
    {                                                                                             |
        return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);                       |
    }                                                                                             |
                                                                                                  |
    static void __init mx6_sabresd_board_init(void)                              <----------------+
    {
        .....
        imx6q_add_ipuv3(0, &ipu_data[0]);
        if (cpu_is_mx6q()) {
            imx6q_add_ipuv3(1, &ipu_data[1]);                                              <------+
            for (i = 0; i < 4 && i < ARRAY_SIZE(sabresd_fb_data); i++)                            |
                imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]);                                        |
        } else                                                                                    |
            for (i = 0; i < 2 && i < ARRAY_SIZE(sabresd_fb_data); i++)                            |
                imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]);                                        |
        ......                                                                                    |
    }                                                                                             |
                                                                                                  |
    extern const struct imx_ipuv3_data imx6q_ipuv3_data[] __initconst;                     <------+
    #define imx6q_add_ipuv3(id, pdata)    imx_add_ipuv3(id, &imx6q_ipuv3_data[id], pdata)         |
    #define imx6q_add_ipuv3fb(id, pdata)    imx_add_ipuv3_fb(id, pdata)                           |
                                                                                                  |
    struct platform_device *__init imx_add_ipuv3_fb(                                <-------------+
            const int id,
            const struct ipuv3_fb_platform_data *pdata)
    {
        if (pdata->res_size[0] > 0) {
            struct resource res[] = {
                {
                    .start = pdata->res_base[0],
                    .end = pdata->res_base[0] + pdata->res_size[0] - 1,
                    .flags = IORESOURCE_MEM,
                }, {
                    .start = 0,
                    .end = 0,
                    .flags = IORESOURCE_MEM,
                },
            };
    
            if (pdata->res_size[1] > 0) {
                res[1].start = pdata->res_base[1];
                res[1].end = pdata->res_base[1] +
                        pdata->res_size[1] - 1;
            }
    
            return imx_add_platform_device_dmamask("mxc_sdc_fb",
                    id, res, ARRAY_SIZE(res), pdata,
                    sizeof(*pdata), DMA_BIT_MASK(32));
        } else
            return imx_add_platform_device_dmamask("mxc_sdc_fb", id,
                    NULL, 0, pdata, sizeof(*pdata),
                    DMA_BIT_MASK(32));
    }
    

    驱动注册

    kernel/video/mxc/mxc_ipuv3_fb.c

    int __init mxcfb_init(void)
    {
        return platform_driver_register(&mxcfb_driver);       ------+
    }                                                               |
                                                                    |
    static struct platform_driver mxcfb_driver = {             <----+
        .driver = {
               .name = MXCFB_NAME,
               },
        .probe = mxcfb_probe,             -------------------+
        .remove = mxcfb_remove,                              |
        .suspend = mxcfb_suspend,                            |
        .resume = mxcfb_resume,                              |
    };                                                       |
    #define MXCFB_NAME      "mxc_sdc_fb"                     |
                                                             |
                                                             |
    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;
        struct device *disp_dev;
        char buf[32];
        int ret = 0;
                                                 +--------------------------------+
        /* Initialize FB structures */           |                                |
        fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);                          |
        if (!fbi) {                                                               |
            ret = -ENOMEM;                                                        |
            goto init_fbinfo_failed;                                              |
        }                                                                         |
                                                                                  |
        ret = mxcfb_option_setup(pdev, fbi);               ----------------------------+
        if (ret)                                                                  |    |
            goto get_fb_option_failed;                                            |    |
                                                                                  |    |
        mxcfbi = (struct mxcfb_info *)fbi->par;                                   |    |
        spin_lock_init(&mxcfbi->lock);                                            |    |
        mxcfbi->fbi = fbi;                                                        |    |
        mxcfbi->ipu_int_clk = plat_data->int_clk;                                 |    |
        mxcfbi->late_init = plat_data->late_init;                                 |    |
        mxcfbi->first_set_par = true;                                             |    |
        mxcfbi->panel_width_mm = plat_data->panel_width_mm;                       |    |
        mxcfbi->panel_height_mm = plat_data->panel_height_mm;                     |    |
                                                                                  |    |
        ret = mxcfb_dispdrv_init(pdev, fbi);             -----------------------------------+
        if (ret < 0)                                                              |    |    |
            goto init_dispdrv_failed;                                             |    |    |
                                                                                  |    |    |
        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
    ",                    |    |    |    |
                    mxcfbi->ipu_id, mxcfbi->ipu_di);                              |    |    |    |
            goto ipu_in_busy;                                                     |    |    |    |
        }                                                                         |    |    |    |
                                                                                  |    |    |    |
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                     |    |    |    |
        if (res && res->start && 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);   |    |    |    |
            /* Do not clear the fb content drawn in bootloader. */                |    |    |    |
            if (!mxcfbi->late_init)                                               |    |    |    |
                memset(fbi->screen_base, 0, fbi->fix.smem_len);                   |    |    |    |
        }                                                                         |    |    |    |
                                                                                  |    |    |    |
        mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);                                |    |    |    |
        if (IS_ERR(mxcfbi->ipu)) {                                                |    |    |    |
            ret = -ENODEV;                                                        |    |    |    |
            goto get_ipu_failed;                                                  |    |    |    |
        }                                                                         |    |    |    |
                                                                                  |    |    |    |
        /* 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_ch_nf_irq = IPU_IRQ_BG_SYNC_NFACK;                        |    |    |    |
            mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;                   |    |    |    |
            mxcfbi->ipu_vsync_pre_irq = mxcfbi->ipu_di ?                          |    |    |    |
                            IPU_IRQ_VSYNC_PRE_1 :                                 |    |    |    |
                            IPU_IRQ_VSYNC_PRE_0;                                  |    |    |    |
            mxcfbi->ipu_ch = MEM_BG_SYNC;                                         |    |    |    |
            /* Unblank the primary fb only by default */                          |    |    |    |
            if (pdev->id == 0)                                                    |    |    |    |
                mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;        |    |    |    |
            else                                                                  |    |    |    |
                mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;      |    |    |    |
                                                                                  |    |    |    |
            ret = mxcfb_register(fbi);                 ------------------------------------------------+
            if (ret < 0)                                                          |    |    |    |     |
                goto mxcfb_register_failed;                                       |    |    |    |     |
                                                                                  |    |    |    |     |
            ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch,                |    |    |    |     |
                          true, 0x80);                                            |    |    |    |     |
            ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);        |    |    |    |     |
                                                                                  |    |    |    |     |
            res = platform_get_resource(pdev, IORESOURCE_MEM, 1);                 |    |    |    |     |
            ret = mxcfb_setup_overlay(pdev, fbi, res);                            |    |    |    |     |
                                                                                  |    |    |    |     |
            if (ret < 0) {                                                        |    |    |    |     |
                mxcfb_unregister(fbi);                                            |    |    |    |     |
                goto mxcfb_setupoverlay_failed;                                   |    |    |    |     |
            }                                                                     |    |    |    |     |
                                                                                  |    |    |    |     |
            g_dp_in_use[mxcfbi->ipu_id] = true;                                   |    |    |    |     |
                                                                                  |    |    |    |     |
            ret = device_create_file(mxcfbi->ovfbi->dev,                          |    |    |    |     |
                         &dev_attr_fsl_disp_property);                            |    |    |    |     |
            if (ret)                                                              |    |    |    |     |
                dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "               |    |    |    |     |
                                "file for disp property
    ",                       |    |    |    |     |
                                ret);                                             |    |    |    |     |
                                                                                  |    |    |    |     |
            ret = device_create_file(mxcfbi->ovfbi->dev,                          |    |    |    |     |
                         &dev_attr_fsl_disp_dev_property);                        |    |    |    |     |
            if (ret)                                                              |    |    |    |     |
                dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "               |    |    |    |     |
                                "file for disp device "                           |    |    |    |     |
                                "propety
    ", ret);                                |    |    |    |     |
        } else {                                                                  |    |    |    |     |
            mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;                             |    |    |    |     |
            mxcfbi->ipu_ch_nf_irq = IPU_IRQ_DC_SYNC_NFACK;                        |    |    |    |     |
            mxcfbi->ipu_alp_ch_irq = -1;                                          |    |    |    |     |
            mxcfbi->ipu_vsync_pre_irq = mxcfbi->ipu_di ?                          |    |    |    |     |
                            IPU_IRQ_VSYNC_PRE_1 :                                 |    |    |    |     |
                            IPU_IRQ_VSYNC_PRE_0;                                  |    |    |    |     |
            mxcfbi->ipu_ch = MEM_DC_SYNC;                                         |    |    |    |     |
            mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;          |    |    |    |     |
                                                                                  |    |    |    |     |
            ret = mxcfb_register(fbi);                                            |    |    |    |     |
            if (ret < 0)                                                          |    |    |    |     |
                goto mxcfb_register_failed;                                       |    |    |    |     |
        }                                                                         |    |    |    |     |
                                                                                  |    |    |    |     |
        platform_set_drvdata(pdev, fbi);                                          |    |    |    |     |
                                                                                  |    |    |    |     |
        ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_property);          |    |    |    |     |
        if (ret)                                                                  |    |    |    |     |
            dev_err(&pdev->dev, "Error %d on creating file for disp "             |    |    |    |     |
                        "property
    ", ret);                                       |    |    |    |     |
                                                                                  |    |    |    |     |
        ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_dev_property);      |    |    |    |     |
        if (ret)                                                                  |    |    |    |     |
            dev_err(&pdev->dev, "Error %d on creating file for disp "             |    |    |    |     |
                        " device propety
    ", ret);                                |    |    |    |     |
                                                                                  |    |    |    |     |
        disp_dev = mxc_dispdrv_getdev(mxcfbi->dispdrv);                           |    |    |    |     |
        if (disp_dev) {                                                           |    |    |    |     |
            ret = sysfs_create_link(&fbi->dev->kobj,                              |    |    |    |     |
                    &disp_dev->kobj, "disp_dev");                                 |    |    |    |     |
            if (ret)                                                              |    |    |    |     |
                dev_err(&pdev->dev,                                               |    |    |    |     |
                    "Error %d on creating file
    ", ret);                          |    |    |    |     |
        }                                                                         |    |    |    |     |
                                                                                  |    |    |    |     |
        INIT_WORK(&mxcfbi->vsync_pre_work, mxcfb_vsync_pre_work);                 |    |    |    |     |
                                                                                  |    |    |    |     |
        snprintf(buf, sizeof(buf), "mxcfb%d-vsync-pre", fbi->node);               |    |    |    |     |
        mxcfbi->vsync_pre_queue = create_singlethread_workqueue(buf);             |    |    |    |     |
        if (mxcfbi->vsync_pre_queue == NULL) {                                    |    |    |    |     |
            dev_err(fbi->device,                                                  |    |    |    |     |
                "Failed to alloc vsync-pre workqueue
    ");                         |    |    |    |     |
            ret = -ENOMEM;                                                        |    |    |    |     |
            goto workqueue_alloc_failed;                                          |    |    |    |     |
        }                                                                         |    |    |    |     |
                                                                                  |    |    |    |     |
    #ifdef CONFIG_HAS_EARLYSUSPEND                                                |    |    |    |     |
        mxcfbi->fbdrv_earlysuspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;        |    |    |    |     |
        mxcfbi->fbdrv_earlysuspend.suspend = mxcfb_early_suspend;                 |    |    |    |     |
        mxcfbi->fbdrv_earlysuspend.resume = mxcfb_later_resume;                   |    |    |    |     |
        mxcfbi->fbdrv_earlysuspend.data = pdev;                                   |    |    |    |     |
        register_early_suspend(&mxcfbi->fbdrv_earlysuspend);                      |    |    |    |     |
    #endif                                                                        |    |    |    |     |
                                                                                  |    |    |    |     |
    #ifdef CONFIG_LOGO                                                            |    |    |    |     |
        fb_prepare_logo(fbi, 0);                                                  |    |    |    |     |
        fb_show_logo(fbi, 0);                                                     |    |    |    |     |
    #endif                                                                        |    |    |    |     |
        /*                                                                        |    |    |    |     |
         * 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.                           |    |    |    |     |
         *                                                                        |    |    |    |     |
         * zengjf 2015-10-8 this also has down in uboot                           |    |    |    |     |
         */                                                                       |    |    |    |     |
        /*                                                                        |    |    |    |     |
        gpio_request(SABRESD_CABC_EN1, "cabc-en1");                               |    |    |    |     |
        gpio_direction_output(SABRESD_CABC_EN1, 1);                               |    |    |    |     |
        gpio_request(SABRESD_CABC_EN0, "cabc-en0");                               |    |    |    |     |
        gpio_direction_output(SABRESD_CABC_EN0, 1);                               |    |    |    |     |
        */                                                                        |    |    |    |     |
                                                                                  |    |    |    |     |
        return 0;                                                                 |    |    |    |     |
                                                                                  |    |    |    |     |
    workqueue_alloc_failed:                                                       |    |    |    |     |
    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);                                                 |    |    |    |     |
    get_fb_option_failed:                                                         |    |    |    |     |
    init_fbinfo_failed:                                                           |    |    |    |     |
        return ret;                                                               |    |    |    |     |
    }                                                                             |    |    |    |     |
                                                                                  |    |    |    |     |
    static struct fb_ops mxcfb_ops = {                         <------------------+    |    |    |     |
        .owner = THIS_MODULE,                                                          |    |    |     |
        .fb_set_par = mxcfb_set_par,                                                   |    |    |     |
        .fb_check_var = mxcfb_check_var,                                               |    |    |     |
        .fb_setcolreg = mxcfb_setcolreg,                                               |    |    |     |
        .fb_pan_display = mxcfb_pan_display,                                           |    |    |     |
        .fb_ioctl = mxcfb_ioctl,                                                       |    |    |     |
        .fb_mmap = mxcfb_mmap,                                                         |    |    |     |
        .fb_fillrect = cfb_fillrect,                                                   |    |    |     |
        .fb_copyarea = cfb_copyarea,                                                   |    |    |     |
        .fb_imageblit = cfb_imageblit,                                                 |    |    |     |
        .fb_blank = mxcfb_blank,                                                       |    |    |     |
    };                                                                                 |    |    |     |
                                                                                       |    |    |     |
                                                                                       |    |    |     |
    /*                                                                                 |    |    |     |
     * Parse user specified options (`video=trident:')                                 |    |    |     |
     * example:                                                                        |    |    |     |
     *     video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,bpp=16,noaccel                |    |    |     |
     *    video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,fbpix=RGB565                   |    |    |     |
     */                                                                                |    |    |     |
    static int mxcfb_option_setup(struct platform_device *pdev, struct fb_info *fbi) <-+    |    |     |
    {                                                                                       |    |     |
        struct ipuv3_fb_platform_data *pdata = pdev->dev.platform_data;                     |    |     |
        char *options, *opt, *fb_mode_str = NULL;                                           |    |     |
        char name[] = "mxcfb0";                                                             |    |     |
        uint32_t fb_pix_fmt = 0;                                                            |    |     |
                                                                                            |    |     |
        name[5] += pdev->id;                                                                |    |     |
        if (fb_get_options(name, &options)) {                              -------------+   |    |     |
            dev_err(&pdev->dev, "Can't get fb option for %s!
    ", name);                 |   |    |     |
            return -ENODEV;                                                             |   |    |     |
        }                                                                               |   |    |     |
                                                                                        |   |    |     |
        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);                      |   |    |     |
                pdata->disp_dev[strlen(opt) - 4] = '';                                |   |    |     |
            } else if (!strncmp(opt, "if=", 3)) {                                       |   |    |     |
                if (!strncmp(opt+3, "RGB24", 5))                                        |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_RGB24;                       |   |    |     |
                else if (!strncmp(opt+3, "BGR24", 5))                                   |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_BGR24;                       |   |    |     |
                else if (!strncmp(opt+3, "GBR24", 5))                                   |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_GBR24;                       |   |    |     |
                else if (!strncmp(opt+3, "RGB565", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_RGB565;                      |   |    |     |
                else if (!strncmp(opt+3, "RGB666", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_RGB666;                      |   |    |     |
                else if (!strncmp(opt+3, "YUV444", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_YUV444;                      |   |    |     |
                else if (!strncmp(opt+3, "LVDS666", 7))                                 |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_LVDS666;                     |   |    |     |
                else if (!strncmp(opt+3, "YUYV16", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_YUYV;                        |   |    |     |
                else if (!strncmp(opt+3, "UYVY16", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_UYVY;                        |   |    |     |
                else if (!strncmp(opt+3, "YVYU16", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_YVYU;                        |   |    |     |
                else if (!strncmp(opt+3, "VYUY16", 6))                                  |   |    |     |
                    pdata->interface_pix_fmt = IPU_PIX_FMT_VYUY;                        |   |    |     |
            } else if (!strncmp(opt, "fbpix=", 6)) {                                    |   |    |     |
                if (!strncmp(opt+6, "RGB24", 5))                                        |   |    |     |
                    fb_pix_fmt = IPU_PIX_FMT_RGB24;                                     |   |    |     |
                else if (!strncmp(opt+6, "BGR24", 5))                                   |   |    |     |
                    fb_pix_fmt = IPU_PIX_FMT_BGR24;                                     |   |    |     |
                else if (!strncmp(opt+6, "RGB32", 5))                                   |   |    |     |
                    fb_pix_fmt = IPU_PIX_FMT_RGB32;                                     |   |    |     |
                else if (!strncmp(opt+6, "BGR32", 5))                                   |   |    |     |
                    fb_pix_fmt = IPU_PIX_FMT_BGR32;                                     |   |    |     |
                else if (!strncmp(opt+6, "ABGR32", 6))                                  |   |    |     |
                    fb_pix_fmt = IPU_PIX_FMT_ABGR32;                                    |   |    |     |
                else if (!strncmp(opt+6, "RGB565", 6))                                  |   |    |     |
                    fb_pix_fmt = IPU_PIX_FMT_RGB565;                                    |   |    |     |
                                                                                        |   |    |     |
                if (fb_pix_fmt) {                                                       |   |    |     |
                    pixfmt_to_var(fb_pix_fmt, &fbi->var);                               |   |    |     |
                    pdata->default_bpp =                                                |   |    |     |
                        fbi->var.bits_per_pixel;                                        |   |    |     |
                }                                                                       |   |    |     |
            } else if (!strncmp(opt, "int_clk", 7)) {                                   |   |    |     |
                pdata->int_clk = true;                                                  |   |    |     |
                continue;                                                               |   |    |     |
            } else if (!strncmp(opt, "bpp=", 4)) {                                      |   |    |     |
                /* bpp setting cannot overwirte fbpix setting */                        |   |    |     |
                if (fb_pix_fmt)                                                         |   |    |     |
                    continue;                                                           |   |    |     |
                                                                                        |   |    |     |
                pdata->default_bpp =                                                    |   |    |     |
                    simple_strtoul(opt + 4, NULL, 0);                                   |   |    |     |
                                                                                        |   |    |     |
                fb_pix_fmt = bpp_to_pixfmt(pdata->default_bpp);                         |   |    |     |
                if (fb_pix_fmt)                                                         |   |    |     |
                    pixfmt_to_var(fb_pix_fmt, &fbi->var);                               |   |    |     |
            } else                                                                      |   |    |     |
                fb_mode_str = opt;                                                      |   |    |     |
        }                                                                               |   |    |     |
                                                                                        |   |    |     |
        if (fb_mode_str)                                                                |   |    |     |
            pdata->mode_str = fb_mode_str;                                              |   |    |     |
                                                                                        |   |    |     |
        return 0;                                                                       |   |    |     |
    }                                                                                   |   |    |     |
                                                                                        |   |    |     |
    drivers/video/fbmem.c                                                               |   |    |     |
    /**                                                                                 |   |    |     |
     * fb_get_options - get kernel boot parameters                                      |   |    |     |
     * @name:   framebuffer name as it would appear in                                  |   |    |     |
     *          the boot parameter line                                                 |   |    |     |
     *          (video=<name>:<options>)                                                |   |    |     |
     * @option: the option will be stored here                                          |   |    |     |
     *                                                                                  |   |    |     |
     * NOTE: Needed to maintain backwards compatibility                                 |   |    |     |
     */                                                                                 |   |    |     |
    //                                                                                  |   |    |     |
    int fb_get_options(char *name, char **option)                              <--------+   |    |     |
    {                                                                                       |    |     |
        char *opt, *options = NULL;                                                         |    |     |
        int retval = 0;                                                                     |    |     |
        int name_len = strlen(name), i;                                                     |    |     |
                                                                                            |    |     |
        if (name_len && ofonly && strncmp(name, "offb", 4))                                 |    |     |
            retval = 1;                                                                     |    |     |
                                                                                            |    |     |
        if (name_len && !retval) {                                                          |    |     |
            for (i = 0; i < FB_MAX; i++) {                                                  |    |     |
                if (video_options[i] == NULL)                                               |    |     |
                    continue;                                                               |    |     |
                if (!video_options[i][0])                                                   |    |     |
                    continue;                                                               |    |     |
                opt = video_options[i];                                                     |    |     |
                if (!strncmp(name, opt, name_len) &&                                        |    |     |
                    opt[name_len] == ':')                                                   |    |     |
                    options = opt + name_len + 1;                                           |    |     |
            }                                                                               |    |     |
        }                                                                                   |    |     |
        if (options && !strncmp(options, "off", 3))                                         |    |     |
            retval = 1;                                                                     |    |     |
                                                                                            |    |     |
        if (option)                                                                         |    |     |
            *option = options;                                                              |    |     |
                                                                                            |    |     |
        return retval;                                                                      |    |     |
    }                                                                                       |    |     |
                                                                                            |    |     |
    static int mxcfb_dispdrv_init(struct platform_device *pdev,             <---------------+    |     |
            struct fb_info *fbi)                                                                 |     |
    {                                                                                            |     |
        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;                                                                             |     |
                                                                                                 |     |
        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)] = '';                                                |     |
        } else {                                                                                 |     |
            memcpy(disp_dev, plat_data->disp_dev,                                                |     |
                    strlen(plat_data->disp_dev));                                                |     |
            disp_dev[strlen(plat_data->disp_dev)] = '';                                        |     |
        }                                                                                        |     |
                                                                                                 |     |
        dev_info(&pdev->dev, "register mxc display driver %s
    ", disp_dev);                      |     |
                                                                                                 |     |
        mxcfbi->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);                             |     |
        if (IS_ERR(mxcfbi->dispdrv)) {                                                           |     |
            ret = PTR_ERR(mxcfbi->dispdrv);                                                      |     |
            dev_err(&pdev->dev, "NO mxc display driver found!
    ");                               |     |
            return 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;                                                                              |     |
    }                                                                                            |     |
                                                                                                 |     |
    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 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);
        }
    
        mxcfb_check_var(&fbi->var, fbi);
    
        mxcfb_set_fix(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);
    
        if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq,
            mxcfb_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
            dev_err(fbi->device, "Error registering EOF irq handler.
    ");
            ret = -EBUSY;
            goto err0;
        }
        ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq);
        if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq,
            mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
            dev_err(fbi->device, "Error registering NFACK irq handler.
    ");
            ret = -EBUSY;
            goto err1;
        }
        ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq);
    
        if (mxcfbi->ipu_vsync_pre_irq != -1) {
            if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_vsync_pre_irq,
                        mxcfb_vsync_pre_irq_handler, 0,
                        MXCFB_NAME, fbi) != 0) {
                dev_err(fbi->device, "Error registering VSYNC irq "
                             "handler.
    ");
                ret = -EBUSY;
                goto err2;
            }
            ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_vsync_pre_irq);
        }
    
        if (mxcfbi->ipu_alp_ch_irq != -1)
            if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq,
                    mxcfb_alpha_irq_handler, IPU_IRQF_ONESHOT,
                        MXCFB_NAME, fbi) != 0) {
                dev_err(fbi->device, "Error registering alpha irq "
                        "handler.
    ");
                ret = -EBUSY;
                goto err3;
            }
    
        if (!mxcfbi->late_init) {
            fbi->var.activate |= FB_ACTIVATE_FORCE;
            console_lock();
            fbi->flags |= FBINFO_MISC_USEREVENT;
            ret = fb_set_var(fbi, &fbi->var);
            fbi->flags &= ~FBINFO_MISC_USEREVENT;
            console_unlock();
            if (ret < 0) {
                dev_err(fbi->device, "Error fb_set_var ret:%d
    ", ret);
                goto err4;
            }
    
            if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
                console_lock();
                ret = fb_blank(fbi, FB_BLANK_UNBLANK);
                console_unlock();
                if (ret < 0) {
                    dev_err(fbi->device,
                        "Error fb_blank ret:%d
    ", ret);
                    goto err5;
                }
            }
        } else {
            /*
             * Setup the channel again though bootloader
             * has done this, then set_par() can stop the
             * channel neatly and re-initialize it .
             */
            if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
                console_lock();
                _setup_disp_channel1(fbi);
                ipu_enable_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
                console_unlock();
            }
        }
    
        ret = register_framebuffer(fbi);                             -----------------+
        if (ret < 0)                                                                  |
            goto err6;                                                                |
                                                                                      |
        return ret;                                                                   |
    err6:                                                                             |
        if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {                                 |
            console_lock();                                                           |
            if (!mxcfbi->late_init)                                                   |
                fb_blank(fbi, FB_BLANK_POWERDOWN);                                    |
            else {                                                                    |
                ipu_disable_channel(mxcfbi->ipu, mxcfbi->ipu_ch,                      |
                            true);                                                    |
                ipu_uninit_channel(mxcfbi->ipu, mxcfbi->ipu_ch);                      |
            }                                                                         |
            console_unlock();                                                         |
        }                                                                             |
    err5:                                                                             |
    err4:                                                                             |
        if (mxcfbi->ipu_alp_ch_irq != -1)                                             |
            ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);                   |
    err3:                                                                             |
        if (mxcfbi->ipu_vsync_pre_irq != -1)                                          |
            ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_vsync_pre_irq, fbi);                |
    err2:                                                                             |
        ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq, fbi);                        |
    err1:                                                                             |
        ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);                           |
    err0:                                                                             |
        return ret;                                                                   |
    }                                                                                 |
                                                                                      |
    drivers/video/fbmem.c                                                             |
    register_framebuffer(struct fb_info *fb_info)                       <-------------+
    {
        int ret;
    
        mutex_lock(&registration_lock);
        ret = do_register_framebuffer(fb_info);                         -----+
        mutex_unlock(&registration_lock);                                    |
                                                                             |
        return ret;                                                          |
    }                                                                        |
                                                                             |
    static int do_register_framebuffer(struct fb_info *fb_info)         <----+
    {
        int i;
        struct fb_event event;
        struct fb_videomode mode;
    
        if (fb_check_foreignness(fb_info))
            return -ENOSYS;
    
        do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
                         fb_is_primary_device(fb_info));
    
        if (num_registered_fb == FB_MAX)
            return -ENXIO;
    
        num_registered_fb++;
        for (i = 0 ; i < FB_MAX; i++)
            if (!registered_fb[i])
                break;
        fb_info->node = i;
        atomic_set(&fb_info->count, 1);
        mutex_init(&fb_info->lock);
        mutex_init(&fb_info->mm_lock);
    
        fb_info->dev = device_create(fb_class, fb_info->device,
                         MKDEV(FB_MAJOR, i), NULL, "fb%d", i);                  --------------------------->> // 设备节点创建  /dev/fb0
        if (IS_ERR(fb_info->dev)) {
            /* Not fatal */
            printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld
    ", i, PTR_ERR(fb_info->dev));
            fb_info->dev = NULL;
        } else
            fb_init_device(fb_info);
    
        if (fb_info->pixmap.addr == NULL) {
            fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
            if (fb_info->pixmap.addr) {
                fb_info->pixmap.size = FBPIXMAPSIZE;
                fb_info->pixmap.buf_align = 1;
                fb_info->pixmap.scan_align = 1;
                fb_info->pixmap.access_align = 32;
                fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
            }
        }
        fb_info->pixmap.offset = 0;
    
        if (!fb_info->pixmap.blit_x)
            fb_info->pixmap.blit_x = ~(u32)0;
    
        if (!fb_info->pixmap.blit_y)
            fb_info->pixmap.blit_y = ~(u32)0;
    
        if (!fb_info->modelist.prev || !fb_info->modelist.next)
            INIT_LIST_HEAD(&fb_info->modelist);
    
        fb_var_to_videomode(&mode, &fb_info->var);
        fb_add_videomode(&mode, &fb_info->modelist);
        registered_fb[i] = fb_info;
    
        event.info = fb_info;
        if (!lock_fb_info(fb_info))
            return -ENODEV;
        fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
        unlock_fb_info(fb_info);
        return 0;
    }
    
  • 相关阅读:
    mybatis
    mybatis
    hadoop完全分布式搭建
    用构造器确保初始化
    HashMap的内部结构与hash冲突
    方法重载 与 方法覆盖
    Django后台管理admin或者adminx中使用富文本编辑器
    Celery在Django中的使用介绍
    django.db.utils.InternalError: (1060, "Duplicate column name 'user_id'")迁移报错解决方法
    Django2.0版本以上与pymsql 不匹配问题以及解决方法
  • 原文地址:https://www.cnblogs.com/helloworldtoyou/p/5824797.html
Copyright © 2020-2023  润新知