⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcilib.c

📁 source code of armboot for s3c4510
💻 C
📖 第 1 页 / 共 3 页
字号:
    if (val < align)
        return align;
    // ...finally, if there is need to move the value upwards, do so...
    if ((val & ~(align - 1)) != 0)
        return (((val) + ((align) - 1)) & ~((align) - 1));
    else
        return val;
}


/*============================================================================
 *
 *  description: Allocate space in PCI IO memory
 *
 *  returns:     Where in PCI memory allocated
 *
 *  Note: Calling this code has a side effect of moving the global
 *        IO base on.
 */
UINT32 PCIir_AllocateIOSpace (UINT32 size)
{
    UINT32 alignto;
    UINT32 base;

    // align in minimum sized chunks of DEFAULT_IO_ALIGNMENT
    alignto = MAX (size, DEFAULT_IO_ALIGNMENT);
    base = ALIGN (g_u32PciIoBase, alignto);
    g_u32PciIoBase = base + size;

    return base;
}


/*============================================================================
 *
 *  description: Allocate space in PCI memory
 *
 *  returns:     Where in PCI memory allocated
 *
 *  Note: Calling this code has a side effect of moving the global
 *        Memory base on.
 */
static UINT32 PCIir_AllocateMemSpace (UINT32 size)
{
    UINT32 alignto;
    UINT32 base;


    // align in minimum sized chunks of DEFAULT_MEMORY_ALIGNMENT
    alignto = MAX (size, DEFAULT_MEMORY_ALIGNMENT);
    base = ALIGN (g_u32PciMemBase, alignto);
    g_u32PciMemBase = base + size;

    return base;
}


/*============================================================================
 *
 * description: this routine will attempt to glean resource requirements
 *      from the device pointed to by handle
 *
 * returns: void
 */
