1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 高通平台msm8953 display子系统学习

高通平台msm8953 display子系统学习

时间:2024-01-10 18:05:19

相关推荐

高通平台msm8953 display子系统学习

硬件上,高通平台有一个mipi-dsi接口连接LCM,由MDP(mobile display processor)进行管理,就是一般说的LCD控制器

软件上,高通平台提供MDSS(Multimedia Display Sub-system)进行管理

软件驱动目录:kernel/msm-4.9/drivers/video/fbdev/msm

主要分为三部分:

MDP驱动:对使用的硬件资源进行初始化,同时在fb设备中注册mdp的使用接口,文件mdss_mdp3.c

DSI驱动:解析模组厂商提供的panel的dtsi文件,从哪个文件中能够获取到panel的mode,分辨率,还有Driver IC的初始化command;文件mdss_dsi_panel.c

FB驱动:实现Linux Framebuffer的注册和为上层用户提供访问控制接口;文件mdss_fb.c

一般的执行顺序是: MDP probe → DSI probe → FB probe

下面分析每部分的代码

LCD控制器、I2C控制器等一般都是平台设备,设备用platform_device表示,驱动用platform_driver表示。

MDP设备在dts文件中定义:

msm8953-mdss.dtsi&soc {mdss_mdp: qcom,mdss_mdp@1a00000 {compatible = "qcom,mdss_mdp";reg = <0x01a00000 0x90000>,<0x01ab0000 0x1040>;reg-names = "mdp_phys", "vbif_phys";interrupts = <0 72 0>;vdd-supply = <&gdsc_mdss>;/* Bus Scale Settings */qcom,msm-bus,name = "mdss_mdp";qcom,msm-bus,num-cases = <3>;qcom,msm-bus,num-paths = <1>;qcom,msm-bus,vectors-KBps =<22 512 0 0>,<22 512 0 6400000>,<22 512 0 6400000>;/* Fudge factors */qcom,mdss-ab-factor = <1 1>;/* 1 time */qcom,mdss-ib-factor = <1 1>;/* 1 time */qcom,mdss-clk-factor = <105 100>;/* 1.05 times */qcom,max-mixer-width = <2048>;qcom,max-pipe-width = <2048>;

MDP驱动的注册:

static const struct of_device_id mdss_mdp_dt_match[] = {{.compatible = "qcom,mdss_mdp",},{}};MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);static struct platform_driver mdss_mdp_driver = {.probe = mdss_mdp_probe,.remove = mdss_mdp_remove,.suspend = mdss_mdp_suspend,.resume = mdss_mdp_resume,.shutdown = NULL,.driver = {/** Driver name must match the device name added in* platform.c.*/.name = "mdp",.of_match_table = mdss_mdp_dt_match,.pm = &mdss_mdp_pm_ops,},};static int mdss_mdp_register_driver(void){return platform_driver_register(&mdss_mdp_driver);}static int __init mdss_mdp_driver_init(void){int ret;ret = mdss_mdp_register_driver();if (ret) {pr_err("mdp_register_driver() failed!\n");return ret;}return 0;}

老套路,设备和驱动匹配之后,调用mdss_mdp_probe函数,这个函数首先分配mdss_data_type结构体内存,然后对成员进行初始化:

static int mdss_mdp_probe(struct platform_device *pdev){struct resource *res;int rc;struct mdss_data_type *mdata;uint32_t intf_sel = 0;uint32_t split_display = 0;int num_of_display_on = 0;int i = 0;if (!pdev->dev.of_node) {pr_err("MDP driver only supports device tree probe\n");return -ENOTSUPP;}if (mdss_res) {pr_err("MDP already initialized\n");return -EINVAL;}mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL);if (mdata == NULL)return -ENOMEM;pdev->id = 0;mdata->pdev = pdev;platform_set_drvdata(pdev, mdata);mdss_res = mdata;mutex_init(&mdata->reg_lock);mutex_init(&mdata->reg_bus_lock);mutex_init(&mdata->bus_lock);INIT_LIST_HEAD(&mdata->reg_bus_clist);atomic_set(&mdata->sd_client_count, 0);atomic_set(&mdata->active_intf_cnt, 0);mdss_res->mdss_util = mdss_get_util_intf();if (mdss_res->mdss_util == NULL) {pr_err("Failed to get mdss utility functions\n");return -ENODEV;}mdss_res->mdss_util->get_iommu_domain = mdss_smmu_get_domain_id;mdss_res->mdss_util->iommu_attached = is_mdss_iommu_attached;mdss_res->mdss_util->iommu_ctrl = mdss_iommu_ctrl;mdss_res->mdss_util->bus_scale_set_quota = mdss_bus_scale_set_quota;mdss_res->mdss_util->bus_bandwidth_ctrl = mdss_bus_bandwidth_ctrl;mdss_res->mdss_util->panel_intf_type = mdss_panel_intf_type;mdss_res->mdss_util->panel_intf_status = mdss_panel_get_intf_status;rc = msm_mdss_ioremap_byname(pdev, &mdata->mdss_io, "mdp_phys");if (rc) {pr_err("unable to map MDP base\n");goto probe_done;}pr_debug("MDSS HW Base addr=0x%x len=0x%x\n",(int) (unsigned long) mdata->mdss_io.base,mdata->mdss_io.len);rc = msm_mdss_ioremap_byname(pdev, &mdata->vbif_io, "vbif_phys");if (rc) {pr_err("unable to map MDSS VBIF base\n");goto probe_done;}pr_debug("MDSS VBIF HW Base addr=0x%x len=0x%x\n",(int) (unsigned long) mdata->vbif_io.base,mdata->vbif_io.len);rc = msm_mdss_ioremap_byname(pdev, &mdata->vbif_nrt_io,"vbif_nrt_phys");if (rc)pr_debug("unable to map MDSS VBIF non-realtime base\n");elsepr_debug("MDSS VBIF NRT HW Base addr=%pK len=0x%x\n",mdata->vbif_nrt_io.base, mdata->vbif_nrt_io.len);res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);if (!res) {pr_err("unable to get MDSS irq\n");rc = -ENOMEM;goto probe_done;}mdss_mdp_hw.irq_info = kcalloc(1, sizeof(struct irq_info), GFP_KERNEL);if (!mdss_mdp_hw.irq_info)return -ENOMEM;mdss_mdp_hw.irq_info->irq = res->start;mdss_mdp_hw.ptr = mdata;/* export misc. interrupts to external driver */mdata->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 32,&mdss_irq_domain_ops, mdata);if (!mdata->irq_domain) {pr_err("unable to add linear domain\n");rc = -ENOMEM;goto probe_done;}mdss_misc_hw.irq_info = mdss_intr_line();rc = mdss_res->mdss_util->register_irq(&mdss_misc_hw);if (rc)pr_err("mdss_register_irq failed.\n");rc = mdss_mdp_res_init(mdata);if (rc) {pr_err("unable to initialize mdss mdp resources\n");goto probe_done;}rc = mdss_mdp_retention_init(mdata);if (rc) {pr_err("unable to initialize mdss mdp retention\n");goto probe_done;}pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT_MS);if (mdata->idle_pc_enabled)pm_runtime_use_autosuspend(&pdev->dev);pm_runtime_set_suspended(&pdev->dev);pm_runtime_enable(&pdev->dev);if (!pm_runtime_enabled(&pdev->dev))mdss_mdp_footswitch_ctrl(mdata, true);rc = mdss_mdp_bus_scale_register(mdata);if (rc) {pr_err("unable to register bus scaling\n");goto probe_done;}/** enable clocks and read mdp_rev as soon as possible once* kernel is up.*/mdss_mdp_footswitch_ctrl_splash(true);mdss_hw_rev_init(mdata);/*populate hw iomem base info from device tree*/rc = mdss_mdp_parse_dt(pdev);if (rc) {pr_err("unable to parse device tree\n");goto probe_done;}rc = mdss_mdp_get_cmdline_config(pdev);if (rc) {pr_err("Error in panel override:rc=[%d]\n", rc);goto probe_done;}rc = mdss_mdp_debug_init(pdev, mdata);if (rc) {pr_err("unable to initialize mdp debugging\n");goto probe_done;}rc = mdss_mdp_scaler_init(mdata, &pdev->dev);if (rc)goto probe_done;rc = mdss_mdp_register_sysfs(mdata);if (rc)pr_err("unable to register mdp sysfs nodes\n");rc = mdss_fb_register_mdp_instance(&mdp5);if (rc)pr_err("unable to register mdp instance\n");rc = mdss_res->mdss_util->register_irq(&mdss_mdp_hw);if (rc)pr_err("mdss_register_irq failed.\n");rc = mdss_smmu_init(mdata, &pdev->dev);if (rc)pr_err("mdss smmu init failed\n");mdss_mdp_set_supported_formats(mdata);mdss_res->mdss_util->mdp_probe_done = true;mdss_hw_init(mdata);rc = mdss_mdp_pp_init(&pdev->dev);if (rc)pr_err("unable to initialize mdss pp resources\n");/* Restoring Secure configuration during boot-up */if (mdss_mdp_req_init_restore_cfg(mdata))__mdss_restore_sec_cfg(mdata);if (mdss_has_quirk(mdata, MDSS_QUIRK_BWCPANIC)) {mdata->default_panic_lut0 = readl_relaxed(mdata->mdp_base +MMSS_MDP_PANIC_LUT0);mdata->default_panic_lut1 = readl_relaxed(mdata->mdp_base +MMSS_MDP_PANIC_LUT1);mdata->default_robust_lut = readl_relaxed(mdata->mdp_base +MMSS_MDP_ROBUST_LUT);}/** Read the DISP_INTF_SEL register to check if display was enabled in* bootloader or not. If yes, let handoff handle removing the extra* clk/regulator votes else turn off clk/regulators because purpose* here is to get mdp_rev.*/intf_sel = readl_relaxed(mdata->mdp_base +MDSS_MDP_REG_DISP_INTF_SEL);split_display = readl_relaxed(mdata->mdp_base +MDSS_MDP_REG_SPLIT_DISPLAY_EN);mdata->splash_intf_sel = intf_sel;mdata->splash_split_disp = split_display;if (intf_sel != 0) {for (i = 0; i < 4; i++)num_of_display_on += ((intf_sel >> i*8) & 0x000000FF);/** For split display enabled - DSI0, DSI1 interfaces are* considered as single display. So decrement* 'num_of_display_on' by 1*/if (split_display)num_of_display_on--;}if (!num_of_display_on) {mdss_mdp_footswitch_ctrl_splash(false);msm_bus_scale_client_update_request(mdata->bus_hdl, 0);mdata->ao_bw_uc_idx = 0;} else {mdata->handoff_pending = true;/** If multiple displays are enabled in LK, ctrl_splash off will* be called multiple times during splash_cleanup. Need to* enable it symmetrically*/for (i = 1; i < num_of_display_on; i++)mdss_mdp_footswitch_ctrl_splash(true);}mdp_intr_cb = kcalloc(ARRAY_SIZE(mdp_irq_map),sizeof(struct intr_callback), GFP_KERNEL);if (mdp_intr_cb == NULL)return -ENOMEM;mdss_res->mdp_irq_mask = kcalloc(ARRAY_SIZE(mdp_intr_reg),sizeof(u32), GFP_KERNEL);if (mdss_res->mdp_irq_mask == NULL)return -ENOMEM;pr_info("mdss version = 0x%x, bootloader display is %s, num %d, intf_sel=0x%08x\n",mdata->mdp_rev, num_of_display_on ? "on" : "off",num_of_display_on, intf_sel);probe_done:if (IS_ERR_VALUE((unsigned long)rc)) {if (!num_of_display_on)mdss_mdp_footswitch_ctrl_splash(false);if (mdata->regulator_notif_register)regulator_unregister_notifier(mdata->fs,&(mdata->gdsc_cb));mdss_mdp_hw.ptr = NULL;mdss_mdp_pp_term(&pdev->dev);mutex_destroy(&mdata->reg_lock);mdss_res = NULL;}return rc;}

