Mxc_ipuv3_fb.c Analysis of Three framebuffers of MX51

Source: Internet
Author: User

MX51 supports three framebuffers: fb0, Fb1, and fb2.

/Dev/graphics/fb0,/dev/graphics/Fb1:

One is the primary framebuffer of the system and the other is the framebuffer output by tvout. By default, fb0 performs primary (that is, used to display the UI on the primary LCD ), fb1 performs secondary (that is, it is used to display data on the tvout output ).

Based on the actual physical connection in the project, if the primary LCD is connected to disp0, use the default settings. If the primary LCD is connected to disp1, add di1_primary to the kernel startup parameter.

/Dev/graphics/fb2:

Framebuffer used for overlay and video data display. It only supports bpp16 and the data format is yuv422. It can be synthesized in dp (display process) and data from mem_bg_sync, then it is sent to DC/di.

In mxc framebuffer probe, the first registered mxc framebuffer (fb0 or Fb1, this framebuffer serves as the framebuffer of the main LCD) uses mem_bg_sync, and the second registered mxc framebuffer (fb0 or Fb1, this framebuffer acts as the framebuffer used by tvout) uses mem_dc_sync, And the last registered framebuffer (fb2) uses mem_fg_sync.

Mem_bg_sync and mem_fg_sync are unique resources in mx5x IPU, which means that each channel can only be occupied by one of the framebuffer. In fact, the mem_dc_sync channel does not exist, but is used to directly connect to DC.

Note that the data in these framebuffer is not directly connected to the display device, and there may be a DP processing unit of MX51 IPU in the middle. DP Unit is responsible for processing the data from fb0 Fb1 fb2, including color conversion, layer merging, Gamma processing, and cursor processing are sent to DC-> Di-> display device.

FSL creates a FSL-Specific Property file fsl_disp_property under/sys/class/graphics/fbx/. The following is displayed on my machine:

# cat /sys/class/graphics/fb0/fsl_disp_property2-layer-fb-bg# cat /sys/class/graphics/fb1/fsl_disp_property1-layer-fb# cat /sys/class/graphics/fb2/fsl_disp_property2-layer-fb-fg

2-layer-fb-bg, indicating that fb0 uses the mem_bg_sync channel, merges data from the display process module of IPU and mem_fg_sync channel, and then sends the data to the DC.

1-layer-fb indicates that Fb1 uses the mem_dc_sync channel and directly connects to di (display interface) without passing through the display process module)

2-layber-fb-fg, indicating that fb2 uses the mem_fg_sync channel, merges data from the display process module of IPU and mem_bg_sync channel, and then sends the data to the DC.

You can also modify/sys/class/graphics/fb0/fsl_disp_property and/sys/class/graphics/Fb1/fsl_disp_property at the application layer by running the following command:

Echo 1-layer-fb>/sys/class/graphics/fb0/fsl_disp_property or ECHO 2-layer-fb-bg>/sys/class/graphics/Fb1/fsl_disp_property

Note that the two functions are the same, and fb0 and Fb1 exchange display channels. The purpose of FSL to introduce this attribute is to provide an interface for upper-layer applications, this allows the application layer to control whether fb0 Fb1 uses the mem_bg_sync or mem_dc_sync channel, which may be confusing. Why should the application layer select the fb0 Fb1 channel? First, we need to clarify the differences between mem_bg_sync and mem_dc_sync.

Imx51/imx53 IPU supports three types of display channels: mem_bg_sync, mem_fg_sync, and mem_dc_sync. framebuffer can only transmit data through one of the three channels, which are physically unique, only one framebuffer can be used at a time.

MEM_BG_SYNC:fb0 -> DP (full plane) -> DC -> DI0MEM_FG_SYNC:fb2 -> DP (partial plane) -> DC -> DI0MEM_DC_SYNC:fb1 -> DC -> DI1

Mem_bg_sync and mem_fg_sync are merged in DP. This function is called overlay.

Normally, the UI from fb0 and the video data from fb2 are merged in DP and sent to di0. Then we can see the effect of the UI floating on the video. However, when activating a dual-screen, you usually want to send the video data and UI to the back-screen (di1). The front screen only displays the UI. In this case, Fb1 needs to have mem_bg_sync. In this case, the display channels of Fb1 and fb0 need to be exchanged as follows:

MEM_BG_SYNC: fb1 -> DP (full plane) -> DC -> DI0MEM_FG_SYNC: fb2 -> DP (partial plane) -> DC -> DI1MEM_DC_SYNC: fb0 -> DC -> DI0

