1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-10-24 GuEe-GUI first version
9 */
10
11 #include <rthw.h>
12 #include <rtthread.h>
13
14 #include <drivers/pci.h>
15
16 struct rt_spinlock rt_pci_lock = { 0 };
17
18 #ifdef RT_PCI_LOCKLESS
19 #define pci_lock_config(l) do { (void)(l); } while (0)
20 #define pci_unlock_config(l) do { (void)(l); } while (0)
21 #else
22 #define pci_lock_config(l) l = rt_spin_lock_irqsave(&rt_pci_lock)
23 #define pci_unlock_config(l) rt_spin_unlock_irqrestore(&rt_pci_lock, l)
24 #endif
25
26 #define PCI_OPS_READ(name, type) \
27 rt_err_t rt_pci_bus_read_config_##name(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, type *value) \
28 { \
29 rt_err_t err; \
30 rt_ubase_t level; \
31 rt_uint32_t data = 0; \
32 pci_lock_config(level); \
33 err = bus->ops->read(bus, devfn, reg, sizeof(type), &data); \
34 *value = err ? (type)(~0) : (type)data; \
35 pci_unlock_config(level); \
36 return err; \
37 }
38
39 #define PCI_OPS_WRITE(name, type) \
40 rt_err_t rt_pci_bus_write_config_##name(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg, type value) \
41 { \
42 rt_err_t err; \
43 rt_ubase_t level; \
44 pci_lock_config(level); \
45 err = bus->ops->write(bus, devfn, reg, sizeof(type), value); \
46 pci_unlock_config(level); \
47 return err; \
48 }
49
50 #define PCI_OPS(name, type) \
51 PCI_OPS_READ(name, type) \
52 PCI_OPS_WRITE(name, type)
53
PCI_OPS(u8,rt_uint8_t)54 PCI_OPS(u8, rt_uint8_t)
55 PCI_OPS(u16, rt_uint16_t)
56 PCI_OPS(u32, rt_uint32_t)
57
58 #undef PCI_OP_WRITE
59 #undef PCI_OP_READ
60 #undef PCI_OPS
61
62 rt_err_t rt_pci_bus_read_config_uxx(struct rt_pci_bus *bus,
63 rt_uint32_t devfn, int reg, int width, rt_uint32_t *value)
64 {
65 void *base;
66
67 if ((base = bus->ops->map(bus, devfn, reg)))
68 {
69 if (width == 1)
70 {
71 *value = HWREG8(base);
72 }
73 else if (width == 2)
74 {
75 *value = HWREG16(base);
76 }
77 else
78 {
79 *value = HWREG32(base);
80 }
81
82 return RT_EOK;
83 }
84
85 return -RT_ERROR;
86 }
87
rt_pci_bus_write_config_uxx(struct rt_pci_bus * bus,rt_uint32_t devfn,int reg,int width,rt_uint32_t value)88 rt_err_t rt_pci_bus_write_config_uxx(struct rt_pci_bus *bus,
89 rt_uint32_t devfn, int reg, int width, rt_uint32_t value)
90 {
91 void *base;
92
93 if ((base = bus->ops->map(bus, devfn, reg)))
94 {
95 if (width == 1)
96 {
97 HWREG8(base) = value;
98 }
99 else if (width == 2)
100 {
101 HWREG16(base) = value;
102 }
103 else
104 {
105 HWREG32(base) = value;
106 }
107
108 return RT_EOK;
109 }
110
111 return -RT_ERROR;
112 }
113
rt_pci_bus_read_config_generic_u32(struct rt_pci_bus * bus,rt_uint32_t devfn,int reg,int width,rt_uint32_t * value)114 rt_err_t rt_pci_bus_read_config_generic_u32(struct rt_pci_bus *bus,
115 rt_uint32_t devfn, int reg, int width, rt_uint32_t *value)
116 {
117 void *base;
118
119 if ((base = bus->ops->map(bus, devfn, reg)))
120 {
121 *value = HWREG32(base);
122
123 if (width <= 2)
124 {
125 *value = (*value >> (8 * (reg & 3))) & ((1 << (width * 8)) - 1);
126 }
127
128 return RT_EOK;
129 }
130
131 return -RT_ERROR;
132 }
133
rt_pci_bus_write_config_generic_u32(struct rt_pci_bus * bus,rt_uint32_t devfn,int reg,int width,rt_uint32_t value)134 rt_err_t rt_pci_bus_write_config_generic_u32(struct rt_pci_bus *bus,
135 rt_uint32_t devfn, int reg, int width, rt_uint32_t value)
136 {
137 void *base;
138
139 if ((base = bus->ops->map(bus, devfn, reg & ~0x3)))
140 {
141 if (width == 4)
142 {
143 HWREG32(base) = value;
144 }
145 else
146 {
147 rt_uint32_t mask, tmp;
148
149 mask = ~(((1 << (width * 8)) - 1) << ((reg & 0x3) * 8));
150 tmp = HWREG32(base) & mask;
151 tmp |= value << ((reg & 0x3) * 8);
152 HWREG32(base) = tmp;
153 }
154
155 return RT_EOK;
156 }
157
158 return -RT_ERROR;
159 }
160