这里msm_mdss_ioremap_byname(pdev, &mdata->mdss_io, “mdp_phys”)进行IO内存映射,以便可以通过内存操作直接访问外设寄存器。

static struct resource *msm_mdss_get_res_byname(struct platform_device *pdev,unsigned int type, const char *name){struct resource *res = NULL;res = platform_get_resource_byname(pdev, type, name);if (!res)DEV_ERR("%s: '%s' resource not found\n", __func__, name);return res;} /* msm_mdss_get_res_byname */EXPORT_SYMBOL(msm_mdss_get_res_byname);int msm_mdss_ioremap_byname(struct platform_device *pdev,struct mdss_io_data *io_data, const char *name){struct resource *res = NULL;if (!pdev || !io_data) {DEV_ERR("%pS->%s: invalid input\n",__builtin_return_address(0), __func__);return -EINVAL;}res = msm_mdss_get_res_byname(pdev, IORESOURCE_MEM, name);if (!res) {DEV_ERR("%pS->%s: '%s' msm_mdss_get_res_byname failed\n",__builtin_return_address(0), __func__, name);return -ENODEV;}io_data->len = (u32)resource_size(res);io_data->base = ioremap(res->start, io_data->len);if (!io_data->base) {DEV_ERR("%pS->%s: '%s' ioremap failed\n",__builtin_return_address(0), __func__, name);return -EIO;}return 0;} /* msm_mdss_ioremap_byname */

