1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: MIT

#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>

#include "ast_ddc.h"
#include "ast_drv.h"

/*
 * Encoder
 */

static const struct drm_encoder_funcs ast_sil164_encoder_funcs = {
	.destroy = drm_encoder_cleanup,
};

/*
 * Connector
 */

static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector)
{
	struct ast_connector *ast_connector = to_ast_connector(connector);
	int count;

	if (ast_connector->physical_status == connector_status_connected) {
		count = drm_connector_helper_get_modes(connector);
	} else {
		drm_edid_connector_update(connector, NULL);

		/*
		 * There's no EDID data without a connected monitor. Set BMC-
		 * compatible modes in this case. The XGA default resolution
		 * should work well for all BMCs.
		 */
		count = drm_add_modes_noedid(connector, 4096, 4096);
		if (count)
			drm_set_preferred_mode(connector, 1024, 768);
	}

	return count;
}

static int ast_sil164_connector_helper_detect_ctx(struct drm_connector *connector,
						  struct drm_modeset_acquire_ctx *ctx,
						  bool force)
{
	struct ast_connector *ast_connector = to_ast_connector(connector);
	enum drm_connector_status status;

	status = drm_connector_helper_detect_from_ddc(connector, ctx, force);

	if (status != ast_connector->physical_status)
		++connector->epoch_counter;
	ast_connector->physical_status = status;

	return connector_status_connected;
}

static const struct drm_connector_helper_funcs ast_sil164_connector_helper_funcs = {
	.get_modes = ast_sil164_connector_helper_get_modes,
	.detect_ctx = ast_sil164_connector_helper_detect_ctx,
};

static const struct drm_connector_funcs ast_sil164_connector_funcs = {
	.reset = drm_atomic_helper_connector_reset,
	.fill_modes = drm_helper_probe_single_connector_modes,
	.destroy = drm_connector_cleanup,
	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};

static int ast_sil164_connector_init(struct drm_device *dev, struct drm_connector *connector)
{
	struct ast_device *ast = to_ast_device(dev);
	struct i2c_adapter *ddc;
	int ret;

	ddc = ast_ddc_create(ast);
	if (IS_ERR(ddc)) {
		ret = PTR_ERR(ddc);
		drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret);
		return ret;
	}

	ret = drm_connector_init_with_ddc(dev, connector, &ast_sil164_connector_funcs,
					  DRM_MODE_CONNECTOR_DVII, ddc);
	if (ret)
		return ret;

	drm_connector_helper_add(connector, &ast_sil164_connector_helper_funcs);

	connector->interlace_allowed = 0;
	connector->doublescan_allowed = 0;

	connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;

	return 0;
}

int ast_sil164_output_init(struct ast_device *ast)
{
	struct drm_device *dev = &ast->base;
	struct drm_crtc *crtc = &ast->crtc;
	struct drm_encoder *encoder = &ast->output.sil164.encoder;
	struct ast_connector *ast_connector = &ast->output.sil164.connector;
	struct drm_connector *connector = &ast_connector->base;
	int ret;

	ret = drm_encoder_init(dev, encoder, &ast_sil164_encoder_funcs,
			       DRM_MODE_ENCODER_TMDS, NULL);
	if (ret)
		return ret;
	encoder->possible_crtcs = drm_crtc_mask(crtc);

	ret = ast_sil164_connector_init(dev, connector);
	if (ret)
		return ret;
	ast_connector->physical_status = connector->status;

	ret = drm_connector_attach_encoder(connector, encoder);
	if (ret)
		return ret;

	return 0;
}
此生若是錯在相逢 求一個善終