it6122 mipi2lvds芯片调试

此次调试的是Linux系统的kernel5.10

dts配置


	ite_bridge: it6122@6c {
		status = "okay";
		compatible = "ite,it6122";
		reg = <0x6c>;
		ite,bypass_mode;
		ite,bypass_hsw = <40>;
		ite,bypass_vsw = <2>;
		//ite,hresync;
		ite,dsi-lanes = <4>;
		ite,dsi-channel = <0>;
		ite,skip-stage = <3>;
		ite,hs-settle = <4>;
		mipi-inv-mclk;
		lvds-dual-mode;
		lvds-vesa-mode;
		lvds-swing-level=<6>;
		//lvds-ssc-enable;
		lvds-sdm = <0x3333>;
		lvds-sdm-inv = <0x106>;
		pinctrl-0 = <&it612x_irq>;
		interrupt-parent = <&gpio1>;
		interrupts = ;
		reset-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
		vcc1v2-gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_HIGH>;
		vcc1v8-gpios = <&gpio2 RK_PA7 GPIO_ACTIVE_HIGH>;
		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			port@0 {
				reg = <0>;
				mipi_in: endpoint {
					remote-endpoint = <&dsi_out_panel>;
				};
			};
			port@1 {
				reg = <1>;
				lvds_out: endpoint {
					remote-endpoint = <&lvds_panel>;
				};
			};
		};
	};


&dsi0 {
	status = "disabled";
	//rockchip,lane-rate = <1000>;

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@1 {
			reg = <1>;
			dsi_out_panel: endpoint {
				remote-endpoint = <&mipi_in>;
			};
		};
	};

};

	lvds_panel0: panel {
		status = "okay";
		compatible = "auo,g190ean01","simple-panel";
		backlight = <&backlight>;
		reset-delay-ms = <10>;
		enable-delay-ms = <10>;
		prepare-delay-ms = <10>;
		unprepare-delay-ms = <10>;
		disable-delay-ms = <60>;

		disp_timings0: display-timings {
			native-mode = <&timing0>;
			timing0: timing0 {
				clock-frequency = <132000000>;
				hactive = <1080>;
				vactive = <1920>;
				hfront-porch = <15>;
				hsync-len = <4>;
				hback-porch = <30>;
				vfront-porch = <15>;
				vsync-len = <2>;
				vback-porch = <15>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <0>;
				pixelclk-active = <0>;
			};
		};
		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			port@0 {
				reg = <0>;
				lvds_panel: endpoint {
					remote-endpoint = <&lvds_out>;
				};
			};
		};
	};


流程

在这里插入图片描述
现在要添加的是it6122就是drm bridge

在dw-mipi-dsi2-rockchip.c中dw_mipi_dsi2_bind函数


static int dw_mipi_dsi2_bind(struct device *dev, struct device *master,
			    void *data)
{
	struct dw_mipi_dsi2 *dsi2 = dev_get_drvdata(dev);
	struct drm_device *drm_dev = data;
	struct drm_encoder *encoder = &dsi2->encoder;
	struct device_node *of_node = dsi2->dev->of_node;
	struct drm_connector *connector = NULL;
	enum drm_bridge_attach_flags flags;
	int ret;

	dsi2->drm_dev = drm_dev;
	ret = dw_mipi_dsi2_dual_channel_probe(dsi2);
	if (ret)
		return ret;

	if (dsi2->master)
		return 0;

	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1,
					  &dsi2->panel, &dsi2->bridge);
	if (ret) {
		DRM_DEV_ERROR(dev, "Failed to find panel or bridge: %d\n", ret);
		return ret;
	}

	dw_mipi_dsi2_get_dsc_params_from_sink(dsi2, dsi2->panel, dsi2->bridge);
	encoder->possible_crtcs = rockchip_drm_of_find_possible_crtcs(drm_dev,
								      of_node);

	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
	if (ret) {
		DRM_ERROR("Failed to initialize encoder with drm\n");
		return ret;
	}

	drm_encoder_helper_add(encoder, &dw_mipi_dsi2_encoder_helper_funcs);

	if (dsi2->bridge) {
		struct list_head *connector_list =
			&drm_dev->mode_config.connector_list;

		dsi2->bridge->driver_private = &dsi2->host;
		dsi2->bridge->encoder = encoder;

		flags = dsi2->bridge->ops & DRM_BRIDGE_OP_MODES ?
			DRM_BRIDGE_ATTACH_NO_CONNECTOR : 0;
		ret = drm_bridge_attach(encoder, dsi2->bridge, NULL, flags);
		if (ret) {
			DRM_DEV_ERROR(dev,
				      "Failed to attach bridge: %d\n", ret);
			goto encoder_cleanup;
		}

		if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
			list_for_each_entry(connector, connector_list, head)
				if (drm_connector_has_possible_encoder(connector,
								       encoder))
					break;
	}

	if (dsi2->panel || (dsi2->bridge && (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))) {
		ret = dw_mipi_dsi2_connector_init(dsi2);
		if (ret)
			goto encoder_cleanup;

		connector = &dsi2->connector;
	}

	if (connector) {
		ret = dw_mipi_dsi2_register_sub_dev(dsi2, connector);
		if (ret)
			goto encoder_cleanup;
	}

	pm_runtime_enable(dsi2->dev);
	if (dsi2->slave)
		pm_runtime_enable(dsi2->slave->dev);

	return 0;

