예제 #1
0
static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector)
{
	struct rcar_du_connector *con = to_rcar_connector(connector);
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder);
	struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);

	if (sfuncs->get_modes == NULL)
		return 0;

	return sfuncs->get_modes(encoder, connector);
}
예제 #2
0
static enum drm_connector_status
rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
	struct rcar_du_connector *con = to_rcar_connector(connector);
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder);
	struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);

	if (sfuncs->detect == NULL)
		return connector_status_unknown;

	return sfuncs->detect(encoder, connector);
}
예제 #3
0
static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector,
					     struct drm_display_mode *mode)
{
	struct rcar_du_connector *con = to_rcar_connector(connector);
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(con->encoder);
	struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);

	if (sfuncs->mode_valid == NULL)
		return MODE_OK;

	return sfuncs->mode_valid(encoder, mode);
}
예제 #4
0
int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
				struct rcar_du_encoder *renc,
				/* TODO const */ struct device_node *np)
{
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
	struct rcar_du_lvds_connector *lvdscon;
	struct drm_connector *connector;
	struct display_timing timing;
	int ret;

	lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL);
	if (lvdscon == NULL)
		return -ENOMEM;

	ret = of_get_display_timing(np, "panel-timing", &timing);
	if (ret < 0)
		return ret;

	videomode_from_timing(&timing, &lvdscon->panel.mode);

	of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm);
	of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm);

	connector = &lvdscon->connector.connector;
	connector->display_info.width_mm = lvdscon->panel.width_mm;
	connector->display_info.height_mm = lvdscon->panel.height_mm;

	ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
				 DRM_MODE_CONNECTOR_LVDS);
	if (ret < 0)
		return ret;

	drm_connector_helper_add(connector, &connector_helper_funcs);
	ret = drm_connector_register(connector);
	if (ret < 0)
		return ret;

	drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
	drm_object_property_set_value(&connector->base,
		rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);

	ret = drm_mode_connector_attach_encoder(connector, encoder);
	if (ret < 0)
		return ret;

	connector->encoder = encoder;
	lvdscon->connector.encoder = renc;

	return 0;
}
예제 #5
0
int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
			 struct rcar_du_encoder *renc, struct device_node *np)
{
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
	struct drm_i2c_encoder_driver *driver;
	struct i2c_client *i2c_slave;
	struct rcar_du_hdmienc *hdmienc;
	int ret;

	hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL);
	if (hdmienc == NULL)
		return -ENOMEM;

	/* Locate the slave I2C device and driver. */
	i2c_slave = of_find_i2c_device_by_node(np);
	if (!i2c_slave || !i2c_get_clientdata(i2c_slave))
		return -EPROBE_DEFER;

	hdmienc->dev = &i2c_slave->dev;

	if (hdmienc->dev->driver == NULL) {
		ret = -EPROBE_DEFER;
		goto error;
	}

	/* Initialize the slave encoder. */
	driver = to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc->dev->driver));
	ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave);
	if (ret < 0)
		goto error;

	ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
			       DRM_MODE_ENCODER_TMDS);
	if (ret < 0)
		goto error;

	drm_encoder_helper_add(encoder, &encoder_helper_funcs);

	renc->hdmi = hdmienc;
	hdmienc->renc = renc;

	return 0;

error:
	put_device(hdmienc->dev);
	return ret;
}
예제 #6
0
int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
				struct rcar_du_encoder *renc)
{
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
	struct rcar_du_connector *rcon;
	struct drm_connector *connector;
	int ret;

	rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL);
	if (rcon == NULL)
		return -ENOMEM;

	connector = &rcon->connector;
	connector->display_info.width_mm = 0;
	connector->display_info.height_mm = 0;
	connector->interlace_allowed = true;
	connector->polled = DRM_CONNECTOR_POLL_HPD;

	ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
				 DRM_MODE_CONNECTOR_HDMIA);
	if (ret < 0)
		return ret;

	drm_connector_helper_add(connector, &connector_helper_funcs);
	ret = drm_connector_register(connector);
	if (ret < 0)
		return ret;

	connector->dpms = DRM_MODE_DPMS_OFF;
	drm_object_property_set_value(&connector->base,
		rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);

	ret = drm_mode_connector_attach_encoder(connector, encoder);
	if (ret < 0)
		return ret;

	rcon->encoder = renc;

	return 0;
}
예제 #7
0
int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
			 struct rcar_du_encoder *renc, struct device_node *np)
{
	struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
	struct drm_bridge *bridge;
	struct rcar_du_hdmienc *hdmienc;
	int ret;

	hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL);
	if (hdmienc == NULL)
		return -ENOMEM;

	/* Locate the DRM bridge from the HDMI encoder DT node. */
	bridge = of_drm_find_bridge(np);
	if (!bridge)
		return -EPROBE_DEFER;

	ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
			       DRM_MODE_ENCODER_TMDS, NULL);
	if (ret < 0)
		return ret;

	drm_encoder_helper_add(encoder, &encoder_helper_funcs);

	renc->hdmi = hdmienc;
	hdmienc->renc = renc;

	/* Link the bridge to the encoder. */
	bridge->encoder = encoder;
	encoder->bridge = bridge;

	ret = drm_bridge_attach(rcdu->ddev, bridge);
	if (ret) {
		drm_encoder_cleanup(encoder);
		return ret;
	}

	return 0;
}
예제 #8
0
int rcar_du_encoder_init(struct rcar_du_device *rcdu,
			 enum rcar_du_encoder_type type,
			 enum rcar_du_output output,
			 struct device_node *enc_node,
			 struct device_node *con_node)
{
	struct rcar_du_encoder *renc;
	struct drm_encoder *encoder;
	unsigned int encoder_type;
	int ret;

	renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
	if (renc == NULL)
		return -ENOMEM;

	renc->output = output;
	encoder = rcar_encoder_to_drm_encoder(renc);

	switch (output) {
	case RCAR_DU_OUTPUT_LVDS0:
		renc->lvds = rcdu->lvds[0];
		break;

	case RCAR_DU_OUTPUT_LVDS1:
		renc->lvds = rcdu->lvds[1];
		break;

	default:
		break;
	}

	switch (type) {
	case RCAR_DU_ENCODER_VGA:
		encoder_type = DRM_MODE_ENCODER_DAC;
		break;
	case RCAR_DU_ENCODER_LVDS:
		encoder_type = DRM_MODE_ENCODER_LVDS;
		break;
	case RCAR_DU_ENCODER_HDMI:
		encoder_type = DRM_MODE_ENCODER_TMDS;
		break;
	case RCAR_DU_ENCODER_NONE:
	default:
		/* No external encoder, use the internal encoder type. */
		encoder_type = rcdu->info->routes[output].encoder_type;
		break;
	}

	if (type == RCAR_DU_ENCODER_HDMI) {
		ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
		if (ret < 0)
			goto done;
	} else {
		ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
				       encoder_type, NULL);
		if (ret < 0)
			goto done;

		drm_encoder_helper_add(encoder, &encoder_helper_funcs);
	}

	switch (encoder_type) {
	case DRM_MODE_ENCODER_LVDS:
		ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
		break;

	case DRM_MODE_ENCODER_DAC:
		ret = rcar_du_vga_connector_init(rcdu, renc);
		break;

	case DRM_MODE_ENCODER_TMDS:
		/* connector managed by the bridge driver */
		break;

	default:
		ret = -EINVAL;
		break;
	}

done:
	if (ret < 0) {
		if (encoder->name)
			encoder->funcs->destroy(encoder);
		devm_kfree(rcdu->dev, renc);
	}

	return ret;
}