mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 05:29:43 +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!");
|
LOG_F(ERROR, "Couldn't register AMIC registers!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register I/O devices
|
||||||
this->scsi = std::unique_ptr<Ncr53C94> (new Ncr53C94());
|
this->scsi = std::unique_ptr<Ncr53C94> (new Ncr53C94());
|
||||||
this->escc = std::unique_ptr<EsccController> (new EsccController());
|
this->escc = std::unique_ptr<EsccController> (new EsccController());
|
||||||
this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID));
|
this->mace = std::unique_ptr<MaceController> (new MaceController(MACE_ID));
|
||||||
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda());
|
this->viacuda = std::unique_ptr<ViaCuda> (new ViaCuda());
|
||||||
|
|
||||||
|
// initialize sound HW
|
||||||
this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma());
|
this->snd_out_dma = std::unique_ptr<AmicSndOutDma> (new AmicSndOutDma());
|
||||||
this->awacs = std::unique_ptr<AwacDevicePdm> (new AwacDevicePdm());
|
this->awacs = std::unique_ptr<AwacDevicePdm> (new AwacDevicePdm());
|
||||||
this->awacs->set_dma_out(this->snd_out_dma.get());
|
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) {
|
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) {
|
switch(offset) {
|
||||||
|
case AMICReg::Monitor_Id:
|
||||||
|
return this->mon_id;
|
||||||
case AMICReg::Diag_Reg:
|
case AMICReg::Diag_Reg:
|
||||||
return 0xFFU; // this value allows the machine to boot normally
|
return 0xFFU; // this value allows the machine to boot normally
|
||||||
case AMICReg::SCSI_DMA_Ctrl:
|
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:
|
case AMICReg::VIA2_IER:
|
||||||
LOG_F(INFO, "AMIC VIA2 Interrupt Enable Register updated, val=%x", value);
|
LOG_F(INFO, "AMIC VIA2 Interrupt Enable Register updated, val=%x", value);
|
||||||
break;
|
break;
|
||||||
case AMICReg::Video_Mode_Reg:
|
case AMICReg::Video_Mode:
|
||||||
LOG_F(INFO, "AMIC Video Mode Register set to %x", value);
|
LOG_F(INFO, "AMIC Video Mode Register set to %x", value);
|
||||||
break;
|
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:
|
case AMICReg::Int_Ctrl:
|
||||||
LOG_F(INFO, "AMIC Interrupt Control Register set to %X", value);
|
LOG_F(INFO, "AMIC Interrupt Control Register set to %X", value);
|
||||||
break;
|
break;
|
||||||
|
@ -30,6 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include <devices/ethernet/mace.h>
|
#include <devices/ethernet/mace.h>
|
||||||
#include <devices/serial/escc.h>
|
#include <devices/serial/escc.h>
|
||||||
#include <devices/sound/awacs.h>
|
#include <devices/sound/awacs.h>
|
||||||
|
#include <devices/video/displayid.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -98,7 +99,9 @@ enum AMICReg : uint32_t {
|
|||||||
VIA2_IER = 0x26013,
|
VIA2_IER = 0x26013,
|
||||||
|
|
||||||
// Video control registers
|
// Video control registers
|
||||||
Video_Mode_Reg = 0x28000,
|
Video_Mode = 0x28000,
|
||||||
|
Color_Ctrl = 0x28001,
|
||||||
|
Monitor_Id = 0x28002,
|
||||||
|
|
||||||
Int_Ctrl = 0x2A000,
|
Int_Ctrl = 0x2A000,
|
||||||
|
|
||||||
@ -152,6 +155,10 @@ private:
|
|||||||
std::unique_ptr<AwacDevicePdm> awacs;
|
std::unique_ptr<AwacDevicePdm> awacs;
|
||||||
|
|
||||||
std::unique_ptr<AmicSndOutDma> snd_out_dma;
|
std::unique_ptr<AmicSndOutDma> snd_out_dma;
|
||||||
|
|
||||||
|
// on-board video
|
||||||
|
std::unique_ptr<DisplayID> disp_id;
|
||||||
|
uint8_t mon_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AMIC_H
|
#endif // AMIC_H
|
||||||
|
@ -175,9 +175,9 @@ uint32_t ATIRage::read_reg(uint32_t offset, uint32_t size) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size) {
|
void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size)
|
||||||
uint32_t gpio_val;
|
{
|
||||||
uint16_t gpio_dir;
|
uint8_t gpio_levels, gpio_dirs;
|
||||||
|
|
||||||
// writing internal registers with necessary endian conversion
|
// writing internal registers with necessary endian conversion
|
||||||
write_mem(&this->mm_regs[offset], value, size);
|
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;
|
break;
|
||||||
case ATI_GP_IO:
|
case ATI_GP_IO:
|
||||||
if (offset < (ATI_GP_IO + 2)) {
|
if (offset < (ATI_GP_IO + 2)) {
|
||||||
gpio_val = READ_DWORD_LE_A(&this->mm_regs[ATI_GP_IO]);
|
gpio_levels = this->mm_regs[ATI_GP_IO+1];
|
||||||
gpio_dir = (gpio_val >> 16) & 0x3FFF;
|
gpio_levels = ((gpio_levels & 0x30) >> 3) | (gpio_levels & 1);
|
||||||
WRITE_WORD_LE_A(
|
gpio_dirs = this->mm_regs[ATI_GP_IO+3];
|
||||||
&this->mm_regs[ATI_GP_IO],
|
gpio_dirs = ((gpio_dirs & 0x30) >> 3) | (gpio_dirs & 1);
|
||||||
this->disp_id->read_monitor_sense(gpio_val, gpio_dir));
|
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;
|
break;
|
||||||
case ATI_CLOCK_CNTL:
|
case ATI_CLOCK_CNTL:
|
||||||
|
@ -37,72 +37,58 @@ DisplayID::DisplayID(Disp_Id_Kind id_kind)
|
|||||||
this->prev_state = I2CState::STOP;
|
this->prev_state = I2CState::STOP;
|
||||||
this->last_sda = 1;
|
this->last_sda = 1;
|
||||||
this->last_scl = 1;
|
this->last_scl = 1;
|
||||||
this->data_out = 0x3000;
|
|
||||||
this->data_ptr = 0;
|
this->data_ptr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t DisplayID::read_monitor_sense(uint8_t levels, uint8_t dirs)
|
||||||
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 scl, sda;
|
uint8_t scl, sda;
|
||||||
uint16_t result;
|
uint16_t result;
|
||||||
|
|
||||||
if ((dirs & 0x3100) == 0 && (data & 0x3100) == 0x3100) {
|
|
||||||
LOG_F(WARNING, "DisplayID: Monitor sense lines tristated!");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(this->id_kind) {
|
switch(this->id_kind) {
|
||||||
case Disp_Id_Kind::DDC2B:
|
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" */
|
In the input mode, GPIO pins will be read "high" */
|
||||||
scl = (dirs & 0x1000) ? !!(data & 0x1000) : 1;
|
scl = (dirs & 2) ? !!(levels & 2) : 1;
|
||||||
sda = (dirs & 0x2000) ? !!(data & 0x2000) : 1;
|
sda = (dirs & 4) ? !!(levels & 4) : 1;
|
||||||
|
|
||||||
return update_ddc_i2c(sda, scl);
|
return update_ddc_i2c(sda, scl);
|
||||||
case Disp_Id_Kind::AppleSense:
|
case Disp_Id_Kind::AppleSense:
|
||||||
switch (dirs & 0x3100) {
|
switch ((dirs << 3) | levels) {
|
||||||
case 0:
|
case 0x23: // Sense line 2 pulled low
|
||||||
result = ((this->std_sense_code & 6) << 11) | ((this->std_sense_code & 1) << 8);
|
return ((this->ext_sense_code >> 4) & 3);
|
||||||
break;
|
case 0x15: // Sense line 1 pulled low
|
||||||
case 0x2000: /* Sense line 2 is low */
|
return (((this->ext_sense_code & 8) >> 1) |
|
||||||
result = ((this->ext_sense_code & 0x20) << 7) | ((this->ext_sense_code & 0x10) << 4);
|
((this->ext_sense_code & 4) >> 2));
|
||||||
break;
|
case 0xE: // Sense line 0 pulled low
|
||||||
case 0x1000: /* Sense line 1 is low */
|
return ((this->ext_sense_code & 3) << 1);
|
||||||
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;
|
|
||||||
default:
|
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;
|
bool clk_gone_high = false;
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ public:
|
|||||||
DisplayID(Disp_Id_Kind id_kind);
|
DisplayID(Disp_Id_Kind id_kind);
|
||||||
~DisplayID() = default;
|
~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:
|
protected:
|
||||||
uint16_t set_result(uint8_t sda, uint8_t scl);
|
uint8_t set_result(uint8_t sda, uint8_t scl);
|
||||||
uint16_t update_ddc_i2c(uint8_t sda, uint8_t scl);
|
uint8_t update_ddc_i2c(uint8_t sda, uint8_t scl);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Disp_Id_Kind id_kind;
|
Disp_Id_Kind id_kind;
|
||||||
@ -75,7 +75,6 @@ private:
|
|||||||
uint8_t prev_state;
|
uint8_t prev_state;
|
||||||
uint8_t last_sda;
|
uint8_t last_sda;
|
||||||
uint8_t last_scl;
|
uint8_t last_scl;
|
||||||
uint16_t data_out;
|
|
||||||
int bit_count; /* number of bits processed so far */
|
int bit_count; /* number of bits processed so far */
|
||||||
uint8_t byte; /* byte value being currently transferred */
|
uint8_t byte; /* byte value being currently transferred */
|
||||||
uint8_t dev_addr; /* current device address */
|
uint8_t dev_addr; /* current device address */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user