Channel Exchange Code

swap_disp_chan1673 static ssize_t swap_disp_chan(struct device *dev,1674                   struct device_attribute *attr,1675                   const char *buf, size_t count)1676 {1677     struct fb_info *info = dev_get_drvdata(dev);1678     struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;1679     struct mxcfb_info *fg_mxcfbi = NULL;1680 1681     acquire_console_sem();1682     /* swap only happen between DP-BG and DC, while DP-FG disable */1683     if (((mxcfbi->ipu_ch == MEM_BG_SYNC) &&1684          (strstr(buf, "1-layer-fb") != NULL)) ||1685         ((mxcfbi->ipu_ch == MEM_DC_SYNC) &&1686          (strstr(buf, "2-layer-fb-bg") != NULL))) {1687         int i;1688 1689         for (i = 0; i < num_registered_fb; i++) {1690             fg_mxcfbi =1691                 (struct mxcfb_info *)mxcfb_info[i]->par;1692             if (fg_mxcfbi->ipu_ch == MEM_FG_SYNC)1693                 break;1694             else1695                 fg_mxcfbi = NULL;1696         }1697         if (!fg_mxcfbi ||1698             fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {1699             dev_err(dev,1700                 "Can not switch while fb2(fb-fg) is on.\n");1701             release_console_sem();1702             return count;1703         }1704 1705         if (swap_channels(info) < 0)1706             dev_err(dev, "Swap display channel failed.\n");1707     }1708 1709     release_console_sem();1710     return count;1711 }1712 DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan);

1682 ~ 1686 only fb0 and Fb1 are involved in the exchange of display channels. fb2 only uses mem_fg_sync
1705 call swap_channels to implement channel Switching

swap_channels 545 static int swap_channels(struct fb_info *fbi) 546 { 547     int i; 548     int swap_mode; 549     ipu_channel_t ch_to; 550     struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par; 551     struct fb_info *fbi_to = NULL; 552     struct mxcfb_info *mxc_fbi_to; 553  554     /* what's the target channel? */ 555     if (mxc_fbi_from->ipu_ch == MEM_BG_SYNC) 556         ch_to = MEM_DC_SYNC; 557     else 558         ch_to = MEM_BG_SYNC; 559  560     for (i = 0; i < num_registered_fb; i++) { 561         mxc_fbi_to = 562             (struct mxcfb_info *)mxcfb_info[i]->par; 563         if (mxc_fbi_to->ipu_ch == ch_to) { 564             fbi_to = mxcfb_info[i]; 565             break; 566         } 567     } 568     if (fbi_to == NULL) 569         return -1; 570  571     ipu_clear_irq(mxc_fbi_from->ipu_ch_irq); 572     ipu_clear_irq(mxc_fbi_to->ipu_ch_irq); 573     ipu_free_irq(mxc_fbi_from->ipu_ch_irq, fbi); 574     ipu_free_irq(mxc_fbi_to->ipu_ch_irq, fbi_to); 575  576     if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) { 577         if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK) 578             swap_mode = BOTH_ON; 579         else 580             swap_mode = SRC_ON; 581     } else { 582         if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK) 583             swap_mode = TGT_ON; 584         else 585             swap_mode = BOTH_OFF; 586     } 587  588     /* tvout di-1: for DC use UYVY, for DP use RGB */ 589     if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_DC_SYNC) { 590         fbi->var.bits_per_pixel = 16; 591         fbi->var.nonstd = IPU_PIX_FMT_UYVY; 592     } else if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_BG_SYNC) { 593         fbi->var.nonstd = 0; 594     } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_DC_SYNC) { 595         fbi_to->var.nonstd = 0; 596     } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_BG_SYNC) { 597         fbi->var.bits_per_pixel = 16; 598         fbi->var.nonstd = IPU_PIX_FMT_UYVY; 599     } 600  601     switch (swap_mode) { 602     case BOTH_ON: 603         /* disable target->switch src->enable target */ 604         _swap_channels(fbi, fbi_to, true); 605         break; 606     case SRC_ON: 607         /* just switch src */ 608         _swap_channels(fbi, fbi_to, false); 609         break; 610     case TGT_ON: 611         /* just switch target */ 612         _swap_channels(fbi_to, fbi, false); 613         break; 614     case BOTH_OFF: 615         /* switch directly, no more need to do */ 616         mxc_fbi_to->ipu_ch = mxc_fbi_from->ipu_ch; 617         mxc_fbi_from->ipu_ch = ch_to; 618         i = mxc_fbi_from->ipu_ch_irq; 619         mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq; 620         mxc_fbi_to->ipu_ch_irq = i; 621         break; 622     default: 623         break; 624     } 625  626     if (ipu_request_irq(mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0, 627         MXCFB_NAME, fbi) != 0) { 628         dev_err(fbi->device, "Error registering irq %d\n", 629             mxc_fbi_from->ipu_ch_irq); 630         return -EBUSY; 631     } 632     ipu_disable_irq(mxc_fbi_from->ipu_ch_irq); 633     if (ipu_request_irq(mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0, 634         MXCFB_NAME, fbi_to) != 0) { 635         dev_err(fbi_to->device, "Error registering irq %d\n", 636             mxc_fbi_to->ipu_ch_irq); 637         return -EBUSY; 638     } 639     ipu_disable_irq(mxc_fbi_to->ipu_ch_irq); 640  641     return 0; 642 } 