首先调用platform_get_resource_byname获得resource结构体,该结构体定义如下,这个结构体的每个成员值对应dts文件中的reg和reg-names属性。该resource是在系统开机初始化时调用struct resource *request_mem_region生成。获得物理基地址后,调用ioremap将物理基地址映射到虚拟地址空间,就能在驱动中进行访问。

struct resource {resource_size_t start; //表示资源的起始值,resource_size_t end; //表示资源的最后一个字节的地址, 如果是中断,end和satrt相同const char *name; // 可不写unsigned long flags; //资源的类型struct resource *parent, *sibling, *child;};reg = <0x01a00000 0x90000>,<0x01ab0000 0x1040>;reg-names = "mdp_phys", "vbif_phys";

DSI驱动的注册:

mdss_dsi.c 该文件中注册两个模块,dsi driver和dsi ctrl driver。mdss_dsi_probe中初始化dsi控制器,

mdss_dsi_ctrl_probe中解析模组厂提供的panel的dtsi文件。从文件中获得panel的mode、分辨率、帧率、command数据等

static const struct of_device_id mdss_dsi_dt_match[] = {{.compatible = "qcom,mdss-dsi"},{}};MODULE_DEVICE_TABLE(of, mdss_dsi_dt_match);static struct platform_driver mdss_dsi_driver = {.probe = mdss_dsi_probe,.remove = mdss_dsi_remove,.shutdown = NULL,.driver = {.name = "mdss_dsi",.of_match_table = mdss_dsi_dt_match,},};static struct platform_driver mdss_dsi_ctrl_driver = {.probe = mdss_dsi_ctrl_probe,.remove = mdss_dsi_ctrl_remove,.shutdown = NULL,.driver = {.name = "mdss_dsi_ctrl",.of_match_table = mdss_dsi_ctrl_dt_match,},};static int mdss_dsi_register_driver(void){return platform_driver_register(&mdss_dsi_driver);}static int __init mdss_dsi_driver_init(void){int ret;ret = mdss_dsi_register_driver();if (ret) {pr_err("mdss_dsi_register_driver() failed!\n");return ret;}return ret;}module_init(mdss_dsi_driver_init);static int mdss_dsi_ctrl_register_driver(void){return platform_driver_register(&mdss_dsi_ctrl_driver);}static int __init mdss_dsi_ctrl_driver_init(void){int ret;ret = mdss_dsi_ctrl_register_driver();if (ret) {pr_err("mdss_dsi_ctrl_register_driver() failed!\n");return ret;}return ret;}module_init(mdss_dsi_ctrl_driver_init);

FB驱动的注册:

static const struct of_device_id mdss_fb_dt_match[] = {{.compatible = "qcom,mdss-fb",},{}};EXPORT_COMPAT("qcom,mdss-fb");static struct platform_driver mdss_fb_driver = {.probe = mdss_fb_probe,.remove = mdss_fb_remove,.suspend = mdss_fb_suspend,.resume = mdss_fb_resume,.shutdown = mdss_fb_shutdown,.driver = {.name = "mdss_fb",.of_match_table = mdss_fb_dt_match,.pm = &mdss_fb_pm_ops,},};int __init mdss_fb_init(void){int rc = -ENODEV;if (fb_get_options("msmfb", NULL))return rc;if (platform_driver_register(&mdss_fb_driver))return rc;return 0;}

mdss-fb在设备树中配置如下,注意这个有三个compatible属性都是qcom,mdss-fb的节点

msm8953-mdss.dtsi&soc {mdss_fb0: qcom,mdss_fb_primary {cell-index = <0>;compatible = "qcom,mdss-fb";qcom,cont-splash-memory {linux,contiguous-region = <&cont_splash_mem>;};};mdss_fb1: qcom,mdss_fb_wfd {cell-index = <1>;compatible = "qcom,mdss-fb";};mdss_fb2: qcom,mdss_fb_secondary {cell-index = <2>;compatible = "qcom,mdss-fb";}

设备和驱动匹配成功后,调用mdss_fb_probe

static int mdss_fb_probe(struct platform_device *pdev){struct msm_fb_data_type *mfd = NULL;struct mdss_panel_data *pdata;struct fb_info *fbi;int rc;const char *data;if (fbi_list_index >= MAX_FBI_LIST)return -ENOMEM;pdata = dev_get_platdata(&pdev->dev);if (!pdata)return -EPROBE_DEFER;if (!mdp_instance) {pr_err("mdss mdp resource not initialized yet\n");return -ENODEV;}/** alloc framebuffer info + par data*/fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);if (fbi == NULL) {pr_err("can't allocate framebuffer info data!\n");return -ENOMEM;}mfd = (struct msm_fb_data_type *)fbi->par;mfd->key = MFD_KEY;mfd->fbi = fbi;mfd->panel_info = &pdata->panel_info;mfd->panel.type = pdata->panel_info.type;mfd->panel.id = mfd->index;mfd->fb_page = MDSS_FB_NUM;mfd->index = fbi_list_index;mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;mfd->ext_ad_ctrl = -1;if (mfd->panel_info && mfd->panel_info->brightness_max > 0)MDSS_BRIGHT_TO_BL(mfd->bl_level, backlight_led.brightness,mfd->panel_info->bl_max, mfd->panel_info->brightness_max);elsemfd->bl_level = 0;mfd->bl_scale = 1024;mfd->bl_min_lvl = 30;mfd->ad_bl_level = 0;mfd->fb_imgType = MDP_RGBA_8888;mfd->calib_mode_bl = 0;mfd->unset_bl_level = U32_MAX;mfd->bl_extn_level = -1;mfd->pdev = pdev;if (mfd->panel.type == SPI_PANEL)mfd->fb_imgType = MDP_RGB_565;if (mfd->panel.type == MIPI_VIDEO_PANEL || mfd->panel.type ==MIPI_CMD_PANEL || mfd->panel.type == SPI_PANEL){rc = of_property_read_string(pdev->dev.of_node,"qcom,mdss-fb-format", &data);if (!rc) {if (!strcmp(data, "rgb888"))mfd->fb_imgType = MDP_RGB_888;else if (!strcmp(data, "rgb565"))mfd->fb_imgType = MDP_RGB_565;elsemfd->fb_imgType = MDP_RGBA_8888;}}mfd->split_fb_left = mfd->split_fb_right = 0;mdss_fb_set_split_mode(mfd, pdata);pr_info("fb%d: split_mode:%d left:%d right:%d\n", mfd->index,mfd->split_mode, mfd->split_fb_left, mfd->split_fb_right);mfd->mdp = *mdp_instance;rc = of_property_read_bool(pdev->dev.of_node,"qcom,boot-indication-enabled");if (rc) {led_trigger_register_simple("boot-indication",&(mfd->boot_notification_led));}INIT_LIST_HEAD(&mfd->file_list);mutex_init(&mfd->bl_lock);mutex_init(&mfd->mdss_sysfs_lock);mutex_init(&mfd->switch_lock);fbi_list[fbi_list_index++] = fbi;platform_set_drvdata(pdev, mfd);rc = mdss_fb_register(mfd);if (rc)return rc;mdss_fb_create_sysfs(mfd);mdss_fb_send_panel_event(mfd, MDSS_EVENT_FB_REGISTERED, fbi);if (mfd->mdp.init_fnc) {rc = mfd->mdp.init_fnc(mfd);if (rc) {pr_err("init_fnc failed\n");return rc;}}mdss_fb_init_fps_info(mfd);rc = pm_runtime_set_active(mfd->fbi->dev);if (rc < 0)pr_err("pm_runtime: fail to set active.\n");pm_runtime_enable(mfd->fbi->dev);/* android supports only one lcd-backlight/lcd for now */if (!lcd_backlight_registered) {backlight_led.brightness = mfd->panel_info->brightness_max;backlight_led.max_brightness = mfd->panel_info->brightness_max;if (led_classdev_register(&pdev->dev, &backlight_led))pr_err("led_classdev_register failed\n");elselcd_backlight_registered = 1;}mdss_fb_init_panel_modes(mfd, pdata);mfd->mdp_sync_pt_data.fence_name = "mdp-fence";if (mfd->mdp_sync_pt_data.timeline == NULL) {char timeline_name[32];snprintf(timeline_name, sizeof(timeline_name),"mdss_fb_%d", mfd->index);mfd->mdp_sync_pt_data.timeline =mdss_create_timeline(timeline_name);if (mfd->mdp_sync_pt_data.timeline == NULL) {pr_err("cannot create release fence time line\n");return -ENOMEM;}mfd->mdp_sync_pt_data.notifier.notifier_call =__mdss_fb_sync_buf_done_callback;}mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type);if (mfd->mdp.splash_init_fnc)mfd->mdp.splash_init_fnc(mfd);/** Register with input driver for a callback for command mode panels.* When there is an input event, mdp clocks will be turned on to reduce* latency when a frame update happens.* For video mode panels, idle timeout will be delayed so that userspace* does not get an idle event while new frames are expected. In case of* an idle event, user space tries to fall back to GPU composition which* can lead to increased load when there are new frames.*/if (mfd->mdp.input_event_handler &&((mfd->panel_info->type == MIPI_CMD_PANEL) ||(mfd->panel_info->type == MIPI_VIDEO_PANEL)))if (mdss_fb_register_input_handler(mfd))pr_err("failed to register input handler\n");INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);return rc;}

