2 MDP,DSI,FB代码分析

本文深入解析了MDP模块在Linux驱动中的初始化流程,包括硬件资源的初始化,以及MDP接口的注册。同时,详细阐述了DSI驱动器的工作原理,包括解析面板配置文件,初始化DSI资源,以及创建DSI控制器设备的过程。最后,介绍了FB驱动的注册流程,以及如何通过解析设备树获取屏幕信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MDP分析

MDP主要对使用的硬件资源进行初始化,同时在fb设备中注册mdp的使用接口。

MDP使用的设备树在:

msm8909-mdss.dtsi

主要代码:

static int mdp3_probe(struct platform_device *pdev)
{
	int rc;
	/* 创建msm_mdp_interface结构体,里边包含mdp的初始化等,这些函数会在fb初始化时调用 */
    static struct msm_mdp_interface mdp3_interface = {
	.init_fnc = mdp3_init,
	.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
	.panel_register_done = mdp3_panel_register_done,
	.fb_stride = mdp3_fb_stride,
	.check_dsi_status = mdp3_check_dsi_ctrl_status,
	};
    /* 初始化mdp3_res */
	mdp3_res = devm_kzalloc(&pdev->dev, sizeof(struct mdp3_hw_resource),
				GFP_KERNEL);
	/* mdp3_res->mdss_util执行全局变量mdss_util,初始化之,fb注册时会用到 */
	mdp3_res->mdss_util = mdss_get_util_intf();
	mdp3_res->mdss_util->get_iommu_domain = mdp3_get_iommu_domain;
	mdp3_res->mdss_util->iommu_attached = is_mdss_iommu_attached;
	mdp3_res->mdss_util->iommu_ctrl = mdp3_iommu_ctrl;
	mdp3_res->mdss_util->bus_scale_set_quota = mdp3_bus_scale_set_quota;
	mdp3_res->mdss_util->panel_intf_type = mdp3_panel_intf_type;
	mdp3_res->mdss_util->dyn_clk_gating_ctrl =
		mdp3_dynamic_clock_gating_ctrl;
	/* 调用改函数,将mdp3_interface赋值给全局变量mdp_instance,用fb注册时初始化mdp等操作 */
	rc = mdss_fb_register_mdp_instance(&mdp3_interface);
	/* 标志mdp已经执行probe,dsi probe会检测 */
	mdp3_res->mdss_util->mdp_probe_done = true;
}	

看下mdp3_interface.init_fnc mdp3_init实现:

static int mdp3_init(struct msm_fb_data_type *mfd)
{
	int rc;

	rc = mdp3_ctrl_init(mfd);
	if (rc) {
		pr_err("mdp3 ctl init fail\n");
		return rc;
	}

	rc = mdp3_ppp_res_init(mfd);
	if (rc)
		pr_err("mdp3 ppp res init fail\n");

	return rc;
}

主要看mdp3_ctrl_init()的实现:

int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
{
	struct device *dev = mfd->fbi->dev;
	struct msm_mdp_interface *mdp3_interface = &mfd->mdp;
	struct mdp3_session_data *mdp3_session = NULL;
	u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
	int rc;
	int splash_mismatch = 0;

	pr_info("mdp3_ctrl_init\n");
	rc = mdp3_parse_dt_splash(mfd);
	if (rc)
		splash_mismatch = 1;

	mdp3_interface->on_fnc = mdp3_ctrl_on;
	mdp3_interface->off_fnc = mdp3_ctrl_off;
	mdp3_interface->do_histogram = NULL;
	mdp3_interface->cursor_update = NULL;
	mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
	mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
	mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
	mdp3_interface->lut_update = NULL;
	mdp3_interface->configure_panel = mdp3_update_panel_info;
	...
	rc = mdp3_intf_init(mdp3_session->intf);
	return rc;
}

在msm_mdp_interface的init_fnc中,为mdp3_interface添加了更多的操作,包括上下电操作,ioctl控制函数,mdp屏幕信息获取等。

DSI驱动器

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

DSI驱动在mdss_dsi.c中,其中注册了两个驱动,第一个是

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 int mdss_dsi_register_driver(void)
{
	return platform_driver_register(&mdss_dsi_driver);
}

