Rewrite DisplayID to work with AMIC & ATI Rage.

This commit is contained in:
Maxim Poliakovski 2021-11-30 01:26:32 +01:00
parent c2991149fd
commit 609fb43726
5 changed files with 75 additions and 61 deletions

View File

@ -50,14 +50,19 @@ AMIC::AMIC()
LOG_F(ERROR, "Couldn't register AMIC registers!");
}
// register I/O devices
this->scsi = std::unique_ptr<Ncr53C94> (new Ncr53C94());
this->escc = std::unique_ptr<EsccController> (new EsccController());
this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID));
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda());
// initialize sound HW
this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma());
this->awacs = std::unique_ptr<AwacDevicePdm> (new AwacDevicePdm());
this->awacs->set_dma_out(this->snd_out_dma.get());
// initialize on-board video
this->disp_id = std::unique_ptr<DisplayID> (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;

View File

@ -30,6 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/ethernet/mace.h>
#include <devices/serial/escc.h>
#include <devices/sound/awacs.h>
#include <devices/video/displayid.h>
#include <cinttypes>
#include <memory>
@ -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<AwacDevicePdm> awacs;
std::unique_ptr<AmicSndOutDma> snd_out_dma;
// on-board video
std::unique_ptr<DisplayID> disp_id;
uint8_t mon_id;
};
#endif // AMIC_H

View File

@ -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:

View File

@ -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;

View File

@ -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 */