调用framebuffer_alloc分配一个fbi内存,该函数将struct fb_info和私有数据的内存info->par一起分配,并且按sizeof(long)对齐。这种方法分配了连续的内存,减少内存的碎片化,是一种常用的方法。

struct fb_info *framebuffer_alloc(size_t size, struct device *dev){#define BYTES_PER_LONG (BITS_PER_LONG/8)#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))int fb_info_size = sizeof(struct fb_info);struct fb_info *info;char *p;if (size)fb_info_size += PADDING;p = kzalloc(fb_info_size + size, GFP_KERNEL);if (!p)return NULL;info = (struct fb_info *) p;if (size)info->par = p + fb_info_size;info->device = dev;info->fbcon_rotate_hint = -1;#if IS_ENABLED(CONFIG_FB_BACKLIGHT)mutex_init(&info->bl_curve_mutex);#endifreturn info;#undef PADDING#undef BYTES_PER_LONG}EXPORT_SYMBOL(framebuffer_alloc);

接下来调用mdss_fb_register对fb_info结构体进行填充,调用register_framebuffer完成fb的注册

static int mdss_fb_register(struct msm_fb_data_type *mfd){int ret = -ENODEV;int bpp;char panel_name[20];struct mdss_panel_info *panel_info = mfd->panel_info;struct fb_info *fbi = mfd->fbi;struct fb_fix_screeninfo *fix;struct fb_var_screeninfo *var;int *id;/** fb info initialization*/fix = &fbi->fix;var = &fbi->var;fix->type_aux = 0;/* if type == FB_TYPE_INTERLEAVED_PLANES */fix->visual = FB_VISUAL_TRUECOLOR;/* True Color */fix->ywrapstep = 0;/* No support */fix->mmio_start = 0;/* No MMIO Address */fix->mmio_len = 0;/* No MMIO Address */fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */var->xoffset = 0,/* Offset from virtual to visible */var->yoffset = 0,/* resolution */var->grayscale = 0,/* No graylevels */var->nonstd = 0,/* standard pixel format */var->activate = FB_ACTIVATE_VBL,/* activate it at vsync */var->height = -1,/* height of picture in mm */var->width = -1,/* width of picture in mm */var->accel_flags = 0,/* acceleration flags */var->sync = 0,/* see FB_SYNC_* */var->rotate = 0,/* angle we rotate counter clockwise */mfd->op_enable = false;mdss_panelinfo_to_fb_var(panel_info, var);fix->type = panel_info->is_3d_panel;if (mfd->mdp.fb_stride)fix->line_length = mfd->mdp.fb_stride(mfd->index, var->xres,bpp);elsefix->line_length = var->xres * bpp;var->xres_virtual = var->xres;var->yres_virtual = panel_info->yres * mfd->fb_page;var->bits_per_pixel = bpp * 8;/* FrameBuffer color depth *//** Populate smem length here for uspace to get the* Framebuffer size when FBIO_FSCREENINFO ioctl is called.*/fix->smem_len = PAGE_ALIGN(fix->line_length * var->yres) * mfd->fb_page;/* id field for fb app */id = (int *)&mfd->panel;snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);fbi->fbops = &mdss_fb_ops;fbi->flags = FBINFO_FLAG_DEFAULT;fbi->pseudo_palette = mdss_fb_pseudo_palette;mfd->ref_cnt = 0;mfd->panel_power_state = MDSS_PANEL_POWER_OFF;mfd->dcm_state = DCM_UNINIT;if (mdss_fb_alloc_fbmem(mfd))pr_warn("unable to allocate fb memory in fb register\n");mfd->op_enable = true;mutex_init(&mfd->update.lock);mutex_init(&mfd->no_update.lock);mutex_init(&mfd->mdp_sync_pt_data.sync_mutex);atomic_set(&mfd->mit_cnt, 0);atomic_set(&mfd->commits_pending, 0);atomic_set(&mfd->ioctl_ref_cnt, 0);atomic_set(&mfd->kickoff_pending, 0);init_timer(&mfd->no_update.timer);mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;mfd->no_update.timer.data = (unsigned long)mfd;mfd->update.ref_count = 0;mfd->no_update.ref_count = 0;mfd->update.init_done = false;init_completion(&mfd->p);init_completion(&mfd->p);init_completion(&mfd->power_off_comp);init_completion(&mfd->power_set_comp);init_waitqueue_head(&mfd->commit_wait_q);init_waitqueue_head(&mfd->idle_wait_q);init_waitqueue_head(&mfd->ioctl_q);init_waitqueue_head(&mfd->kickoff_wait_q);ret = fb_alloc_cmap(&fbi->cmap, 256, 0);if (ret)pr_err("fb_alloc_cmap() failed!\n");if (register_framebuffer(fbi) < 0) {fb_dealloc_cmap(&fbi->cmap);mfd->op_enable = false;return -EPERM;}snprintf(panel_name, ARRAY_SIZE(panel_name), "mdss_panel_fb%d",mfd->index);mdss_panel_debugfs_init(panel_info, panel_name);pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index,fbi->var.xres, fbi->var.yres);return 0;}