另一个是:

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_ctrl_register_driver(void)
{
	return platform_driver_register(&mdss_dsi_ctrl_driver);
}

先看第一个驱动的probe函数:

static int mdss_dsi_probe(struct platform_device *pdev)
{
    struct mdss_panel_cfg *pan_cfg = NULL;
	struct mdss_util_intf *util;
	/* 获得全局变量mdp_instance,在mdp probe时注册 */
	util = mdss_get_util_intf();
    /* 将dsi资源信息保存到全局变量mdss_dsi_res,初始化dsi时钟 */
    rc = mdss_dsi_res_init(pdev);
    /* 创建qcom,mdss-dsi-ctrl设备,我们这里说的第二个驱动就是该设备对应的驱动 */
    of_platform_populate(pdev->dev.of_node, mdss_dsi_ctrl_dt_match,
				NULL, &pdev->dev);
	return rc;
}

在dis_driver中,主要获取对了dsi时钟等信息,初始化了mdss_dsi_res.然后创建了dsi_ctrl的平台设备,让其可以和之后注册的dsi_ctrl驱动相匹配。

接下来看dsi_ctrl驱动的注册:

@mdss_dsi.c
static int mdss_dsi_ctrl_probe(struct platform_device *pdev)
{
    int rc = 0;
    struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
    const char *ctrl_name;
    
    ctrl_name = of_get_property(pdev->dev.of_node, "label", NULL);
    /* panel配置 */
    dsi_pan_node = mdss_dsi_config_panel(pdev, index);
    
    rc = dsi_panel_device_register(pdev, dsi_pan_node, ctrl_pdata);
    
    return 0;
}

首先看mdss_dsi_config_panel()配置函数中的mdss_dsi_panel_init()的实现:

@mdss_dsi_panel.c
int mdss_dsi_panel_init(struct device_node *node,
	struct mdss_dsi_ctrl_pdata *ctrl_pdata,
	int ndx)
{
	int rc = 0;
	static const char *panel_name;
	struct mdss_panel_info *pinfo;

	pinfo = &ctrl_pdata->panel_data.panel_info;

	pinfo->panel_name[0] = '\0';
	/* 设置panel名字 */
	panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL);
	
	/* 找到dsi panel节点,保存在dsi_pan_node */
	dsi_pan_node = mdss_dsi_find_panel_of_node(pdev, panel_cfg);
	/* 从dsi节点读取panel信息,并保存到结果在ctrl_pdata->panel_data.panel_info中 */
	rc = mdss_panel_parse_dt(node, ctrl_pdata);

	pinfo->dynamic_switch_pending = false;
	pinfo->is_lpm_mode = false;
	pinfo->esd_rdy = false;
    // 屏上电操作
	ctrl_pdata->on = mdss_dsi_panel_on;
	ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on;
	// 屏下电操作
	ctrl_pdata->off = mdss_dsi_panel_off;
	ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config;
	// 背光设置
	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
	// 切换模式
	ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
	ctrl_pdata->panel_data.set_idle = mdss_dsi_panel_set_idle_mode;
	ctrl_pdata->panel_data.get_idle = mdss_dsi_panel_get_idle_mode;

	return 0;
}

在配置中,首先通过mdss_panel_parse_dt()函数解析dsi和屏信息的设备设,屏的信息,在fb注册时,将使用到。然后初始化了mdss_dsi_ctrl_pdata结构体中的操作函数指针,这些函数指针将用在fb中的熄灭屏,设置屏幕亮度等操作。

主要工作在dsi_panel_device_register()函数中完成。现在看起实现:

@mdss_dsi.c
int dsi_panel_device_register(struct platform_device *ctrl_pdev,
	struct device_node *pan_node, struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
    struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
    mipi  = &(pinfo->mipi);
    /* mipi模式 */
	pinfo->type =
		((mipi->mode == DSI_VIDEO_MODE)
			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
	/* 后面会有event发送给dsi,会在mdss_dsi_event_handler中处理 */
	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
	ctrl_pdata->panel_data.get_fb_node = mdss_dsi_get_fb_node_cb;
	mdss_dsi_ctrl_init(&ctrl_pdev->dev, ctrl_pdata);
	
	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
}
FB驱动

FB驱动在mdss_fb.c中完成,实现Linux Framebuffer的注册已经相关操作。

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;
}
module_init(mdss_fb_init);

