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