mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-24 12:30:05 +00:00
VIA-CUDA: hackish support for SPD.
This commit is contained in:
parent
cf3f8b6db1
commit
01c38b7348
@ -3,6 +3,11 @@
|
||||
#include "macio.h"
|
||||
#include "viacuda.h"
|
||||
|
||||
/** Heathrow Mac I/O device emulation.
|
||||
|
||||
Author: Max Poliakovski 2019
|
||||
*/
|
||||
|
||||
using namespace std;
|
||||
|
||||
HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
|
||||
@ -113,6 +118,9 @@ uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size)
|
||||
cout << "read from MIO:Int_Clear1 register" << endl;
|
||||
res = this->int_clear1;
|
||||
break;
|
||||
case 0x34: /* heathrowIDs / HEATHROW_MBCR (Linux): media bay config reg? */
|
||||
res = 0xF0700000UL;
|
||||
break;
|
||||
case 0x38:
|
||||
cout << "read from MIO:Feat_Ctrl register" << endl;
|
||||
res = this->feat_ctrl;
|
||||
|
@ -5,6 +5,10 @@
|
||||
//if you want to distribute this.
|
||||
//(divingkatae#1017 on Discord)
|
||||
|
||||
/** VIA-CUDA combo device emulation.
|
||||
|
||||
Author: Max Poliakovski 2019
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cinttypes>
|
||||
@ -187,15 +191,25 @@ void ViaCuda::cuda_write(uint8_t new_state)
|
||||
}
|
||||
}
|
||||
|
||||
void ViaCuda::cuda_null_response(uint32_t pkt_type, uint32_t pkt_flag, uint32_t cmd)
|
||||
void ViaCuda::cuda_response_header(uint32_t pkt_type, uint32_t pkt_flag)
|
||||
{
|
||||
this->out_buf[0] = pkt_type;
|
||||
this->out_buf[1] = pkt_flag;
|
||||
this->out_buf[2] = cmd;
|
||||
this->out_buf[2] = this->in_buf[1]; /* copy original cmd */
|
||||
this->out_count = 3;
|
||||
this->out_pos = 0;
|
||||
}
|
||||
|
||||
void ViaCuda::cuda_error_response(uint32_t error)
|
||||
{
|
||||
this->out_buf[0] = CUDA_PKT_ERROR;
|
||||
this->out_buf[1] = error;
|
||||
this->out_buf[2] = this->in_buf[0];
|
||||
this->out_buf[3] = this->in_buf[1]; /* copy original cmd */
|
||||
this->out_count = 4;
|
||||
this->out_pos = 0;
|
||||
}
|
||||
|
||||
void ViaCuda::cuda_process_packet()
|
||||
{
|
||||
if (this->in_count < 2) {
|
||||
@ -204,10 +218,10 @@ void ViaCuda::cuda_process_packet()
|
||||
}
|
||||
|
||||
switch(this->in_buf[0]) {
|
||||
case 0:
|
||||
case CUDA_PKT_ADB:
|
||||
cout << "Cuda: ADB packet received" << endl;
|
||||
break;
|
||||
case 1:
|
||||
case CUDA_PKT_PSEUDO:
|
||||
cout << "Cuda: pseudo command packet received" << endl;
|
||||
cout << "Command: " << hex << (uint32_t)(this->in_buf[1]) << endl;
|
||||
cout << "Data count: " << dec << this->in_count << endl;
|
||||
@ -226,21 +240,87 @@ void ViaCuda::cuda_pseudo_command(int cmd, int data_count)
|
||||
{
|
||||
switch(cmd) {
|
||||
case CUDA_READ_WRITE_I2C:
|
||||
cuda_null_response(1, 0, cmd);
|
||||
cuda_response_header(CUDA_PKT_PSEUDO, 0);
|
||||
/* bit 0 of the I2C address byte indicates operation kind:
|
||||
0 - write to device, 1 - read from device
|
||||
In the case of reading, Cuda will append one-byte result
|
||||
to the response packet header */
|
||||
if (this->in_buf[2] & 1) {
|
||||
this->out_buf[3] = 0xDD; /* send dummy byte for now */
|
||||
this->out_count++;
|
||||
i2c_simple_transaction(this->in_buf[2], &this->in_buf[3], this->in_count - 3);
|
||||
break;
|
||||
case CUDA_COMB_FMT_I2C:
|
||||
/* HACK:
|
||||
This command performs the so-called open-ended transaction, i.e.
|
||||
Cuda will continue to send data as long as handshaking is completed
|
||||
for each byte. To support that, we'd need another emulation approach.
|
||||
Fortunately, HWInit is known to read/write max. 4 bytes at once
|
||||
so we're going to use a prefilled buffer to make it work.
|
||||
*/
|
||||
cuda_response_header(CUDA_PKT_PSEUDO, 0);
|
||||
if (this->in_count >= 5) {
|
||||
i2c_comb_transaction(this->in_buf[2], this->in_buf[3], this->in_buf[4],
|
||||
&this->in_buf[5], this->in_count - 5);
|
||||
}
|
||||
break;
|
||||
case CUDA_OUT_PB0: /* undocumented call! */
|
||||
cout << "Cuda: send " << dec << (int)(this->in_buf[2]) << " to PB0" << endl;
|
||||
cuda_null_response(1, 0, cmd);
|
||||
cuda_response_header(CUDA_PKT_PSEUDO, 0);
|
||||
break;
|
||||
default:
|
||||
cout << "Cuda: unsupported pseudo command 0x" << hex << cmd << endl;
|
||||
cuda_error_response(CUDA_ERR_BAD_CMD);
|
||||
}
|
||||
}
|
||||
|
||||
void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t *in_buf,
|
||||
int in_bytes)
|
||||
{
|
||||
int tr_type = dev_addr & 1;
|
||||
|
||||
switch(dev_addr & 0xFE) {
|
||||
case 0x50: /* unknown device on the Gossamer board */
|
||||
if (tr_type) { /* read */
|
||||
/* send dummy byte for now */
|
||||
this->out_buf[this->out_count++] = 0xDD;
|
||||
} else {
|
||||
/* ignore writes */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cout << "Unsupported I2C device 0x" << hex << (int)dev_addr << endl;
|
||||
cuda_error_response(CUDA_ERR_I2C);
|
||||
}
|
||||
}
|
||||
|
||||
void ViaCuda::i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr,
|
||||
uint8_t dev_addr1, const uint8_t *in_buf, int in_bytes)
|
||||
{
|
||||
int tr_type = dev_addr1 & 1;
|
||||
|
||||
if ((dev_addr & 0xFE) != (dev_addr1 & 0xFE)) {
|
||||
cout << "I2C combined, dev_addr mismatch!" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(dev_addr1 & 0xFE) {
|
||||
case 0xAE: /* SDRAM EEPROM, no clue which one */
|
||||
if (tr_type) { /* read */
|
||||
if (sub_addr != 2) {
|
||||
cout << "Unsupported read position 0x" << hex << (int)sub_addr
|
||||
<< " in SDRAM EEPROM 0x" << hex << (int)dev_addr1;
|
||||
return;
|
||||
}
|
||||
/* FIXME: hardcoded SPD EEPROM values! This should be a proper
|
||||
I2C device with user-configurable params */
|
||||
this->out_buf[this->out_count++] = 0x04; /* memory type = SDRAM */
|
||||
this->out_buf[this->out_count++] = 0x0B; /* row address bits per bank */
|
||||
this->out_buf[this->out_count++] = 0x09; /* col address bits per bank */
|
||||
this->out_buf[this->out_count++] = 0x02; /* num of RAM banks */
|
||||
} else {
|
||||
/* ignore writes */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cout << "Unsupported I2C device 0x" << hex << (int)dev_addr1 << endl;
|
||||
cuda_error_response(CUDA_ERR_I2C);
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,15 @@ enum {
|
||||
CUDA_TREQ = 0x08 /* Cuda requests transaction from host */
|
||||
};
|
||||
|
||||
/** Cuda packet types. */
|
||||
enum {
|
||||
CUDA_PKT_ADB = 0,
|
||||
CUDA_PKT_PSEUDO = 1,
|
||||
CUDA_PKT_ERROR = 2,
|
||||
CUDA_PKT_TICK = 3,
|
||||
CUDA_PKT_POWER = 4
|
||||
};
|
||||
|
||||
/** Cuda pseudo commands. */
|
||||
enum {
|
||||
CUDA_READ_WRITE_I2C = 0x22, /* read/write I2C device */
|
||||
@ -65,6 +74,12 @@ enum {
|
||||
CUDA_OUT_PB0 = 0x26, /* output one bit to Cuda's PB0 line */
|
||||
};
|
||||
|
||||
/** Cuda error codes. */
|
||||
enum {
|
||||
CUDA_ERR_BAD_CMD = 2, /* invalid pseudo command */
|
||||
CUDA_ERR_I2C = 5 /* invalid I2C data or no acknowledge */
|
||||
};
|
||||
|
||||
|
||||
class ViaCuda
|
||||
{
|
||||
@ -94,9 +109,15 @@ private:
|
||||
bool cuda_ready();
|
||||
void assert_sr_int();
|
||||
void cuda_write(uint8_t new_state);
|
||||
void cuda_null_response(uint32_t pkt_type, uint32_t pkt_flag, uint32_t cmd);
|
||||
void cuda_response_header(uint32_t pkt_type, uint32_t pkt_flag);
|
||||
void cuda_error_response(uint32_t error);
|
||||
void cuda_process_packet();
|
||||
void cuda_pseudo_command(int cmd, int data_count);
|
||||
|
||||
/* I2C related methods */
|
||||
void i2c_simple_transaction(uint8_t dev_addr, const uint8_t *in_buf, int in_bytes);
|
||||
void i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1,
|
||||
const uint8_t *in_buf, int in_bytes);
|
||||
};
|
||||
|
||||
#endif /* VIACUDA_H */
|
||||
|
Loading…
Reference in New Issue
Block a user