mdss_fb_driver的实现:

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,
	},
};

compatible为"qcom,mdss-fb"在msm8909-mdss.dtsi中有定义。因此platform_driver的probe将被调用。整个fb注册过程大都也在这其中完成。

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;
    
    /* 获取plat_data,含有在mdss_dsi中解析出的屏信息 */
    pdata = dev_get_platdata(&pdev->dev);
    /* 分配fbi结构体,用来注册fb */
    fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
    
    /* fbi->par执行mfd,保存私有数据  mfd保存了屏的所以信息 */
    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->fb_imgType = MDP_RGBA_8888;
	...
	platform_set_drvdata(pdev, mfd);
	/* 完成fb的注册,从mfd中取出屏信息放到fbi中,进行fb注册,并包含fb给用户空间的的操作函数 */
	rc = mdss_fb_register(mfd);
	/* 初始化mdp */
	if (mfd->mdp.init_fnc) {
		rc = mfd->mdp.init_fnc(mfd);
		if (rc) {
			pr_err("init_fnc failed\n");
			return rc;
		}
	}
	
	/* 注册背光灯设备 */
	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_create_sysfs(mfd);
	/* 发送注册事件,处理的hanlder在mdss_dsi中定义 */
	mdss_fb_send_panel_event(mfd, MDSS_EVENT_FB_REGISTERED, fbi);
}

在上面代码中,首先通过dev_get_platdata()获取屏的信息,然后创建一个msm_fb_data_type结构体,将屏信息全部放在了mfd中。调用mdss_fb_register()进行fb的注册。

