[a31845f7] | 1 | /* Routines to access PCI memory/configuration space and other PCI related |
---|
| 2 | * functions the PCI Library provides. |
---|
| 3 | * |
---|
| 4 | * COPYRIGHT (c) 2010. |
---|
| 5 | * Cobham Gaisler AB. |
---|
| 6 | * |
---|
| 7 | * The license and distribution terms for this file may be |
---|
| 8 | * found in the file LICENSE in this distribution or at |
---|
| 9 | * http://www.rtems.com/license/LICENSE. |
---|
| 10 | */ |
---|
| 11 | |
---|
| 12 | |
---|
| 13 | #ifndef __PCI_ACCESS_H__ |
---|
| 14 | #define __PCI_ACCESS_H__ |
---|
| 15 | |
---|
| 16 | #include <stdint.h> |
---|
| 17 | #include <libcpu/byteorder.h> |
---|
| 18 | #include <pci.h> |
---|
| 19 | |
---|
| 20 | /* Let BSP configure load/store from PCI */ |
---|
| 21 | #include <bsp.h> |
---|
| 22 | |
---|
| 23 | #ifdef __cplusplus |
---|
| 24 | extern "C" { |
---|
| 25 | #endif |
---|
| 26 | |
---|
| 27 | /* Identification of a PCI configuration space device (16-bit) */ |
---|
| 28 | typedef uint16_t pci_dev_t; |
---|
| 29 | /* Create a PCI Configuration Space ID */ |
---|
| 30 | #define PCI_DEV(bus, slot, func) (((bus)<<8) | ((slot)<<3) | (func)) |
---|
| 31 | /* Get Bus of a PCI Configuration Space ID */ |
---|
| 32 | #define PCI_DEV_BUS(dev) (((dev) >> 8) & 0xff) |
---|
| 33 | /* Get Slot/Device of a PCI Configuration Space ID */ |
---|
| 34 | #define PCI_DEV_SLOT(dev) (((dev) >> 3) & 0x1f) |
---|
| 35 | /* Get Function of a PCI Configuration Space ID */ |
---|
| 36 | #define PCI_DEV_FUNC(dev) ((dev) & 0x7) |
---|
| 37 | /* Get Device and Function of a PCI Configuration Space ID */ |
---|
| 38 | #define PCI_DEV_DEVFUNC(dev) ((dev) & 0xff) |
---|
| 39 | /* Expand Device into argument lists */ |
---|
| 40 | #define PCI_DEV_EXPAND(dev) PCI_DEV_BUS((dev)), PCI_DEV_SLOT((dev)), PCI_DEV_FUNC((dev)) |
---|
| 41 | |
---|
| 42 | /* Configuration Space Read/Write Operations */ |
---|
| 43 | struct pci_cfg_ops { |
---|
| 44 | /* Configuration Space Access and Setup Routines */ |
---|
| 45 | int (*read8)(pci_dev_t dev, int ofs, uint8_t *data); |
---|
| 46 | int (*read16)(pci_dev_t dev, int ofs, uint16_t *data); |
---|
| 47 | int (*read32)(pci_dev_t dev, int ofs, uint32_t *data); |
---|
| 48 | int (*write8)(pci_dev_t dev, int ofs, uint8_t data); |
---|
| 49 | int (*write16)(pci_dev_t dev, int ofs, uint16_t data); |
---|
| 50 | int (*write32)(pci_dev_t dev, int ofs, uint32_t data); |
---|
| 51 | }; |
---|
| 52 | |
---|
| 53 | /* Read a register over PCI I/O Space, and swap it if necessary (due to |
---|
| 54 | * PCI endianness) |
---|
| 55 | */ |
---|
| 56 | struct pci_io_ops { |
---|
| 57 | uint8_t (*read8)(uint8_t *adr); |
---|
| 58 | uint16_t(*read16)(uint16_t *adr); |
---|
| 59 | uint32_t (*read32)(uint32_t *adr); |
---|
| 60 | void (*write8)(uint8_t *adr, uint8_t data); |
---|
| 61 | void (*write16)(uint16_t *adr, uint16_t data); |
---|
| 62 | void (*write32)(uint32_t *adr, uint32_t data); |
---|
| 63 | }; |
---|
| 64 | |
---|
| 65 | /* Read a register over PCI Memory Space (non-prefetchable memory), and |
---|
| 66 | * swap it if necessary (due to PCI endianness) |
---|
| 67 | */ |
---|
| 68 | struct pci_memreg_ops { |
---|
| 69 | uint8_t (*ld8)(uint8_t *adr); |
---|
| 70 | void (*st8)(uint8_t *adr, uint8_t data); |
---|
| 71 | |
---|
| 72 | uint16_t(*ld_le16)(uint16_t *adr); |
---|
| 73 | void (*st_le16)(uint16_t *adr, uint16_t data); |
---|
| 74 | uint16_t(*ld_be16)(uint16_t *adr); |
---|
| 75 | void (*st_be16)(uint16_t *adr, uint16_t data); |
---|
| 76 | |
---|
| 77 | uint32_t (*ld_le32)(uint32_t *adr); |
---|
| 78 | void (*st_le32)(uint32_t *adr, uint32_t data); |
---|
| 79 | uint32_t (*ld_be32)(uint32_t *adr); |
---|
| 80 | void (*st_be32)(uint32_t *adr, uint32_t data); |
---|
| 81 | }; |
---|
| 82 | |
---|
| 83 | typedef uint8_t (*pci_ld8_t)(uint8_t *adr); |
---|
| 84 | typedef void (*pci_st8_t)(uint8_t *adr, uint8_t data); |
---|
| 85 | typedef uint16_t(pci_ld16_t)(uint16_t *adr); |
---|
| 86 | typedef void (*pci_st16_t)(uint16_t *adr, uint16_t data); |
---|
| 87 | typedef uint32_t (*pci_ld32_t)(uint32_t *adr); |
---|
| 88 | typedef void (*pci_st32_t)(uint32_t *adr, uint32_t data); |
---|
| 89 | |
---|
| 90 | struct pci_access_drv { |
---|
| 91 | /* Configuration */ |
---|
| 92 | struct pci_cfg_ops cfg; |
---|
| 93 | |
---|
| 94 | /* I/O Access operations */ |
---|
| 95 | struct pci_io_ops io; |
---|
| 96 | |
---|
| 97 | /* Registers over Memory Access operations. Note that these funcs |
---|
| 98 | * are only for code that need to be compatible with both Big-Endian |
---|
| 99 | * and Little-Endian PCI bus or for some other reason need function |
---|
| 100 | * pointers to access functions. Normally drivers use the inline |
---|
| 101 | * functions for Registers-over-Memory access to avoid extra function |
---|
| 102 | * call. |
---|
| 103 | */ |
---|
| 104 | struct pci_memreg_ops *memreg; |
---|
| 105 | |
---|
| 106 | /* Translate from PCI address to CPU address (dir=0). Translate |
---|
| 107 | * CPU address to PCI address (dir!=0). The address will can be |
---|
| 108 | * used to perform I/O access or memory access by CPU or PCI DMA |
---|
| 109 | * peripheral. |
---|
| 110 | * |
---|
| 111 | * address In/Out. CPU address or PCI address. |
---|
| 112 | * type Access type. 1=I/O, 2=MEMIO, 3=MEM |
---|
| 113 | * dir Translate direction. 0=PCI-to-CPU, 0!=CPU-to-PCI, |
---|
| 114 | * |
---|
| 115 | * Return Value |
---|
| 116 | * 0 = Success |
---|
| 117 | * -1 = Requested Address not mapped into other address space |
---|
| 118 | * i.e. not accessible |
---|
| 119 | */ |
---|
| 120 | int (*translate)(uint32_t *address, int type, int dir); |
---|
| 121 | }; |
---|
| 122 | |
---|
| 123 | /* Access Routines valid after a PCI-Access-Driver has registered */ |
---|
| 124 | extern struct pci_access_drv pci_access_ops; |
---|
| 125 | |
---|
| 126 | /* Register PCI Access Driver */ |
---|
| 127 | extern int pci_access_drv_register(struct pci_access_drv *drv); |
---|
| 128 | |
---|
| 129 | /* Set/unset bits in command and status register of a PCI device */ |
---|
| 130 | extern void pci_modify_cmdsts(pci_dev_t dev, uint32_t mask, uint32_t val); |
---|
| 131 | |
---|
| 132 | /* Enable Memory in command register */ |
---|
| 133 | static inline void pci_mem_enable(pci_dev_t dev) |
---|
| 134 | { |
---|
| 135 | pci_modify_cmdsts(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MEMORY); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | static inline void pci_mem_disable(pci_dev_t dev) |
---|
| 139 | { |
---|
| 140 | pci_modify_cmdsts(dev, PCI_COMMAND_MEMORY, 0); |
---|
| 141 | } |
---|
| 142 | |
---|
| 143 | static inline void pci_io_enable(pci_dev_t dev) |
---|
| 144 | { |
---|
| 145 | pci_modify_cmdsts(dev, PCI_COMMAND_IO, PCI_COMMAND_IO); |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | static inline void pci_io_disable(pci_dev_t dev) |
---|
| 149 | { |
---|
| 150 | pci_modify_cmdsts(dev, PCI_COMMAND_IO, 0); |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | static inline void pci_master_enable(pci_dev_t dev) |
---|
| 154 | { |
---|
| 155 | pci_modify_cmdsts(dev, PCI_COMMAND_MASTER, PCI_COMMAND_MASTER); |
---|
| 156 | } |
---|
| 157 | |
---|
| 158 | static inline void pci_master_disable(pci_dev_t dev) |
---|
| 159 | { |
---|
| 160 | pci_modify_cmdsts(dev, PCI_COMMAND_MASTER, 0); |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | /* Configuration Space Access Read Routines */ |
---|
| 164 | extern int pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *data); |
---|
| 165 | extern int pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *data); |
---|
| 166 | extern int pci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *data); |
---|
| 167 | |
---|
| 168 | /* Configuration Space Access Write Routines */ |
---|
| 169 | extern int pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t data); |
---|
| 170 | extern int pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t data); |
---|
| 171 | extern int pci_cfg_w32(pci_dev_t dev, int ofs, uint32_t data); |
---|
| 172 | |
---|
| 173 | /* Read a register over PCI I/O Space */ |
---|
| 174 | extern uint8_t pci_io_r8(uint32_t adr); |
---|
| 175 | extern uint16_t pci_io_r16(uint32_t adr); |
---|
| 176 | extern uint32_t pci_io_r32(uint32_t adr); |
---|
| 177 | |
---|
| 178 | /* Write a register over PCI I/O Space */ |
---|
| 179 | extern void pci_io_w8(uint32_t adr, uint8_t data); |
---|
| 180 | extern void pci_io_w16(uint32_t adr, uint16_t data); |
---|
| 181 | extern void pci_io_w32(uint32_t adr, uint32_t data); |
---|
| 182 | |
---|
| 183 | /* Translate PCI address into CPU accessible address */ |
---|
| 184 | static inline int pci_pci2cpu(uint32_t *address, int type) |
---|
| 185 | { |
---|
| 186 | return pci_access_ops.translate(address, type, 0); |
---|
| 187 | } |
---|
| 188 | |
---|
| 189 | /* Translate CPU accessible address into PCI address (for DMA) */ |
---|
| 190 | static inline int pci_cpu2pci(uint32_t *address, int type) |
---|
| 191 | { |
---|
| 192 | return pci_access_ops.translate(address, type, 1); |
---|
| 193 | } |
---|
| 194 | |
---|
| 195 | /*** Read/Write a register over PCI Memory Space ***/ |
---|
| 196 | |
---|
| 197 | static inline uint8_t pci_ld8(volatile uint8_t *addr) |
---|
| 198 | { |
---|
| 199 | return *addr; |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | static inline void pci_st8(volatile uint8_t *addr, uint8_t val) |
---|
| 203 | { |
---|
| 204 | *addr = val; |
---|
| 205 | } |
---|
| 206 | |
---|
| 207 | #ifdef BSP_PCI_BIG_ENDIAN |
---|
| 208 | |
---|
| 209 | /* BSP has decided Big Endian PCI Bus (non-standard) */ |
---|
| 210 | |
---|
| 211 | static inline uint16_t pci_ld_le16(volatile uint16_t *addr) |
---|
| 212 | { |
---|
| 213 | return ld_be16(addr); |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | static inline void pci_st_le16(volatile uint16_t *addr, uint16_t val) |
---|
| 217 | { |
---|
| 218 | st_be16(addr, val); |
---|
| 219 | } |
---|
| 220 | |
---|
| 221 | static inline uint32_t pci_ld_le32(volatile uint32_t *addr) |
---|
| 222 | { |
---|
| 223 | return ld_be32(addr); |
---|
| 224 | } |
---|
| 225 | |
---|
| 226 | static inline void pci_st_le32(volatile uint32_t *addr, uint32_t val) |
---|
| 227 | { |
---|
| 228 | st_be32(addr, val); |
---|
| 229 | } |
---|
| 230 | |
---|
| 231 | static inline uint16_t pci_ld_be16(volatile uint16_t *addr) |
---|
| 232 | { |
---|
| 233 | return ld_le16(addr); |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | static inline void pci_st_be16(volatile uint16_t *addr, uint16_t val) |
---|
| 237 | { |
---|
| 238 | st_le16(addr, val); |
---|
| 239 | } |
---|
| 240 | |
---|
| 241 | static inline uint32_t pci_ld_be32(volatile uint32_t *addr) |
---|
| 242 | { |
---|
| 243 | return ld_le32(addr); |
---|
| 244 | } |
---|
| 245 | |
---|
| 246 | static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val) |
---|
| 247 | { |
---|
| 248 | st_le32(addr, val); |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | #else |
---|
| 252 | |
---|
| 253 | /* Little Endian PCI Bus */ |
---|
| 254 | |
---|
| 255 | static inline uint16_t pci_ld_le16(volatile uint16_t *addr) |
---|
| 256 | { |
---|
| 257 | return ld_le16(addr); |
---|
| 258 | } |
---|
| 259 | |
---|
| 260 | static inline void pci_st_le16(volatile uint16_t *addr, uint16_t val) |
---|
| 261 | { |
---|
| 262 | st_le16(addr, val); |
---|
| 263 | } |
---|
| 264 | |
---|
| 265 | static inline uint32_t pci_ld_le32(volatile uint32_t *addr) |
---|
| 266 | { |
---|
| 267 | return ld_le32(addr); |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | static inline void pci_st_le32(volatile uint32_t *addr, uint32_t val) |
---|
| 271 | { |
---|
| 272 | st_le32(addr, val); |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | static inline uint16_t pci_ld_be16(volatile uint16_t *addr) |
---|
| 276 | { |
---|
| 277 | return ld_be16(addr); |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | static inline void pci_st_be16(volatile uint16_t *addr, uint16_t val) |
---|
| 281 | { |
---|
| 282 | st_be16(addr, val); |
---|
| 283 | } |
---|
| 284 | |
---|
| 285 | static inline uint32_t pci_ld_be32(volatile uint32_t *addr) |
---|
| 286 | { |
---|
| 287 | return ld_be32(addr); |
---|
| 288 | } |
---|
| 289 | |
---|
| 290 | static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val) |
---|
| 291 | { |
---|
| 292 | st_be32(addr, val); |
---|
| 293 | } |
---|
| 294 | |
---|
| 295 | #endif |
---|
| 296 | |
---|
| 297 | /* Registers-over-Memory Space access routines. The routines are not inlined |
---|
| 298 | * so it is possible during run-time to select which function implemention |
---|
| 299 | * to use. The use of these functions are not recommended since it will have a |
---|
| 300 | * performance penalty. |
---|
| 301 | * |
---|
| 302 | * 8-bit accesses are the same for Little and Big endian PCI buses. |
---|
| 303 | */ |
---|
| 304 | uint8_t pci_mem_ld8(uint8_t *adr); |
---|
| 305 | void pci_mem_st8(uint8_t *adr, uint8_t data); |
---|
| 306 | /* Registers-over-Memory Space - Generic Big endian PCI bus definitions */ |
---|
| 307 | uint16_t pci_mem_be_ld_le16(uint16_t *adr); |
---|
| 308 | uint16_t pci_mem_be_ld_be16(uint16_t *adr); |
---|
| 309 | uint32_t pci_mem_be_ld_le32(uint32_t *adr); |
---|
| 310 | uint32_t pci_mem_be_ld_be32(uint32_t *adr); |
---|
| 311 | void pci_mem_be_st_le16(uint16_t *adr, uint16_t data); |
---|
| 312 | void pci_mem_be_st_be16(uint16_t *adr, uint16_t data); |
---|
| 313 | void pci_mem_be_st_le32(uint32_t *adr, uint32_t data); |
---|
| 314 | void pci_mem_be_st_be32(uint32_t *adr, uint32_t data); |
---|
| 315 | /* Registers-over-Memory Space - Generic Little endian PCI bus definitions */ |
---|
| 316 | uint16_t pci_mem_le_ld_le16(uint16_t *adr); |
---|
| 317 | uint16_t pci_mem_le_ld_be16(uint16_t *adr); |
---|
| 318 | uint32_t pci_mem_le_ld_le32(uint32_t *adr); |
---|
| 319 | uint32_t pci_mem_le_ld_be32(uint32_t *adr); |
---|
| 320 | void pci_mem_le_st_le16(uint16_t *adr, uint16_t data); |
---|
| 321 | void pci_mem_le_st_be16(uint16_t *adr, uint16_t data); |
---|
| 322 | void pci_mem_le_st_le32(uint32_t *adr, uint32_t data); |
---|
| 323 | void pci_mem_le_st_be32(uint32_t *adr, uint32_t data); |
---|
| 324 | |
---|
| 325 | /* Get Read/Write function for accessing a register over PCI Memory Space |
---|
| 326 | * (non-inline functions). |
---|
| 327 | * |
---|
| 328 | * Arguments |
---|
| 329 | * wr 0(Read), 1(Write) |
---|
| 330 | * size 1(Byte), 2(Word), 4(Double Word) |
---|
| 331 | * func Where function pointer will be stored |
---|
| 332 | * endian PCI_LITTLE_ENDIAN or PCI_BIG_ENDIAN |
---|
| 333 | * type 1(I/O), 3(REG over MEM), 4(CFG) |
---|
| 334 | * |
---|
| 335 | * Return |
---|
| 336 | * 0 Found function |
---|
| 337 | * others No such function defined by host driver or BSP |
---|
| 338 | */ |
---|
| 339 | extern int pci_access_func(int wr, int size, void **func, int endian, int type); |
---|
| 340 | |
---|
| 341 | /* Predefined functions for Host drivers or BSPs that define the |
---|
| 342 | * register-over-memory space functions operations. |
---|
| 343 | */ |
---|
| 344 | extern struct pci_memreg_ops pci_mem_le_ops; /* For Little-Endian PCI bus */ |
---|
| 345 | extern struct pci_memreg_ops pci_mem_be_ops; /* For Big-Endian PCI bus */ |
---|
| 346 | |
---|
| 347 | #ifdef __cplusplus |
---|
| 348 | } |
---|
| 349 | #endif |
---|
| 350 | |
---|
| 351 | #endif /* !__PCI_ACCESS_H__ */ |
---|