Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Mar 24-27, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2012 Russell King
  3 *  Rewritten from the dovefb driver, and Armada510 manuals.
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License version 2 as
  7 * published by the Free Software Foundation.
  8 */
  9#include <drm/drmP.h>
 10#include <drm/drm_crtc_helper.h>
 11#include <drm/drm_edid.h>
 12#include <drm/drm_encoder_slave.h>
 13#include "armada_drm.h"
 14#include "armada_output.h"
 15#include "armada_slave.h"
 16
 17static int armada_drm_slave_get_modes(struct drm_connector *conn)
 18{
 19	struct drm_encoder *enc = armada_drm_connector_encoder(conn);
 20	int count = 0;
 21
 22	if (enc) {
 23		struct drm_encoder_slave *slave = to_encoder_slave(enc);
 24
 25		count = slave->slave_funcs->get_modes(enc, conn);
 26	}
 27
 28	return count;
 29}
 30
 31static void armada_drm_slave_destroy(struct drm_encoder *enc)
 32{
 33	struct drm_encoder_slave *slave = to_encoder_slave(enc);
 34	struct i2c_client *client = drm_i2c_encoder_get_client(enc);
 35
 36	if (slave->slave_funcs)
 37		slave->slave_funcs->destroy(enc);
 38	if (client)
 39		i2c_put_adapter(client->adapter);
 40
 41	drm_encoder_cleanup(&slave->base);
 42	kfree(slave);
 43}
 44
 45static const struct drm_encoder_funcs armada_drm_slave_encoder_funcs = {
 46	.destroy	= armada_drm_slave_destroy,
 47};
 48
 49static const struct drm_connector_helper_funcs armada_drm_slave_helper_funcs = {
 50	.get_modes	= armada_drm_slave_get_modes,
 51	.mode_valid	= armada_drm_slave_encoder_mode_valid,
 52	.best_encoder	= armada_drm_connector_encoder,
 53};
 54
 55static const struct drm_encoder_helper_funcs drm_slave_encoder_helpers = {
 56	.dpms = drm_i2c_encoder_dpms,
 57	.save = drm_i2c_encoder_save,
 58	.restore = drm_i2c_encoder_restore,
 59	.mode_fixup = drm_i2c_encoder_mode_fixup,
 60	.prepare = drm_i2c_encoder_prepare,
 61	.commit = drm_i2c_encoder_commit,
 62	.mode_set = drm_i2c_encoder_mode_set,
 63	.detect = drm_i2c_encoder_detect,
 64};
 65
 66static int
 67armada_drm_conn_slave_create(struct drm_connector *conn, const void *data)
 68{
 69	const struct armada_drm_slave_config *config = data;
 70	struct drm_encoder_slave *slave;
 71	struct i2c_adapter *adap;
 72	int ret;
 73
 74	conn->interlace_allowed = config->interlace_allowed;
 75	conn->doublescan_allowed = config->doublescan_allowed;
 76	conn->polled = config->polled;
 77
 78	drm_connector_helper_add(conn, &armada_drm_slave_helper_funcs);
 79
 80	slave = kzalloc(sizeof(*slave), GFP_KERNEL);
 81	if (!slave)
 82		return -ENOMEM;
 83
 84	slave->base.possible_crtcs = config->crtcs;
 85
 86	adap = i2c_get_adapter(config->i2c_adapter_id);
 87	if (!adap) {
 88		kfree(slave);
 89		return -EPROBE_DEFER;
 90	}
 91
 92	ret = drm_encoder_init(conn->dev, &slave->base,
 93			       &armada_drm_slave_encoder_funcs,
 94			       DRM_MODE_ENCODER_TMDS);
 95	if (ret) {
 96		DRM_ERROR("unable to init encoder\n");
 97		i2c_put_adapter(adap);
 98		kfree(slave);
 99		return ret;
100	}
101
102	ret = drm_i2c_encoder_init(conn->dev, slave, adap, &config->info);
103	i2c_put_adapter(adap);
104	if (ret) {
105		DRM_ERROR("unable to init encoder slave\n");
106		armada_drm_slave_destroy(&slave->base);
107		return ret;
108	}
109
110	drm_encoder_helper_add(&slave->base, &drm_slave_encoder_helpers);
111
112	ret = slave->slave_funcs->create_resources(&slave->base, conn);
113	if (ret) {
114		armada_drm_slave_destroy(&slave->base);
115		return ret;
116	}
117
118	ret = drm_mode_connector_attach_encoder(conn, &slave->base);
119	if (ret) {
120		armada_drm_slave_destroy(&slave->base);
121		return ret;
122	}
123
124	conn->encoder = &slave->base;
125
126	return ret;
127}
128
129static const struct armada_output_type armada_drm_conn_slave = {
130	.connector_type	= DRM_MODE_CONNECTOR_HDMIA,
131	.create		= armada_drm_conn_slave_create,
132	.set_property	= armada_drm_slave_encoder_set_property,
133};
134
135int armada_drm_connector_slave_create(struct drm_device *dev,
136	const struct armada_drm_slave_config *config)
137{
138	return armada_output_create(dev, &armada_drm_conn_slave, config);
139}