void PCIir_AssignResources (PCIDevice_t * device)
{
    UINT32 base, mask, size;
    int i;
    UINT32 barFlag = 0;
    UINT32 slot,offset, func, bus, PciCommandData,PciVendorID;
    UINT16 RomDataAtZero=0;


    /* set up the bus, slot and func */
    bus = device->bus;
    slot = device->slot;
    func = device->func;


    /* Disable PCI IO and memory accesses */
    PciCommandData = ((~0x3)&PCICFG_Read16(bus, slot, func, PCIHCMD_OFF));
    PCICFG_Write16 (bus, slot, func, PCIHCMD_OFF, PciCommandData);

    /* allocate an irq number */
    if (slot!=0)
         PCIir_AllocateInterrupt (device);

    offset = PCIHBAR0_OFF;
    /* Scan each of the BARS for this device */
    for (i = 0; i < PCI_MAX_BAR; i++)
    {
        /* write PCI_INVALID to BAR to get size, then read it back */
        PCICFG_Write32 (bus, slot, func, offset, PCI_INVALID);

        base = PCICFG_Read32 (bus, slot, func, offset);
        /* check if this is an implemented BAR (size != 0) */
        if (base != 0)
        {
            /* Assign some PCI memory (IO or Memory) space to this BAR */
            if (base & PCI_IO_ENABLE)
            {
                /* ******************** IO space BAR ******************** */
                /* The bottom 2 bits of the BAR for PCI IO look like this:
                    0    must be 1 (0 = memory, 1 = IO)
                    1    reserved */

                /* figure out how much memory is wanted */
                base &= ~0x3;
                mask = (~base << 1) | 0x1;
                size = (mask & base) & 0xFFFFFFFF;

                Print("\nslot[%2x], func[%x], iosize[%8x]", slot, func, size);

                /* allocate (aligned) space in IO */
                base = PCIir_AllocateIOSpace (size);
                PCICFG_Write32 (bus, slot, func, offset, base | 0x1);
                barFlag |= PCI_IO_ENABLE;
                PciVendorID = PCICFG_Read16(bus,slot, func, PCIHVID_OFF);
            }
            else//  if (base & PCI_IO_ENABLE)
            {
                /* ******************** MEM space BAR ******************** */
                /* WARNING: I assume only one type of memory - dangerous! */
                UINT32 type;

                /* The bottom 4 bits of the BAR for PCI memory look like this:
                    0    must be zero (0 = memory, 1 = IO)
                    1:2  type of space needed
                    (00 = 32 bit, 01 = below 1M, 10 = 64 bit address)
                    3    prefetchable */

                type = base & 0x6;
                base &= (~0xf);
                mask = (~base << 1) | 0x1;
                size = (mask & base) & 0xFFFFFFFF;

                Print("\nslot[%2x], func[%x], memsize[%8x]", slot, func, size);

                /* cope (or rather don't) with different flavours of memory */
                switch (type)
                {
                    case 0x00:  /* 32 bit */
                        break;
                    case 0x02:  /* below 1M */
                        continue;
                    case 0x04:  /* 64 bit */
                        offset += 4;
                        continue;
                    default:
                        continue;
                }
                /* allocate some (aligned) space in PCI memory */
                base = PCIir_AllocateMemSpace (size);
                PCICFG_Write32 (bus, slot, func, offset, base);

                barFlag |= PCI_MEM_ENABLE;
            }
        }   //end (base != 0)
        /* increment the BAR offset value */
        offset += 4;
    }

    /* now do the ROM stuff */
    //To Prevent the enabling of the ROM address decoder
    //??PCIHEXPR_OFF
    PCICFG_Write32 (bus,  slot, func, PCIHEXPR_OFF, (PCI_INVALID&0xfffffffe));
    base = PCICFG_Read32 (bus, slot, func, PCIHEXPR_OFF);
    if (base & ~PCI_EXP_ROM_ENABLE)
    {
        // valid ROM space, figure out how much it wants/needs
        base &= ~PCI_EXP_ROM_ENABLE;
        size = (~base + 1);

        Print("\nslot=%2x, romsize=%8x\n", slot, size);

        // Allocate some (aligned) memory space
        base = PCIir_AllocateMemSpace (size);

        // Let the device see it, but don't enable accesses.
        // This is because, according to the specification,
        // the device may share an address decoder between
        // the Expansion ROM base and other base address
        // registers.  In other words, any device driver wishing
        // to access the ROM must set the enable bit (bit 0) before
        // proceeding and clear it afterwards.
        PCICFG_Write32 (bus, slot, func, PCIHEXPR_OFF, base + PCI_EXP_ROM_ENABLE);

        // ROM gets added to PCI memory, so allow accesses
        barFlag |= PCI_MEM_ENABLE;
        RomDataAtZero = *(UINT16 *)AHB_2_PCI_MEM(base);
        if (RomDataAtZero== EXPROM_INSERTED)
        {
                ;
                /*======================================================
                    - A code image must be copied into system DRAM and its initialization code must
                        be executed.
                    - In a PC environment, the ROM code image must be copied into RAM Address :
                        0x000C_0000 ~ 0x000D_FFFF.
                    - If the class code indiacate this is VGA device's ROM, its code image must be copied
                        into memory starting at location 0x000C_0000
                =======================================================*/
        }
    }
    /* Enable PCI IO and memory accesses as found by scan, with MASTER */
    barFlag |= PCI_MASTER_ENABLE;
    PCICFG_Write16 (bus, slot, func, PCIHCMD_OFF, (PciCommandData|barFlag));
    PCICFG_Write8 (bus, slot, func, PCIHCMD_OFF, 0xFF);
    //Disable the ROM Address Decoder.
     PCICFG_Write32 (bus, slot, func, PCIHEXPR_OFF, ~PCI_EXP_ROM_ENABLE);
}


/*============================================================================
 *
 *  description: Allocate an interrupt #
 *
 *  returns:     void
 *
 */

