From af5a096532ad8d7ca051cfa4d7958afbceb2116b Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Fri, 23 Aug 2019 21:30:30 +0200 Subject: [PATCH] MPC106: add support for PCI devices. --- devices/mpc106.cpp | 92 +++++++++++++++++++++++++++++----------------- devices/mpc106.h | 28 ++++++++++---- 2 files changed, 80 insertions(+), 40 deletions(-) diff --git a/devices/mpc106.cpp b/devices/mpc106.cpp index 3607199..7c90630 100644 --- a/devices/mpc106.cpp +++ b/devices/mpc106.cpp @@ -16,20 +16,20 @@ #include "memctrlbase.h" #include "mmiodevice.h" -#include "../viacuda.h" #include "mpc106.h" -#include "../ppcemumain.h" -#include "../ppcmemory.h" -MPC106::MPC106() : MemCtrlBase("Grackle") +MPC106::MPC106() : MemCtrlBase("Grackle"), PCIDevice("Grackle PCI host bridge") { /* add memory mapped I/O region for MPC106 registers */ add_mmio_region(0xFEC00000, 0x300000, this); + + this->pci_0_bus.clear(); } MPC106::~MPC106() { + this->pci_0_bus.clear(); } uint32_t MPC106::read(uint32_t offset, int size) @@ -56,7 +56,7 @@ void MPC106::write(uint32_t offset, uint32_t value, int size) uint32_t MPC106::pci_read(uint32_t size) { - int bus_num, dev_num, fun_num, reg_num; + int bus_num, dev_num, fun_num, reg_offs; bus_num = (this->config_addr >> 8) & 0xFF; if (bus_num) { @@ -65,16 +65,20 @@ uint32_t MPC106::pci_read(uint32_t size) return 0; } - dev_num = (this->config_addr >> 19) & 0x1F; - fun_num = (this->config_addr >> 16) & 0x07; - reg_num = (this->config_addr >> 24) & 0xFC; + dev_num = (this->config_addr >> 19) & 0x1F; + fun_num = (this->config_addr >> 16) & 0x07; + reg_offs = (this->config_addr >> 24) & 0xFC; if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself - return myself_read(reg_num, size); + return this->pci_cfg_read(reg_offs, size); } else { - std::cout << this->name << " err: reading from device " << dev_num - << " not supported yet" << std::endl; - return 0; + if (this->pci_0_bus.count(dev_num)) { + return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size); + } else { + std::cout << this->name << " err: read attempt from non-existing PCI device " + << dev_num << std::endl; + return 0; + } } return 0; @@ -82,7 +86,7 @@ uint32_t MPC106::pci_read(uint32_t size) void MPC106::pci_write(uint32_t value, uint32_t size) { - int bus_num, dev_num, fun_num, reg_num; + int bus_num, dev_num, fun_num, reg_offs; bus_num = (this->config_addr >> 8) & 0xFF; if (bus_num) { @@ -91,33 +95,37 @@ void MPC106::pci_write(uint32_t value, uint32_t size) return; } - dev_num = (this->config_addr >> 19) & 0x1F; - fun_num = (this->config_addr >> 16) & 0x07; - reg_num = (this->config_addr >> 24) & 0xFC; + dev_num = (this->config_addr >> 19) & 0x1F; + fun_num = (this->config_addr >> 16) & 0x07; + reg_offs = (this->config_addr >> 24) & 0xFC; if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself - myself_write(reg_num, value, size); + this->pci_cfg_write(reg_offs, value, size); } else { - std::cout << this->name << " err: writing to device " << dev_num - << " not supported yet" << std::endl; + if (this->pci_0_bus.count(dev_num)) { + this->pci_0_bus[dev_num]->pci_cfg_write(reg_offs, value, size); + } else { + std::cout << this->name << " err: write attempt to non-existing PCI device " + << dev_num << std::endl; + } } } -uint32_t MPC106::myself_read(int reg_num, uint32_t size) +uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size) { #ifdef MPC106_DEBUG - printf("read from Grackle register %08X\n", reg_num); + printf("read from Grackle register %08X\n", reg_offs); #endif switch(size) { case 1: - return this->my_pci_cfg_hdr[reg_num]; + return this->my_pci_cfg_hdr[reg_offs]; break; case 2: - return READ_WORD_BE(&this->my_pci_cfg_hdr[reg_num]); + return READ_WORD_BE(&this->my_pci_cfg_hdr[reg_offs]); break; case 4: - return READ_DWORD_BE(&this->my_pci_cfg_hdr[reg_num]); + return READ_DWORD_BE(&this->my_pci_cfg_hdr[reg_offs]); break; default: std::cout << "MPC106 read error: invalid size parameter " << size @@ -127,29 +135,47 @@ uint32_t MPC106::myself_read(int reg_num, uint32_t size) return 0; } -void MPC106::myself_write(int reg_num, uint32_t value, uint32_t size) +void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) { #ifdef MPC106_DEBUG - printf("write %08X to Grackle register %08X\n", value, reg_num); + printf("write %08X to Grackle register %08X\n", value, reg_offs); #endif // FIXME: implement write-protection for read-only registers switch(size) { case 1: - this->my_pci_cfg_hdr[reg_num] = value & 0xFF; + this->my_pci_cfg_hdr[reg_offs] = value & 0xFF; break; case 2: - this->my_pci_cfg_hdr[reg_num] = (value >> 8) & 0xFF; - this->my_pci_cfg_hdr[reg_num+1] = value & 0xFF; + this->my_pci_cfg_hdr[reg_offs] = (value >> 8) & 0xFF; + this->my_pci_cfg_hdr[reg_offs+1] = value & 0xFF; break; case 4: - this->my_pci_cfg_hdr[reg_num] = (value >> 24) & 0xFF; - this->my_pci_cfg_hdr[reg_num+1] = (value >> 16) & 0xFF; - this->my_pci_cfg_hdr[reg_num+2] = (value >> 8) & 0xFF; - this->my_pci_cfg_hdr[reg_num+3] = value & 0xFF; + this->my_pci_cfg_hdr[reg_offs] = (value >> 24) & 0xFF; + this->my_pci_cfg_hdr[reg_offs+1] = (value >> 16) & 0xFF; + this->my_pci_cfg_hdr[reg_offs+2] = (value >> 8) & 0xFF; + this->my_pci_cfg_hdr[reg_offs+3] = value & 0xFF; break; default: std::cout << "MPC106 read error: invalid size parameter " << size << std::endl; } } + +bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance) +{ + if (this->pci_0_bus.count(dev_num)) // is dev_num already registered? + return false; + + this->pci_0_bus[dev_num] = dev_instance; + + dev_instance->set_host(this); + + return true; +} + +bool MPC106::pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj) +{ + // FIXME: add sanity checks! + return this->add_mmio_region(start_addr, size, obj); +} diff --git a/devices/mpc106.h b/devices/mpc106.h index 13f6b74..71898d0 100644 --- a/devices/mpc106.h +++ b/devices/mpc106.h @@ -9,7 +9,7 @@ Author: Max Poliakovski - Grackle IC is a combined memory and PCI controller manufactored by Motorola. + Grackle IC is a combined memory and PCI controller manufactured by Motorola. It's the central device in the Gossamer architecture. Manual: https://www.nxp.com/docs/en/reference-manual/MPC106UM.pdf @@ -23,11 +23,14 @@ #define MPC106_H_ #include +#include #include "memctrlbase.h" #include "mmiodevice.h" +#include "pcidevice.h" +#include "pcihost.h" -class MPC106 : public MemCtrlBase, public MMIODevice +class MPC106 : public MemCtrlBase, public PCIDevice, public PCIHost { public: using MemCtrlBase::name; @@ -37,14 +40,23 @@ public: uint32_t read(uint32_t offset, int size); void write(uint32_t offset, uint32_t value, int size); + /* PCI host bridge API */ + bool pci_register_device(int dev_num, PCIDevice *dev_instance); + protected: /* PCI access */ uint32_t pci_read(uint32_t size); void pci_write(uint32_t value, uint32_t size); - /* my own registers access */ - uint32_t myself_read(int reg_num, uint32_t size); - void myself_write(int reg_num, uint32_t value, uint32_t size); + /* my own PCI configuration registers access */ + uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); + void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); + + void set_host(PCIHost *host_instance) {}; // unimplemented for now + + /* PCI host bridge API */ + //bool pci_register_device(int dev_num, PCIDevice *dev_instance); + bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj); private: uint8_t my_pci_cfg_hdr[256] = { @@ -54,8 +66,8 @@ private: 0x80, 0x00, // PCI status 0x40, // revision ID: 4.0 0x00, // standard programming - 0x00, // subclass code - 0x06, // class code + 0x00, // subclass code: host bridge + 0x06, // class code: bridge device [0x73] = 0xCD, // default value for ODCR [0xA8] = 0x10, 0x00, 0x00, 0xFF, // PICR1 [0xAC] = 0x0C, 0x06, 0x0C, 0x00, // PICR2 @@ -70,6 +82,8 @@ private: uint32_t config_addr; //uint32_t config_data; + + std::unordered_map pci_0_bus; }; #endif