LibXenon
Bare-metal Xbox 360 homebrew library
Loading...
Searching...
No Matches
xenos_edid.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006 Luc Verhaegen (quirks list)
3 * Copyright (c) 2007-2008 Intel Corporation
4 * Jesse Barnes <jesse.barnes@intel.com>
5 *
6 * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
7 * FB layer.
8 * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sub license,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice (including the
18 * next paragraph) shall be included in all copies or substantial portions
19 * of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 */
29
30/* edited to fit in libxenon */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <time/time.h>
36#include <xenon_smc/xenon_smc.h>
37#include <debug.h>
38#include "xenos_edid.h"
39
40/* define the number of Extension EDID block */
41#define MAX_EDID_EXT_NUM 4
42
43/* Valid EDID header has these bytes */
44static const u8 edid_header[] = {
45 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
46};
47
56static BOOL edid_is_valid(struct edid *edid)
57{
58 int i, score = 0;
59 u8 csum = 0;
60 u8 *raw_edid = (u8 *)edid;
61
62 for (i = 0; i < sizeof(edid_header); i++)
63 if (raw_edid[i] == edid_header[i])
64 score++;
65
66 if (score == 8) ;
67 else if (score >= 6) {
68 printf("Fixing EDID header\n");
69 memcpy(raw_edid, edid_header, sizeof(edid_header));
70 } else
71 goto bad;
72
73 for (i = 0; i < EDID_LENGTH; i++)
74 csum += raw_edid[i];
75 if (csum) {
76 printf("EDID checksum is invalid, remainder is %d\n", csum);
77 goto bad;
78 }
79
80 if (edid->version != 1) {
81 printf("EDID has major version %d, instead of 1\n", edid->version);
82 goto bad;
83 }
84
85 if (edid->revision > 4)
86 printf("EDID minor > 4, assuming backward compatibility\n");
87
88 return 1;
89
90bad:
91 return 0;
92}
93
94static int ddc_init(){
95 int ret=0;
96
98
99 ret=xenon_smc_i2c_write(0x1ec, 0);
100 if(ret) goto err;
101
102 // address
103 ret=xenon_smc_i2c_write(0x1ed, 0xa0);
104 if(ret) goto err;
105
106 // 1 byte at a time
107 ret=xenon_smc_i2c_write(0x1f0, 1);
108 if(ret) goto err;
109 ret=xenon_smc_i2c_write(0x1f1, 0);
110 if(ret) goto err;
111 ret=xenon_smc_i2c_write(0x1f5, 1);
112 if(ret) goto err;
113
114 // reset
115 ret=xenon_smc_i2c_write(0x1f3, 0xf);
116 if(ret) goto err;
117 ret=xenon_smc_i2c_write(0x1f3, 0xa);
118 if(ret) goto err;
119 ret=xenon_smc_i2c_write(0x1f3, 9);
120 if(ret) goto err;
121 ret=xenon_smc_i2c_write(0x1f2, 0x60);
122
123err:
125 return ret;
126}
127
128static int ddc_read_byte(int offset,unsigned char *b){
129 int ret=0;
130 unsigned char bb;
131
133
134 // offset
135 ret=xenon_smc_i2c_write(0x1ee, offset>>8);
136 if(ret) goto err;
137 ret=xenon_smc_i2c_write(0x1ef, offset&0xff);
138 if(ret) goto err;
139
140 // start
141 ret=xenon_smc_i2c_write(0x1f3, 4);
142 if(ret) goto err;
143
144 // wait for end
145 for(;;){
146 ret=xenon_smc_i2c_read(0x1f2, &bb);
147 if(ret) goto err;
148 if(!(bb&0x10)) break;
149 udelay(10);
150 }
151
152 // read result
153 ret=xenon_smc_i2c_read(0x1f4, b);
154 if(ret) goto err;
155
156err:
158 return ret;
159}
160
161
172int xenos_do_probe_ddc_edid(unsigned char *buf, int len)
173{
174 int i;
175
176 if(ddc_init()) return -1;
177
178 for(i=0;i<len;++i) if (ddc_read_byte(i,&buf[i])) return -1;
179
180// buffer_dump(buf,len);
181 return 0;
182}
183
184static int xenos_ddc_read_edid(unsigned char *buf, int len)
185{
186 int i;
187
188 for (i = 0; i < 4; i++) {
189 if (xenos_do_probe_ddc_edid(buf, len))
190 return -1;
191 if (edid_is_valid((struct edid *)buf))
192 return 0;
193 }
194
195 /* repeated checksum failures; warn, but carry on */
196 printf("EDID invalid.\n");
197 return -1;
198}
199
210{
211 int ret;
212 struct edid *edid;
213
214 edid = malloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1));
215 if (edid == NULL) {
216 printf("Failed to allocate EDID\n");
217 goto end;
218 }
219
220 /* Read first EDID block */
221 ret = xenos_ddc_read_edid((unsigned char *)edid, EDID_LENGTH);
222 if (ret != 0)
223 goto clean_up;
224
225 /* There are EDID extensions to be read */
226 if (edid->extensions != 0) {
227 int edid_ext_num = edid->extensions;
228
229 if (edid_ext_num > MAX_EDID_EXT_NUM) {
230 printf(
231 "The number of extension(%d) is "
232 "over max (%d), actually read number (%d)\n",
233 edid_ext_num, MAX_EDID_EXT_NUM,
235 /* Reset EDID extension number to be read */
236 edid_ext_num = MAX_EDID_EXT_NUM;
237 }
238 /* Read EDID including extensions too */
239 ret = xenos_ddc_read_edid((unsigned char *)edid, EDID_LENGTH * (edid_ext_num + 1));
240 if (ret != 0)
241 goto clean_up;
242
243 }
244
245 goto end;
246
247clean_up:
248 free(edid);
249 edid = NULL;
250end:
251 return edid;
252
253}
254
255#define HDMI_IDENTIFIER 0x000C03
256#define VENDOR_BLOCK 0x03
265{
266 char *edid_ext = NULL;
267 int i, hdmi_id, edid_ext_num;
268 int start_offset, end_offset;
269 BOOL is_hdmi = FALSE;
270
271 /* No EDID or EDID extensions */
272 if (edid == NULL || edid->extensions == 0)
273 goto end;
274
275 /* Chose real EDID extension number */
276 edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
278
279 /* Find CEA extension */
280 for (i = 0; i < edid_ext_num; i++) {
281 edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
282 /* This block is CEA extension */
283 if (edid_ext[0] == 0x02)
284 break;
285 }
286
287 if (i == edid_ext_num)
288 goto end;
289
290 /* Data block offset in CEA extension block */
291 start_offset = 4;
292 end_offset = edid_ext[2];
293
294 /*
295 * Because HDMI identifier is in Vendor Specific Block,
296 * search it from all data blocks of CEA extension.
297 */
298 for (i = start_offset; i < end_offset;
299 /* Increased by data block len */
300 i += ((edid_ext[i] & 0x1f) + 1)) {
301 /* Find vendor specific block */
302 if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
303 hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
304 edid_ext[i + 3] << 16;
305 /* Find HDMI identifier */
306 if (hdmi_id == HDMI_IDENTIFIER)
307 is_hdmi = TRUE;
308 break;
309 }
310 }
311
312end:
313 return is_hdmi;
314}
#define NULL
Definition: def.h:47
u8 version
Definition: xenos_edid.h:176
u8 revision
Definition: xenos_edid.h:177
u8 extensions
Definition: xenos_edid.h:202
void udelay(int u)
Definition: time.c:12
#define FALSE
Definition: usbhack.h:58
int xenon_smc_i2c_read(uint16_t addr, uint8_t *val)
Definition: xenon_smc.c:219
int xenon_smc_i2c_write(uint16_t addr, uint8_t val)
Definition: xenon_smc.c:192
int xenon_smc_i2c_ddc_lock(int lock)
Definition: xenon_smc.c:172
#define HDMI_IDENTIFIER
Definition: xenos_edid.c:255
#define MAX_EDID_EXT_NUM
Definition: xenos_edid.c:41
int xenos_do_probe_ddc_edid(unsigned char *buf, int len)
Definition: xenos_edid.c:172
BOOL xenos_detect_hdmi_monitor(struct edid *edid)
Definition: xenos_edid.c:264
struct edid * xenos_get_edid()
Definition: xenos_edid.c:209
#define VENDOR_BLOCK
Definition: xenos_edid.c:256
#define EDID_LENGTH
Definition: xenos_edid.h:33
uint8_t u8
8bit unsigned integer
Definition: xetypes.h:12
#define TRUE
True.
Definition: xetypes.h:52
unsigned int BOOL
Definition: xetypes.h:46