mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 06:29:38 +00:00
Rewrite DisplayID to work with AMIC & ATI Rage.
This commit is contained in:
parent
c2991149fd
commit
609fb43726
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user