void PCIir_AllocateInterrupt (PCIDevice_t * device)
{
    PCIDevice_t *curr;
    UINT8 pin;
    UINT8 interrupt;


    // read the interrupt pin from the device
    pin = PCICFG_Read8 (device->bus, device->slot, device->func, PCIHINTPIN_OFF);

    // figure out the interrupt number
    if (device->bus == 0)
    {
        // Primary bus
        //   pin is this device's pin
        //   curr is this device
        curr = device;
    }
    else
    {
        // Secondary bus or beyond
        curr = device;
        while (curr->bus != 0)
        {
            // swizzle the interrupt pins through each PCI-PCI bridge
            pin = bridgeSwizzle (pin, curr->slot);
            curr = curr->parent;
        }
        // pin is now the pin of the last bridge
        // curr is the last PCI-PCI bridge
    }

    // work out the interrupt number from the slot/pin
    // ??
    interrupt = PCIMapInterrupt(pin, curr->slot);

    // write it to the device (this will be read later by a device driver)
    PCICFG_Write8(device->bus, device->slot, device->func, PCIHINTLINE_OFF, interrupt);
}


/*============================================================================
 *
 * A small note about bridges and interrupts.    The DECchip 21050 (and later chips)
 * adheres to the PCI-PCI bridge specification.   This says that the interrupts on
 * the other side of a bridge are swizzled in the following manner:
 *
 * Dev    Interrupt   Interrupt
 *        Pin on      Pin on
 *        Device      Connector
 *
 *   4    A           A
 *        B           B
 *        C           C
 *        D           D
 *
 *   5    A           B
 *        B           C
 *        C           D
 *        D           A
 *
 *   6    A           C
 *        B           D
 *        C           A
 *        D           B
 *
 *   7    A           D
 *        B           A
 *        C           B
 *        D           C
 *
 *   Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
 *   Thus, each swizzle is ((pin-1) + (device#-4)) % 4
 *
 */
UINT8 bridgeSwizzle (UINT8 pin, UINT32 slot)
{
    return (((pin - 1) + slot) % 4) + 1;
}


/*============================================================================
 *
 * parameters:  bus = which pin (A=1, B=2, C=3, D=4)
 *              slot = which slot (IDSEL = slot + 11)
 *
 * description: this routine returns the interrupt # that this slot/pin
 *              combination will use.
 *              S3C2510X have only one PCI interrupt input pin(PCI_nINTA),
 *              so we may not use interrupt mapping.
 *              But for further system or controller,we prepare this routine.
 *
 * calls:   none
 *
 * returns: Board specific interrupt #
 *
 */

UINT8 PCIMapInterrupt(UINT8 pin, UINT8 slot)
{
    static const UINT8 s_u8IrqTab[21][4] =  {
        // INTA  INTB  INTC  INTD
        {INTA, INTB, INTC, INTD},  // idsel 11, slot  0
        {INTB, INTC, INTD, INTA},  // idsel 12, slot  1
        {INTC, INTD, INTA, INTB},  // idsel 13, slot  2
        {INTD, INTA, INTB, INTC},  // idsel 14, slot  3
        {INTA, INTB, INTC, INTD},  // idsel 15, slot  4
        {INTB, INTC, INTD, INTA},  // idsel 16, slot  5
        {INTC, INTD, INTA, INTB},  // idsel 17, slot  6
        {INTD, INTA, INTB, INTC},  // idsel 18, slot  7
        {INTA, INTB, INTC, INTD},  // idsel 19, slot  8
        {INTB, INTC, INTD, INTA},  // idsel 20, slot  9
        {INTC, INTD, INTA, INTB},  // idsel 21, slot 10
        {INTD, INTA, INTB, INTC},  // idsel 22, slot 11
        {INTA, INTB, INTC, INTD},  // idsel 23, slot 12
        {INTB, INTC, INTD, INTA},  // idsel 24, slot 13
        {INTC, INTD, INTA, INTB},  // idsel 25, slot 14
        {INTD, INTA, INTB, INTC},  // idsel 26, slot 15
        {INTA, INTB, INTC, INTD},  // idsel 27, slot 16
        {INTB, INTC, INTD, INTA},  // idsel 28, slot 17
        {INTC, INTD, INTA, INTB},  // idsel 29, slot 18
        {INTD, INTA, INTB, INTC},  // idsel 30, slot 19
        {INTA, INTB, INTC, INTD}   // idsel 31, slot 20
    };

    // if PIN = 0, default to A ,Pin=0 means ,this devices dose not use interrupt pin
    if (pin == 0)
        pin = 1;

    // return the magic number
    return s_u8IrqTab[slot][pin - 1];
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -