diff options
author | Dave Airlie <airlied@redhat.com> | 2009-12-07 16:07:28 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-07 19:22:31 -0500 |
commit | 746c1aa4d100f7441423050f34be79f401fbf7d4 (patch) | |
tree | 23e021bb2e9250fd03e88875b1715039f1d3da8a /drivers/gpu | |
parent | d904ef9b00a4473af16766e99f17bdbb5f0fde65 (diff) |
drm/radeon/kms: initial radeon displayport porting
This is enough to retrieve EDID and DPCP.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/radeon/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_dp.c | 275 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 57 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_encoders.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_i2c.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 21 |
8 files changed, 498 insertions, 24 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index b5713eedd6e1..feb52eee4314 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile | |||
@@ -49,7 +49,7 @@ radeon-y += radeon_device.o radeon_kms.o \ | |||
49 | radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ | 49 | radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ |
50 | rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ | 50 | rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ |
51 | r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ | 51 | r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ |
52 | r600_blit_kms.o radeon_pm.o | 52 | r600_blit_kms.o radeon_pm.o atombios_dp.o |
53 | 53 | ||
54 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o | 54 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o |
55 | 55 | ||
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c new file mode 100644 index 000000000000..a4bc80113385 --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios_dp.c | |||
@@ -0,0 +1,275 @@ | |||
1 | /* | ||
2 | * Copyright 2007-8 Advanced Micro Devices, Inc. | ||
3 | * Copyright 2008 Red Hat Inc. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice shall be included in | ||
13 | * all copies or substantial portions of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
21 | * OTHER DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: Dave Airlie | ||
24 | * Alex Deucher | ||
25 | */ | ||
26 | #include "drmP.h" | ||
27 | #include "radeon_drm.h" | ||
28 | #include "radeon.h" | ||
29 | |||
30 | #include "atom.h" | ||
31 | #include "atom-bits.h" | ||
32 | #include "drm_dp_helper.h" | ||
33 | |||
34 | #define DP_LINK_STATUS_SIZE 6 | ||
35 | |||
36 | bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, | ||
37 | int num_bytes, u8 *read_byte, | ||
38 | u8 read_buf_len, u8 delay) | ||
39 | { | ||
40 | struct drm_device *dev = chan->dev; | ||
41 | struct radeon_device *rdev = dev->dev_private; | ||
42 | PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args; | ||
43 | int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); | ||
44 | unsigned char *base; | ||
45 | |||
46 | memset(&args, 0, sizeof(args)); | ||
47 | |||
48 | base = (unsigned char *)rdev->mode_info.atom_context->scratch; | ||
49 | |||
50 | memcpy(base, req_bytes, num_bytes); | ||
51 | |||
52 | args.lpAuxRequest = 0; | ||
53 | args.lpDataOut = 16; | ||
54 | args.ucDataOutLen = 0; | ||
55 | args.ucChannelID = chan->i2c_id; | ||
56 | args.ucDelay = delay; | ||
57 | |||
58 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
59 | |||
60 | if (args.ucReplyStatus) { | ||
61 | DRM_ERROR("failed to get auxch %02x%02x %02x %02x 0x%02x %02x\n", | ||
62 | req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], | ||
63 | chan->i2c_id, args.ucReplyStatus); | ||
64 | return false; | ||
65 | } | ||
66 | |||
67 | if (args.ucDataOutLen && read_byte && read_buf_len) { | ||
68 | if (read_buf_len < args.ucDataOutLen) { | ||
69 | DRM_ERROR("Buffer to small for return answer %d %d\n", | ||
70 | read_buf_len, args.ucDataOutLen); | ||
71 | return false; | ||
72 | } | ||
73 | { | ||
74 | int len = min(read_buf_len, args.ucDataOutLen); | ||
75 | memcpy(read_byte, base + 16, len); | ||
76 | } | ||
77 | } | ||
78 | return true; | ||
79 | } | ||
80 | |||
81 | int radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clock, | ||
82 | uint8_t ucconfig, uint8_t lane_num) | ||
83 | { | ||
84 | DP_ENCODER_SERVICE_PARAMETERS args; | ||
85 | int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); | ||
86 | |||
87 | memset(&args, 0, sizeof(args)); | ||
88 | args.ucLinkClock = dp_clock / 10; | ||
89 | args.ucConfig = ucconfig; | ||
90 | args.ucAction = action; | ||
91 | args.ucLaneNum = lane_num; | ||
92 | args.ucStatus = 0; | ||
93 | |||
94 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
95 | return args.ucStatus; | ||
96 | } | ||
97 | |||
98 | int radeon_dp_getsinktype(struct radeon_connector *radeon_connector) | ||
99 | { | ||
100 | struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; | ||
101 | struct drm_device *dev = radeon_connector->base.dev; | ||
102 | struct radeon_device *rdev = dev->dev_private; | ||
103 | |||
104 | return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, | ||
105 | radeon_dig_connector->uc_i2c_id, 0); | ||
106 | } | ||
107 | |||
108 | union dig_transmitter_control { | ||
109 | DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; | ||
110 | DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; | ||
111 | }; | ||
112 | |||
113 | bool radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, uint16_t address, | ||
114 | uint8_t send_bytes, uint8_t *send) | ||
115 | { | ||
116 | struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; | ||
117 | struct drm_device *dev = radeon_connector->base.dev; | ||
118 | struct radeon_device *rdev = dev->dev_private; | ||
119 | u8 msg[20]; | ||
120 | u8 msg_len, dp_msg_len; | ||
121 | bool ret; | ||
122 | |||
123 | dp_msg_len = 4; | ||
124 | msg[0] = address; | ||
125 | msg[1] = address >> 8; | ||
126 | msg[2] = AUX_NATIVE_WRITE << 4; | ||
127 | dp_msg_len += send_bytes; | ||
128 | msg[3] = (dp_msg_len << 4) | (send_bytes - 1); | ||
129 | |||
130 | if (send_bytes > 16) | ||
131 | return false; | ||
132 | |||
133 | memcpy(&msg[4], send, send_bytes); | ||
134 | msg_len = 4 + send_bytes; | ||
135 | ret = radeon_process_aux_ch(radeon_dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0); | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16_t address, | ||
140 | uint8_t delay, uint8_t expected_bytes, | ||
141 | uint8_t *read_p) | ||
142 | { | ||
143 | struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; | ||
144 | struct drm_device *dev = radeon_connector->base.dev; | ||
145 | struct radeon_device *rdev = dev->dev_private; | ||
146 | u8 msg[20]; | ||
147 | u8 msg_len, dp_msg_len; | ||
148 | bool ret = false; | ||
149 | msg_len = 4; | ||
150 | dp_msg_len = 4; | ||
151 | msg[0] = address; | ||
152 | msg[1] = address >> 8; | ||
153 | msg[2] = AUX_NATIVE_READ << 4; | ||
154 | msg[3] = (dp_msg_len) << 4; | ||
155 | msg[3] |= expected_bytes - 1; | ||
156 | |||
157 | ret = radeon_process_aux_ch(radeon_dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay); | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | void radeon_dp_getdpcp(struct radeon_connector *radeon_connector) | ||
162 | { | ||
163 | struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; | ||
164 | u8 msg[25]; | ||
165 | int ret; | ||
166 | |||
167 | ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCP_REV, 0, 8, msg); | ||
168 | if (ret) { | ||
169 | memcpy(radeon_dig_connector->dpcp, msg, 8); | ||
170 | { | ||
171 | int i; | ||
172 | printk("DPCP: "); | ||
173 | for (i = 0; i < 8; i++) | ||
174 | printk("%02x ", msg[i]); | ||
175 | printk("\n"); | ||
176 | } | ||
177 | } | ||
178 | radeon_dig_connector->dpcp[0] = 0; | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, | ||
183 | u8 link_status[DP_LINK_STATUS_SIZE]) | ||
184 | { | ||
185 | int ret; | ||
186 | ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, 100, | ||
187 | DP_LINK_STATUS_SIZE, link_status); | ||
188 | if (!ret) { | ||
189 | DRM_ERROR("displayport link status failed\n"); | ||
190 | return false; | ||
191 | } | ||
192 | |||
193 | DRM_INFO("link status %02x %02x %02x %02x %02x %02x\n", | ||
194 | link_status[0], link_status[1], link_status[2], | ||
195 | link_status[3], link_status[4], link_status[5]); | ||
196 | return true; | ||
197 | } | ||
198 | |||
199 | static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) | ||
200 | { | ||
201 | struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; | ||
202 | if (radeon_dig_connector->dpcp[0] >= 0x11) { | ||
203 | radeon_dp_aux_native_write(radeon_connector, 0x600, 1, | ||
204 | &power_state); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static void dp_update_dpvs_emph(struct radeon_connector *radeon_connector, | ||
209 | u8 train_set[4]) | ||
210 | { | ||
211 | struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; | ||
212 | |||
213 | // radeon_dp_digtransmitter_setup_vsemph(); | ||
214 | radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET, | ||
215 | 0/* lc */, train_set); | ||
216 | } | ||
217 | |||
218 | static void dp_set_training(struct radeon_connector *radeon_connector, | ||
219 | u8 training) | ||
220 | { | ||
221 | radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_PATTERN_SET, | ||
222 | 1, &training); | ||
223 | } | ||
224 | |||
225 | int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, | ||
226 | uint8_t write_byte, uint8_t *read_byte) | ||
227 | { | ||
228 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | ||
229 | struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter; | ||
230 | int ret = 0; | ||
231 | uint16_t address = algo_data->address; | ||
232 | uint8_t msg[5]; | ||
233 | uint8_t reply[2]; | ||
234 | int msg_len, dp_msg_len; | ||
235 | int reply_bytes; | ||
236 | |||
237 | /* Set up the command byte */ | ||
238 | if (mode & MODE_I2C_READ) | ||
239 | msg[2] = AUX_I2C_READ << 4; | ||
240 | else | ||
241 | msg[2] = AUX_I2C_WRITE << 4; | ||
242 | |||
243 | if (!(mode & MODE_I2C_STOP)) | ||
244 | msg[2] |= AUX_I2C_MOT << 4; | ||
245 | |||
246 | msg[0] = address; | ||
247 | msg[1] = address >> 8; | ||
248 | |||
249 | reply_bytes = 1; | ||
250 | |||
251 | msg_len = 4; | ||
252 | dp_msg_len = 3; | ||
253 | switch (mode) { | ||
254 | case MODE_I2C_WRITE: | ||
255 | msg[4] = write_byte; | ||
256 | msg_len++; | ||
257 | dp_msg_len += 2; | ||
258 | break; | ||
259 | case MODE_I2C_READ: | ||
260 | dp_msg_len += 1; | ||
261 | break; | ||
262 | default: | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | msg[3] = (dp_msg_len) << 4; | ||
267 | ret = radeon_process_aux_ch(auxch, msg, msg_len, reply, reply_bytes, 0); | ||
268 | |||
269 | if (ret) { | ||
270 | if (read_byte) | ||
271 | *read_byte = reply[0]; | ||
272 | return reply_bytes; | ||
273 | } | ||
274 | return -EREMOTEIO; | ||
275 | } | ||
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 5e414102c875..de05ac976472 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -47,7 +47,7 @@ radeon_add_atom_connector(struct drm_device *dev, | |||
47 | int connector_type, | 47 | int connector_type, |
48 | struct radeon_i2c_bus_rec *i2c_bus, | 48 | struct radeon_i2c_bus_rec *i2c_bus, |
49 | bool linkb, uint32_t igp_lane_info, | 49 | bool linkb, uint32_t igp_lane_info, |
50 | uint16_t connector_object_id); | 50 | uint16_t connector_object_id, uint8_t uc_i2c_id); |
51 | 51 | ||
52 | /* from radeon_legacy_encoder.c */ | 52 | /* from radeon_legacy_encoder.c */ |
53 | extern void | 53 | extern void |
@@ -60,8 +60,8 @@ union atom_supported_devices { | |||
60 | struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; | 60 | struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device | 63 | static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *dev, |
64 | *dev, uint8_t id) | 64 | uint8_t id) |
65 | { | 65 | { |
66 | struct radeon_device *rdev = dev->dev_private; | 66 | struct radeon_device *rdev = dev->dev_private; |
67 | struct atom_context *ctx = rdev->mode_info.atom_context; | 67 | struct atom_context *ctx = rdev->mode_info.atom_context; |
@@ -276,7 +276,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
276 | uint16_t igp_lane_info, conn_id, connector_object_id; | 276 | uint16_t igp_lane_info, conn_id, connector_object_id; |
277 | bool linkb; | 277 | bool linkb; |
278 | struct radeon_i2c_bus_rec ddc_bus; | 278 | struct radeon_i2c_bus_rec ddc_bus; |
279 | 279 | ATOM_I2C_ID_CONFIG_ACCESS i2c_id; | |
280 | atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); | 280 | atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); |
281 | 281 | ||
282 | if (data_offset == 0) | 282 | if (data_offset == 0) |
@@ -302,7 +302,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
302 | path = (ATOM_DISPLAY_OBJECT_PATH *) addr; | 302 | path = (ATOM_DISPLAY_OBJECT_PATH *) addr; |
303 | path_size += le16_to_cpu(path->usSize); | 303 | path_size += le16_to_cpu(path->usSize); |
304 | linkb = false; | 304 | linkb = false; |
305 | 305 | i2c_id.ucAccess = 0; | |
306 | if (device_support & le16_to_cpu(path->usDeviceTag)) { | 306 | if (device_support & le16_to_cpu(path->usDeviceTag)) { |
307 | uint8_t con_obj_id, con_obj_num, con_obj_type; | 307 | uint8_t con_obj_id, con_obj_num, con_obj_type; |
308 | 308 | ||
@@ -420,7 +420,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
420 | asObjects[j]. | 420 | asObjects[j]. |
421 | usRecordOffset)); | 421 | usRecordOffset)); |
422 | ATOM_I2C_RECORD *i2c_record; | 422 | ATOM_I2C_RECORD *i2c_record; |
423 | 423 | ||
424 | while (record->ucRecordType > 0 | 424 | while (record->ucRecordType > 0 |
425 | && record-> | 425 | && record-> |
426 | ucRecordType <= | 426 | ucRecordType <= |
@@ -431,6 +431,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
431 | i2c_record = | 431 | i2c_record = |
432 | (ATOM_I2C_RECORD | 432 | (ATOM_I2C_RECORD |
433 | *) record; | 433 | *) record; |
434 | i2c_id.sbfAccess = i2c_record->sucI2cId; | ||
434 | line_mux = | 435 | line_mux = |
435 | i2c_record-> | 436 | i2c_record-> |
436 | sucI2cId. | 437 | sucI2cId. |
@@ -473,7 +474,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
473 | usDeviceTag), | 474 | usDeviceTag), |
474 | connector_type, &ddc_bus, | 475 | connector_type, &ddc_bus, |
475 | linkb, igp_lane_info, | 476 | linkb, igp_lane_info, |
476 | connector_object_id); | 477 | connector_object_id, i2c_id.ucAccess); |
477 | 478 | ||
478 | } | 479 | } |
479 | } | 480 | } |
@@ -692,7 +693,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
692 | connector_type, | 693 | connector_type, |
693 | &bios_connectors[i].ddc_bus, | 694 | &bios_connectors[i].ddc_bus, |
694 | false, 0, | 695 | false, 0, |
695 | connector_object_id); | 696 | connector_object_id, 0); |
696 | } | 697 | } |
697 | } | 698 | } |
698 | 699 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 7ab3c501b4dd..733427555ee1 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -896,6 +896,54 @@ struct drm_connector_funcs radeon_dvi_connector_funcs = { | |||
896 | .force = radeon_dvi_force, | 896 | .force = radeon_dvi_force, |
897 | }; | 897 | }; |
898 | 898 | ||
899 | static int radeon_dp_get_modes(struct drm_connector *connector) | ||
900 | { | ||
901 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | ||
902 | int ret; | ||
903 | |||
904 | ret = radeon_ddc_get_modes(radeon_connector); | ||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector) | ||
909 | { | ||
910 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | ||
911 | struct drm_encoder *encoder = NULL; | ||
912 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
913 | struct drm_mode_object *obj; | ||
914 | int i; | ||
915 | enum drm_connector_status ret = connector_status_disconnected; | ||
916 | int sink_type; | ||
917 | bool dret; | ||
918 | |||
919 | if (radeon_connector->edid) { | ||
920 | kfree(radeon_connector->edid); | ||
921 | radeon_connector->edid = NULL; | ||
922 | } | ||
923 | |||
924 | sink_type = radeon_dp_getsinktype(radeon_connector); | ||
925 | if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { | ||
926 | radeon_dp_getdpcp(radeon_connector); | ||
927 | ret = connector_status_connected; | ||
928 | } | ||
929 | return ret; | ||
930 | } | ||
931 | |||
932 | struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { | ||
933 | .get_modes = radeon_dp_get_modes, | ||
934 | .mode_valid = radeon_dvi_mode_valid, | ||
935 | .best_encoder = radeon_dvi_encoder, | ||
936 | }; | ||
937 | |||
938 | struct drm_connector_funcs radeon_dp_connector_funcs = { | ||
939 | .dpms = drm_helper_connector_dpms, | ||
940 | .detect = radeon_dp_detect, | ||
941 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
942 | .set_property = radeon_connector_set_property, | ||
943 | .destroy = radeon_connector_destroy, | ||
944 | .force = radeon_dvi_force, | ||
945 | }; | ||
946 | |||
899 | void | 947 | void |
900 | radeon_add_atom_connector(struct drm_device *dev, | 948 | radeon_add_atom_connector(struct drm_device *dev, |
901 | uint32_t connector_id, | 949 | uint32_t connector_id, |
@@ -904,7 +952,7 @@ radeon_add_atom_connector(struct drm_device *dev, | |||
904 | struct radeon_i2c_bus_rec *i2c_bus, | 952 | struct radeon_i2c_bus_rec *i2c_bus, |
905 | bool linkb, | 953 | bool linkb, |
906 | uint32_t igp_lane_info, | 954 | uint32_t igp_lane_info, |
907 | uint16_t connector_object_id) | 955 | uint16_t connector_object_id, uint8_t uc_i2c_id) |
908 | { | 956 | { |
909 | struct radeon_device *rdev = dev->dev_private; | 957 | struct radeon_device *rdev = dev->dev_private; |
910 | struct drm_connector *connector; | 958 | struct drm_connector *connector; |
@@ -1030,10 +1078,13 @@ radeon_add_atom_connector(struct drm_device *dev, | |||
1030 | radeon_dig_connector->linkb = linkb; | 1078 | radeon_dig_connector->linkb = linkb; |
1031 | radeon_dig_connector->igp_lane_info = igp_lane_info; | 1079 | radeon_dig_connector->igp_lane_info = igp_lane_info; |
1032 | radeon_connector->con_priv = radeon_dig_connector; | 1080 | radeon_connector->con_priv = radeon_dig_connector; |
1033 | drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); | 1081 | drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); |
1034 | ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); | 1082 | ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); |
1035 | if (ret) | 1083 | if (ret) |
1036 | goto failed; | 1084 | goto failed; |
1085 | /* add DP i2c bus */ | ||
1086 | radeon_dig_connector->uc_i2c_id = uc_i2c_id; | ||
1087 | radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, "DP-auxch", true, uc_i2c_id); | ||
1037 | if (i2c_bus->valid) { | 1088 | if (i2c_bus->valid) { |
1038 | radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); | 1089 | radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); |
1039 | if (!radeon_connector->ddc_bus) | 1090 | if (!radeon_connector->ddc_bus) |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 62b02372cb09..a1c2804b694d 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -337,6 +337,13 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) | |||
337 | { | 337 | { |
338 | int ret = 0; | 338 | int ret = 0; |
339 | 339 | ||
340 | if (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) { | ||
341 | struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; | ||
342 | if (dig->dp_i2c_bus) { | ||
343 | radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter); | ||
344 | DRM_INFO("got edid %p from DP\n", radeon_connector->edid); | ||
345 | } | ||
346 | } | ||
340 | if (!radeon_connector->ddc_bus) | 347 | if (!radeon_connector->ddc_bus) |
341 | return -1; | 348 | return -1; |
342 | if (!radeon_connector->edid) { | 349 | if (!radeon_connector->edid) { |
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 291f6dd3683c..37f5ea1af969 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c | |||
@@ -851,6 +851,99 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) | |||
851 | } | 851 | } |
852 | 852 | ||
853 | static void | 853 | static void |
854 | atombios_dig_transmitter_setup_vsemph(struct drm_encoder *encoder, u8 lane_num, | ||
855 | u8 lane_set) | ||
856 | { | ||
857 | struct drm_device *dev = encoder->dev; | ||
858 | struct radeon_device *rdev = dev->dev_private; | ||
859 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
860 | union dig_transmitter_control args; | ||
861 | int index = 0, num = 0; | ||
862 | uint8_t frev, crev; | ||
863 | struct radeon_encoder_atom_dig *dig; | ||
864 | struct drm_connector *connector; | ||
865 | struct radeon_connector *radeon_connector; | ||
866 | struct radeon_connector_atom_dig *dig_connector; | ||
867 | |||
868 | connector = radeon_get_connector_for_encoder(encoder); | ||
869 | if (!connector) | ||
870 | return; | ||
871 | |||
872 | radeon_connector = to_radeon_connector(connector); | ||
873 | |||
874 | if (!radeon_encoder->enc_priv) | ||
875 | return; | ||
876 | |||
877 | dig = radeon_encoder->enc_priv; | ||
878 | |||
879 | if (!radeon_connector->con_priv) | ||
880 | return; | ||
881 | |||
882 | dig_connector = radeon_connector->con_priv; | ||
883 | |||
884 | memset(&args, 0, sizeof(args)); | ||
885 | |||
886 | if (ASIC_IS_DCE32(rdev)) | ||
887 | index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); | ||
888 | else { | ||
889 | switch (radeon_encoder->encoder_id) { | ||
890 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | ||
891 | index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); | ||
892 | break; | ||
893 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: | ||
894 | index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); | ||
895 | break; | ||
896 | } | ||
897 | } | ||
898 | |||
899 | atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev); | ||
900 | |||
901 | args.v1.ucAction = ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH; | ||
902 | args.v1.asMode.ucLaneSel = lane_num; | ||
903 | args.v1.asMode.ucLaneSet = lane_set; | ||
904 | |||
905 | if (ASIC_IS_DCE32(rdev)) { | ||
906 | args.v2.acConfig.fDPConnector = 1; | ||
907 | |||
908 | if (dig->dig_block) | ||
909 | args.v2.acConfig.ucEncoderSel = 1; | ||
910 | |||
911 | switch (radeon_encoder->encoder_id) { | ||
912 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | ||
913 | args.v2.acConfig.ucTransmitterSel = 0; | ||
914 | num = 0; | ||
915 | break; | ||
916 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: | ||
917 | args.v2.acConfig.ucTransmitterSel = 1; | ||
918 | num = 1; | ||
919 | break; | ||
920 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: | ||
921 | args.v2.acConfig.ucTransmitterSel = 2; | ||
922 | num = 2; | ||
923 | break; | ||
924 | } | ||
925 | } else { | ||
926 | args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; | ||
927 | |||
928 | switch (radeon_encoder->encoder_id) { | ||
929 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | ||
930 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; | ||
931 | if (dig_connector->linkb) | ||
932 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; | ||
933 | else | ||
934 | args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
939 | |||
940 | if (ASIC_IS_DCE32(rdev)) | ||
941 | DRM_INFO("Output UNIPHY%d transmitter VSEMPH setup success\n", num); | ||
942 | else | ||
943 | DRM_INFO("Output DIG%d transmitter VSEMPH setup success\n", num); | ||
944 | } | ||
945 | |||
946 | static void | ||
854 | atombios_yuv_setup(struct drm_encoder *encoder, bool enable) | 947 | atombios_yuv_setup(struct drm_encoder *encoder, bool enable) |
855 | { | 948 | { |
856 | struct drm_device *dev = encoder->dev; | 949 | struct drm_device *dev = encoder->dev; |
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 6c645fb4dad8..f200312dd5df 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c | |||
@@ -172,20 +172,19 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, | |||
172 | return NULL; | 172 | return NULL; |
173 | 173 | ||
174 | i2c->adapter.owner = THIS_MODULE; | 174 | i2c->adapter.owner = THIS_MODULE; |
175 | i2c->adapter.algo_data = &i2c->algo; | ||
176 | i2c->dev = dev; | 175 | i2c->dev = dev; |
177 | i2c->algo.setsda = set_data; | 176 | i2c_set_adapdata(&i2c->adapter, i2c); |
178 | i2c->algo.setscl = set_clock; | 177 | i2c->adapter.algo_data = &i2c->algo.bit; |
179 | i2c->algo.getsda = get_data; | 178 | i2c->algo.bit.setsda = set_data; |
180 | i2c->algo.getscl = get_clock; | 179 | i2c->algo.bit.setscl = set_clock; |
181 | i2c->algo.udelay = 20; | 180 | i2c->algo.bit.getsda = get_data; |
181 | i2c->algo.bit.getscl = get_clock; | ||
182 | i2c->algo.bit.udelay = 20; | ||
182 | /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always | 183 | /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always |
183 | * make this, 2 jiffies is a lot more reliable */ | 184 | * make this, 2 jiffies is a lot more reliable */ |
184 | i2c->algo.timeout = 2; | 185 | i2c->algo.bit.timeout = 2; |
185 | i2c->algo.data = i2c; | 186 | i2c->algo.bit.data = i2c; |
186 | i2c->rec = *rec; | 187 | i2c->rec = *rec; |
187 | i2c_set_adapdata(&i2c->adapter, i2c); | ||
188 | |||
189 | ret = i2c_bit_add_bus(&i2c->adapter); | 188 | ret = i2c_bit_add_bus(&i2c->adapter); |
190 | if (ret) { | 189 | if (ret) { |
191 | DRM_INFO("Failed to register i2c %s\n", name); | 190 | DRM_INFO("Failed to register i2c %s\n", name); |
@@ -199,6 +198,37 @@ out_free: | |||
199 | 198 | ||
200 | } | 199 | } |
201 | 200 | ||
201 | struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, | ||
202 | const char *name, bool dp, u8 i2c_id) | ||
203 | { | ||
204 | struct radeon_i2c_chan *i2c; | ||
205 | int ret; | ||
206 | |||
207 | i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); | ||
208 | if (i2c == NULL) | ||
209 | return NULL; | ||
210 | |||
211 | i2c->i2c_id = i2c_id; | ||
212 | i2c->adapter.owner = THIS_MODULE; | ||
213 | i2c->dev = dev; | ||
214 | i2c_set_adapdata(&i2c->adapter, i2c); | ||
215 | i2c->adapter.algo_data = &i2c->algo.dp; | ||
216 | i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; | ||
217 | i2c->algo.dp.address = 0; | ||
218 | ret = i2c_dp_aux_add_bus(&i2c->adapter); | ||
219 | if (ret) { | ||
220 | DRM_INFO("Failed to register i2c %s\n", name); | ||
221 | goto out_free; | ||
222 | } | ||
223 | |||
224 | return i2c; | ||
225 | out_free: | ||
226 | kfree(i2c); | ||
227 | return NULL; | ||
228 | |||
229 | } | ||
230 | |||
231 | |||
202 | void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) | 232 | void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) |
203 | { | 233 | { |
204 | if (!i2c) | 234 | if (!i2c) |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 135693d5437e..ce1cdc748f1f 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <drm_crtc.h> | 33 | #include <drm_crtc.h> |
34 | #include <drm_mode.h> | 34 | #include <drm_mode.h> |
35 | #include <drm_edid.h> | 35 | #include <drm_edid.h> |
36 | #include <drm_dp_helper.h> | ||
36 | #include <linux/i2c.h> | 37 | #include <linux/i2c.h> |
37 | #include <linux/i2c-id.h> | 38 | #include <linux/i2c-id.h> |
38 | #include <linux/i2c-algo-bit.h> | 39 | #include <linux/i2c-algo-bit.h> |
@@ -164,10 +165,14 @@ struct radeon_pll { | |||
164 | }; | 165 | }; |
165 | 166 | ||
166 | struct radeon_i2c_chan { | 167 | struct radeon_i2c_chan { |
167 | struct drm_device *dev; | ||
168 | struct i2c_adapter adapter; | 168 | struct i2c_adapter adapter; |
169 | struct i2c_algo_bit_data algo; | 169 | struct drm_device *dev; |
170 | union { | ||
171 | struct i2c_algo_dp_aux_data dp; | ||
172 | struct i2c_algo_bit_data bit; | ||
173 | } algo; | ||
170 | struct radeon_i2c_bus_rec rec; | 174 | struct radeon_i2c_bus_rec rec; |
175 | uint8_t i2c_id; | ||
171 | }; | 176 | }; |
172 | 177 | ||
173 | /* mostly for macs, but really any system without connector tables */ | 178 | /* mostly for macs, but really any system without connector tables */ |
@@ -328,6 +333,9 @@ struct radeon_encoder { | |||
328 | struct radeon_connector_atom_dig { | 333 | struct radeon_connector_atom_dig { |
329 | uint32_t igp_lane_info; | 334 | uint32_t igp_lane_info; |
330 | bool linkb; | 335 | bool linkb; |
336 | uint16_t uc_i2c_id; | ||
337 | struct radeon_i2c_chan *dp_i2c_bus; | ||
338 | u8 dpcp[8]; | ||
331 | }; | 339 | }; |
332 | 340 | ||
333 | struct radeon_connector { | 341 | struct radeon_connector { |
@@ -344,6 +352,8 @@ struct radeon_connector { | |||
344 | void *con_priv; | 352 | void *con_priv; |
345 | bool dac_load_detect; | 353 | bool dac_load_detect; |
346 | uint16_t connector_object_id; | 354 | uint16_t connector_object_id; |
355 | /* need to keep this for display port */ | ||
356 | // | ||
347 | }; | 357 | }; |
348 | 358 | ||
349 | struct radeon_framebuffer { | 359 | struct radeon_framebuffer { |
@@ -351,6 +361,13 @@ struct radeon_framebuffer { | |||
351 | struct drm_gem_object *obj; | 361 | struct drm_gem_object *obj; |
352 | }; | 362 | }; |
353 | 363 | ||
364 | extern int radeon_dp_getsinktype(struct radeon_connector *radeon_connector); | ||
365 | extern void radeon_dp_getdpcp(struct radeon_connector *connector); | ||
366 | extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, | ||
367 | uint8_t write_byte, uint8_t *read_byte); | ||
368 | |||
369 | extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, | ||
370 | const char *name, bool dp, u8 i2c_id); | ||
354 | extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, | 371 | extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, |
355 | struct radeon_i2c_bus_rec *rec, | 372 | struct radeon_i2c_bus_rec *rec, |
356 | const char *name); | 373 | const char *name); |