From 609fb437260e86a07c0693bb55d557ab437d9e9a Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Tue, 30 Nov 2021 01:26:32 +0100 Subject: [PATCH] Rewrite DisplayID to work with AMIC & ATI Rage. --- devices/ioctrl/amic.cpp | 23 ++++++++++- devices/ioctrl/amic.h | 9 ++++- devices/video/atirage.cpp | 17 ++++---- devices/video/displayid.cpp | 80 +++++++++++++++---------------------- devices/video/displayid.h | 7 ++-- 5 files changed, 75 insertions(+), 61 deletions(-) diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp index e89fc7b..2660ebb 100644 --- a/devices/ioctrl/amic.cpp +++ b/devices/ioctrl/amic.cpp @@ -50,14 +50,19 @@ AMIC::AMIC() LOG_F(ERROR, "Couldn't register AMIC registers!"); } + // register I/O devices this->scsi = std::unique_ptr (new Ncr53C94()); this->escc = std::unique_ptr (new EsccController()); this->mace = std::unique_ptr (new MaceController(MACE_ID)); this->viacuda = std::unique_ptr (new ViaCuda()); + // initialize sound HW this->snd_out_dma = std::unique_ptr (new AmicSndOutDma()); this->awacs = std::unique_ptr (new AwacDevicePdm()); this->awacs->set_dma_out(this->snd_out_dma.get()); + + // initialize on-board video + this->disp_id = std::unique_ptr (new DisplayID(Disp_Id_Kind::AppleSense)); } bool AMIC::supports_type(HWCompType type) { @@ -108,6 +113,8 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size) } switch(offset) { + case AMICReg::Monitor_Id: + return this->mon_id; case AMICReg::Diag_Reg: return 0xFFU; // this value allows the machine to boot normally case AMICReg::SCSI_DMA_Ctrl: @@ -193,9 +200,23 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) case AMICReg::VIA2_IER: LOG_F(INFO, "AMIC VIA2 Interrupt Enable Register updated, val=%x", value); break; - case AMICReg::Video_Mode_Reg: + case AMICReg::Video_Mode: LOG_F(INFO, "AMIC Video Mode Register set to %x", value); break; + case AMICReg::Monitor_Id: { + // extract and convert pin directions (0 - input, 1 - output) + uint8_t dirs = ~value & 7; + if (!dirs && !(value & 8)) { + LOG_F(INFO, "AMIC: Monitor sense lines tristated"); + } + // propagate bit 3 to all pins configured as output + // set levels of all intput pins to "1" + uint8_t levels = (7 ^ dirs) | (((value & 8) ? 7 : 0) & dirs); + // read monitor sense lines and store the result in the bits 4-6 + this->mon_id = (this->mon_id & 0xF) | + (this->disp_id->read_monitor_sense(levels, dirs) << 4); + } + break; case AMICReg::Int_Ctrl: LOG_F(INFO, "AMIC Interrupt Control Register set to %X", value); break; diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h index f895a7c..711929e 100644 --- a/devices/ioctrl/amic.h +++ b/devices/ioctrl/amic.h @@ -30,6 +30,7 @@ along with this program. If not, see . #include #include #include +#include #include #include @@ -98,7 +99,9 @@ enum AMICReg : uint32_t { VIA2_IER = 0x26013, // Video control registers - Video_Mode_Reg = 0x28000, + Video_Mode = 0x28000, + Color_Ctrl = 0x28001, + Monitor_Id = 0x28002, Int_Ctrl = 0x2A000, @@ -152,6 +155,10 @@ private: std::unique_ptr awacs; std::unique_ptr snd_out_dma; + + // on-board video + std::unique_ptr disp_id; + uint8_t mon_id; }; #endif // AMIC_H diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index a9c18a2..5d4f723 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -175,9 +175,9 @@ uint32_t ATIRage::read_reg(uint32_t offset, uint32_t size) { return res; } -void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size) { - uint32_t gpio_val; - uint16_t gpio_dir; +void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size) +{ + uint8_t gpio_levels, gpio_dirs; // writing internal registers with necessary endian conversion write_mem(&this->mm_regs[offset], value, size); @@ -207,11 +207,12 @@ void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size) { break; case ATI_GP_IO: if (offset < (ATI_GP_IO + 2)) { - gpio_val = READ_DWORD_LE_A(&this->mm_regs[ATI_GP_IO]); - gpio_dir = (gpio_val >> 16) & 0x3FFF; - WRITE_WORD_LE_A( - &this->mm_regs[ATI_GP_IO], - this->disp_id->read_monitor_sense(gpio_val, gpio_dir)); + gpio_levels = this->mm_regs[ATI_GP_IO+1]; + gpio_levels = ((gpio_levels & 0x30) >> 3) | (gpio_levels & 1); + gpio_dirs = this->mm_regs[ATI_GP_IO+3]; + gpio_dirs = ((gpio_dirs & 0x30) >> 3) | (gpio_dirs & 1); + gpio_levels = this->disp_id->read_monitor_sense(gpio_levels, gpio_dirs); + this->mm_regs[ATI_GP_IO+1] = ((gpio_levels & 6) << 3) | (gpio_levels & 1); } break; case ATI_CLOCK_CNTL: diff --git a/devices/video/displayid.cpp b/devices/video/displayid.cpp index 3686c53..0f94504 100644 --- a/devices/video/displayid.cpp +++ b/devices/video/displayid.cpp @@ -37,72 +37,58 @@ DisplayID::DisplayID(Disp_Id_Kind id_kind) this->prev_state = I2CState::STOP; this->last_sda = 1; this->last_scl = 1; - this->data_out = 0x3000; this->data_ptr = 0; } - -uint16_t DisplayID::set_result(uint8_t sda, uint8_t scl) -{ - this->last_sda = sda; - this->last_scl = scl; - - if (scl) { - this->data_out |= 0x1000; - } else { - this->data_out &= ~0x1000U; - } - - if (sda) { - this->data_out |= 0x2000; - } else { - this->data_out &= ~0x2000U; - } - - return this->data_out; -} - - -uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs) +uint8_t DisplayID::read_monitor_sense(uint8_t levels, uint8_t dirs) { uint8_t scl, sda; uint16_t result; - if ((dirs & 0x3100) == 0 && (data & 0x3100) == 0x3100) { - LOG_F(WARNING, "DisplayID: Monitor sense lines tristated!"); - } - switch(this->id_kind) { case Disp_Id_Kind::DDC2B: - /* if GPIO pins are in the output mode, pick up their values + /* If GPIO pins are in the output mode, pick up their levels. In the input mode, GPIO pins will be read "high" */ - scl = (dirs & 0x1000) ? !!(data & 0x1000) : 1; - sda = (dirs & 0x2000) ? !!(data & 0x2000) : 1; + scl = (dirs & 2) ? !!(levels & 2) : 1; + sda = (dirs & 4) ? !!(levels & 4) : 1; return update_ddc_i2c(sda, scl); case Disp_Id_Kind::AppleSense: - switch (dirs & 0x3100) { - case 0: - result = ((this->std_sense_code & 6) << 11) | ((this->std_sense_code & 1) << 8); - break; - case 0x2000: /* Sense line 2 is low */ - result = ((this->ext_sense_code & 0x20) << 7) | ((this->ext_sense_code & 0x10) << 4); - break; - case 0x1000: /* Sense line 1 is low */ - result = ((this->ext_sense_code & 8) << 10) | ((this->ext_sense_code & 4) << 6); - break; - case 0x100: /* Sense line 0 is low */ - result = ((this->ext_sense_code & 2) << 12) | ((this->ext_sense_code & 1) << 12); - break; + switch ((dirs << 3) | levels) { + case 0x23: // Sense line 2 pulled low + return ((this->ext_sense_code >> 4) & 3); + case 0x15: // Sense line 1 pulled low + return (((this->ext_sense_code & 8) >> 1) | + ((this->ext_sense_code & 4) >> 2)); + case 0xE: // Sense line 0 pulled low + return ((this->ext_sense_code & 3) << 1); default: - result = 0x3100U; + return this->std_sense_code; } - return result; } } +uint8_t DisplayID::set_result(uint8_t sda, uint8_t scl) +{ + uint16_t data_out; -uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl) + this->last_sda = sda; + this->last_scl = scl; + + data_out = 0; + + if (scl) { + data_out |= 2; + } + + if (sda) { + data_out |= 4; + } + + return data_out; +} + +uint8_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl) { bool clk_gone_high = false; diff --git a/devices/video/displayid.h b/devices/video/displayid.h index 6fbf317..c74f1bd 100644 --- a/devices/video/displayid.h +++ b/devices/video/displayid.h @@ -58,11 +58,11 @@ public: DisplayID(Disp_Id_Kind id_kind); ~DisplayID() = default; - uint16_t read_monitor_sense(uint16_t data, uint16_t dirs); + uint8_t read_monitor_sense(uint8_t levels, uint8_t dirs); protected: - uint16_t set_result(uint8_t sda, uint8_t scl); - uint16_t update_ddc_i2c(uint8_t sda, uint8_t scl); + uint8_t set_result(uint8_t sda, uint8_t scl); + uint8_t update_ddc_i2c(uint8_t sda, uint8_t scl); private: Disp_Id_Kind id_kind; @@ -75,7 +75,6 @@ private: uint8_t prev_state; uint8_t last_sda; uint8_t last_scl; - uint16_t data_out; int bit_count; /* number of bits processed so far */ uint8_t byte; /* byte value being currently transferred */ uint8_t dev_addr; /* current device address */