550 mxc_fbi_from has the same meaning as the word surface. Which fb_info do we want to exchange, that is, the exchange source?

555 ~ 558 the exchange only occurs between mem_dc_sync and mem_bg_sync. If the source FB channel is mem_bg_sync, we want to switch to mem_dc_sync, and vice versa.

560 ~ 567 find the framebuffer in which the target channel is located.

576 ~ 586 swap_mode: record the blank status of source and DEST framebuffer

571 ~ 574 first release the IPU channel interrupt Number of from and to, because the IPU channel interrupt number will also be exchanged with the Channel

589 ~ 599 I have no idea

601 ~ 613 _ swap_channels for exchange

614 ~ 620 if both fbi_from and fbi_to are in the blank state, you can directly switch the channel. Note that the channel interruption number must also be exchanged because the channel and channel interruption number are one-to-one.

626 ~ 642 apply for ipu irq again for fbi_from and fbi_to. Here IRQ is disable, but it doesn't matter. When the pan_display operation is performed, ipu irq will be available.

swap_channels 504 static int _swap_channels(struct fb_info *fbi, 505               struct fb_info *fbi_to, bool both_on) 506 { 507     int retval, tmp; 508     ipu_channel_t old_ch; 509     struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par; 510     struct mxcfb_info *mxc_fbi_to = (struct mxcfb_info *)fbi_to->par; 511  512     if (both_on) { 513         ipu_disable_channel(mxc_fbi_to->ipu_ch, true); 514         ipu_uninit_channel(mxc_fbi_to->ipu_ch); 515     } 516  517     /* switch the mxc fbi parameters */ 518     old_ch = mxc_fbi_from->ipu_ch; 519     mxc_fbi_from->ipu_ch = mxc_fbi_to->ipu_ch; 520     mxc_fbi_to->ipu_ch = old_ch; 521     tmp = mxc_fbi_from->ipu_ch_irq; 522     mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq; 523     mxc_fbi_to->ipu_ch_irq = tmp; 524  525     _setup_disp_channel1(fbi); 526     retval = _setup_disp_channel2(fbi); 527     if (retval) 528         return retval; 529  530     /* switch between dp and dc, disable old idmac, enable new idmac */ 531     retval = ipu_swap_channel(old_ch, mxc_fbi_from->ipu_ch); 532     ipu_uninit_channel(old_ch); 533  534     if (both_on) { 535         _setup_disp_channel1(fbi_to); 536         retval = _setup_disp_channel2(fbi_to); 537         if (retval) 538             return retval; 539         ipu_enable_channel(mxc_fbi_to->ipu_ch); 540     } 541  542     return retval; 543 }

504 ~ 505 the function has three parameters: @ FBI is source, @ fbi_to is DEST, @ both_on is true, then @ fbi_to is unblank; false, then @ fbi_to is blank. Here @ FBI must be in the unblank state, otherwise this function will not be called.

512 ~ 515 destroy the @ fbi_to channel before switching

518 ~ 523 exchange channel and channel IRQ

525 ~ 528 after the switch is complete, set the disp channel parameters.

531 ~ 532 now, the channel number has been switched, but one more thing has not been done yet. We know which di the DC channel connects to in the control register dc_wr_ch_conf_x of DC channel, we want to switch the channel, but do not want to change the configuration to Di. Ipu_swap_channel switches the di configuration of two DC channels.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.