/* * Intel 815EP MCH Bridge * * Authors: Tiseno100, * * Copyright 2022 Tiseno100. */ #include #include #include #include #include #include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include "x86.h" #include <86box/timer.h> #include <86box/io.h> #include <86box/device.h> #include <86box/mem.h> #include <86box/pci.h> #include <86box/smram.h> #include <86box/spd.h> #include <86box/video.h> #include <86box/chipset.h> #ifdef ENABLE_INTEL_815EP_LOG int intel_815ep_do_log = ENABLE_INTEL_815EP_LOG; static void intel_815ep_log(const char *fmt, ...) { va_list ap; if (intel_815ep_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else #define intel_815ep_log(fmt, ...) #endif typedef struct intel_815ep_t { uint8_t pci_conf[256]; smram_t *lsmm_segment, *h_segment, *usmm_segment; void *agpgart; } intel_815ep_t; static void intel_815ep_agp_aperature(intel_815ep_t *dev) { uint32_t aperature_base, aperature_size_calc; int aperature_size, aperature_enable; aperature_base = dev->pci_conf[0x13] << 24; aperature_size = !!(dev->pci_conf[0xb4] & 8); aperature_size_calc = 1 << (aperature_size ? 25 : 24); /* 815EP has the choice of 64 & 32MB only */ aperature_enable = aperature_base != 0; if(aperature_size) dev->pci_conf[0x13] &= 0xfe; if(aperature_enable) intel_815ep_log("Intel 815EP AGP Aperature: Enabled at size 0x%x and size of %dMB\n", aperature_base, aperature_size ? 64 : 32); else intel_815ep_log("Intel 815EP AGP Aperature: AGP Aperature disabled\n"); agpgart_set_aperture(dev->agpgart, aperature_base, aperature_size_calc, aperature_enable); } static void intel_usmm_segment_recalc(intel_815ep_t *dev, uint8_t val) { intel_815ep_log("Intel 815EP MCH: USMM update to status %d\n", val); /* Check the 815EP datasheet for status */ smram_disable(dev->h_segment); smram_disable(dev->usmm_segment); if(val != 0) smram_enable(dev->h_segment, 0xfeea0000, 0x000a0000, 0x20000, 0, 1); if(val >= 2) { /* TOM recalc based on intel_4x0.c by OBattler */ uint32_t tom = (mem_size << 10); mem_set_mem_state_smm(tom, 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); uint32_t size = (val != 3) ? 0x100000 : 0x80000; smram_enable(dev->usmm_segment, tom + 0x10000000, tom, size, 0, 1); mem_set_mem_state_smm(tom, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } } static void intel_lsmm_segment_recalc(intel_815ep_t *dev, uint8_t val) { intel_815ep_log("Intel 815EP MCH: LSMM update to status %d\n", val); /* Check the 815EP datasheet for status */ smram_disable(dev->lsmm_segment); switch(val) { case 1: smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 1, 0); break; case 2: smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 0, 0); break; case 3: smram_enable(dev->lsmm_segment, 0x000a0000, 0x000a0000, 0x20000, 0, 1); break; } flushmmucache(); } static void intel_pam_recalc(int addr, uint8_t val) { int region = 0xc0000 + ((addr - 0x5a) << 15); if(addr == 0x59) mem_set_mem_state_both(0xf0000, 0x10000, ((val & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); else { mem_set_mem_state_both(region, 0x4000, ((val & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x02) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); mem_set_mem_state_both(region + 0x4000, 0x4000, ((val & 0x10) ? MEM_READ_INTERNAL : MEM_READ_EXTANY) | ((val & 0x20) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY)); } flushmmucache_nopc(); } static void intel_815ep_gart_table(intel_815ep_t *dev) { uint32_t agp_gart_base = (dev->pci_conf[0xbb] << 24) | (dev->pci_conf[0xba] << 16) | (dev->pci_conf[0xb9] << 8); intel_815ep_log("Intel 815EP AGP GART: GART address updated at 0x%x\n", agp_gart_base); agpgart_set_gart(dev->agpgart, agp_gart_base); } static void intel_815ep_write(int func, int addr, uint8_t val, void *priv) { intel_815ep_t *dev = (intel_815ep_t *)priv; intel_815ep_log("Intel 815EP MCH: dev->regs[%02x] = %02x\n", addr, val); if(func) return; switch(addr) { case 0x05: dev->pci_conf[addr] = val & 3; break; case 0x07: dev->pci_conf[addr] &= val & 0x70; break; case 0x2c ... 0x2f: if(dev->pci_conf[addr] != 0) dev->pci_conf[addr] = val; break; case 0x13: dev->pci_conf[addr] = val; intel_815ep_agp_aperature(dev); break; case 0x50: dev->pci_conf[addr] = val & 0xdc; break; case 0x51: dev->pci_conf[addr] = val & 2; // Brute force to AGP Mode break; case 0x52: case 0x54: if (!(dev->pci_conf[0x70] & 2)) { dev->pci_conf[addr] = val & ((addr & 4) ? 0x0f : 0xff); spd_write_drbs_intel_815ep(dev->pci_conf); } break; case 0x53: dev->pci_conf[addr] = val; break; case 0x58: dev->pci_conf[addr] = val & 0x80; break; case 0x59 ... 0x5f: dev->pci_conf[addr] = val; intel_pam_recalc(addr, val); break; case 0x70: if(!(dev->pci_conf[0x70] & 2)) { dev->pci_conf[addr] = val & 0xfe; intel_usmm_segment_recalc(dev, (val >> 4) & 3); } else { dev->pci_conf[addr] = (dev->pci_conf[addr] & 0xfa) | (val & 4); } intel_lsmm_segment_recalc(dev, (val >> 2) & 3); break; case 0x72: dev->pci_conf[addr] = val & 0xfb; break; case 0x73: dev->pci_conf[addr] = val & 0xa8; break; case 0x92 ... 0x93: dev->pci_conf[addr] = val; break; case 0x94: dev->pci_conf[addr] = val & 0x3f; break; case 0x98: dev->pci_conf[addr] = val & 0x77; break; case 0x99: dev->pci_conf[addr] = val & 0x80; break; case 0x9a: dev->pci_conf[addr] = val & 0xef; break; case 0x9b: case 0x9d: dev->pci_conf[addr] = val & 0x80; break; case 0xa4: dev->pci_conf[addr] = val & 7; break; case 0xa8: dev->pci_conf[addr] = val & 0x37; break; case 0xa9: dev->pci_conf[addr] = (val & 2) | 1; break; case 0xb0: dev->pci_conf[addr] = val & 0x81; break; case 0xb4: dev->pci_conf[addr] = val & 8; intel_815ep_agp_aperature(dev); break; case 0xb9: dev->pci_conf[addr] = val & 0xf0; intel_815ep_gart_table(dev); break; case 0xba: dev->pci_conf[addr] = val; intel_815ep_gart_table(dev); break; case 0xbb: dev->pci_conf[addr] = val & 0x1f; intel_815ep_gart_table(dev); break; case 0xbc ... 0xbd: dev->pci_conf[addr] = val & 0xf8; break; case 0xbe: dev->pci_conf[addr] = val & 0x28; break; case 0xcb: dev->pci_conf[addr] = val & 0x3f; break; } } static uint8_t intel_815ep_read(int func, int addr, void *priv) { intel_815ep_t *dev = (intel_815ep_t *)priv; intel_815ep_log("Intel 815EP MCH: dev->regs[%02x] (%02x)\n", addr, dev->pci_conf[addr]); if(func) return 0xff; if(addr == 0x51) // Bit 2 is Write Only. It cannot be read. return dev->pci_conf[addr] & 3; else if(addr == 0x52) return intel_815ep_get_banking(); else return dev->pci_conf[addr]; } static void intel_815ep_reset(void *priv) { intel_815ep_t *dev = (intel_815ep_t *)priv; memset(dev->pci_conf, 0x00, sizeof(dev->pci_conf)); /* Wash out the registers */ dev->pci_conf[0x00] = 0x86; /* Intel */ dev->pci_conf[0x01] = 0x80; dev->pci_conf[0x02] = 0x30; /* 815EP */ dev->pci_conf[0x03] = 0x11; dev->pci_conf[0x04] = 0x06; dev->pci_conf[0x06] = 0x90; dev->pci_conf[0x08] = 0x02; dev->pci_conf[0x0b] = 0x06; dev->pci_conf[0x10] = 0x03; dev->pci_conf[0x34] = 0xa0; dev->pci_conf[0x50] = 0x40; dev->pci_conf[0x88] = 0x09; dev->pci_conf[0x89] = 0xa0; dev->pci_conf[0x8a] = 0x04; dev->pci_conf[0x8b] = 0xf1; dev->pci_conf[0x92] = 0xff; dev->pci_conf[0x93] = 0xff; dev->pci_conf[0x94] = 0xff; dev->pci_conf[0x95] = 0xff; dev->pci_conf[0xa0] = 0x02; dev->pci_conf[0xa2] = 0x20; dev->pci_conf[0xa4] = 0x07; dev->pci_conf[0xa5] = 0x02; dev->pci_conf[0xa7] = 0x1f; dev->pci_conf[0xa9] = 0x01; /* Hack: Brute Force AGP Enabled */ intel_815ep_agp_aperature(dev); /* Configure AGP Aperature */ for(int i = 0x59; i <= 0x5f; i++) /* Reset PAM to defaults */ intel_pam_recalc(i, 0); intel_lsmm_segment_recalc(dev, 0); /* Reset LSMM SMRAM to defaults */ intel_usmm_segment_recalc(dev, 0); /* Reset USMM SMRAM to defaults */ intel_815ep_gart_table(dev); /* Reset AGP GART to defaults */ } static void intel_815ep_close(void *priv) { intel_815ep_t *dev = (intel_815ep_t *)priv; smram_del(dev->lsmm_segment); smram_del(dev->h_segment); smram_del(dev->usmm_segment); free(dev); } static void * intel_815ep_init(const device_t *info) { intel_815ep_t *dev = (intel_815ep_t *)malloc(sizeof(intel_815ep_t)); memset(dev, 0, sizeof(intel_815ep_t)); /* Bus Speed(815EP runs at 133Mhz) */ if(cpu_busspeed >= 133333333) cpu_set_pci_speed(133333333); else cpu_set_pci_speed(cpu_busspeed); /* Device */ pci_add_card(PCI_ADD_NORTHBRIDGE, intel_815ep_read, intel_815ep_write, dev); /* Device 0: Intel 815EP MCH */ /* AGP Bridge */ device_add(&intel_815ep_agp_device); /* AGP GART*/ dev->agpgart = device_add(&agpgart_device); /* L1 & L2 Cache */ cpu_cache_int_enabled = 1; cpu_cache_ext_enabled = 1; cpu_update_waitstates(); /* SMRAM Segments */ dev->lsmm_segment = smram_add(); dev->h_segment = smram_add(); dev->usmm_segment = smram_add(); intel_815ep_reset(dev); return dev; } const device_t intel_815ep_device = { .name = "Intel 815EP MCH Bridge", .internal_name = "intel_815ep", .flags = DEVICE_PCI, .local = 0, .init = intel_815ep_init, .close = intel_815ep_close, .reset = intel_815ep_reset, { .available = NULL }, .speed_changed = NULL, .force_redraw = NULL, .config = NULL };