当前位置:网站首页>Qualcomm platform msm8953 display subsystem learning
Qualcomm platform msm8953 display subsystem learning
2022-06-22 07:28:00 【Neilo_ chen】
On the hardware , The Qualcomm platform has a mipi-dsi Interface connection LCM, from MDP(mobile display processor) Conduct management , Generally speaking LCD controller
Software , Provided by Qualcomm platform MDSS(Multimedia Display Sub-system) Conduct management
Software driver Directory :kernel/msm-4.9/drivers/video/fbdev/msm
It is divided into three parts :
MDP drive : Initialize the hardware resources used , At the same time fb Register in the device mdp The use interface of , file mdss_mdp3.c
DSI drive : Analyze the information provided by the module manufacturer panel Of dtsi file , Which file can be obtained from panel Of mode, The resolution of the , also Driver IC The initialization command; file mdss_dsi_panel.c
FB drive : Realization Linux Framebuffer Register and provide access control interface for upper users ; file mdss_fb.c
The general order of execution is : MDP probe → DSI probe → FB probe
Let's analyze each part of the code
LCD controller 、I2C Controllers are generally platform equipment , For equipment platform_device Express , For driving platform_driver Express .
MDP Equipment in dts The document defines :
msm8953-mdss.dtsi
&soc {
mdss_mdp: qcom,[email protected]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 Driver registration :
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;
}
Old ways , After the device and the drive are matched , call mdss_mdp_probe function , This function first assigns mdss_data_type Structure memory , Then initialize the members :
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");
else
pr_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;
}
here msm_mdss_ioremap_byname(pdev, &mdata->mdss_io, “mdp_phys”) Conduct IO Memory mapping , So that peripheral registers can be accessed directly through memory operation .
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 */
First call platform_get_resource_byname get resource Structure , The structure is defined as follows , Each member value of this structure corresponds to dts In the document reg and reg-names attribute . The resource Is called during system startup initialization struct resource *request_mem_region Generate . After obtaining the physical base address , call ioremap Map the physical base address to the virtual address space , It can be accessed in the driver .
struct resource {
resource_size_t start; // Represents the starting value of the resource ,
resource_size_t end; // Represents the address of the last byte of the resource , If it's an interruption ,end and satrt identical
const char *name; // Don't write
unsigned long flags; // The type of resources
struct resource *parent, *sibling, *child;
};
reg = <0x01a00000 0x90000>,
<0x01ab0000 0x1040>;
reg-names = "mdp_phys", "vbif_phys";
DSI Driver registration :
mdss_dsi.c This file registers two modules ,dsi driver and dsi ctrl driver.mdss_dsi_probe In the initialization dsi controller ,
mdss_dsi_ctrl_probe Provided by the Chinese resolution module factory panel Of dtsi file . Get... From the file panel Of mode、 The resolution of the 、 Frame rate 、command Data etc.
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 Driver registration :
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 Configure the following in the device tree , Notice that there are three compatible Properties are all qcom,mdss-fb The node of
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";
}
After the device and driver match successfully , call 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);
else
mfd->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;
else
mfd->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");
else
lcd_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;
}
call framebuffer_alloc Allocate one fbi Memory , This function will struct fb_info And private data memory info->par Distribute together , And press sizeof(long) alignment . This method allocates contiguous memory , Reduce memory fragmentation , Is a common method .
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);
#endif
return info;
#undef PADDING
#undef BYTES_PER_LONG
}
EXPORT_SYMBOL(framebuffer_alloc);
Next call mdss_fb_register Yes fb_info The structure is filled , call register_framebuffer complete fb Registration of
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);
else
fix->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->mdp_sync_pt_data.commit_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->update.comp);
init_completion(&mfd->no_update.comp);
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 For application layer and framebuffer Memory mapping for
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;
}
This call led_classdev_register Register backlight equipment
/* 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");
else
lcd_backlight_registered = 1;
}
The process of turning on the screen and turning off the screen (fb_ioctl)
边栏推荐
- Time string to timestamp
- A simple examination system based on C language
- 5、 Image component
- Taobao assistant can not be used. How to export the baby in the warehouse to backup the data package
- Open version - inventory description
- Pytorch idea and implementation of keras code conversion for CNN image classification
- Matlab用深度学习循环神经网络RNN长短期记忆LSTM进行波形时间序列数据预测
- How to upload Taobao tmall products with one click
- Typescript & explain in, keyof, extensions, index signature, record and typeof in detail (updated from time to time)
- Notes on algebra 10.1: understanding of symmetric polynomials and derivation of cubic resolvents
猜你喜欢

MySQL面试真题(二十)——视频数据分析实战

How to authorize a picture in a store to another store? What are the methods of unauthorized replication

Antd - a-upload-dragger drag upload component - Basic accumulation

Matlab uses deep learning recurrent neural network RNN long-term and short-term memory LSTM to predict waveform time series data

How to batch copy babies by sales volume in Taoying

Chromedriver all versions download

Get through version 4.3 mind map

Matlab suddenly fails to open. It disappears after running. There is no solution for the task manager

What if the finder fails to respond continuously? Finder unresponsive solution tutorial

How to import Taobao products into another store
随机推荐
Wechat applet camouflage page (change the page content regularly)
Solution to the problem of "brand abuse such as brand inconsistency and stacking in the published product information" prompted by copying and uploading
Image interpolation (nearest neighbor, bilinear)
JS implementation of random generation of 16 bit key -- Basic accumulation
ASP. Net core development experience
[usecols parameter of pd.read\u excel ((), list error reason]
Open source get through version - integral function
RFID warehouse management system solution implementation visualization process
antd——a-upload-dragger拖拽上传组件——基础积累
Get through version - bargain activity
Matlab用深度学习循环神经网络RNN长短期记忆LSTM进行波形时间序列数据预测
Summary of methods for calculating the number of solutions of indefinite equations
FFMPEG坑
Wechat games (2)
Find and replace the spaces, Nan and special symbols contained in a column of data in the dataframe
Remote Desktop Manager
Wechat applet service provider sub merchant payment order interface
Crmeb mall order shipping function
33歲程序員的年中總結
Taobao assistant can not be used. How to export the baby in the warehouse to backup the data package