<think>嗯,用户之前让我介绍了马尔科夫决策过程(MDP),现在他们想了解如何在Python中实现MDP。我需要先回顾一下MDP的基本组成部分,然后思考如何用代码表示这些部分。可能用户需要的是一个简单的示例,展示如何构建MDP模型,并实现值迭代或策略迭代算法。 首先,用户可能对Python中的类结构不太熟悉,所以需要用简单易懂的方式构建MDP的各个组件,比如状态、动作、转移概率和奖励函数。然后,可能需要解释值迭代和策略迭代的算法步骤,并展示如何用代码实现这些算法。 考虑到用户可能是学生或者刚入门的开发者,代码应该简洁明了,并附有注释。同时,可能需要提供一个具体的例子,比如网格世界问题,这样用户可以更直观地理解代码的运行过程。此外,用户可能对如何测试代码和验证结果感兴趣,所以最好包括一个示例运行和输出。 还需要注意代码的效率和可读性,避免使用过于复杂的结构。例如,转移概率可以用字典或嵌套字典来表示,这样方便查找和更新。奖励函数同样可以用字典结构存储每个状态-动作对的奖励值。 另外,用户可能对值迭代和策略迭代的区别不太清楚,所以在解释代码时,需要简要说明两者的不同,比如值迭代通过不断更新值函数直到收敛,而策略迭代则交替评估和改进策略。 最后,确保代码示例正确无误,能够实际运行,并给出预期的结果,比如最优值函数和最优策略。这有助于用户验证他们的实现是否正确,并加深对MDP求解过程的理解。</think>以下是使用Python实现马尔科夫决策过程(MDP)的核心代码示例,涵盖**值迭代(Value Iteration)**和**策略迭代(Policy Iteration)**两种经典算法。我们以简单的**网格世界(GridWorld)**为例进行说明。 --- ### 一、MDP模型定义 假设一个3x3网格世界,智能体从左上角出发,目标是到达右下角的终点,每移动一步奖励-1,到达终点奖励+10。 ```python import numpy as np # 定义MDP参数 states = [(i, j) for i in range(3) for j in range(3)] # 状态集合:3x3网格 actions = ['up', 'down', 'left', 'right'] # 动作集合 gamma = 0.9 # 折扣因子 # 转移概率函数 P(s' | s, a)(简化模型:确定性转移) def transition(s, a): i, j = s if a == 'up' and i > 0: return (i-1, j) elif a == 'down' and i < 2: return (i+1, j) elif a == 'left' and j > 0: return (i, j-1) elif a == 'right' and j < 2: return (i, j+1) else: return s # 无法移动时保持原位 # 奖励函数 R(s, a, s') def reward(s, a, s_next): if s_next == (2, 2): # 到达终点奖励+10 return 10 else: # 普通移动奖励-1 return -1 ``` --- ### 二、值迭代(Value Iteration)代码实现 值迭代通过不断更新状态值函数$V(s)$,直到收敛到最优值函数$V^*$。 ```python def value_iteration(states, actions, gamma, theta=1e-6): V = {s: 0 for s in states} # 初始化值函数 while True: delta = 0 for s in states: if s == (2, 2): # 终点状态无需更新 continue v_old = V[s] max_value = -float('inf') for a in actions: s_next = transition(s, a) r = reward(s, a, s_next) # 更新值函数(确定性转移) candidate = r + gamma * V[s_next] if candidate > max_value: max_value = candidate V[s] = max_value delta = max(delta, abs(v_old - V[s])) if delta < theta: # 收敛条件 break # 提取最优策略 policy = {} for s in states: if s == (2, 2): policy[s] = None continue best_action = None max_value = -float('inf') for a in actions: s_next = transition(s, a) r = reward(s, a, s_next) value = r + gamma * V[s_next] if value > max_value: max_value = value best_action = a policy[s] = best_action return V, policy ``` --- ### 三、策略迭代(Policy Iteration)代码实现 策略迭代交替进行**策略评估**和**策略改进**,直到策略稳定。 ```python def policy_iteration(states, actions, gamma, theta=1e-6): # 初始化随机策略 policy = {s: np.random.choice(actions) for s in states if s != (2, 2)} policy[(2, 2)] = None # 终点无动作 while True: # 策略评估 V = {s: 0 for s in states} while True: delta = 0 for s in states: if s == (2, 2): continue v_old = V[s] a = policy[s] s_next = transition(s, a) r = reward(s, a, s_next) V[s] = r + gamma * V[s_next] delta = max(delta, abs(v_old - V[s])) if delta < theta: break # 策略改进 policy_stable = True for s in states: if s == (2, 2): continue old_action = policy[s] max_value = -float('inf') best_action = None for a in actions: s_next = transition(s, a) r = reward(s, a, s_next) value = r + gamma * V[s_next] if value > max_value: max_value = value best_action = a if best_action != old_action: policy_stable = False policy[s] = best_action if policy_stable: break return V, policy ``` --- ### 四、运行示例 ```python # 运行值迭代 V_vi, policy_vi = value_iteration(states, actions, gamma) print("值迭代结果 - 最优值函数:") for s in states: print(f"V({s}) = {V_vi[s]:.2f}") print("\n最优策略:") for s in states: print(f"Policy({s}) = {policy_vi[s]}") # 运行策略迭代 V_pi, policy_pi = policy_iteration(states, actions, gamma) print("\n策略迭代结果 - 最优策略:") for s in states: print(f"Policy({s}) = {policy_pi[s]}") ``` --- ### 五、输出示例(简化) ```text 值迭代结果 - 最优值函数: V((0, 0)) = 51.12 V((0, 1)) = 58.53 V((0, 2)) = 65.52 ... 最优策略: Policy((0, 0)) → 'right' Policy((0, 1)) → 'right' Policy((0, 2)) → 'down' ... ``` --- ### 六、关键点说明 1. **转移概率简化**:示例假设动作执行是确定性的(如`transition`函数),实际中可能需要处理概率分布。 2. **奖励设计**:奖励函数直接影响策略学习效果,需根据实际问题调整。 3. **扩展性**:代码可扩展为随机转移(修改`transition`返回概率分布)或复杂状态编码(如使用类封装状态)。 实际应用中,MDP常用于强化学习框架(如Gym库),结合Q-learning、DQN等算法处理更复杂的环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值