sdb.c 3.27 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
#include "hw/memlayout.h"

#define SDB_INTERCONNET 0x00
#define SDB_DEVICE      0x01
#define SDB_BRIDGE      0x02
#define SDB_EMPTY       0xFF

typedef struct pair64 {
  uint32_t high;
  uint32_t low;
} pair64_t;

struct sdb_empty {
  int8_t reserved[63];
  uint8_t record_type;
};

struct sdb_product {
  pair64_t vendor_id;
  uint32_t device_id;
  uint32_t version;
  uint32_t date;
  int8_t   name[19];
  uint8_t  record_type;
};

struct sdb_component {
  pair64_t addr_first;
  pair64_t addr_last;
  struct sdb_product product;
};

struct sdb_device {
  uint16_t abi_class;
  uint8_t  abi_ver_major;
  uint8_t  abi_ver_minor;
  uint32_t bus_specific;
  struct sdb_component sdb_component;
};

struct sdb_bridge {
  pair64_t sdb_child;
  struct sdb_component sdb_component;
};

struct sdb_interconnect {
  uint32_t sdb_magic;
  uint16_t sdb_records;
  uint8_t  sdb_version;
  uint8_t  sdb_bus_type;
  struct sdb_component sdb_component;
};

typedef union sdb_record {
  struct sdb_empty        empty;
  struct sdb_device       device;
  struct sdb_bridge       bridge;
  struct sdb_interconnect interconnect;
} sdb_record_t;

static unsigned char* find_device_deep(unsigned int base, unsigned int sdb, unsigned int devid) {
  sdb_record_t* record = (sdb_record_t*)sdb;
  int records = record->interconnect.sdb_records;
  int i;
  
  for (i = 0; i < records; ++i, ++record) {
    if (record->empty.record_type == SDB_BRIDGE) {
      unsigned char* out = 
        find_device_deep(
          base + record->bridge.sdb_component.addr_first.low,
          record->bridge.sdb_child.low,
          devid);
      if (out) return out;
    }
    if (record->empty.record_type == SDB_DEVICE && 
        record->device.sdb_component.product.device_id == devid) {
      break;
    }
  }
  
  if (i == records) return 0;
  return (unsigned char*)(base + record->device.sdb_component.addr_first.low);
}

static void print_devices_deep(unsigned int base, unsigned int sdb) {
  sdb_record_t* record = (sdb_record_t*)sdb;
  int records = record->interconnect.sdb_records;
  int i;
  char buf[20];
  
  for (i = 0; i < records; ++i, ++record) {
    if (record->empty.record_type == SDB_BRIDGE)
      print_devices_deep(
        base + record->bridge.sdb_component.addr_first.low,
        record->bridge.sdb_child.low);
    
    if (record->empty.record_type != SDB_DEVICE) continue;
    
    memcpy(buf, record->device.sdb_component.product.name, 19);
    buf[19] = 0;
    mprintf("%8x:%8x 0x%8x %s\n", 
            record->device.sdb_component.product.vendor_id.low,
            record->device.sdb_component.product.device_id, 
            base + record->device.sdb_component.addr_first.low,
            buf);
  }
}

static unsigned char* find_device(unsigned int devid) {
  find_device_deep(0, SDB_ADDRESS, devid);
}

void sdb_print_devices(void) {
  mprintf("SDB memory map:\n");
  print_devices_deep(0, SDB_ADDRESS);
  mprintf("---\n");
}

void sdb_find_devices(void) {
  BASE_MINIC         = find_device(0xab28633a);
  BASE_EP            = find_device(0x650c2d4f);
  BASE_SOFTPLL       = find_device(0x65158dc0);
  BASE_PPS_GEN       = find_device(0xde0d8ced);
  BASE_SYSCON        = find_device(0xff07fc47);
  BASE_UART          = find_device(0xe2d13d04);
  BASE_ONEWIRE       = find_device(0x779c5443);
127
  BASE_ETHERBONE_CFG = find_device(0x68202b22);
128
}