fbi->fbops = &mdss_fb_ops;static struct fb_ops mdss_fb_ops = {.owner = THIS_MODULE,.fb_open = mdss_fb_open,.fb_release = mdss_fb_release,.fb_check_var = mdss_fb_check_var,/* vinfo check */.fb_set_par = mdss_fb_set_par,/* set the video mode */.fb_blank = mdss_fb_blank,/* blank display */.fb_pan_display = mdss_fb_pan_display,/* pan display */.fb_ioctl_v2 = mdss_fb_ioctl,/* perform fb specific ioctl */#ifdef CONFIG_COMPAT.fb_compat_ioctl_v2 = mdss_fb_compat_ioctl,#endif.fb_mmap = mdss_fb_mmap,};

fb_mmap 用于应用层和framebuffer的内存映射

static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma){struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;int rc = -EINVAL;if (mfd->fb_mmap_type == MDP_FB_MMAP_ION_ALLOC) {rc = mdss_fb_fbmem_ion_mmap(info, vma);} else if (mfd->fb_mmap_type == MDP_FB_MMAP_PHYSICAL_ALLOC) {rc = mdss_fb_physical_mmap(info, vma);} else {if (!info->fix.smem_start && !mfd->fb_ion_handle) {rc = mdss_fb_fbmem_ion_mmap(info, vma);mfd->fb_mmap_type = MDP_FB_MMAP_ION_ALLOC;} else {rc = mdss_fb_physical_mmap(info, vma);mfd->fb_mmap_type = MDP_FB_MMAP_PHYSICAL_ALLOC;}}if (rc < 0)pr_err("fb mmap failed with rc = %d\n", rc);return rc;}

这里调用led_classdev_register注册背光灯设备

/* android supports only one lcd-backlight/lcd for now */if (!lcd_backlight_registered) {backlight_led.brightness = mfd->panel_info->brightness_max;backlight_led.max_brightness = mfd->panel_info->brightness_max;if (led_classdev_register(&pdev->dev, &backlight_led))pr_err("led_classdev_register failed\n");elselcd_backlight_registered = 1;}

开机亮屏灭屏流程(fb_ioctl)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。