1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12#include <stdio.h>
13#include <assert.h>
14#include <pci/pci.h>
15#include <pci/ioreg.h>
16
17void libpci_out(uint32_t port_no, uint32_t val, uint8_t size) {
18    assert(size == 1 || size == 2 || size == 4);
19    int UNUSED ret = libpci_iowrite(port_no, val, size);
20    assert(ret == 0);
21}
22
23uint32_t libpci_in(uint32_t port_no, uint8_t size) {
24    assert(size == 1 || size == 2 || size == 4);
25    uint32_t val = 0;
26    int UNUSED ret = libpci_ioread(port_no, &val, size);
27    assert(ret == 0);
28    return val;
29}
30
31void libpci_out32(uint32_t port_no, uint32_t val) {
32    libpci_out(port_no, val, 4);
33}
34
35uint32_t libpci_in32(uint32_t port_no) {
36    return libpci_in(port_no, 4);
37}
38
39void libpci_out16(uint32_t port_no, uint32_t val) {
40    libpci_out(port_no, val, 2);
41}
42
43uint32_t libpci_in16(uint32_t port_no) {
44    return libpci_in(port_no, 2);
45}
46
47void libpci_out8(uint32_t port_no, uint32_t val) {
48    libpci_out(port_no, val, 1);
49}
50
51uint32_t libpci_in8(uint32_t port_no) {
52    return libpci_in(port_no, 1);
53}
54
55uint32_t libpci_read_reg32(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg) {
56    reg &= ~MASK(2);
57    libpci_out32(PCI_CONF_PORT_ADDR, 0x80000000 | bus << 16 | dev << 11 | fun << 8 | reg);
58    return libpci_in32(PCI_CONF_PORT_DATA);
59}
60
61void libpci_write_reg32(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg, uint32_t val) {
62    reg &= ~MASK(2);
63    libpci_out32(PCI_CONF_PORT_ADDR, 0x80000000 | bus << 16 | dev << 11 | fun << 8 | reg);
64    libpci_out32(PCI_CONF_PORT_DATA, val);
65}
66
67uint16_t libpci_read_reg16(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg) {
68    reg &= ~MASK(1);
69    libpci_out32(PCI_CONF_PORT_ADDR, 0x80000000 | bus << 16 | dev << 11 | fun << 8 | (reg & ~MASK(2)));
70    return ( libpci_in32(PCI_CONF_PORT_DATA) >> ((reg & MASK(2)) * 8) ) & 0xFFFF;
71}
72
73void libpci_write_reg16(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg, uint16_t val) {
74    reg &= ~MASK(1);
75    libpci_out32(PCI_CONF_PORT_ADDR, 0x80000000 | bus << 16 | dev << 11 | fun << 8 | reg);
76    libpci_out16(PCI_CONF_PORT_DATA, val);
77}
78
79uint16_t libpci_read_reg8(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg) {
80    libpci_out32(PCI_CONF_PORT_ADDR, 0x80000000 | bus << 16 | dev << 11 | fun << 8 | (reg & ~MASK(2)));
81    return ( libpci_in32(PCI_CONF_PORT_DATA) >> ((reg & MASK(2)) * 8) ) & 0xFF;
82}
83
84void libpci_write_reg8(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg, uint8_t val) {
85    libpci_out32(PCI_CONF_PORT_ADDR, 0x80000000 | bus << 16 | dev << 11 | fun << 8 | reg);
86    libpci_out8(PCI_CONF_PORT_DATA, val);
87}
88
89uint32_t libpci_read_reg(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg, uint8_t size) {
90    switch (size) {
91    case 1: return (uint32_t) libpci_read_reg8(bus, dev, fun, reg);
92    case 2: return (uint32_t) libpci_read_reg16(bus, dev, fun, reg);
93    case 4: return (uint32_t) libpci_read_reg32(bus, dev, fun, reg);
94    default:
95        assert(!"libpci_read_reg: unsupported size.");
96        return 0xFFFFFFFF;
97    }
98}
99
100void libpci_write_reg(uint8_t bus, uint8_t dev, uint8_t fun, uint8_t reg, uint32_t val, uint8_t size) {
101    switch (size) {
102    case 1: libpci_write_reg8(bus, dev, fun, reg, val); return;
103    case 2: libpci_write_reg16(bus, dev, fun, reg, val); return;
104    case 4: libpci_write_reg32(bus, dev, fun, reg, val); return;
105    default:
106        assert(!"libpci_write_reg: unsupported size.");
107        return;
108    }
109}
110
111void libpci_portno_reverse_lookup(uint32_t port_no, uint8_t *bus, uint8_t *dev, uint8_t *fun,
112                                  uint8_t *reg) {
113    if (bus) {
114        *bus = (port_no >> 16) & MASK(8);
115    }
116    if (dev) {
117        *dev = (port_no >> 11) & MASK(5);
118    }
119    if (fun) {
120        *fun = (port_no >> 8) & MASK(3);
121    }
122    if (reg) {
123        *reg = port_no & MASK(8);
124    }
125}
126