encoder_cleanup:
	encoder->funcs->destroy(encoder);

	return ret;
}

关键函数drm_of_find_panel_or_bridge通过dts中dsi0节点的endpoint找到连接的bridge或panel

int drm_of_find_panel_or_bridge(const struct device_node *np,
				int port, int endpoint,
				struct drm_panel **panel,
				struct drm_bridge **bridge)
{
	int ret = -EPROBE_DEFER;
	struct device_node *remote;

	if (!panel && !bridge)
		return -EINVAL;
	if (panel)
		*panel = NULL;

	/*
	 * of_graph_get_remote_node() produces a noisy error message if port
	 * node isn't found and the absence of the port is a legit case here,
	 * so at first we silently check whether graph presents in the
	 * device-tree node.
	 */
	if (!of_graph_is_present(np))
		return -ENODEV;

	remote = of_graph_get_remote_node(np, port, endpoint);
	if (!remote)
		return -ENODEV;

	if (panel) {
		*panel = of_drm_find_panel(remote);
		if (!IS_ERR(*panel))
			ret = 0;
		else
			*panel = NULL;
	}

	/* No panel found yet, check for a bridge next. */
	if (bridge) {
		if (ret) {
			*bridge = of_drm_find_bridge(remote);
			if (*bridge)
				ret = 0;
		} else {
			*bridge = NULL;
		}

	}

	of_node_put(remote);
	return ret;
}

it6122驱动会在probe中会通过drm_bridge_add将it6122->bridge添加到bridge_list中,所以这里dsi2->bridge通过of_drm_find_bridge被赋值为it6122->bridge

static int it6121_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct device_node *np = dev->of_node;
	struct it6121 *it6121;
	int ret;

	printk("====>%s,line %d\n",__func__,__LINE__);
	it6121 = devm_kzalloc(dev, sizeof(*it6121), GFP_KERNEL);
	if (!it6121)
		return -ENOMEM;

	// it6121->split_mode = of_property_read_bool(np, "split-mode");

	it6121->i2c = client;

	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &it6121->panel, NULL);
	if (ret < 0)
		return ret;
	if (!(it6121->panel))
		return -ENODEV;

	it6121->panel_bridge = devm_drm_panel_bridge_add(dev, it6121->panel);
	if (IS_ERR(it6121->panel_bridge))
		return PTR_ERR(it6121->panel_bridge);

	it6121->regmap = devm_regmap_init_i2c(client,
						&it6121_regmap_config);
	if (IS_ERR(it6121->regmap)) {
		ret = PTR_ERR(it6121->regmap);
		goto unregister_i2c;
	}

	it6121->reset_gpio = devm_gpiod_get_optional(dev, "reset",
							GPIOD_OUT_LOW);
	if (IS_ERR(it6121->reset_gpio)) {
		ret = PTR_ERR(it6121->reset_gpio);

		if (ret != -EPROBE_DEFER)
			dev_err(dev, "Failed to get reset gpio: %d\n", ret);

		goto unregister_i2c;
	}

	it6121->vcc1v2 = devm_gpiod_get_optional(dev, "vcc1v2",
							GPIOD_ASIS);
	if (IS_ERR(it6121->vcc1v2)) {
		ret = PTR_ERR(it6121->vcc1v2);

		if (ret != -EPROBE_DEFER)
			dev_err(dev, "Failed to get vcc1v2 gpio: %d\n", ret);

		goto unregister_i2c;
	}

	it6121->vcc1v8 = devm_gpiod_get_optional(dev, "vcc1v8",
							GPIOD_ASIS);
	if (IS_ERR(it6121->vcc1v8)) {
		ret = PTR_ERR(it6121->vcc1v8);

		if (ret != -EPROBE_DEFER)
			dev_err(dev, "Failed to get vcc1v8 gpio: %d\n", ret);

		goto unregister_i2c;
	}
	ret = it6121_parse_dt(dev->of_node, it6121);
	if (ret) {
		goto unregister_i2c;
	}

	//it6121->hresync = 0;
	it6121->u8SysSts = 0;
	ret = it6122_power_on(it6121);
	if (ret) {
		dev_err(dev, "Failed to power on \n");
		goto unregister_i2c;
	}
	// disable all interrupt
	regmap_write(it6121->regmap, 0x09, 0x0);
	regmap_write(it6121->regmap, 0x0A, 0x0);
	regmap_write(it6121->regmap, 0x0B, 0x0);

	ret = it6121_check_chipid(it6121);		// check ite612x dev id

	if (ret)
		goto unregister_i2c;

	// it6121_config_reset(it6121);
	// msleep(100);

