symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/ppc4xx_pci.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * This program is free software; you can redistribute it and/or modify
       
     3  * it under the terms of the GNU General Public License, version 2, as
       
     4  * published by the Free Software Foundation.
       
     5  *
       
     6  * This program is distributed in the hope that it will be useful,
       
     7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
     8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
     9  * GNU General Public License for more details.
       
    10  *
       
    11  * You should have received a copy of the GNU General Public License
       
    12  * along with this program; if not, write to the Free Software
       
    13  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    14  *
       
    15  * Copyright IBM Corp. 2008
       
    16  *
       
    17  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
       
    18  */
       
    19 
       
    20 /* This file implements emulation of the 32-bit PCI controller found in some
       
    21  * 4xx SoCs, such as the 440EP. */
       
    22 
       
    23 #include "hw.h"
       
    24 #include "ppc.h"
       
    25 #include "ppc4xx.h"
       
    26 
       
    27 typedef target_phys_addr_t pci_addr_t;
       
    28 #include "pci.h"
       
    29 #include "pci_host.h"
       
    30 #include "bswap.h"
       
    31 
       
    32 #undef DEBUG
       
    33 #ifdef DEBUG
       
    34 #define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
       
    35 #else
       
    36 #define DPRINTF(fmt, args...)
       
    37 #endif /* DEBUG */
       
    38 
       
    39 struct PCIMasterMap {
       
    40     uint32_t la;
       
    41     uint32_t ma;
       
    42     uint32_t pcila;
       
    43     uint32_t pciha;
       
    44 };
       
    45 
       
    46 struct PCITargetMap {
       
    47     uint32_t ms;
       
    48     uint32_t la;
       
    49 };
       
    50 
       
    51 #define PPC4xx_PCI_NR_PMMS 3
       
    52 #define PPC4xx_PCI_NR_PTMS 2
       
    53 
       
    54 struct PPC4xxPCIState {
       
    55     struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
       
    56     struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
       
    57 
       
    58     PCIHostState pci_state;
       
    59     PCIDevice *pci_dev;
       
    60 };
       
    61 typedef struct PPC4xxPCIState PPC4xxPCIState;
       
    62 
       
    63 #define PCIC0_CFGADDR       0x0
       
    64 #define PCIC0_CFGDATA       0x4
       
    65 
       
    66 /* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
       
    67  * PCI accesses. */
       
    68 #define PCIL0_PMM0LA        0x0
       
    69 #define PCIL0_PMM0MA        0x4
       
    70 #define PCIL0_PMM0PCILA     0x8
       
    71 #define PCIL0_PMM0PCIHA     0xc
       
    72 #define PCIL0_PMM1LA        0x10
       
    73 #define PCIL0_PMM1MA        0x14
       
    74 #define PCIL0_PMM1PCILA     0x18
       
    75 #define PCIL0_PMM1PCIHA     0x1c
       
    76 #define PCIL0_PMM2LA        0x20
       
    77 #define PCIL0_PMM2MA        0x24
       
    78 #define PCIL0_PMM2PCILA     0x28
       
    79 #define PCIL0_PMM2PCIHA     0x2c
       
    80 
       
    81 /* PCI Target Map (PTM) registers specify which PCI addresses are translated to
       
    82  * PLB accesses. */
       
    83 #define PCIL0_PTM1MS        0x30
       
    84 #define PCIL0_PTM1LA        0x34
       
    85 #define PCIL0_PTM2MS        0x38
       
    86 #define PCIL0_PTM2LA        0x3c
       
    87 #define PCI_REG_SIZE        0x40
       
    88 
       
    89 
       
    90 static uint32_t pci4xx_cfgaddr_readl(void *opaque, target_phys_addr_t addr)
       
    91 {
       
    92     PPC4xxPCIState *ppc4xx_pci = opaque;
       
    93 
       
    94     return ppc4xx_pci->pci_state.config_reg;
       
    95 }
       
    96 
       
    97 static CPUReadMemoryFunc *pci4xx_cfgaddr_read[] = {
       
    98     &pci4xx_cfgaddr_readl,
       
    99     &pci4xx_cfgaddr_readl,
       
   100     &pci4xx_cfgaddr_readl,
       
   101 };
       
   102 
       
   103 static void pci4xx_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
       
   104                                   uint32_t value)
       
   105 {
       
   106     PPC4xxPCIState *ppc4xx_pci = opaque;
       
   107 
       
   108 #ifdef TARGET_WORDS_BIGENDIAN
       
   109     value = bswap32(value);
       
   110 #endif
       
   111 
       
   112     ppc4xx_pci->pci_state.config_reg = value & ~0x3;
       
   113 }
       
   114 
       
   115 static CPUWriteMemoryFunc *pci4xx_cfgaddr_write[] = {
       
   116     &pci4xx_cfgaddr_writel,
       
   117     &pci4xx_cfgaddr_writel,
       
   118     &pci4xx_cfgaddr_writel,
       
   119 };
       
   120 
       
   121 static CPUReadMemoryFunc *pci4xx_cfgdata_read[] = {
       
   122     &pci_host_data_readb,
       
   123     &pci_host_data_readw,
       
   124     &pci_host_data_readl,
       
   125 };
       
   126 
       
   127 static CPUWriteMemoryFunc *pci4xx_cfgdata_write[] = {
       
   128     &pci_host_data_writeb,
       
   129     &pci_host_data_writew,
       
   130     &pci_host_data_writel,
       
   131 };
       
   132 
       
   133 static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset,
       
   134                                   uint32_t value)
       
   135 {
       
   136     struct PPC4xxPCIState *pci = opaque;
       
   137 
       
   138 #ifdef TARGET_WORDS_BIGENDIAN
       
   139     value = bswap32(value);
       
   140 #endif
       
   141 
       
   142     /* We ignore all target attempts at PCI configuration, effectively
       
   143      * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
       
   144 
       
   145     switch (offset) {
       
   146     case PCIL0_PMM0LA:
       
   147         pci->pmm[0].la = value;
       
   148         break;
       
   149     case PCIL0_PMM0MA:
       
   150         pci->pmm[0].ma = value;
       
   151         break;
       
   152     case PCIL0_PMM0PCIHA:
       
   153         pci->pmm[0].pciha = value;
       
   154         break;
       
   155     case PCIL0_PMM0PCILA:
       
   156         pci->pmm[0].pcila = value;
       
   157         break;
       
   158 
       
   159     case PCIL0_PMM1LA:
       
   160         pci->pmm[1].la = value;
       
   161         break;
       
   162     case PCIL0_PMM1MA:
       
   163         pci->pmm[1].ma = value;
       
   164         break;
       
   165     case PCIL0_PMM1PCIHA:
       
   166         pci->pmm[1].pciha = value;
       
   167         break;
       
   168     case PCIL0_PMM1PCILA:
       
   169         pci->pmm[1].pcila = value;
       
   170         break;
       
   171 
       
   172     case PCIL0_PMM2LA:
       
   173         pci->pmm[2].la = value;
       
   174         break;
       
   175     case PCIL0_PMM2MA:
       
   176         pci->pmm[2].ma = value;
       
   177         break;
       
   178     case PCIL0_PMM2PCIHA:
       
   179         pci->pmm[2].pciha = value;
       
   180         break;
       
   181     case PCIL0_PMM2PCILA:
       
   182         pci->pmm[2].pcila = value;
       
   183         break;
       
   184 
       
   185     case PCIL0_PTM1MS:
       
   186         pci->ptm[0].ms = value;
       
   187         break;
       
   188     case PCIL0_PTM1LA:
       
   189         pci->ptm[0].la = value;
       
   190         break;
       
   191     case PCIL0_PTM2MS:
       
   192         pci->ptm[1].ms = value;
       
   193         break;
       
   194     case PCIL0_PTM2LA:
       
   195         pci->ptm[1].la = value;
       
   196         break;
       
   197 
       
   198     default:
       
   199         printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
       
   200                (unsigned long)offset);
       
   201         break;
       
   202     }
       
   203 }
       
   204 
       
   205 static uint32_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset)
       
   206 {
       
   207     struct PPC4xxPCIState *pci = opaque;
       
   208     uint32_t value;
       
   209 
       
   210     switch (offset) {
       
   211     case PCIL0_PMM0LA:
       
   212         value = pci->pmm[0].la;
       
   213         break;
       
   214     case PCIL0_PMM0MA:
       
   215         value = pci->pmm[0].ma;
       
   216         break;
       
   217     case PCIL0_PMM0PCIHA:
       
   218         value = pci->pmm[0].pciha;
       
   219         break;
       
   220     case PCIL0_PMM0PCILA:
       
   221         value = pci->pmm[0].pcila;
       
   222         break;
       
   223 
       
   224     case PCIL0_PMM1LA:
       
   225         value = pci->pmm[1].la;
       
   226         break;
       
   227     case PCIL0_PMM1MA:
       
   228         value = pci->pmm[1].ma;
       
   229         break;
       
   230     case PCIL0_PMM1PCIHA:
       
   231         value = pci->pmm[1].pciha;
       
   232         break;
       
   233     case PCIL0_PMM1PCILA:
       
   234         value = pci->pmm[1].pcila;
       
   235         break;
       
   236 
       
   237     case PCIL0_PMM2LA:
       
   238         value = pci->pmm[2].la;
       
   239         break;
       
   240     case PCIL0_PMM2MA:
       
   241         value = pci->pmm[2].ma;
       
   242         break;
       
   243     case PCIL0_PMM2PCIHA:
       
   244         value = pci->pmm[2].pciha;
       
   245         break;
       
   246     case PCIL0_PMM2PCILA:
       
   247         value = pci->pmm[2].pcila;
       
   248         break;
       
   249 
       
   250     case PCIL0_PTM1MS:
       
   251         value = pci->ptm[0].ms;
       
   252         break;
       
   253     case PCIL0_PTM1LA:
       
   254         value = pci->ptm[0].la;
       
   255         break;
       
   256     case PCIL0_PTM2MS:
       
   257         value = pci->ptm[1].ms;
       
   258         break;
       
   259     case PCIL0_PTM2LA:
       
   260         value = pci->ptm[1].la;
       
   261         break;
       
   262 
       
   263     default:
       
   264         printf("%s: invalid PCI internal register 0x%lx\n", __func__,
       
   265                (unsigned long)offset);
       
   266         value = 0;
       
   267     }
       
   268 
       
   269 #ifdef TARGET_WORDS_BIGENDIAN
       
   270     value = bswap32(value);
       
   271 #endif
       
   272 
       
   273     return value;
       
   274 }
       
   275 
       
   276 static CPUReadMemoryFunc *pci_reg_read[] = {
       
   277     &ppc4xx_pci_reg_read4,
       
   278     &ppc4xx_pci_reg_read4,
       
   279     &ppc4xx_pci_reg_read4,
       
   280 };
       
   281 
       
   282 static CPUWriteMemoryFunc *pci_reg_write[] = {
       
   283     &ppc4xx_pci_reg_write4,
       
   284     &ppc4xx_pci_reg_write4,
       
   285     &ppc4xx_pci_reg_write4,
       
   286 };
       
   287 
       
   288 static void ppc4xx_pci_reset(void *opaque)
       
   289 {
       
   290     struct PPC4xxPCIState *pci = opaque;
       
   291 
       
   292     memset(pci->pmm, 0, sizeof(pci->pmm));
       
   293     memset(pci->ptm, 0, sizeof(pci->ptm));
       
   294 }
       
   295 
       
   296 /* On Bamboo, all pins from each slot are tied to a single board IRQ. This
       
   297  * may need further refactoring for other boards. */
       
   298 static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
       
   299 {
       
   300     int slot = pci_dev->devfn >> 3;
       
   301 
       
   302     DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
       
   303             pci_dev->devfn, irq_num, slot);
       
   304 
       
   305     return slot - 1;
       
   306 }
       
   307 
       
   308 static void ppc4xx_pci_set_irq(qemu_irq *pci_irqs, int irq_num, int level)
       
   309 {
       
   310     DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
       
   311     qemu_set_irq(pci_irqs[irq_num], level);
       
   312 }
       
   313 
       
   314 static void ppc4xx_pci_save(QEMUFile *f, void *opaque)
       
   315 {
       
   316     PPC4xxPCIState *controller = opaque;
       
   317     int i;
       
   318 
       
   319     pci_device_save(controller->pci_dev, f);
       
   320 
       
   321     for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
       
   322         qemu_put_be32s(f, &controller->pmm[i].la);
       
   323         qemu_put_be32s(f, &controller->pmm[i].ma);
       
   324         qemu_put_be32s(f, &controller->pmm[i].pcila);
       
   325         qemu_put_be32s(f, &controller->pmm[i].pciha);
       
   326     }
       
   327 
       
   328     for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
       
   329         qemu_put_be32s(f, &controller->ptm[i].ms);
       
   330         qemu_put_be32s(f, &controller->ptm[i].la);
       
   331     }
       
   332 }
       
   333 
       
   334 static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id)
       
   335 {
       
   336     PPC4xxPCIState *controller = opaque;
       
   337     int i;
       
   338 
       
   339     if (version_id != 1)
       
   340         return -EINVAL;
       
   341 
       
   342     pci_device_load(controller->pci_dev, f);
       
   343 
       
   344     for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
       
   345         qemu_get_be32s(f, &controller->pmm[i].la);
       
   346         qemu_get_be32s(f, &controller->pmm[i].ma);
       
   347         qemu_get_be32s(f, &controller->pmm[i].pcila);
       
   348         qemu_get_be32s(f, &controller->pmm[i].pciha);
       
   349     }
       
   350 
       
   351     for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
       
   352         qemu_get_be32s(f, &controller->ptm[i].ms);
       
   353         qemu_get_be32s(f, &controller->ptm[i].la);
       
   354     }
       
   355 
       
   356     return 0;
       
   357 }
       
   358 
       
   359 /* XXX Interrupt acknowledge cycles not supported. */
       
   360 PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
       
   361                         target_phys_addr_t config_space,
       
   362                         target_phys_addr_t int_ack,
       
   363                         target_phys_addr_t special_cycle,
       
   364                         target_phys_addr_t registers)
       
   365 {
       
   366     PPC4xxPCIState *controller;
       
   367     int index;
       
   368     static int ppc4xx_pci_id;
       
   369 
       
   370     controller = qemu_mallocz(sizeof(PPC4xxPCIState));
       
   371     if (!controller)
       
   372         return NULL;
       
   373 
       
   374     controller->pci_state.bus = pci_register_bus(ppc4xx_pci_set_irq,
       
   375                                                  ppc4xx_pci_map_irq,
       
   376                                                  pci_irqs, 0, 4);
       
   377 
       
   378     controller->pci_dev = pci_register_device(controller->pci_state.bus,
       
   379                                               "host bridge", sizeof(PCIDevice),
       
   380                                               0, NULL, NULL);
       
   381     controller->pci_dev->config[0x00] = 0x14; // vendor_id
       
   382     controller->pci_dev->config[0x01] = 0x10;
       
   383     controller->pci_dev->config[0x02] = 0x7f; // device_id
       
   384     controller->pci_dev->config[0x03] = 0x02;
       
   385     controller->pci_dev->config[0x0a] = 0x80; // class_sub = other bridge type
       
   386     controller->pci_dev->config[0x0b] = 0x06; // class_base = PCI_bridge
       
   387 
       
   388     /* CFGADDR */
       
   389     index = cpu_register_io_memory(0, pci4xx_cfgaddr_read,
       
   390                                    pci4xx_cfgaddr_write, controller);
       
   391     if (index < 0)
       
   392         goto free;
       
   393     cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
       
   394 
       
   395     /* CFGDATA */
       
   396     index = cpu_register_io_memory(0, pci4xx_cfgdata_read,
       
   397                                    pci4xx_cfgdata_write,
       
   398                                    &controller->pci_state);
       
   399     if (index < 0)
       
   400         goto free;
       
   401     cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
       
   402 
       
   403     /* Internal registers */
       
   404     index = cpu_register_io_memory(0, pci_reg_read, pci_reg_write, controller);
       
   405     if (index < 0)
       
   406         goto free;
       
   407     cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
       
   408 
       
   409     qemu_register_reset(ppc4xx_pci_reset, controller);
       
   410 
       
   411     /* XXX load/save code not tested. */
       
   412     register_savevm("ppc4xx_pci", ppc4xx_pci_id++, 1,
       
   413                     ppc4xx_pci_save, ppc4xx_pci_load, controller);
       
   414 
       
   415     return controller->pci_state.bus;
       
   416 
       
   417 free:
       
   418     printf("%s error\n", __func__);
       
   419     qemu_free(controller);
       
   420     return NULL;
       
   421 }