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