From 93a1ccabb982a7cbe20ded2f02fdc7ffa4950af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 19 Sep 2007 22:36:55 +0000 Subject: [PATCH] * Separated I2C from DDC a bit more. * i2c_bus now contains a i2c_timing structure, so that you don't need both to talk to the I2C bus. * Therefore, there is now a void ddc2_init_timing() function to get the the timing DDC needs. * Cleanup in radeon's monitor_detection.c, and updated it to work with the DDC/I2C changes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22265 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/graphics/common/ddc.h | 19 +- headers/private/graphics/common/i2c.h | 33 +- src/add-ons/accelerants/common/ddc.c | 68 +- src/add-ons/accelerants/common/i2c.c | 754 +++++------ .../accelerants/radeon/monitor_detection.c | 1206 +++++++++-------- 5 files changed, 1034 insertions(+), 1046 deletions(-) diff --git a/headers/private/graphics/common/ddc.h b/headers/private/graphics/common/ddc.h index 5e8f7b3d56..7de40e8b08 100644 --- a/headers/private/graphics/common/ddc.h +++ b/headers/private/graphics/common/ddc.h @@ -1,21 +1,20 @@ /* - Copyright (c) 2003, Thomas Kurschel - - - Part of DDC driver - - Main DDC communication + * Copyright (c) 2003, Thomas Kurschel + * Distributed under the terms of the MIT License. */ - #ifndef _DDC_H #define _DDC_H + #include "i2c.h" #include "edid.h" + +void ddc2_init_timing(i2c_bus *bus); + // read EDID and VDIF from monitor via ddc2 // (currently, *vdif and *vdif_len is always set to null) -status_t ddc2_read_edid1( const i2c_bus *bus, edid1_info *edid, - void **vdif, size_t *vdif_len ); +status_t ddc2_read_edid1(const i2c_bus *bus, edid1_info *edid, + void **vdif, size_t *vdifLength); -#endif +#endif /* _DDC_H */ diff --git a/headers/private/graphics/common/i2c.h b/headers/private/graphics/common/i2c.h index 17eee85661..dc067c814a 100644 --- a/headers/private/graphics/common/i2c.h +++ b/headers/private/graphics/common/i2c.h @@ -1,17 +1,14 @@ /* - Copyright (c) 2003, Thomas Kurschel - - - Part of DDC driver - - I2C protocoll -*/ - + * Copyright 2003, Thomas Kurschel. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _I2C_H #define _I2C_H + #include + // timing for i2c bus typedef struct i2c_timing { // general timing as defined by standard @@ -39,31 +36,29 @@ typedef struct i2c_timing { // set signals on bus -typedef status_t (*i2c_set_signals)( void *cookie, int scl, int sda ); +typedef status_t (*i2c_set_signals)(void *cookie, int clock, int data); // read signals from bus -typedef status_t (*i2c_get_signals)( void *cookie, int *scl, int *sda ); - +typedef status_t (*i2c_get_signals)(void *cookie, int *clock, int *data); // i2c bus definition typedef struct i2c_bus { void *cookie; // user-defined cookie + i2c_timing timing; i2c_set_signals set_signals; // callback to set signals i2c_get_signals get_signals; // callback to detect signals } i2c_bus; // send and receive data via i2c bus -status_t i2c_send_receive( const i2c_bus *bus, const i2c_timing *timing, - int slave_address, - const uint8 *write_buffer, size_t write_len, - uint8 *read_buffer, size_t read_len ); +status_t i2c_send_receive(const i2c_bus *bus, int slave_address, + const uint8 *writeBuffer, size_t writeLength, uint8 *readBuffer, + size_t readLength); - // fill with standard 100kHz bus timing -void i2c_get100k_timing( i2c_timing *timing ); +void i2c_get100k_timing(i2c_timing *timing); // fill with standard 400kHz bus timing // (as timing resolution is 1 microsecond, we cannot reach full speed!) -void i2c_get400k_timing( i2c_timing *timing ); +void i2c_get400k_timing(i2c_timing *timing); -#endif +#endif /* _I2C_H */ diff --git a/src/add-ons/accelerants/common/ddc.c b/src/add-ons/accelerants/common/ddc.c index e9773de402..804769cb5d 100644 --- a/src/add-ons/accelerants/common/ddc.c +++ b/src/add-ons/accelerants/common/ddc.c @@ -3,10 +3,8 @@ * Distributed under the terms of the MIT License. */ - /*! - Part of DDC driver - Main DDC communication + DDC communication */ @@ -56,36 +54,26 @@ verify_checksum(const uint8 *data, size_t len) //! Read ddc2 data from monitor static status_t -ddc2_read(const i2c_bus *bus, int start, uint8 *buffer, size_t len) +ddc2_read(const i2c_bus *bus, int start, uint8 *buffer, size_t length) { - uint8 write_buffer[2]; - i2c_timing timing; + status_t status = B_OK; + uint8 writeBuffer[2]; int i; - status_t res = B_OK; - write_buffer[0] = start & 0xff; - write_buffer[1] = (start >> 8) & 0xff; - - i2c_get100k_timing(&timing); - - timing.start_timeout = 550; - timing.byte_timeout = 2200; - timing.bit_timeout = 40; - timing.ack_start_timeout = 40; - timing.ack_timeout = 40; + writeBuffer[0] = start & 0xff; + writeBuffer[1] = (start >> 8) & 0xff; for (i = 0; i < READ_RETRIES; ++i) { - res = i2c_send_receive(bus, &timing, - 0xa0, write_buffer, start < 0x100 ? 1 : 2, - buffer, len); + status = i2c_send_receive(bus, 0xa0, writeBuffer, + start < 0x100 ? 1 : 2, buffer, length); // don't verify checksum - it's often broken - if (res == B_OK /*&& verify_checksum( buffer, len ) == B_OK*/) + if (status == B_OK /*&& verify_checksum( buffer, len ) == B_OK*/) break; - res = B_ERROR; + status = B_ERROR; } - return res; + return status; } @@ -133,30 +121,42 @@ ddc2_read_vdif(const i2c_bus *bus, int start, #endif +void +ddc2_init_timing(i2c_bus *bus) +{ + i2c_get100k_timing(&bus->timing); + + // VESA standard + bus->timing.start_timeout = 550; + bus->timing.byte_timeout = 2200; + bus->timing.bit_timeout = 40; + bus->timing.ack_start_timeout = 40; + bus->timing.ack_timeout = 40; +} + + //! Read EDID and VDIF from monitor via ddc2 status_t ddc2_read_edid1(const i2c_bus *bus, edid1_info *edid, - void **vdif, size_t *vdif_len) + void **vdif, size_t *vdifLength) { - status_t res; edid1_raw raw; - - res = ddc2_read(bus, 0, (uint8 *)&raw, sizeof(raw)); - if (res != B_OK) - return res; + status_t status = ddc2_read(bus, 0, (uint8 *)&raw, sizeof(raw)); + if (status != B_OK) + return status; edid_decode(edid, &raw); *vdif = NULL; - *vdif_len = 0; + *vdifLength = 0; // skip vdif as long as it's not tested #if 0 - res = ddc2_read_vdif(bus, sizeof(raw) * (edid->num_sections + 1), + status = ddc2_read_vdif(bus, sizeof(raw) * (edid->num_sections + 1), vdif, vdif_len); - if (res != B_OK) - return res; + if (status != B_OK) + return status; #endif - + return B_OK; } diff --git a/src/add-ons/accelerants/common/i2c.c b/src/add-ons/accelerants/common/i2c.c index 09363822d5..b01f5e810e 100644 --- a/src/add-ons/accelerants/common/i2c.c +++ b/src/add-ons/accelerants/common/i2c.c @@ -1,398 +1,30 @@ /* + * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved. * Copyright 2003, Thomas Kurschel. All Rights Reserved. * Distributed under the terms of the MIT License. */ - /*! - Part of DDC driver - I2C protocoll + I2C protocol */ -#include "ddc_int.h" #include "i2c.h" #include #include -/*! - There's no spin in user space, but we need it to wait a couple - of microseconds only - (in this case, snooze has much too much overhead) -*/ -void -spin(bigtime_t delay) -{ - bigtime_t start_time = system_time(); - - while (system_time() - start_time < delay) - ; -} - - -//! Wait until slave releases clock signal ("clock stretching") -static status_t -wait_for_clk(const i2c_bus *bus, const i2c_timing *timing, - bigtime_t timeout) -{ - bigtime_t start_time; - - // wait for clock signal to raise - spin(timing->r); - - start_time = system_time(); - - while (1) { - int clk, data; - - bus->get_signals(bus->cookie, &clk, &data); - if (clk != 0) - return B_OK; - - if (system_time() - start_time > timeout) - return B_TIMEOUT; - - spin(timing->r); - } -} - - -//! Send start or repeated start condition -static status_t -send_start_condition(const i2c_bus *bus, const i2c_timing *timing) -{ - status_t res; - - bus->set_signals(bus->cookie, 1, 1); - - res = wait_for_clk(bus, timing, timing->start_timeout); - if (res != B_OK) { - SHOW_FLOW0(3, "Timeout sending start condition"); - return res; - } - - spin(timing->su_sta); - bus->set_signals(bus->cookie, 1, 0); - spin(timing->hd_sta); - bus->set_signals(bus->cookie, 0, 0); - spin(timing->f); - - return B_OK; -} - - -//! Send stop condition -static status_t -send_stop_condition(const i2c_bus *bus, const i2c_timing *timing) -{ - status_t res; - - bus->set_signals(bus->cookie, 0, 0); - spin(timing->r); - bus->set_signals(bus->cookie, 1, 0); - - // a slave may wait for us, so let elapse the acknowledge timeout - // to make the slave release bus control - res = wait_for_clk(bus, timing, timing->ack_timeout); - if (res != B_OK) { - SHOW_FLOW0(3, "Timeout sending stop condition"); - return res; - } - - spin(timing->su_sto); - bus->set_signals(bus->cookie, 1, 1); - spin(timing->buf); - - SHOW_FLOW0(3, ""); - - return B_OK; -} - - -//! Send one bit -static status_t -send_bit(const i2c_bus *bus, const i2c_timing *timing, bool bit, int timeout) -{ - status_t res; - - //SHOW_FLOW( 3, "%d", bit & 1 ); - - bus->set_signals(bus->cookie, 0, bit & 1); - spin(timing->su_dat); - bus->set_signals(bus->cookie, 1, bit & 1); - - res = wait_for_clk(bus, timing, timeout); - if (res != B_OK) { - SHOW_FLOW0(3, "Timeout when sending next bit"); - return res; - } - - spin(timing->high); - bus->set_signals(bus->cookie, 0, bit & 1); - spin(timing->f + timing->low); - - return B_OK; -} - - -//! Send acknowledge and wait for reply -static status_t -send_acknowledge(const i2c_bus *bus, const i2c_timing *timing) -{ - status_t res; - bigtime_t start_time; - - // release data so slave can modify it - bus->set_signals(bus->cookie, 0, 1); - spin(timing->su_dat); - bus->set_signals(bus->cookie, 1, 1); - - res = wait_for_clk(bus, timing, timing->ack_start_timeout); - if (res != B_OK) { - SHOW_FLOW0(3, "Timeout when sending acknowledge"); - return res; - } - - // data and clock is high, now wait for slave to pull data low - // (according to spec, this can happen any time once clock is high) - start_time = system_time(); - - while (1) { - int clk, data; - - bus->get_signals(bus->cookie, &clk, &data); - - if (data == 0) - break; - - if (system_time() - start_time > timing->ack_timeout) { - SHOW_FLOW0(3, "Slave didn't acknowledge byte"); - return B_TIMEOUT; - } - - spin(timing->r); - } - - SHOW_FLOW0(4, "Success!"); - - // make sure we've waited at least t_high - spin(timing->high); - - bus->set_signals(bus->cookie, 0, 1); - spin(timing->f + timing->low); - - return B_OK; -} - - -//! Send byte and wait for acknowledge if is true -static status_t -send_byte(const i2c_bus *bus, const i2c_timing *timing, - uint8 byte, bool acknowledge) -{ - int i; - - SHOW_FLOW( 3, "%x ", byte ); - - for (i = 7; i >= 0; --i) { - status_t res; - - res = send_bit(bus, timing, byte >> i, - i == 7 ? timing->byte_timeout : timing->bit_timeout); - if (res != B_OK) - return res; - } - - if (acknowledge) - return send_acknowledge(bus, timing); - else - return B_OK; -} - - -//! Send slave address, obeying 10-bit addresses and general call addresses -static status_t -send_slave_address( const i2c_bus *bus, const i2c_timing *timing, - int slave_address, bool is_write ) -{ - status_t res; - - res = send_byte(bus, timing, (slave_address & 0xfe) | !is_write, true); - if (res != B_OK) - return res; - - // there are the following special cases if the first byte looks like: - // - 0000 0000 - general call address (second byte with address follows) - // - 0000 0001 - start byte - // - 0000 001x - CBus address - // - 0000 010x - address reserved for different bus format - // - 0000 011x | - // - 0000 1xxx |-> reserved - // - 1111 1xxx | - // - 1111 0xxx - 10 bit address (second byte contains remaining 8 bits) - - // the lsb is 0 for write and 1 for read (except for general call address) - if ((slave_address & 0xff) != 0 && (slave_address & 0xf8) != 0xf0) - return B_OK; - - return send_byte(bus, timing, slave_address >> 8, true); - // send second byte if required -} - - -//! Receive one bit -static status_t -receive_bit(const i2c_bus *bus, const i2c_timing *timing, - bool *bit, int timeout) -{ - status_t res; - int clk, data; - - bus->set_signals(bus->cookie, 1, 1); - // release clock - - // wait for slave to raise clock - res = wait_for_clk(bus, timing, timeout); - if (res != B_OK) { - SHOW_FLOW0(3, "Timeout waiting for bit sent by slave"); - return res; - } - - bus->get_signals(bus->cookie, &clk, &data); - // sample data - - spin(timing->high); - // leave clock high for minimal time - - bus->set_signals(bus->cookie, 0, 1); - // pull clock low so slave waits for us before next bit - - spin(timing->f + timing->low); - // let it settle and leave it low for minimal time - // to make sure slave has finished bit transmission too - - *bit = data; - return B_OK; -} - - -/*! receive byte - Send positive acknowledge afterwards if is true, - else send negative one -*/ -static status_t -receive_byte(const i2c_bus *bus, const i2c_timing *timing, - uint8 *res_byte, bool acknowledge) -{ - uint8 byte = 0; - int i; - - // pull clock low to let slave wait for us - bus->set_signals(bus->cookie, 0, 1); - - for (i = 7; i >= 0; --i) { - status_t res; - bool bit; - - res = receive_bit(bus, timing, &bit, - i == 7 ? timing->byte_timeout : timing->bit_timeout); - if (res != B_OK) - return res; - - byte = (byte << 1) | bit; - } - - //SHOW_FLOW( 3, "%x ", byte ); - - *res_byte = byte; - - return send_bit(bus, timing, acknowledge ? 0 : 1, timing->bit_timeout); -} - - -//! Send multiple bytes -static status_t -send_bytes(const i2c_bus *bus, const i2c_timing *timing, - const uint8 *write_buffer, ssize_t write_len) -{ - SHOW_FLOW( 3, "len=%ld", write_len ); - - for (; write_len > 0; --write_len, ++write_buffer) { - status_t res; - - res = send_byte(bus, timing, *write_buffer, true); - if (res != B_OK) - return res; - } - - return B_OK; -} - - -//! Receive multiple bytes -static status_t -receive_bytes(const i2c_bus *bus, const i2c_timing *timing, - uint8 *read_buffer, ssize_t read_len) -{ - SHOW_FLOW(3, "len=%ld", read_len); - - for (; read_len > 0; --read_len, ++read_buffer) { - status_t res; - - res = receive_byte(bus, timing, read_buffer, read_len > 1); - if (res != B_OK) - return res; - } - - return B_OK; -} - - -//! Combined i2c send+receive format -status_t -i2c_send_receive(const i2c_bus *bus, const i2c_timing *timing, - int slave_address, const uint8 *write_buffer, size_t write_len, - uint8 *read_buffer, size_t read_len) -{ - status_t res; - - res = send_start_condition(bus, timing); - if (res != B_OK) - return res; - - res = send_slave_address(bus, timing, slave_address, true); - if (res != B_OK) - goto err; - - res = send_bytes(bus, timing, write_buffer, write_len); - if (res != B_OK) - goto err; - - res = send_start_condition(bus, timing); - if (res != B_OK) - return res; - - res = send_slave_address(bus, timing, slave_address, false); - if (res != B_OK) - goto err; - - res = receive_bytes(bus, timing, read_buffer, read_len); - if (res != B_OK) - goto err; - - res = send_stop_condition(bus, timing); - return res; - -err: - SHOW_FLOW0(3, "Cancelling transmission"); - send_stop_condition(bus, timing); - return res; -} +//#define TRACE_I2C +#ifdef TRACE_I2C +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x...) _sPrintf("I2C: " x) +#else +# define TRACE(x...) ; +#endif //! Timining for 100kHz bus (fractional parts are rounded up) -i2c_timing i2c_timing_100k = { +const static i2c_timing kTiming100k = { buf : 5, hd_sta : 4, low : 5, @@ -414,7 +46,7 @@ i2c_timing i2c_timing_100k = { // timing for 400 kHz bus // (argh! heavy up-rounding here) -i2c_timing i2c_timing_400k = { +const static i2c_timing kTiming400k = { buf : 2, hd_sta : 1, low : 2, @@ -426,7 +58,7 @@ i2c_timing i2c_timing_400k = { f : 1, su_sto : 1, - // see i2c_timing_100k + // see kTiming100k start_timeout : 2, byte_timeout : 2, bit_timeout : 2, @@ -435,15 +67,373 @@ i2c_timing i2c_timing_400k = { }; +/*! + There's no spin in user space, but we need it to wait a couple + of microseconds only + (in this case, snooze has much too much overhead) +*/ +void +spin(bigtime_t delay) +{ + bigtime_t startTime = system_time(); + + while (system_time() - startTime < delay) + ; +} + + +//! Wait until slave releases clock signal ("clock stretching") +static status_t +wait_for_clk(const i2c_bus *bus, bigtime_t timeout) +{ + bigtime_t startTime; + + // wait for clock signal to raise + spin(bus->timing.r); + + startTime = system_time(); + + while (true) { + int clk, data; + + bus->get_signals(bus->cookie, &clk, &data); + if (clk != 0) + return B_OK; + + if (system_time() - startTime > timeout) + return B_TIMEOUT; + + spin(bus->timing.r); + } +} + + +//! Send start or repeated start condition +static status_t +send_start_condition(const i2c_bus *bus) +{ + status_t status; + + bus->set_signals(bus->cookie, 1, 1); + + status = wait_for_clk(bus, bus->timing.start_timeout); + if (status != B_OK) { + TRACE("send_start_condition(): Timeout sending start condition\n"); + return status; + } + + spin(bus->timing.su_sta); + bus->set_signals(bus->cookie, 1, 0); + spin(bus->timing.hd_sta); + bus->set_signals(bus->cookie, 0, 0); + spin(bus->timing.f); + + return B_OK; +} + + +//! Send stop condition +static status_t +send_stop_condition(const i2c_bus *bus) +{ + status_t status; + + bus->set_signals(bus->cookie, 0, 0); + spin(bus->timing.r); + bus->set_signals(bus->cookie, 1, 0); + + // a slave may wait for us, so let elapse the acknowledge timeout + // to make the slave release bus control + status = wait_for_clk(bus, bus->timing.ack_timeout); + if (status != B_OK) { + TRACE("send_stop_condition(): Timeout sending stop condition\n"); + return status; + } + + spin(bus->timing.su_sto); + bus->set_signals(bus->cookie, 1, 1); + spin(bus->timing.buf); + + return B_OK; +} + + +//! Send one bit +static status_t +send_bit(const i2c_bus *bus, bool bit, int timeout) +{ + status_t status; + + //TRACE("send_bit(bit = %d)\n", bit & 1); + + bus->set_signals(bus->cookie, 0, bit & 1); + spin(bus->timing.su_dat); + bus->set_signals(bus->cookie, 1, bit & 1); + + status = wait_for_clk(bus, timeout); + if (status != B_OK) { + TRACE("send_bit(): Timeout when sending next bit\n"); + return status; + } + + spin(bus->timing.high); + bus->set_signals(bus->cookie, 0, bit & 1); + spin(bus->timing.f + bus->timing.low); + + return B_OK; +} + + +//! Send acknowledge and wait for reply +static status_t +send_acknowledge(const i2c_bus *bus) +{ + status_t status; + bigtime_t startTime; + + // release data so slave can modify it + bus->set_signals(bus->cookie, 0, 1); + spin(bus->timing.su_dat); + bus->set_signals(bus->cookie, 1, 1); + + status = wait_for_clk(bus, bus->timing.ack_start_timeout); + if (status != B_OK) { + TRACE("send_acknowledge(): Timeout when sending acknowledge\n"); + return status; + } + + // data and clock is high, now wait for slave to pull data low + // (according to spec, this can happen any time once clock is high) + startTime = system_time(); + + while (true) { + int clk, data; + + bus->get_signals(bus->cookie, &clk, &data); + + if (data == 0) + break; + + if (system_time() - startTime > bus->timing.ack_timeout) { + TRACE("send_acknowledge(): Slave didn't acknowledge byte\n"); + return B_TIMEOUT; + } + + spin(bus->timing.r); + } + + TRACE("send_acknowledge(): Success!\n"); + + // make sure we've waited at least t_high + spin(bus->timing.high); + + bus->set_signals(bus->cookie, 0, 1); + spin(bus->timing.f + bus->timing.low); + + return B_OK; +} + + +//! Send byte and wait for acknowledge if is true +static status_t +send_byte(const i2c_bus *bus, uint8 byte, bool acknowledge) +{ + int i; + + //TRACE("send_byte(byte = %x)\n", byte); + + for (i = 7; i >= 0; --i) { + status_t status = send_bit(bus, byte >> i, + i == 7 ? bus->timing.byte_timeout : bus->timing.bit_timeout); + if (status != B_OK) + return status; + } + + if (acknowledge) + return send_acknowledge(bus); + + return B_OK; +} + + +//! Send slave address, obeying 10-bit addresses and general call addresses +static status_t +send_slave_address(const i2c_bus *bus, int slaveAddress, bool isWrite) +{ + status_t status; + + status = send_byte(bus, (slaveAddress & 0xfe) | !isWrite, true); + if (status != B_OK) + return status; + + // there are the following special cases if the first byte looks like: + // - 0000 0000 - general call address (second byte with address follows) + // - 0000 0001 - start byte + // - 0000 001x - CBus address + // - 0000 010x - address reserved for different bus format + // - 0000 011x | + // - 0000 1xxx |-> reserved + // - 1111 1xxx | + // - 1111 0xxx - 10 bit address (second byte contains remaining 8 bits) + + // the lsb is 0 for write and 1 for read (except for general call address) + if ((slaveAddress & 0xff) != 0 && (slaveAddress & 0xf8) != 0xf0) + return B_OK; + + return send_byte(bus, slaveAddress >> 8, true); + // send second byte if required +} + + +//! Receive one bit +static status_t +receive_bit(const i2c_bus *bus, bool *bit, int timeout) +{ + status_t status; + int clk, data; + + bus->set_signals(bus->cookie, 1, 1); + // release clock + + // wait for slave to raise clock + status = wait_for_clk(bus, timeout); + if (status != B_OK) { + TRACE("receive_bit(): Timeout waiting for bit sent by slave\n"); + return status; + } + + bus->get_signals(bus->cookie, &clk, &data); + // sample data + + spin(bus->timing.high); + // leave clock high for minimal time + + bus->set_signals(bus->cookie, 0, 1); + // pull clock low so slave waits for us before next bit + + spin(bus->timing.f + bus->timing.low); + // let it settle and leave it low for minimal time + // to make sure slave has finished bit transmission too + + *bit = data; + return B_OK; +} + + +/*! + Send positive acknowledge afterwards if is true, + else send negative one +*/ +static status_t +receive_byte(const i2c_bus *bus, uint8 *resultByte, bool acknowledge) +{ + uint8 byte = 0; + int i; + + // pull clock low to let slave wait for us + bus->set_signals(bus->cookie, 0, 1); + + for (i = 7; i >= 0; i--) { + bool bit; + + status_t status = receive_bit(bus, &bit, + i == 7 ? bus->timing.byte_timeout : bus->timing.bit_timeout); + if (status != B_OK) + return status; + + byte = (byte << 1) | bit; + } + + //SHOW_FLOW(3, "%x ", byte); + + *resultByte = byte; + + return send_bit(bus, acknowledge ? 0 : 1, bus->timing.bit_timeout); +} + + +//! Send multiple bytes +static status_t +send_bytes(const i2c_bus *bus, const uint8 *writeBuffer, ssize_t writeLength) +{ + TRACE("send_bytes(length = %ld)\n", writeLength); + + for (; writeLength > 0; --writeLength, ++writeBuffer) { + status_t status = send_byte(bus, *writeBuffer, true); + if (status != B_OK) + return status; + } + + return B_OK; +} + + +//! Receive multiple bytes +static status_t +receive_bytes(const i2c_bus *bus, uint8 *readBuffer, ssize_t readLength) +{ + TRACE("receive_bytes(length = %ld)\n", writeLength); + + for (; readLength > 0; --readLength, ++readBuffer) { + status_t status = receive_byte(bus, readBuffer, readLength > 1); + if (status != B_OK) + return status; + } + + return B_OK; +} + + +// #pragma mark - exported functions + + +//! Combined i2c send+receive format +status_t +i2c_send_receive(const i2c_bus *bus, int slaveAddress, const uint8 *writeBuffer, + size_t writeLength, uint8 *readBuffer, size_t readLength) +{ + status_t status = send_start_condition(bus); + if (status != B_OK) + return status; + + status = send_slave_address(bus, slaveAddress, true); + if (status != B_OK) + goto err; + + status = send_bytes(bus, writeBuffer, writeLength); + if (status != B_OK) + goto err; + + status = send_start_condition(bus); + if (status != B_OK) + return status; + + status = send_slave_address(bus, slaveAddress, false); + if (status != B_OK) + goto err; + + status = receive_bytes(bus, readBuffer, readLength); + if (status != B_OK) + goto err; + + return send_stop_condition(bus); + +err: + TRACE("i2c_send_receive(): Cancelling transmission\n"); + send_stop_condition(bus); + return status; +} + + void i2c_get100k_timing(i2c_timing *timing) { - *timing = i2c_timing_100k; + *timing = kTiming100k; } void i2c_get400k_timing(i2c_timing *timing) { - *timing = i2c_timing_400k; + *timing = kTiming400k; } diff --git a/src/add-ons/accelerants/radeon/monitor_detection.c b/src/add-ons/accelerants/radeon/monitor_detection.c index 521c0aba97..f1a1ec5618 100644 --- a/src/add-ons/accelerants/radeon/monitor_detection.c +++ b/src/add-ons/accelerants/radeon/monitor_detection.c @@ -1,12 +1,15 @@ /* - Copyright (c) 2002-2004 Thomas Kurschel - + * Copyright 2002-2004, Thomas Kurschel. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ - Part of Radeon accelerant - - Monitor detection +/*! + Radeon monitor detection */ +#include +#include + #include "radeon_accelerant.h" #include "mmio.h" #include "crtc_regs.h" @@ -21,8 +24,7 @@ #include "theatre_regs.h" #include "set_mode.h" #include "ddc.h" -#include -#include "string.h" + typedef struct { accelerator_info *ai; @@ -30,480 +32,472 @@ typedef struct { } ddc_port_info; -// get I2C signals -static status_t get_signals( void *cookie, int *clk, int *data ) +//! Get I2C signals +static status_t +get_signals(void *cookie, int *clk, int *data) { ddc_port_info *info = (ddc_port_info *)cookie; vuint8 *regs = info->ai->regs; uint32 value; - - value = INREG( regs, info->port ); - + + value = INREG(regs, info->port); *clk = (value >> RADEON_GPIO_Y_SHIFT_1) & 1; *data = (value >> RADEON_GPIO_Y_SHIFT_0) & 1; - + return B_OK; } -// set I2C signals -static status_t set_signals( void *cookie, int clk, int data ) +//! Set I2C signals +static status_t +set_signals(void *cookie, int clk, int data) { ddc_port_info *info = (ddc_port_info *)cookie; vuint8 *regs = info->ai->regs; uint32 value; - value = INREG( regs, info->port ); + value = INREG(regs, info->port); value &= ~(RADEON_GPIO_A_1 | RADEON_GPIO_A_0); value &= ~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1); - value |= ((1-clk) << RADEON_GPIO_EN_SHIFT_1) | ((1-data) << RADEON_GPIO_EN_SHIFT_0); + value |= ((1-clk) << RADEON_GPIO_EN_SHIFT_1) + | ((1-data) << RADEON_GPIO_EN_SHIFT_0); - OUTREG( regs, info->port, value ); - + OUTREG(regs, info->port, value); return B_OK; } -// read EDID information from monitor -// ddc_port - register to use for DDC2 communication -bool Radeon_ReadEDID( accelerator_info *ai, uint32 ddc_port, edid1_info *edid ) +/*! Read EDID information from monitor + ddc_port - register to use for DDC2 communication +*/ +bool +Radeon_ReadEDID(accelerator_info *ai, uint32 ddcPort, edid1_info *edid) { i2c_bus bus; ddc_port_info info; void *vdif; - size_t vdif_len; - status_t res; - + size_t vdifLength; + info.ai = ai; - info.port = ddc_port; - + info.port = ddcPort; + + ddc2_init_timing(&bus); bus.cookie = &info; bus.set_signals = &set_signals; bus.get_signals = &get_signals; - res = ddc2_read_edid1( &bus, edid, &vdif, &vdif_len ); - if( res != B_OK ) + if (ddc2_read_edid1(&bus, edid, &vdif, &vdifLength) != B_OK) return false; - - SHOW_FLOW( 2, "Found DDC-capable monitor @0x%04x", ddc_port ); - if( vdif != NULL ) - free( vdif ); - + SHOW_FLOW(2, "Found DDC-capable monitor @0x%04x", ddcPort); + + free(vdif); return true; } // search for display connect to CRT DAC // colour - true, if only a colour monitor is to be accepted -static bool Radeon_DetectCRTInt( accelerator_info *ai, bool colour ) +static bool +Radeon_DetectCRTInt(accelerator_info *ai, bool colour) { vuint8 *regs = ai->regs; - uint32 old_crtc_ext_cntl, old_dac_ext_cntl, old_dac_cntl, tmp; + uint32 old_crtc_ext_cntl, old_dac_ext_cntl, old_dac_cntl, value; bool found; // makes sure there is a signal - old_crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL ); + old_crtc_ext_cntl = INREG(regs, RADEON_CRTC_EXT_CNTL); - tmp = old_crtc_ext_cntl | RADEON_CRTC_CRT_ON; - OUTREG( regs, RADEON_CRTC_EXT_CNTL, tmp ); + value = old_crtc_ext_cntl | RADEON_CRTC_CRT_ON; + OUTREG(regs, RADEON_CRTC_EXT_CNTL, value); // force DAC to output constant voltage // for colour monitors, RGB is tested, for B/W only G - old_dac_ext_cntl = INREG( regs, RADEON_DAC_EXT_CNTL ); - - tmp = - RADEON_DAC_FORCE_BLANK_OFF_EN | - RADEON_DAC_FORCE_DATA_EN | - (colour ? RADEON_DAC_FORCE_DATA_SEL_RGB : RADEON_DAC_FORCE_DATA_SEL_G) | - (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); - OUTREG( regs, RADEON_DAC_EXT_CNTL, tmp ); - - // enable DAC and tell is to use VGA signals - old_dac_cntl = INREG( regs, RADEON_DAC_CNTL ); - - tmp = old_dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); - tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; - OUTREG( regs, RADEON_DAC_CNTL, tmp ); + old_dac_ext_cntl = INREG(regs, RADEON_DAC_EXT_CNTL); + + value = RADEON_DAC_FORCE_BLANK_OFF_EN | RADEON_DAC_FORCE_DATA_EN + | (colour ? RADEON_DAC_FORCE_DATA_SEL_RGB : RADEON_DAC_FORCE_DATA_SEL_G) + | (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + OUTREG(regs, RADEON_DAC_EXT_CNTL, value); + + // enable DAC and tell it to use VGA signals + old_dac_cntl = INREG(regs, RADEON_DAC_CNTL); + + value = old_dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); + value |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; + OUTREG(regs, RADEON_DAC_CNTL, value); // specs says that we should wait 1µs before checking but sample // code uses 2 ms; we use long delay to be on safe side // (though we don't want to make it too long as the monitor // gets no sync signal now) - snooze( 2000 ); + snooze(2000); // let's see whether there is some - found = (INREG( regs, RADEON_DAC_CNTL ) & RADEON_DAC_CMP_OUTPUT) != 0; - - if( found ) - SHOW_INFO( 2, "Found %s CRT connected to CRT-DAC", colour ? "colour" : "b/w" ); - - OUTREG( regs, RADEON_DAC_CNTL, old_dac_cntl ); - OUTREG( regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl ); - OUTREG( regs, RADEON_CRTC_EXT_CNTL, old_crtc_ext_cntl ); - + found = (INREG(regs, RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) != 0; + if (found) { + SHOW_INFO(2, "Found %s CRT connected to CRT-DAC", + colour ? "colour" : "b/w"); + } + + OUTREG(regs, RADEON_DAC_CNTL, old_dac_cntl); + OUTREG(regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl); + OUTREG(regs, RADEON_CRTC_EXT_CNTL, old_crtc_ext_cntl); + return found; } -// check whethere there is a CRT connected to CRT DAC -static bool Radeon_DetectCRT( accelerator_info *ai ) +//! Check whethere there is a CRT connected to CRT DAC +static bool +Radeon_DetectCRT(accelerator_info *ai) { - vuint32 old_vclk_ecp_cntl, tmp; + vuint32 old_vclk_ecp_cntl, value; bool found; // enforce clock so the DAC gets activated - old_vclk_ecp_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL ); + old_vclk_ecp_cntl = Radeon_INPLL(ai->regs, ai->si->asic, + RADEON_VCLK_ECP_CNTL); - tmp = old_vclk_ecp_cntl & - ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); - Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, tmp ); + value = old_vclk_ecp_cntl + & ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); + Radeon_OUTPLL(ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, value); // search first for colour, then for B/W monitor - found = Radeon_DetectCRTInt( ai, true ) || Radeon_DetectCRTInt( ai, false ); - - Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, old_vclk_ecp_cntl ); - + found = Radeon_DetectCRTInt(ai, true) || Radeon_DetectCRTInt(ai, false); + + Radeon_OUTPLL(ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, + old_vclk_ecp_cntl); + return found; } -// CRT on TV-DAC detection for rv200 and below -// checked for rv200 -static bool Radeon_DetectTVCRT_RV200( accelerator_info *ai ) +//! CRT on TV-DAC detection for rv200 and below checked for rv200 +static bool +Radeon_DetectTVCRT_RV200(accelerator_info *ai) { vuint8 *regs = ai->regs; - uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, tmp; + uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, value; bool found; // enable CRTC2, setting 8 bpp (we just pick any valid value) - old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL ); - - tmp = old_crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; - tmp |= - RADEON_CRTC2_CRT2_ON | - (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, tmp ); - + old_crtc2_gen_cntl = INREG(regs, RADEON_CRTC2_GEN_CNTL); + + value = old_crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; + value |= RADEON_CRTC2_CRT2_ON | (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, value); + // enable TV-DAC, choosing VGA signal level - old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL ); - - tmp = - RADEON_TV_DAC_CNTL_NBLANK | - RADEON_TV_DAC_CNTL_NHOLD | - RADEON_TV_DAC_CNTL_DETECT | - RADEON_TV_DAC_CNTL_STD_PS2; - OUTREG( regs, RADEON_TV_DAC_CNTL, tmp ); - + old_tv_dac_cntl = INREG(regs, RADEON_TV_DAC_CNTL); + + value = RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD + | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_STD_PS2; + OUTREG(regs, RADEON_TV_DAC_CNTL, value); + // enforce constant DAC output voltage on RGB - tmp = - RADEON_DAC2_FORCE_BLANK_OFF_EN | - RADEON_DAC2_FORCE_DATA_EN | - RADEON_DAC_FORCE_DATA_SEL_RGB | - (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); - OUTREG( regs, RADEON_DAC_EXT_CNTL, tmp ); - - old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 ); - + value = RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN + | RADEON_DAC_FORCE_DATA_SEL_RGB + | (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + OUTREG(regs, RADEON_DAC_EXT_CNTL, value); + + old_dac_cntl2 = INREG(regs, RADEON_DAC_CNTL2); + // set DAC in CRT mode and enable detection // TODO: make sure we really use CRTC2 - this is ASIC dependant - tmp = old_dac_cntl2 | RADEON_DAC2_CLK_SEL_CRT | RADEON_DAC2_CMP_EN; - OUTREG( regs, RADEON_DAC_CNTL2, tmp ); - - snooze( 10000 ); + value = old_dac_cntl2 | RADEON_DAC2_CLK_SEL_CRT | RADEON_DAC2_CMP_EN; + OUTREG(regs, RADEON_DAC_CNTL2, value); + + snooze(10000); // let's see what we've got! - found = (INREG( regs, RADEON_DAC_CNTL2 ) & RADEON_DAC2_CMP_OUTPUT) != 0; - - if( found ) - SHOW_INFO0( 2, "Found CRT connected to TV-DAC, i.e. DVI port" ); - - OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 ); - OUTREG( regs, RADEON_DAC_EXT_CNTL, 0 ); - OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl ); - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl ); - + found = (INREG(regs, RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) != 0; + if (found) + SHOW_INFO0(2, "Found CRT connected to TV-DAC, i.e. DVI port"); + + OUTREG(regs, RADEON_DAC_CNTL2, old_dac_cntl2); + OUTREG(regs, RADEON_DAC_EXT_CNTL, 0); + OUTREG(regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl); + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl); + return found; } -// CRT on TV-DAC detection for r300 -// checked for r300 -static bool Radeon_DetectTVCRT_R300( accelerator_info *ai ) + +//! CRT on TV-DAC detection for r300 checked for r300 +static bool +Radeon_DetectTVCRT_R300(accelerator_info *ai) { vuint8 *regs = ai->regs; - uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, tmp; + uint32 old_crtc2_gen_cntl, old_tv_dac_cntl, old_dac_cntl2, value; uint32 old_radeon_gpiopad_a; bool found; - - old_radeon_gpiopad_a = INREG( regs, RADEON_GPIOPAD_A ); + + old_radeon_gpiopad_a = INREG(regs, RADEON_GPIOPAD_A); // whatever these flags mean - let's pray they won't get changed - OUTREGP( regs, RADEON_GPIOPAD_EN, 1, ~1 ); - OUTREGP( regs, RADEON_GPIOPAD_MASK, 1, ~1 ); - OUTREGP( regs, RADEON_GPIOPAD_A, 1, ~1 ); + OUTREGP(regs, RADEON_GPIOPAD_EN, 1, ~1); + OUTREGP(regs, RADEON_GPIOPAD_MASK, 1, ~1); + OUTREGP(regs, RADEON_GPIOPAD_A, 1, ~1); - old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL ); + old_crtc2_gen_cntl = INREG(regs, RADEON_CRTC2_GEN_CNTL); // enable DAC, choose valid pixel format and enable DPMS // as usual, the code doesn't take into account whether the TV-DAC // does really use CRTC2 - tmp = old_crtc2_gen_cntl; - tmp &= ~RADEON_CRTC2_PIX_WIDTH_MASK; - tmp |= - (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT) | - RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT; - - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, tmp ); - - old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL ); - + value = old_crtc2_gen_cntl; + value &= ~RADEON_CRTC2_PIX_WIDTH_MASK; + value |= (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT) | RADEON_CRTC2_CRT2_ON + | RADEON_CRTC2_VSYNC_TRISTAT; + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, value); + + old_tv_dac_cntl = INREG(regs, RADEON_TV_DAC_CNTL); + // enable TV-DAC - OUTREG( regs, RADEON_TV_DAC_CNTL, - RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD | - RADEON_TV_DAC_CNTL_DETECT | - RADEON_TV_DAC_CNTL_STD_PS2 ); + OUTREG(regs, RADEON_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_NBLANK + | RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_DETECT + | RADEON_TV_DAC_CNTL_STD_PS2); // force constant voltage output of DAC for impedance test - OUTREG( regs, RADEON_DAC_EXT_CNTL, - RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN | - RADEON_DAC_FORCE_DATA_SEL_RGB | - (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT )); - - old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 ); + OUTREG(regs, RADEON_DAC_EXT_CNTL, RADEON_DAC2_FORCE_BLANK_OFF_EN + | RADEON_DAC2_FORCE_DATA_EN | RADEON_DAC_FORCE_DATA_SEL_RGB + | (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT)); + + old_dac_cntl2 = INREG(regs, RADEON_DAC_CNTL2); // enable CRT mode of TV-DAC and enable comparator - tmp = old_dac_cntl2 | RADEON_DAC2_CLK_SEL_CRT | RADEON_DAC2_CMP_EN; - - OUTREG( regs, RADEON_DAC_CNTL2, tmp ); - - snooze( 10000 ); - - // check connection of blue data signal to see whether there is a CRT - found = (INREG( regs, RADEON_DAC_CNTL2 ) & RADEON_DAC2_CMP_OUT_B) != 0; - - // clean up the mess - OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 ); - OUTREG( regs, RADEON_DAC_EXT_CNTL, 0 ); - OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl ); - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl ); + OUTREG(regs, RADEON_DAC_CNTL2, old_dac_cntl2 | RADEON_DAC2_CLK_SEL_CRT + | RADEON_DAC2_CMP_EN); + + snooze(10000); + + // check connection of blue data signal to see whether there is a CRT + found = (INREG(regs, RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) != 0; + + // clean up the mess + OUTREG(regs, RADEON_DAC_CNTL2, old_dac_cntl2); + OUTREG(regs, RADEON_DAC_EXT_CNTL, 0); + OUTREG(regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl); + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl); + + OUTREGP(regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1); - OUTREGP( regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1 ); - return found; } -// check whether there is a CRT connected to TV-DAC -static bool Radeon_DetectTVCRT( accelerator_info *ai ) +//! Check whether there is a CRT connected to TV-DAC +static bool +Radeon_DetectTVCRT(accelerator_info *ai) { if (ai->si->is_mobility) return dd_none; - - switch( ai->si->asic ) { - case rt_r100: - // original Radeons have pure DVI only and mobility chips - // have no DVI connector - // TBD: can they have a docking station for CRT on TV-DAC? - return dd_none; - - case rt_rv100: - case rt_rv200: - case rt_rv250: - case rt_rv280: - // IGP is guessed - case rt_rs100: - case rt_rs200: - case rt_rs300: - return Radeon_DetectTVCRT_RV200( ai ); - - case rt_r300: - case rt_r350: - case rt_rv350: - case rt_rv380: - case rt_r420: - return Radeon_DetectTVCRT_R300( ai ); - - case rt_r200: - // r200 has no built-in TV-out and thus no TV-DAC to use for - // second CRT - return dd_none; + + switch (ai->si->asic) { + case rt_r100: + // original Radeons have pure DVI only and mobility chips + // have no DVI connector + // TBD: can they have a docking station for CRT on TV-DAC? + return dd_none; + + case rt_rv100: + case rt_rv200: + case rt_rv250: + case rt_rv280: + // IGP is guessed + case rt_rs100: + case rt_rs200: + case rt_rs300: + return Radeon_DetectTVCRT_RV200(ai); + + case rt_r300: + case rt_r350: + case rt_rv350: + case rt_rv380: + case rt_r420: + return Radeon_DetectTVCRT_R300(ai); + + case rt_r200: + // r200 has no built-in TV-out and thus no TV-DAC to use for + // second CRT + return dd_none; } - + return dd_none; } -// TV detection for rv200 and below -// should work for M6 and RV200 -static display_device_e Radeon_DetectTV_RV200( accelerator_info *ai, bool tv_crt_found ) +//! TV detection for rv200 and below should work for M6 and RV200 +static display_device_e +Radeon_DetectTV_RV200(accelerator_info *ai, bool tv_crt_found) { vuint8 *regs = ai->regs; - uint32 - tmp, old_dac_cntl2, old_crtc_ext_cntl, old_crtc2_gen_cntl, old_tv_master_cntl, - old_tv_dac_cntl, old_pre_dac_mux_cntl, config_cntl; + uint32 value, old_dac_cntl2, old_crtc_ext_cntl, old_crtc2_gen_cntl; + uint32 old_tv_master_cntl, old_tv_dac_cntl, old_pre_dac_mux_cntl; + uint32 config_cntl; display_device_e displays = dd_none; - + // give up if there is a CRT connected to TV-DAC - if( tv_crt_found ) + if (tv_crt_found) return dd_none; // enable TV mode - old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 ); - tmp = old_dac_cntl2 & ~RADEON_DAC2_CLK_SEL_CRT; - OUTREG( regs, RADEON_DAC_CNTL2, tmp ); - - old_crtc_ext_cntl = INREG( regs, RADEON_CRTC_EXT_CNTL ); - old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL ); - old_tv_master_cntl = INREG( regs, RADEON_TV_MASTER_CNTL ); - + old_dac_cntl2 = INREG(regs, RADEON_DAC_CNTL2); + value = old_dac_cntl2 & ~RADEON_DAC2_CLK_SEL_CRT; + OUTREG(regs, RADEON_DAC_CNTL2, value); + + old_crtc_ext_cntl = INREG(regs, RADEON_CRTC_EXT_CNTL); + old_crtc2_gen_cntl = INREG(regs, RADEON_CRTC2_GEN_CNTL); + old_tv_master_cntl = INREG(regs, RADEON_TV_MASTER_CNTL); + // enable TV output - tmp = old_tv_master_cntl | RADEON_TV_MASTER_CNTL_TV_ON; - tmp &= ~( + value = old_tv_master_cntl | RADEON_TV_MASTER_CNTL_TV_ON; + value &= ~( RADEON_TV_MASTER_CNTL_TV_ASYNC_RST | RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX | RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN | RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN | RADEON_TV_MASTER_CNTL_RE_SYNC_NOW_SEL_MASK); - tmp |= + value |= RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST | RADEON_TV_MASTER_CNTL_CRT_ASYNC_RST; - OUTREG( regs, RADEON_TV_MASTER_CNTL, tmp ); + OUTREG(regs, RADEON_TV_MASTER_CNTL, value); - old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL ); + old_tv_dac_cntl = INREG(regs, RADEON_TV_DAC_CNTL); - config_cntl = INREG( regs, RADEON_CONFIG_CNTL ); + config_cntl = INREG(regs, RADEON_CONFIG_CNTL); // unlock TV DAC - tmp = + value = RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_STD_NTSC | (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | ((((config_cntl & RADEON_CFG_ATI_REV_ID_MASK) == 0) ? 8 : 4) << RADEON_TV_DAC_CNTL_DACADJ_SHIFT); - OUTREG( regs, RADEON_TV_DAC_CNTL, tmp ); + OUTREG(regs, RADEON_TV_DAC_CNTL, value); - old_pre_dac_mux_cntl = INREG( regs, RADEON_TV_PRE_DAC_MUX_CNTL ); + old_pre_dac_mux_cntl = INREG(regs, RADEON_TV_PRE_DAC_MUX_CNTL); // force constant DAC output voltage - tmp = + value = RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | (RADEON_TV_MUX_FORCE_DAC_DATA << RADEON_TV_PRE_DAC_MUX_CNTL_RED_MX_SHIFT) | (RADEON_TV_MUX_FORCE_DAC_DATA << RADEON_TV_PRE_DAC_MUX_CNTL_GRN_MX_SHIFT) | (RADEON_TV_MUX_FORCE_DAC_DATA << RADEON_TV_PRE_DAC_MUX_CNTL_BLU_MX_SHIFT) | (0x109 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT); - OUTREG( regs, RADEON_TV_PRE_DAC_MUX_CNTL, tmp ); + OUTREG(regs, RADEON_TV_PRE_DAC_MUX_CNTL, value); // let things settle a bit - snooze( 3000 ); - + snooze(3000); + // now see which wires are connected - tmp = INREG( regs, RADEON_TV_DAC_CNTL ); - if( (tmp & RADEON_TV_DAC_CNTL_GDACDET) != 0 ) { + value = INREG(regs, RADEON_TV_DAC_CNTL); + if ((value & RADEON_TV_DAC_CNTL_GDACDET) != 0) { displays |= dd_stv; - SHOW_INFO0( 2, "S-Video TV-Out is connected" ); + SHOW_INFO0(2, "S-Video TV-Out is connected"); } - - if( (tmp & RADEON_TV_DAC_CNTL_BDACDET) != 0 ) { + + if ((value & RADEON_TV_DAC_CNTL_BDACDET) != 0) { displays |= dd_ctv; - SHOW_INFO0( 2, "Composite TV-Out is connected" ); + SHOW_INFO0(2, "Composite TV-Out is connected"); } - - OUTREG( regs, RADEON_TV_PRE_DAC_MUX_CNTL, old_pre_dac_mux_cntl ); - OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl ); - OUTREG( regs, RADEON_TV_MASTER_CNTL, old_tv_master_cntl ); - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl ); - OUTREG( regs, RADEON_CRTC_EXT_CNTL, old_crtc_ext_cntl ); - OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 ); - + + OUTREG(regs, RADEON_TV_PRE_DAC_MUX_CNTL, old_pre_dac_mux_cntl); + OUTREG(regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl); + OUTREG(regs, RADEON_TV_MASTER_CNTL, old_tv_master_cntl); + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl); + OUTREG(regs, RADEON_CRTC_EXT_CNTL, old_crtc_ext_cntl); + OUTREG(regs, RADEON_DAC_CNTL2, old_dac_cntl2); + return displays; } // TV detection for r300 series // should work for R300 -static display_device_e Radeon_DetectTV_R300( accelerator_info *ai ) +static display_device_e Radeon_DetectTV_R300(accelerator_info *ai) { vuint8 *regs = ai->regs; display_device_e displays = dd_none; uint32 tmp, old_dac_cntl2, old_crtc2_gen_cntl, old_dac_ext_cntl, old_tv_dac_cntl; uint32 old_radeon_gpiopad_a; - old_radeon_gpiopad_a = INREG( regs, RADEON_GPIOPAD_A ); + old_radeon_gpiopad_a = INREG(regs, RADEON_GPIOPAD_A); // whatever these flags mean - let's pray they won't get changed - OUTREGP( regs, RADEON_GPIOPAD_EN, 1, ~1 ); - OUTREGP( regs, RADEON_GPIOPAD_MASK, 1, ~1 ); - OUTREGP( regs, RADEON_GPIOPAD_A, 0, ~1 ); + OUTREGP(regs, RADEON_GPIOPAD_EN, 1, ~1); + OUTREGP(regs, RADEON_GPIOPAD_MASK, 1, ~1); + OUTREGP(regs, RADEON_GPIOPAD_A, 0, ~1); - old_dac_cntl2 = INREG( regs, RADEON_DAC_CNTL2 ); + old_dac_cntl2 = INREG(regs, RADEON_DAC_CNTL2); // set CRT mode (!) of TV-DAC - OUTREG( regs, RADEON_DAC_CNTL2, RADEON_DAC2_CLK_SEL_CRT ); + OUTREG(regs, RADEON_DAC_CNTL2, RADEON_DAC2_CLK_SEL_CRT); - old_crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL ); + old_crtc2_gen_cntl = INREG(regs, RADEON_CRTC2_GEN_CNTL); // enable TV-Out output, but set DPMS mode // (this seems to be not correct if TV-Out is connected to CRTC1, // but it doesn't really hurt having wrong DPMS mode) - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, - RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT ); + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT); - old_dac_ext_cntl = INREG( regs, RADEON_DAC_EXT_CNTL ); + old_dac_ext_cntl = INREG(regs, RADEON_DAC_EXT_CNTL); // force constant voltage output of DAC for impedance test - OUTREG( regs, RADEON_DAC_EXT_CNTL, + OUTREG(regs, RADEON_DAC_EXT_CNTL, RADEON_DAC2_FORCE_BLANK_OFF_EN | RADEON_DAC2_FORCE_DATA_EN | RADEON_DAC_FORCE_DATA_SEL_RGB | - (0xec << RADEON_DAC_FORCE_DATA_SHIFT )); + (0xec << RADEON_DAC_FORCE_DATA_SHIFT)); - old_tv_dac_cntl = INREG( regs, RADEON_TV_DAC_CNTL ); + old_tv_dac_cntl = INREG(regs, RADEON_TV_DAC_CNTL); // get TV-DAC running (or something...) - OUTREG( regs, RADEON_TV_DAC_CNTL, + OUTREG(regs, RADEON_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | - (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT )); + (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT)); - (void)INREG( regs, RADEON_TV_DAC_CNTL ); + (void)INREG(regs, RADEON_TV_DAC_CNTL); - snooze( 4000 ); + snooze(4000); - OUTREG( regs, RADEON_TV_DAC_CNTL, + OUTREG(regs, RADEON_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_STD_NTSC | (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | - (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT )); + (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT)); - (void)INREG( regs, RADEON_TV_DAC_CNTL ); + (void)INREG(regs, RADEON_TV_DAC_CNTL); - snooze( 6000 ); + snooze(6000); // now see which wires are connected - tmp = INREG( regs, RADEON_TV_DAC_CNTL ); - if( (tmp & RADEON_TV_DAC_CNTL_GDACDET) != 0 ) { + tmp = INREG(regs, RADEON_TV_DAC_CNTL); + if ((tmp & RADEON_TV_DAC_CNTL_GDACDET) != 0) { displays |= dd_stv; - SHOW_INFO0( 2, "S-Video TV-Out is connected" ); + SHOW_INFO0(2, "S-Video TV-Out is connected"); } - if( (tmp & RADEON_TV_DAC_CNTL_BDACDET) != 0 ) { + if ((tmp & RADEON_TV_DAC_CNTL_BDACDET) != 0) { displays |= dd_ctv; - SHOW_INFO0( 2, "Composite TV-Out is connected" ); + SHOW_INFO0(2, "Composite TV-Out is connected"); } // clean up the mess we did - OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl ); - OUTREG( regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl ); - OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl ); - OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 ); + OUTREG(regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl); + OUTREG(regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl); + OUTREG(regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl); + OUTREG(regs, RADEON_DAC_CNTL2, old_dac_cntl2); - OUTREGP( regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1 ); + OUTREGP(regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1); return displays; } // save readout of TV detection comparators -static bool readTVDetect( accelerator_info *ai ) +static bool readTVDetect(accelerator_info *ai) { uint32 tmp; int i; @@ -511,192 +505,204 @@ static bool readTVDetect( accelerator_info *ai ) bool detect; // make output constant - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, - RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK ); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK); // check detection result - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp ); + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp); detect = (tmp & RADEON_TV_DAC_CNTL_CMPOUT) != 0; - //SHOW_FLOW( 2, "detect=%d", detect ); + //SHOW_FLOW(2, "detect=%d", detect); start_time = system_time(); do { // wait for stable detect signal - for( i = 0; i < 5; ++i ) { + for (i = 0; i < 5; ++i) { bool cur_detect; - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK | - RADEON_TV_DAC_CNTL_NHOLD ); - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, - RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK ); + RADEON_TV_DAC_CNTL_NHOLD); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK); - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp ); + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp); cur_detect = (tmp & RADEON_TV_DAC_CNTL_CMPOUT) != 0; - //SHOW_FLOW( 2, "cur_detect=%d", cur_detect ); + //SHOW_FLOW(2, "cur_detect=%d", cur_detect); - if( cur_detect != detect ) + if (cur_detect != detect) break; detect = cur_detect; } - if( i == 5 ) { - //SHOW_FLOW( 2, "return %d", detect ); + if (i == 5) { + //SHOW_FLOW(2, "return %d", detect); return detect; } // don't wait forever - give up after 1 second - } while( system_time() - start_time < 1000000 ); - - SHOW_FLOW0( 2, "timeout" ); - + } while (system_time() - start_time < 1000000); + + SHOW_FLOW0(2, "timeout"); return false; } -// detect TV connected to external Theatre-Out -static display_device_e Radeon_DetectTV_Theatre( accelerator_info *ai ) +//! Detect TV connected to external Theatre-Out +static display_device_e +Radeon_DetectTV_Theatre(accelerator_info *ai) { - uint32 - old_tv_dac_cntl, old_pre_dac_mux_cntl, old_modulator_cntl1, old_master_cntl; - uint32 - uv_adr, old_last_fifo_entry, old_mid_fifo_entry, last_fifo_addr; + uint32 old_tv_dac_cntl, old_pre_dac_mux_cntl, old_modulator_cntl1; + uint32 old_master_cntl; + uint32 uv_adr, old_last_fifo_entry, old_mid_fifo_entry, last_fifo_addr; display_device_e displays = dd_none; - - if( ai->si->tv_chip != tc_external_rt1 ) - return dd_none; - - // save previous values (TV-Out may be running) - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &old_tv_dac_cntl ); - - // enable DAC and comparators - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, - RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | - RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_NBLANK ); - - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, &old_pre_dac_mux_cntl ); - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, &old_modulator_cntl1 ); - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, &old_master_cntl ); - - // save output timing - Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_UV_ADR, &uv_adr ); - - last_fifo_addr = (uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) * 2 + 1; - - old_last_fifo_entry = Radeon_TheatreReadFIFO( ai, last_fifo_addr ); - old_mid_fifo_entry = Radeon_TheatreReadFIFO( ai, 0x18f ); - - Radeon_TheatreWriteFIFO( ai, last_fifo_addr, 0x20208 ); - Radeon_TheatreWriteFIFO( ai, 0x18f, 0x3ff2608 ); - - // stop TV-Out to savely program it - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, - RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST | RADEON_TV_MASTER_CNTL_TV_ASYNC_RST ); - - // set constant base level - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, - (0x2c << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | - (0x2c << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT) ); - - // enable output - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, - RADEON_TV_MASTER_CNTL_TV_ASYNC_RST ); - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, - 0 ); + if (ai->si->tv_chip != tc_external_rt1) + return dd_none; + + // save previous values (TV-Out may be running) + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + &old_tv_dac_cntl); + + // enable DAC and comparators + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT + | RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_NBLANK); + + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, + &old_pre_dac_mux_cntl); + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, + &old_modulator_cntl1); + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, + &old_master_cntl); + + // save output timing + Radeon_VIPRead(ai, ai->si->theatre_channel, THEATRE_VIP_UV_ADR, &uv_adr); + + last_fifo_addr = (uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) * 2 + 1; + + old_last_fifo_entry = Radeon_TheatreReadFIFO(ai, last_fifo_addr); + old_mid_fifo_entry = Radeon_TheatreReadFIFO(ai, 0x18f); + + Radeon_TheatreWriteFIFO(ai, last_fifo_addr, 0x20208); + Radeon_TheatreWriteFIFO(ai, 0x18f, 0x3ff2608); + + // stop TV-Out to savely program it + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, + RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST + | RADEON_TV_MASTER_CNTL_TV_ASYNC_RST); + + // set constant base level + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, + (0x2c << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) + | (0x2c << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT)); + + // enable output + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, + RADEON_TV_MASTER_CNTL_TV_ASYNC_RST); + + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, 0); // set constant Composite output - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, - RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | - RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN | - (9 << RADEON_TV_PRE_DAC_MUX_CNTL_BLU_MX_SHIFT) | - (0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT) ); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, + RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN + | RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN + | (9 << RADEON_TV_PRE_DAC_MUX_CNTL_BLU_MX_SHIFT) + | (0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT)); // check for S-Video connection - if( readTVDetect( ai )) { - SHOW_FLOW0( 2, "Composite-Out of Rage Theatre is connected" ); + if (readTVDetect(ai)) { + SHOW_FLOW0(2, "Composite-Out of Rage Theatre is connected"); displays |= dd_ctv; } // enable output changes - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, - RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK | - RADEON_TV_DAC_CNTL_NHOLD ); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT + | RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD); // set constant Y-output of S-Video adapter - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, - RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | - RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN | - (9 << RADEON_TV_PRE_DAC_MUX_CNTL_RED_MX_SHIFT) | - (0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT) ); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, + RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN + | RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN + | (9 << RADEON_TV_PRE_DAC_MUX_CNTL_RED_MX_SHIFT) + | (0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT)); // check for composite connection - if( readTVDetect( ai )) { - SHOW_FLOW0( 2, "S-Video-Out of Rage Theatre is connected" ); + if (readTVDetect(ai)) { + SHOW_FLOW0(2, "S-Video-Out of Rage Theatre is connected"); displays |= dd_stv; } // restore everything - Radeon_TheatreWriteFIFO( ai, last_fifo_addr, old_last_fifo_entry ); - Radeon_TheatreWriteFIFO( ai, 0x18f, old_mid_fifo_entry ); + Radeon_TheatreWriteFIFO(ai, last_fifo_addr, old_last_fifo_entry); + Radeon_TheatreWriteFIFO(ai, 0x18f, old_mid_fifo_entry); + + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, + old_master_cntl); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, + old_modulator_cntl1); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, + old_pre_dac_mux_cntl); + Radeon_VIPWrite(ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, + old_tv_dac_cntl); - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, old_master_cntl ); - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, old_modulator_cntl1 ); - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, old_pre_dac_mux_cntl ); - Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, old_tv_dac_cntl ); - return displays; } -// check whether there is a TV connected to TV-DAC -// returns bit set, i.e. there can be S-Video or composite or both -static display_device_e Radeon_DetectTV( accelerator_info *ai, bool tv_crt_found ) + +/*! + Check whether there is a TV connected to TV-DAC + returns bit set, i.e. there can be S-Video or composite or both +*/ +static display_device_e +Radeon_DetectTV(accelerator_info *ai, bool tv_crt_found) { - switch( ai->si->asic ) { - case rt_r100: - case rt_r200: - return Radeon_DetectTV_Theatre( ai ); - - case rt_rv100: - case rt_rv200: - case rt_rv250: - case rt_rv280: - // IGP method is guessed - case rt_rs100: - case rt_rs200: - case rt_rs300: - return Radeon_DetectTV_RV200( ai, tv_crt_found ); - - case rt_r300: - case rt_r350: - case rt_rv350: - case rt_rv380: - case rt_r420: - return Radeon_DetectTV_R300( ai ); + switch (ai->si->asic) { + case rt_r100: + case rt_r200: + return Radeon_DetectTV_Theatre(ai); + + case rt_rv100: + case rt_rv200: + case rt_rv250: + case rt_rv280: + // IGP method is guessed + case rt_rs100: + case rt_rs200: + case rt_rs300: + return Radeon_DetectTV_RV200(ai, tv_crt_found); + + case rt_r300: + case rt_r350: + case rt_rv350: + case rt_rv380: + case rt_r420: + return Radeon_DetectTV_R300(ai); } - + return dd_none; } -// get native monitor timing, using Detailed Monitor Description -static void Radeon_FindFPTiming_DetailedMonitorDesc( - const edid1_info *edid, fp_info *fp, uint32 *max_hsize, uint32 *max_vsize ) +//! Get native monitor timing, using Detailed Monitor Description +static void +Radeon_FindFPTiming_DetailedMonitorDesc(const edid1_info *edid, fp_info *fp, + uint32 *max_hsize, uint32 *max_vsize) { int i; - - for( i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i ) { - if( edid->detailed_monitor[i].monitor_desc_type == edid1_is_detailed_timing ) { + + for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { + if (edid->detailed_monitor[i].monitor_desc_type == edid1_is_detailed_timing) { const edid1_detailed_timing *timing = &edid->detailed_monitor[i].data.detailed_timing; - - SHOW_FLOW( 2, "Found detailed timing for mode %dx%d in DDC data", - (int)timing->h_active, (int)timing->v_active ); - - if( timing->h_active > *max_hsize && timing->v_active > *max_vsize ) { + + SHOW_FLOW(2, "Found detailed timing for mode %dx%d in DDC data", + (int)timing->h_active, (int)timing->v_active); + + if (timing->h_active > *max_hsize && timing->v_active > *max_vsize) { *max_hsize = timing->h_active; *max_vsize = timing->v_active; @@ -718,77 +724,78 @@ static void Radeon_FindFPTiming_DetailedMonitorDesc( } } -// get native monitor timing, using Standard Timing table; -// this table doesn't contain the actual timing, so we try to find a -// appropriate VESA modes for the resolutions given in the table -static void Radeon_FindFPTiming_StandardTiming( - const edid1_info *edid, fp_info *fp, uint32 *max_hsize, uint32 *max_vsize ) + +/*! Get native monitor timing, using Standard Timing table; + this table doesn't contain the actual timing, so we try to find a + appropriate VESA modes for the resolutions given in the table +*/ +static void +Radeon_FindFPTiming_StandardTiming(const edid1_info *edid, fp_info *fp, + uint32 *max_hsize, uint32 *max_vsize) { int i; - - for( i = 0; i < EDID1_NUM_STD_TIMING; ++i ) { + + for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) { const edid1_std_timing *std_timing = &edid->std_timing[i]; - int best_fit = -1; int best_refresh_deviation = 10000; int j; - - if( std_timing->h_size <= 256 ) + + if (std_timing->h_size <= 256) continue; - - for( j = 0; j < (int)vesa_mode_list_count; ++j ) { + + for (j = 0; j < (int)vesa_mode_list_count; ++j) { int refresh_rate, cur_refresh_deviation; - - if( vesa_mode_list[j].h_display != std_timing->h_size || - vesa_mode_list[j].v_display != std_timing->v_size ) + + if (vesa_mode_list[j].h_display != std_timing->h_size + || vesa_mode_list[j].v_display != std_timing->v_size) continue; - + // take pixel_clock times 1000 because is is in kHz // further, take it times 1000 again, to get 1/1000 frames // as refresh rate - refresh_rate = (int64)vesa_mode_list[j].pixel_clock * 1000*1000 / - (vesa_mode_list[j].h_total * vesa_mode_list[j].v_total); - + refresh_rate = (int64)vesa_mode_list[j].pixel_clock * 1000*1000 + / (vesa_mode_list[j].h_total * vesa_mode_list[j].v_total); + // standard timing is in frames, so multiple by it to get 1/1000 frames // result is scaled by 100 to get difference in percentage; - cur_refresh_deviation = - (100 * (refresh_rate - std_timing->refresh * 1000)) / refresh_rate; - - if( cur_refresh_deviation < 0 ) + cur_refresh_deviation = (100 * (refresh_rate - std_timing->refresh + * 1000)) / refresh_rate; + + if (cur_refresh_deviation < 0) cur_refresh_deviation = -cur_refresh_deviation; - + // less then 1 percent difference is (hopefully) OK, // if there are multiple, we take best one // (if the screen is that picky, it should have defined an enhanced timing) - if( cur_refresh_deviation < 1 && - cur_refresh_deviation < best_refresh_deviation ) - { + if (cur_refresh_deviation < 1 + && cur_refresh_deviation < best_refresh_deviation) { best_fit = j; best_refresh_deviation = cur_refresh_deviation; } } - - if( best_fit < 0 ) { - SHOW_FLOW( 2, "Unsupported standard mode %dx%d@%dHz (not VESA)", - std_timing->h_size, std_timing->v_size, std_timing->refresh ); + + if (best_fit < 0) { + SHOW_FLOW(2, "Unsupported standard mode %dx%d@%dHz (not VESA)", + std_timing->h_size, std_timing->v_size, std_timing->refresh); continue; } - - if( std_timing->h_size > *max_hsize && std_timing->h_size > *max_vsize ) { + + if (std_timing->h_size > *max_hsize && std_timing->h_size > *max_vsize) { const display_timing *timing = &vesa_mode_list[best_fit]; - - SHOW_FLOW( 2, "Found DDC data for standard mode %dx%d", - (int)timing->h_display, (int)timing->v_display ); - + + SHOW_FLOW(2, "Found DDC data for standard mode %dx%d", + (int)timing->h_display, (int)timing->v_display); + *max_hsize = timing->h_display; *max_vsize = timing->h_display; - + // copy it to timing specification fp->panel_xres = timing->h_display; fp->h_blank = timing->h_total - timing->h_display; fp->h_over_plus = timing->h_sync_start - timing->h_display; fp->h_sync_width = timing->h_sync_end - timing->h_sync_start; - + fp->panel_yres = timing->v_display; fp->v_blank = timing->v_total - timing->v_display; fp->v_over_plus = timing->v_sync_start - timing->v_display; @@ -799,105 +806,113 @@ static void Radeon_FindFPTiming_StandardTiming( } } -// read edid data of flat panel and setup its timing accordingly -static status_t Radeon_StoreFPEDID( accelerator_info *ai, int port, const edid1_info *edid ) + +//! Read edid data of flat panel and setup its timing accordingly +static status_t +Radeon_StoreFPEDID(accelerator_info *ai, int port, const edid1_info *edid) { fp_info *fp = &ai->si->flatpanels[port]; uint32 max_hsize, max_vsize; - //SHOW_FLOW0( 2, "EDID data read from DVI port via DDC2:" ); - //edid_dump( edid ); + //SHOW_FLOW0(2, "EDID data read from DVI port via DDC2:"); + //edid_dump(edid); // find detailed timing with maximum resolution max_hsize = max_vsize = 0; - - Radeon_FindFPTiming_DetailedMonitorDesc( edid, fp, &max_hsize, &max_vsize ); + Radeon_FindFPTiming_DetailedMonitorDesc(edid, fp, &max_hsize, &max_vsize); - if( max_hsize == 0 ) { - SHOW_FLOW0( 2, "Timing is not explicitely defined in DDC - checking standard modes" ); - - Radeon_FindFPTiming_StandardTiming( - edid, fp, &max_hsize, &max_vsize ); - - if( max_hsize == 0 ) { - SHOW_FLOW0( 2, "Still found no valid native mode, disabling DVI" ); + if (max_hsize == 0) { + SHOW_FLOW0(2, "Timing is not explicitely defined in DDC - checking standard modes"); + + Radeon_FindFPTiming_StandardTiming(edid, fp, &max_hsize, &max_vsize); + if (max_hsize == 0) { + SHOW_FLOW0(2, "Still found no valid native mode, disabling DVI"); return B_ERROR; } } - - SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d", - fp->panel_xres, fp->h_blank, fp->h_over_plus, fp->h_sync_width ); - SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d", - fp->panel_yres, fp->v_blank, fp->v_over_plus, fp->v_sync_width ); - SHOW_INFO( 2, "pixel_clock=%d kHz", fp->dot_clock ); + + SHOW_INFO(2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d", + fp->panel_xres, fp->h_blank, fp->h_over_plus, fp->h_sync_width); + SHOW_INFO(2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d", + fp->panel_yres, fp->v_blank, fp->v_over_plus, fp->v_sync_width); + SHOW_INFO(2, "pixel_clock=%d kHz", fp->dot_clock); return B_OK; } -static void Radeon_ConnectorInfo( accelerator_info *ai, int port, disp_entity* ptr_entity ) + +static void +Radeon_ConnectorInfo(accelerator_info *ai, int port, disp_entity* ptr_entity) { const char* mon; - const char* ddc = ptr_entity->port_info[port].ddc_type == ddc_none_detected ? "None" : - ptr_entity->port_info[port].ddc_type == ddc_monid ? "Mon ID" : - ptr_entity->port_info[port].ddc_type == ddc_dvi ? "DVI DDC" : - ptr_entity->port_info[port].ddc_type == ddc_vga ? "VGA DDC" : - ptr_entity->port_info[port].ddc_type == ddc_crt2 ? "CRT2 DDC" : "Error"; - - const char* tmds = ptr_entity->port_info[port].tmds_type == tmds_unknown ? "None" : - ptr_entity->port_info[port].tmds_type == tmds_int ? "Internal" : - ptr_entity->port_info[port].tmds_type == tmds_ext ? "External" : "??? "; - - const char* dac = ptr_entity->port_info[port].dac_type == dac_unknown ? "Unknown" : - ptr_entity->port_info[port].dac_type == dac_primary ? "Primary" : - ptr_entity->port_info[port].dac_type == dac_tvdac ? "TV / External" : "Error"; - + const char* ddc = ptr_entity->port_info[port].ddc_type == ddc_none_detected + ? "None" : ptr_entity->port_info[port].ddc_type == ddc_monid + ? "Mon ID" : ptr_entity->port_info[port].ddc_type == ddc_dvi + ? "DVI DDC" : ptr_entity->port_info[port].ddc_type == ddc_vga + ? "VGA DDC" : ptr_entity->port_info[port].ddc_type == ddc_crt2 + ? "CRT2 DDC" : "Error"; + const char* tmds = ptr_entity->port_info[port].tmds_type == tmds_unknown + ? "None" : ptr_entity->port_info[port].tmds_type == tmds_int + ? "Internal" : ptr_entity->port_info[port].tmds_type == tmds_ext + ? "External" : "??? "; + const char* dac = ptr_entity->port_info[port].dac_type == dac_unknown + ? "Unknown" : ptr_entity->port_info[port].dac_type == dac_primary + ? "Primary" : ptr_entity->port_info[port].dac_type == dac_tvdac + ? "TV / External" : "Error"; const char* con; - if (ai->si->is_atombios) { - con = ptr_entity->port_info[port].connector_type == connector_none_atom ? "None" : - ptr_entity->port_info[port].connector_type == connector_vga_atom ? "VGA" : - ptr_entity->port_info[port].connector_type == connector_dvi_i_atom ? "DVI-I" : - ptr_entity->port_info[port].connector_type == connector_dvi_d_atom ? "DVI-D" : - ptr_entity->port_info[port].connector_type == connector_dvi_a_atom ? "DVI-A" : - ptr_entity->port_info[port].connector_type == connector_stv_atom ? "S-Video TV" : - ptr_entity->port_info[port].connector_type == connector_ctv_atom ? "Composite TV" : - ptr_entity->port_info[port].connector_type == connector_lvds_atom ? "LVDS" : - ptr_entity->port_info[port].connector_type == connector_digital_atom ? "Digital" : - ptr_entity->port_info[port].connector_type == connector_unsupported_atom ? "N/A " : "Err "; - } else { - con = ptr_entity->port_info[port].connector_type == connector_none ? "None" : - ptr_entity->port_info[port].connector_type == connector_crt ? "VGA" : - ptr_entity->port_info[port].connector_type == connector_dvi_i ? "DVI-I" : - ptr_entity->port_info[port].connector_type == connector_dvi_d ? "DVI-D" : - ptr_entity->port_info[port].connector_type == connector_proprietary ? "Proprietary" : - ptr_entity->port_info[port].connector_type == connector_stv ? "S-Video TV" : - ptr_entity->port_info[port].connector_type == connector_ctv ? "Composite TV" : - ptr_entity->port_info[port].connector_type == connector_unsupported ? "N/A" : "Err"; - } - - mon = ptr_entity->port_info[port].mon_type == mt_unknown ? "???" : - ptr_entity->port_info[port].mon_type == mt_none ? "None" : - ptr_entity->port_info[port].mon_type == mt_crt ? "CRT " : - ptr_entity->port_info[port].mon_type == mt_lcd ? "LCD " : - ptr_entity->port_info[port].mon_type == mt_dfp ? "DVI " : - ptr_entity->port_info[port].mon_type == mt_ctv ? "Composite TV" : - ptr_entity->port_info[port].mon_type == mt_stv ? "S-Video TV" : "Err ?"; - SHOW_INFO( 2 , "Port %d:- \nMonitor: %s\nConn Type: %s\nDDC Port: %s\nTMDS Type: %s\nDAC Type: %s", - port, mon, con, ddc, tmds, dac); + if (ai->si->is_atombios) { + con = ptr_entity->port_info[port].connector_type == connector_none_atom + ? "None" : ptr_entity->port_info[port].connector_type == connector_vga_atom + ? "VGA" : ptr_entity->port_info[port].connector_type == connector_dvi_i_atom + ? "DVI-I" : ptr_entity->port_info[port].connector_type == connector_dvi_d_atom + ? "DVI-D" : ptr_entity->port_info[port].connector_type == connector_dvi_a_atom + ? "DVI-A" : ptr_entity->port_info[port].connector_type == connector_stv_atom + ? "S-Video TV" : ptr_entity->port_info[port].connector_type == connector_ctv_atom + ? "Composite TV" : ptr_entity->port_info[port].connector_type == connector_lvds_atom + ? "LVDS" : ptr_entity->port_info[port].connector_type == connector_digital_atom + ? "Digital" : ptr_entity->port_info[port].connector_type == connector_unsupported_atom + ? "N/A " : "Err "; + } else { + con = ptr_entity->port_info[port].connector_type == connector_none + ? "None" : ptr_entity->port_info[port].connector_type == connector_crt + ? "VGA" : ptr_entity->port_info[port].connector_type == connector_dvi_i + ? "DVI-I" : ptr_entity->port_info[port].connector_type == connector_dvi_d + ? "DVI-D" : ptr_entity->port_info[port].connector_type == connector_proprietary + ? "Proprietary" : ptr_entity->port_info[port].connector_type == connector_stv + ? "S-Video TV" : ptr_entity->port_info[port].connector_type == connector_ctv + ? "Composite TV" : ptr_entity->port_info[port].connector_type == connector_unsupported + ? "N/A" : "Err"; + } + + mon = ptr_entity->port_info[port].mon_type == mt_unknown ? "???" + : ptr_entity->port_info[port].mon_type == mt_none ? "None" + : ptr_entity->port_info[port].mon_type == mt_crt ? "CRT " + : ptr_entity->port_info[port].mon_type == mt_lcd ? "LCD " + : ptr_entity->port_info[port].mon_type == mt_dfp ? "DVI " + : ptr_entity->port_info[port].mon_type == mt_ctv ? "Composite TV" + : ptr_entity->port_info[port].mon_type == mt_stv ? "S-Video TV" + : "Err ?"; + + SHOW_INFO(2, "Port %d:- \nMonitor: %s\nConn Type: %s\nDDC Port: %s\nTMDS Type: %s\nDAC Type: %s", + port, mon, con, ddc, tmds, dac); } -// detect connected displays devices -// whished_num_heads - how many heads the requested display mode needs -void Radeon_DetectDisplays( accelerator_info *ai ) +/*! + Detect connected displays devices + whished_num_heads - how many heads the requested display mode needs +*/ +void +Radeon_DetectDisplays(accelerator_info *ai) { shared_info *si = ai->si; - + disp_entity* routes = &si->routing; display_device_e displays = 0; display_device_e controlled_displays = ai->vc->controlled_displays; int i; - + uint32 edid_regs[] = { 0, RADEON_GPIO_MONID, @@ -905,116 +920,111 @@ void Radeon_DetectDisplays( accelerator_info *ai ) RADEON_GPIO_VGA_DDC, RADEON_GPIO_CRT2_DDC }; - + // lock hardware so noone bothers us - Radeon_WaitForIdle( ai, true ); - + Radeon_WaitForIdle(ai, true); + // alwats make TMDS_INT port first if (routes->port_info[1].tmds_type == tmds_int) { - radeon_connector swap_entity; swap_entity = routes->port_info[0]; routes->port_info[0] = routes->port_info[1]; routes->port_info[1] = swap_entity; - SHOW_FLOW0( 2, "Swapping TMDS_INT to first port"); - } - else if ( routes->port_info[0].tmds_type != tmds_int && - routes->port_info[1].tmds_type != tmds_int ) { - + SHOW_FLOW0(2, "Swapping TMDS_INT to first port"); + } else if (routes->port_info[0].tmds_type != tmds_int + && routes->port_info[1].tmds_type != tmds_int) { // no TMDS_INT port, make primary DAC port first // On my Inspiron 8600 both internal and external ports are // marked DAC_PRIMARY in BIOS. So be extra careful - only // swap when the first port is not DAC_PRIMARY - if ( routes->port_info[1].dac_type == dac_primary && - routes->port_info[0].dac_type != dac_primary ) { - + if (routes->port_info[1].dac_type == dac_primary + && routes->port_info[0].dac_type != dac_primary) { radeon_connector swap_entity; swap_entity = routes->port_info[0]; routes->port_info[0] = routes->port_info[1]; routes->port_info[1] = swap_entity; - SHOW_FLOW0( 2, "Swapping Primary Dac to front"); + SHOW_FLOW0(2, "Swapping Primary Dac to front"); } } - - if ( si->asic == rt_rs300 ) // RS300 only has single Dac of TV type - { - // For RS300/RS350/RS400 chips, there is no primary DAC. Force VGA port to use TVDAC - if ( routes->port_info[0].connector_type == connector_crt ) { + + if (si->asic == rt_rs300) { + // RS300 only has single Dac of TV type + // For RS300/RS350/RS400 chips, there is no primary DAC. + // Force VGA port to use TVDAC + if (routes->port_info[0].connector_type == connector_crt) { routes->port_info[0].dac_type = dac_tvdac; routes->port_info[1].dac_type = dac_primary; } else { routes->port_info[1].dac_type = dac_primary; routes->port_info[0].dac_type = dac_tvdac; } - } else if ( si->num_crtc == 1 ) { - + } else if (si->num_crtc == 1) { routes->port_info[0].dac_type = dac_primary; } - // use DDC to detect monitors - if we can read DDC, there must be a monitor - for ( i = 0; i < 2; i++ ) - { + // use DDC to detect monitors - if we can read DDC, there must be + // a monitor + for (i = 0; i < 2; i++) { //TODO could skip edid reading instead if we already have it, but what //if monitors have been hot swapped? Also rely on edid for DVI-D detection - //if (routes->port_info[i].mon_type != mt_unknown ) { - // SHOW_FLOW0( 2, "known type, skpping detection" ); + //if (routes->port_info[i].mon_type != mt_unknown) { + // SHOW_FLOW0(2, "known type, skpping detection"); // continue; //} - - memset( &routes->port_info[i].edid , 0, sizeof(edid1_info) ); - switch ( routes->port_info[i].ddc_type ) { + memset(&routes->port_info[i].edid , 0, sizeof(edid1_info)); + switch (routes->port_info[i].ddc_type) { case ddc_monid: case ddc_dvi: case ddc_vga: case ddc_crt2: - if ( Radeon_ReadEDID( ai, edid_regs[routes->port_info[i].ddc_type], &routes->port_info[i].edid )) - { + if (Radeon_ReadEDID(ai, + edid_regs[routes->port_info[i].ddc_type], + &routes->port_info[i].edid)) { routes->port_info[i].edid_valid = true; - SHOW_FLOW( 2, "Edid Data for CRTC %d on line %d", i, routes->port_info[i].ddc_type ); - edid_dump ( &routes->port_info[i].edid ); + SHOW_FLOW(2, "Edid Data for CRTC %d on line %d", i, routes->port_info[i].ddc_type); + edid_dump(&routes->port_info[i].edid); } else { routes->port_info[i].mon_type = mt_none; } - break; + default: - SHOW_FLOW( 2, "No Edid Pin Assigned to CRTC %d ", i ); + SHOW_FLOW(2, "No Edid Pin Assigned to CRTC %d ", i); routes->port_info[i].mon_type = mt_none; } - - if ( routes->port_info[i].edid_valid ) { - - if( routes->port_info[i].edid.display.input_type == 1 ) { - SHOW_FLOW0( 2, "Must be a DVI monitor" ); - + + if (routes->port_info[i].edid_valid) { + if (routes->port_info[i].edid.display.input_type == 1) { + SHOW_FLOW0(2, "Must be a DVI monitor"); + // Note some laptops have a DVI output that uses internal TMDS, // when its DVI is enabled by hotkey, LVDS panel is not used. // In this case, the laptop is configured as DVI+VGA as a normal // desktop card. // Also for laptop, when X starts with lid closed (no DVI connection) // both LDVS and TMDS are disable, we still need to treat it as a LVDS panel. - if ( routes->port_info[i].tmds_type == tmds_ext ){ + if (routes->port_info[i].tmds_type == tmds_ext){ // store info about DVI-connected flat-panel - if( Radeon_StoreFPEDID( ai, i, &routes->port_info[i].edid ) == B_OK ) { - SHOW_INFO0( 2, "Found Ext Laptop DVI" ); + if (Radeon_StoreFPEDID(ai, i, &routes->port_info[i].edid) == B_OK) { + SHOW_INFO0(2, "Found Ext Laptop DVI"); routes->port_info[i].mon_type = mt_dfp; ai->si->flatpanels[i].is_fp2 = true; displays |= dd_dvi_ext; } else { - SHOW_ERROR0( 2, "Disabled Ext DVI - invalid EDID" ); + SHOW_ERROR0(2, "Disabled Ext DVI - invalid EDID"); } } else { - if( INREG( ai->regs, RADEON_FP_GEN_CNTL) & (1 << 7) || ( !si->is_mobility ) ) { + if (INREG(ai->regs, RADEON_FP_GEN_CNTL) & (1 << 7) || (!si->is_mobility)) { // store info about DVI-connected flat-panel - if( Radeon_StoreFPEDID( ai, i, &routes->port_info[i].edid ) == B_OK ) { - SHOW_INFO0( 2, "Found DVI" ); + if (Radeon_StoreFPEDID(ai, i, &routes->port_info[i].edid) == B_OK) { + SHOW_INFO0(2, "Found DVI"); routes->port_info[i].mon_type = mt_dfp; displays |= dd_dvi; } else { - SHOW_ERROR0( 2, "Disabled DVI - invalid EDID" ); + SHOW_ERROR0(2, "Disabled DVI - invalid EDID"); } } else { - SHOW_INFO0( 2, "Laptop Panel Found" ); + SHOW_INFO0(2, "Laptop Panel Found"); routes->port_info[i].mon_type = mt_lcd; displays |= dd_lvds; } @@ -1025,97 +1035,91 @@ void Radeon_DetectDisplays( accelerator_info *ai ) // I'm not sure about Radeons with one CRTC - do they have DVI-I or DVI-D? // anyway - if there are two CRTC, analog portion must be connected // to TV-DAC; if there is one CRTC, it must be the normal VGA-DAC - if( si->num_crtc > 1 ) { - SHOW_FLOW0( 2, "Must be an analog monitor on DVI port" ); + if (si->num_crtc > 1) { + SHOW_FLOW0(2, "Must be an analog monitor on DVI port"); routes->port_info[i].mon_type = mt_crt; displays |= dd_tv_crt; } else { - SHOW_FLOW0( 2, "Seems to be a CRT on VGA port!?" ); + SHOW_FLOW0(2, "Seems to be a CRT on VGA port!?"); routes->port_info[i].mon_type = mt_crt; displays |= dd_crt; } } } } - - - if ( !routes->port_info[0].edid_valid ) { - SHOW_INFO0( 2, "Searching port 0" ); - if ( si->is_mobility && (INREG( ai->regs, RADEON_BIOS_4_SCRATCH) & 4)) { - SHOW_INFO0( 2, "Found Laptop Panel" ); + + if (!routes->port_info[0].edid_valid) { + SHOW_INFO0(2, "Searching port 0"); + if (si->is_mobility && (INREG(ai->regs, RADEON_BIOS_4_SCRATCH) & 4)) { + SHOW_INFO0(2, "Found Laptop Panel"); routes->port_info[0].mon_type = mt_lcd; displays |= dd_lvds; } } - - if ( !routes->port_info[1].edid_valid ) { - - if ( si->is_mobility && (INREG( ai->regs, RADEON_FP2_GEN_CNTL) & RADEON_FP2_FPON)) { - SHOW_INFO0( 2, "Found Ext Laptop DVI" ); + + if (!routes->port_info[1].edid_valid) { + if (si->is_mobility && (INREG(ai->regs, RADEON_FP2_GEN_CNTL) & RADEON_FP2_FPON)) { + SHOW_INFO0(2, "Found Ext Laptop DVI"); routes->port_info[1].mon_type = mt_dfp; displays |= dd_dvi_ext; } } - - if ( routes->port_info[0].mon_type == mt_none ) - { - if ( routes->port_info[1].mon_type == mt_none ) { + + if (routes->port_info[0].mon_type == mt_none) { + if (routes->port_info[1].mon_type == mt_none) { routes->port_info[0].mon_type = mt_crt; } else { radeon_connector swap_entity; swap_entity = routes->port_info[0]; routes->port_info[0] = routes->port_info[1]; routes->port_info[1] = swap_entity; - SHOW_ERROR0( 2, "swapping active port 2 to free port 1" ); + SHOW_ERROR0(2, "swapping active port 2 to free port 1"); } } - + routes->reversed_DAC = false; - if ( routes->port_info[1].dac_type == dac_tvdac ) { - SHOW_ERROR0( 2, "Reversed dac detected (not impl. yet)" ); + if (routes->port_info[1].dac_type == dac_tvdac) { + SHOW_ERROR0(2, "Reversed dac detected (not impl. yet)"); routes->reversed_DAC = true; } - - - + // we may have overseen monitors if they don't support DDC or // have broken DDC data (like mine); // time to do a physical wire test; this test is more reliable, but it // leads to distortions on screen, which is not very nice to look at - + // for DVI, there is no mercy if no DDC data is there - we wouldn't // even know the native resolution of the panel! // all versions have a standard VGA port - if( (displays & dd_crt) == 0 && - (controlled_displays & dd_crt) != 0 && - Radeon_DetectCRT( ai )) + if ((displays & dd_crt) == 0 && (controlled_displays & dd_crt) != 0 + && Radeon_DetectCRT(ai)) displays |= dd_crt; - + // check VGA signal routed to DVI port // (the detection code checks whether there is hardware for that) - if( (displays & dd_tv_crt) == 0 && - (controlled_displays & dd_tv_crt) != 0 && - Radeon_DetectTVCRT( ai )) + if ((displays & dd_tv_crt) == 0 + && (controlled_displays & dd_tv_crt) != 0 + && Radeon_DetectTVCRT(ai)) displays |= dd_tv_crt; // check TV-out connector - if( (controlled_displays && (dd_ctv | dd_stv)) != 0 ) - displays |= Radeon_DetectTV( ai, (displays & dd_tv_crt) != 0 ); + if ((controlled_displays && (dd_ctv | dd_stv)) != 0) + displays |= Radeon_DetectTV(ai, (displays & dd_tv_crt) != 0); + + SHOW_INFO(0, "Detected monitors: 0x%x", displays); - SHOW_INFO( 0, "Detected monitors: 0x%x", displays ); - displays &= controlled_displays; - + // if no monitor found, we define to have a CRT connected to CRT-DAC - if( displays == 0 ) + if (displays == 0) displays = dd_crt; - Radeon_ConnectorInfo( ai, 0, routes); - Radeon_ConnectorInfo( ai, 1, routes); - + Radeon_ConnectorInfo(ai, 0, routes); + Radeon_ConnectorInfo(ai, 1, routes); + ai->vc->connected_displays = displays; - - RELEASE_BEN( si->cp.lock ); + + RELEASE_BEN(si->cp.lock); }