Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:12

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief PCI Access Methods
0007  *
0008  * Routines to access PCI memory/configuration space and other PCI related
0009  * functions the PCI Library provides.
0010  */
0011 
0012 /*
0013  * COPYRIGHT (c) 2010 Cobham Gaisler AB.
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 
0038 #ifndef __PCI_ACCESS_H__
0039 #define __PCI_ACCESS_H__
0040 
0041 #include <stdint.h>
0042 #include <libcpu/byteorder.h>
0043 #include <rtems/score/basedefs.h>
0044 #include <pci.h>
0045 
0046 #ifdef __cplusplus
0047 extern "C" {
0048 #endif
0049 
0050 /* Identification of a PCI configuration space device (16-bit) */
0051 typedef uint16_t pci_dev_t;
0052 /* Create a PCI Configuration Space ID */
0053 #define PCI_DEV(bus, slot, func) (((bus)<<8) | ((slot)<<3) | (func))
0054 /* Get Bus of a PCI Configuration Space ID */
0055 #define PCI_DEV_BUS(dev) (((dev) >> 8) & 0xff)
0056 /* Get Slot/Device of a PCI Configuration Space ID */
0057 #define PCI_DEV_SLOT(dev) (((dev) >> 3) & 0x1f)
0058 /* Get Function of a PCI Configuration Space ID */
0059 #define PCI_DEV_FUNC(dev) ((dev) & 0x7)
0060 /* Get Device and Function of a PCI Configuration Space ID */
0061 #define PCI_DEV_DEVFUNC(dev) ((dev) & 0xff)
0062 /* Expand Device into argument lists */
0063 #define PCI_DEV_EXPAND(dev) PCI_DEV_BUS((dev)), PCI_DEV_SLOT((dev)), PCI_DEV_FUNC((dev))
0064 
0065 /* Configuration Space Read/Write Operations */
0066 struct pci_cfg_ops {
0067     /* Configuration Space Access and Setup Routines */
0068     int (*read8)(pci_dev_t dev, int ofs, uint8_t *data);
0069     int (*read16)(pci_dev_t dev, int ofs, uint16_t *data);
0070     int (*read32)(pci_dev_t dev, int ofs, uint32_t *data);
0071     int (*write8)(pci_dev_t dev, int ofs, uint8_t data);
0072     int (*write16)(pci_dev_t dev, int ofs, uint16_t data);
0073     int (*write32)(pci_dev_t dev, int ofs, uint32_t data);
0074 };
0075 
0076 /* Read a register over PCI I/O Space, and swap it if necessary (due to 
0077  * PCI endianness)
0078  */
0079 struct pci_io_ops {
0080     uint8_t (*read8)(uint8_t *adr);
0081     uint16_t(*read16)(uint16_t *adr);
0082     uint32_t (*read32)(uint32_t *adr);
0083     void (*write8)(uint8_t *adr, uint8_t data);
0084     void (*write16)(uint16_t *adr, uint16_t data);
0085     void (*write32)(uint32_t *adr, uint32_t data);
0086 };
0087 
0088 /* Read a register over PCI Memory Space (non-prefetchable memory), and 
0089  * swap it if necessary (due to PCI endianness)
0090  */
0091 struct pci_memreg_ops {
0092     uint8_t (*ld8)(uint8_t *adr);
0093     void (*st8)(uint8_t *adr, uint8_t data);
0094 
0095     uint16_t(*ld_le16)(uint16_t *adr);
0096     void (*st_le16)(uint16_t *adr, uint16_t data);
0097     uint16_t(*ld_be16)(uint16_t *adr);
0098     void (*st_be16)(uint16_t *adr, uint16_t data);
0099 
0100     uint32_t (*ld_le32)(uint32_t *adr);
0101     void (*st_le32)(uint32_t *adr, uint32_t data);
0102     uint32_t (*ld_be32)(uint32_t *adr);
0103     void (*st_be32)(uint32_t *adr, uint32_t data);
0104 };
0105 
0106 typedef uint8_t (*pci_ld8_t)(uint8_t *adr);
0107 typedef void (*pci_st8_t)(uint8_t *adr, uint8_t data);
0108 typedef uint16_t(pci_ld16_t)(uint16_t *adr);
0109 typedef void (*pci_st16_t)(uint16_t *adr, uint16_t data);
0110 typedef uint32_t (*pci_ld32_t)(uint32_t *adr);
0111 typedef void (*pci_st32_t)(uint32_t *adr, uint32_t data);
0112 
0113 struct pci_access_drv {
0114     /* Configuration */
0115     struct pci_cfg_ops cfg;
0116 
0117     /* I/O Access operations */
0118     struct pci_io_ops io;
0119 
0120     /* Registers over Memory Access operations. Note that these funcs
0121      * are only for code that need to be compatible with both Big-Endian
0122      * and Little-Endian PCI bus or for some other reason need function
0123      * pointers to access functions. Normally drivers use the inline
0124      * functions for Registers-over-Memory access to avoid extra function
0125      * call.
0126      */
0127     struct pci_memreg_ops *memreg;
0128 
0129     /* Translate from PCI address to CPU address (dir=0). Translate
0130      * CPU address to PCI address (dir!=0). The address will can be
0131      * used to perform I/O access or memory access by CPU or PCI DMA
0132      * peripheral.
0133      *
0134      * address    In/Out. CPU address or PCI address.
0135      * type       Access type. 1=I/O, 2=MEMIO, 3=MEM
0136      * dir        Translate direction. 0=PCI-to-CPU, 0!=CPU-to-PCI,
0137      *
0138      * Return Value
0139      *  0   = Success
0140      *  -1  = Requested Address not mapped into other address space
0141      *        i.e. not accessible
0142      */
0143     int (*translate)(uint32_t *address, int type, int dir);
0144 };
0145 
0146 /* Access Routines valid after a PCI-Access-Driver has registered */
0147 extern struct pci_access_drv pci_access_ops;
0148 
0149 /* Register PCI Access Driver */
0150 extern int pci_access_drv_register(struct pci_access_drv *drv);
0151 
0152 /* Set/unset bits in command and status register of a PCI device */
0153 extern void pci_modify_cmdsts(pci_dev_t dev, uint32_t mask, uint32_t val);
0154 
0155 /* Enable Memory in command register */
0156 static inline void pci_mem_enable(pci_dev_t dev)
0157 {
0158     pci_modify_cmdsts(dev, PCIM_CMD_MEMEN, PCIM_CMD_MEMEN);
0159 }
0160 
0161 static inline void pci_mem_disable(pci_dev_t dev)
0162 {
0163     pci_modify_cmdsts(dev, PCIM_CMD_MEMEN, 0);
0164 }
0165 
0166 static inline void pci_io_enable(pci_dev_t dev)
0167 {
0168     pci_modify_cmdsts(dev, PCIM_CMD_PORTEN, PCIM_CMD_PORTEN);
0169 }
0170 
0171 static inline void pci_io_disable(pci_dev_t dev)
0172 {
0173     pci_modify_cmdsts(dev, PCIM_CMD_PORTEN, 0);
0174 }
0175 
0176 static inline void pci_master_enable(pci_dev_t dev)
0177 {
0178     pci_modify_cmdsts(dev, PCIM_CMD_BUSMASTEREN, PCIM_CMD_BUSMASTEREN);
0179 }
0180 
0181 static inline void pci_master_disable(pci_dev_t dev)
0182 {
0183     pci_modify_cmdsts(dev, PCIM_CMD_BUSMASTEREN, 0);
0184 }
0185 
0186 /* Configuration Space Access Read Routines */
0187 extern int pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *data);
0188 extern int pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *data);
0189 extern int pci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *data);
0190 
0191 /* Configuration Space Access Write Routines */
0192 extern int pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t data);
0193 extern int pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t data);
0194 extern int pci_cfg_w32(pci_dev_t dev, int ofs, uint32_t data);
0195 
0196 /* Read a register over PCI I/O Space */
0197 extern uint8_t pci_io_r8(uint32_t adr);
0198 extern uint16_t pci_io_r16(uint32_t adr);
0199 extern uint32_t pci_io_r32(uint32_t adr);
0200 
0201 /* Write a register over PCI I/O Space */
0202 extern void pci_io_w8(uint32_t adr, uint8_t data);
0203 extern void pci_io_w16(uint32_t adr, uint16_t data);
0204 extern void pci_io_w32(uint32_t adr, uint32_t data);
0205 
0206 /* Translate PCI address into CPU accessible address */
0207 static inline int pci_pci2cpu(uint32_t *address, int type)
0208 {
0209     return pci_access_ops.translate(address, type, 0);
0210 }
0211 
0212 /* Translate CPU accessible address into PCI address (for DMA) */
0213 static inline int pci_cpu2pci(uint32_t *address, int type)
0214 {
0215     return pci_access_ops.translate(address, type, 1);
0216 }
0217 
0218 /*** Read/Write a register over PCI Memory Space ***/
0219 
0220 static inline uint8_t pci_ld8(volatile uint8_t *addr)
0221 {
0222     return *addr;
0223 }
0224 
0225 static inline void pci_st8(volatile uint8_t *addr, uint8_t val)
0226 {
0227     *addr = val;
0228 }
0229 
0230 /* Registers-over-Memory Space access routines. The routines are not inlined
0231  * so it is possible during run-time to select which function implemention
0232  * to use. The use of these functions are not recommended since it will have a
0233  * performance penalty.
0234  *
0235  * 8-bit accesses are the same for Little and Big endian PCI buses.
0236  */
0237 uint8_t pci_mem_ld8(uint8_t *adr);
0238 void pci_mem_st8(uint8_t *adr, uint8_t data);
0239 /* Registers-over-Memory Space - Generic Big endian PCI bus definitions */
0240 uint16_t pci_mem_be_ld_le16(uint16_t *adr);
0241 uint16_t pci_mem_be_ld_be16(uint16_t *adr);
0242 uint32_t pci_mem_be_ld_le32(uint32_t *adr);
0243 uint32_t pci_mem_be_ld_be32(uint32_t *adr);
0244 void pci_mem_be_st_le16(uint16_t *adr, uint16_t data);
0245 void pci_mem_be_st_be16(uint16_t *adr, uint16_t data);
0246 void pci_mem_be_st_le32(uint32_t *adr, uint32_t data);
0247 void pci_mem_be_st_be32(uint32_t *adr, uint32_t data);
0248 /* Registers-over-Memory Space - Generic Little endian PCI bus definitions */
0249 uint16_t pci_mem_le_ld_le16(uint16_t *adr);
0250 uint16_t pci_mem_le_ld_be16(uint16_t *adr);
0251 uint32_t pci_mem_le_ld_le32(uint32_t *adr);
0252 uint32_t pci_mem_le_ld_be32(uint32_t *adr);
0253 void pci_mem_le_st_le16(uint16_t *adr, uint16_t data);
0254 void pci_mem_le_st_be16(uint16_t *adr, uint16_t data);
0255 void pci_mem_le_st_le32(uint32_t *adr, uint32_t data);
0256 void pci_mem_le_st_be32(uint32_t *adr, uint32_t data);
0257 
0258 /* Get Read/Write function for accessing a register over PCI Memory Space
0259  * (non-inline functions).
0260  *
0261  * Arguments
0262  *  wr             0(Read), 1(Write)
0263  *  size           1(Byte), 2(Word), 4(Double Word)
0264  *  func           Where function pointer will be stored
0265  *  endian         PCI_LITTLE_ENDIAN or PCI_BIG_ENDIAN
0266  *  type           1(I/O), 3(REG over MEM), 4(CFG)
0267  *
0268  * Return
0269  *  0              Found function
0270  *  others         No such function defined by host driver or BSP
0271  */
0272 extern int pci_access_func(int wr, int size, void **func, int endian, int type);
0273 
0274 /* Predefined functions for Host drivers or BSPs that define the 
0275  * register-over-memory space functions operations.
0276  */
0277 extern struct pci_memreg_ops pci_mem_le_ops; /* For Little-Endian PCI bus */
0278 extern struct pci_memreg_ops pci_mem_be_ops; /* For Big-Endian PCI bus */
0279 
0280 #ifdef __cplusplus
0281 }
0282 #endif
0283 
0284 #endif /* !__PCI_ACCESS_H__ */