Trying to flesh out SATA port initialization

This commit is contained in:
Thomas Oltmann 2025-11-05 19:18:55 +01:00
parent 98b793f699
commit d8467573fb
2 changed files with 56 additions and 5 deletions

View file

@ -7,8 +7,15 @@
#define HBA_GHC_INTR_ENABLE (1 << 1)
#define HBA_GHC_AHCI_ENABLE (1 << 31)
#define PORT_CMD_START (1 << 0)
#define PORT_CMD_FIS_RECV_ENABLE (1 << 4)
#define PORT_CMD_START (1 << 0)
#define PORT_CMD_SPIN_UP_DEVICE (1 << 1)
#define PORT_CMD_FIS_RECV_ENABLE (1 << 4)
#define PORT_CMD_FIS_RECV_RUNNING (1 << 14)
#define PORT_CMD_LIST_RUNNING (1 << 15)
#define PORT_TFD_STS_ERR (1 << 0)
#define PORT_TFD_STS_DRQ (1 << 3)
#define PORT_TFD_STS_BSY (1 << 7)
#define ATA_CMD_READ_SECTOR_EXT 0x24
#define ATA_CMD_READ_DMA_EXT 0x25

View file

@ -181,7 +181,26 @@ void sata_init_port(int port_num)
memset((void *)port->recv_fis_ptr, 0, 256);
memset((void *)port->buffer_ptr, 0, 1024);
// TODO make sure port is in idle state
// If the port is not already idling, we need to get it into the idle state
if (port->port_mem->cmd & (PORT_CMD_START | PORT_CMD_FIS_RECV_ENABLE | PORT_CMD_FIS_RECV_RUNNING | PORT_CMD_LIST_RUNNING)) {
port->port_mem->cmd &= ~PORT_CMD_START;
while (port->port_mem->cmd & PORT_CMD_LIST_RUNNING) {
__asm__ ("pause");
}
if (port->port_mem->cmd & PORT_CMD_FIS_RECV_ENABLE) {
port->port_mem->cmd &= ~PORT_CMD_FIS_RECV_ENABLE;
while (port->port_mem->cmd & PORT_CMD_FIS_RECV_RUNNING) {
__asm__ ("pause");
}
}
}
// Hard reset the port; this shouldn't be neccessary
port->port_mem->sctl = (port->port_mem->sctl & 0xFFFFFFF0) | 1;
Time deassert_time = time_add(time_current(), TIME_FROM_MS(2));
while (time_compare(time_current(), deassert_time) < 0) {}
port->port_mem->sctl = (port->port_mem->sctl & 0xFFFFFFF0) | 0;
// TODO determine how many command slots the HBA supports (CAP.NCS)
@ -190,8 +209,29 @@ void sata_init_port(int port_num)
port->port_mem->fb = pa_to_value(port->recv_fis_pa);
port->port_mem->cmd |= PORT_CMD_FIS_RECV_ENABLE;
port->port_mem->cmd |= PORT_CMD_SPIN_UP_DEVICE;
// TODO clear the PxSERR register
port->port_mem->serr |= (1 << 9) | (1 << 10) | (1 << 11);
//port->port_mem->serr |= (1 << 9) | (1 << 10) | (1 << 11);
port->port_mem->serr = 0xFFFFFFFF;
port->port_mem->is = 0;
printf("Port %d State right before we write the start bit:\n", port_num);
printf("P%d.CI=%x\n", port_num, port->port_mem->ci);
printf("P%d.IS=%x\n", port_num, port->port_mem->is);
printf("P%d.CMD=%x\n", port_num, port->port_mem->cmd);
printf("P%d.TFD=%x\n", port_num, port->port_mem->tfd);
printf("P%d.SSTS=%x\n", port_num, port->port_mem->ssts);
printf("P%d.SCTL=%x\n", port_num, port->port_mem->sctl);
printf("P%d.SERR=%x\n", port_num, port->port_mem->serr);
printf("P%d.SACT=%x\n", port_num, port->port_mem->sact);
#if 1
// Wait for indication that the SATA drive is ready
while (port->port_mem->tfd & (PORT_TFD_STS_ERR | PORT_TFD_STS_DRQ | PORT_TFD_STS_BSY)) {
__asm__ ("pause");
}
#endif
// Start processing commands
port->port_mem->cmd |= PORT_CMD_START;
@ -318,6 +358,10 @@ void sata_init()
__asm__ volatile ("" ::: "memory");
hba.hba_mem->ghc |= HBA_GHC_HOST_RESET;
while (hba.hba_mem->ghc & HBA_GHC_HOST_RESET) {
__asm__ ("pause");
}
hba.hba_mem->ghc |= HBA_GHC_AHCI_ENABLE;
printf("HBA.VS=%x\n", hba.hba_mem->vs);