#if EN_INT_MODE
	thread = kthread_run(ite612x_event_handler, it6121, "synaptics_dsx");

	if (IS_ERR(thread)) {

		ret = PTR_ERR(thread);
		DRM_INFO(" %s: failed to create kernel thread: %d\n", __func__, ret);
	}

	it6121->irq = client->irq;

	ret = devm_request_irq(&client->dev, it6121->irq, (irq_handler_t) ite612x_intr_handler,
				IRQF_TRIGGER_LOW /*IRQF_TRIGGER_FALLING*/, "ite612x_intp", it6121);

	if (ret < 0) {
		DRM_INFO("%s: Failed to register attention interrupt\n",
                                __func__);
		goto unregister_i2c;
	}

#endif
	it6121->bridge.driver_private = it6121;
	it6121->bridge.funcs = &it6121_bridge_funcs;
	it6121->bridge.of_node = np;

#ifndef RASP_PI	
	drm_bridge_add(&it6121->bridge);
#else
	it6121_attach_dsi(it6121);
	it6121_init(it6121);
#endif

	i2c_set_clientdata(client, it6121);

	return ret;

unregister_i2c:
	DRM_INFO("it6121_probe failed\n");
	devm_kfree(dev, it6121);
	if (ret == -EPROBE_DEFER)
		return ret;

	return ret;
}

回到dw_mipi_dsi2_bind函数,接下来将dsi host通过drm_simple_encoder_init,drm_encoder_helper_add注册为encoder

if (dsi2->bridge) {
	struct list_head *connector_list =
		&drm_dev->mode_config.connector_list;

	dsi2->bridge->driver_private = &dsi2->host;
	dsi2->bridge->encoder = encoder;

	flags = dsi2->bridge->ops & DRM_BRIDGE_OP_MODES ?
		DRM_BRIDGE_ATTACH_NO_CONNECTOR : 0;
	ret = drm_bridge_attach(encoder, dsi2->bridge, NULL, flags);
	if (ret) {
		DRM_DEV_ERROR(dev,
			      "Failed to attach bridge: %d\n", ret);
		goto encoder_cleanup;
	}

	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
		list_for_each_entry(connector, connector_list, head)
			if (drm_connector_has_possible_encoder(connector,
							       encoder))
				break;
}

调用drm_bridge_attach,具体调用bridge中的attach函数,也就是it6121_bridge_attach

static int it6121_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
{
	struct it6121 *it6121 = bridge_to_it6121(bridge);
	struct drm_device *drm = bridge->dev;

	int ret;

#if 0 //panel has found in the beginning of probe
	// panel register to ite
	simple_panel_host_register(it6121);
#endif
#if 1
	if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
		dev_err(&it6121->i2c->dev,
			"it6121 driver only copes with atomic updates\n");
		return -ENOTSUPP;
	}

	it6121->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
				   DRM_CONNECTOR_POLL_DISCONNECT;
	ret = drm_connector_init(drm, &it6121->connector,
				 &it6121_connector_funcs,
				 DRM_MODE_CONNECTOR_LVDS);
	if (ret) {
		dev_err(&it6121->i2c->dev,
				"Failed to initialize connector with drm\n");
		return ret;
	}

	drm_connector_helper_add(&it6121->connector,
				 &it6121_connector_helper_funcs);
	drm_connector_attach_encoder(&it6121->connector, bridge->encoder);

#if 0 //delete,drm_panel_attach can't find in kernel-5.10
	ret = drm_panel_attach(it6121->panel, &it6121->connector); 
	if (ret) {
		dev_err(&it6121->i2c->dev, "Failed to attach panel: %d\n", ret);
		drm_connector_cleanup(&it6121->connector);
		return ret;
	}
#endif
#else
	// create connector
#endif
	// attach to dsi host (dsi bridge)
	ret = it6121_attach_dsi(it6121);

	// todo enable detect cable interrupt

	return ret;
}

注册connector,it6121_attach_dsi中of_find_mipi_dsi_host_by_node找到对应的dsi host的节点,mipi_dsi_device_register_full注册dsi device,mipi_dsi_attach调用host的attach函数

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值