1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/types.h>
3 #include <linux/ioport.h>
4 #include <linux/slab.h>
5 #include <linux/export.h>
9 #include "mcb-internal.h"
11 #define for_each_chameleon_cell(dtype, p) \
12 for ((dtype) = get_next_dtype((p)); \
13 (dtype) != CHAMELEON_DTYPE_END; \
14 (dtype) = get_next_dtype((p)))
16 static inline uint32_t get_next_dtype(void __iomem
*p
)
24 static int chameleon_parse_bdd(struct mcb_bus
*bus
,
25 struct chameleon_bar
*cb
,
31 static int chameleon_parse_gdd(struct mcb_bus
*bus
,
32 struct chameleon_bar
*cb
,
33 void __iomem
*base
, int bar_count
)
35 struct chameleon_gdd __iomem
*gdd
=
36 (struct chameleon_gdd __iomem
*) base
;
37 struct mcb_device
*mdev
;
45 mdev
= mcb_alloc_dev(bus
);
49 reg1
= readl(&gdd
->reg1
);
50 reg2
= readl(&gdd
->reg2
);
51 offset
= readl(&gdd
->offset
);
52 size
= readl(&gdd
->size
);
54 mdev
->id
= GDD_DEV(reg1
);
55 mdev
->rev
= GDD_REV(reg1
);
56 mdev
->var
= GDD_VAR(reg1
);
57 mdev
->bar
= GDD_BAR(reg2
);
58 mdev
->group
= GDD_GRP(reg2
);
59 mdev
->inst
= GDD_INS(reg2
);
62 * If the BAR is missing, dev_mapbase is zero, or if the
63 * device is IO mapped we just print a warning and go on with the
64 * next device, instead of completely stop the gdd parser
66 if (mdev
->bar
> bar_count
- 1) {
67 pr_info("No BAR for 16z%03d\n", mdev
->id
);
72 dev_mapbase
= cb
[mdev
->bar
].addr
;
74 pr_info("BAR not assigned for 16z%03d\n", mdev
->id
);
79 if (dev_mapbase
& 0x01) {
80 pr_info("IO mapped Device (16z%03d) not yet supported\n",
86 pr_debug("Found a 16z%03d\n", mdev
->id
);
88 mdev
->irq
.start
= GDD_IRQ(reg1
);
89 mdev
->irq
.end
= GDD_IRQ(reg1
);
90 mdev
->irq
.flags
= IORESOURCE_IRQ
;
92 mdev
->mem
.start
= dev_mapbase
+ offset
;
94 mdev
->mem
.end
= mdev
->mem
.start
+ size
- 1;
95 mdev
->mem
.flags
= IORESOURCE_MEM
;
97 ret
= mcb_device_register(bus
, mdev
);
109 static void chameleon_parse_bar(void __iomem
*base
,
110 struct chameleon_bar
*cb
, int bar_count
)
112 char __iomem
*p
= base
;
118 for (i
= 0; i
< bar_count
; i
++) {
119 cb
[i
].addr
= readl(p
);
120 cb
[i
].size
= readl(p
+ 4);
122 p
+= sizeof(struct chameleon_bar
);
126 static int chameleon_get_bar(void __iomem
**base
, phys_addr_t mapbase
,
127 struct chameleon_bar
**cb
)
129 struct chameleon_bar
*c
;
135 * For those devices which are not connected
136 * to the PCI Bus (e.g. LPC) there is a bar
137 * descriptor located directly after the
138 * chameleon header. This header is comparable
141 dtype
= get_next_dtype(*base
);
142 if (dtype
== CHAMELEON_DTYPE_BAR
) {
145 bar_count
= BAR_CNT(reg
);
146 if (bar_count
<= 0 || bar_count
> CHAMELEON_BAR_MAX
)
149 c
= kcalloc(bar_count
, sizeof(struct chameleon_bar
),
154 chameleon_parse_bar(*base
, c
, bar_count
);
155 *base
+= BAR_DESC_SIZE(bar_count
);
157 c
= kzalloc(sizeof(struct chameleon_bar
), GFP_KERNEL
);
170 int chameleon_parse_cells(struct mcb_bus
*bus
, phys_addr_t mapbase
,
173 struct chameleon_fpga_header
*header
;
174 struct chameleon_bar
*cb
;
175 void __iomem
*p
= base
;
183 hsize
= sizeof(struct chameleon_fpga_header
);
185 header
= kzalloc(hsize
, GFP_KERNEL
);
189 /* Extract header information */
190 memcpy_fromio(header
, p
, hsize
);
191 /* We only support chameleon v2 at the moment */
192 header
->magic
= le16_to_cpu(header
->magic
);
193 if (header
->magic
!= CHAMELEONV2_MAGIC
) {
194 pr_err("Unsupported chameleon version 0x%x\n",
201 bus
->revision
= header
->revision
;
202 bus
->model
= header
->model
;
203 bus
->minor
= header
->minor
;
204 snprintf(bus
->name
, CHAMELEON_FILENAME_LEN
+ 1, "%s",
207 bar_count
= chameleon_get_bar(&p
, mapbase
, &cb
);
213 for_each_chameleon_cell(dtype
, p
) {
215 case CHAMELEON_DTYPE_GENERAL
:
216 ret
= chameleon_parse_gdd(bus
, cb
, p
, bar_count
);
219 p
+= sizeof(struct chameleon_gdd
);
221 case CHAMELEON_DTYPE_BRIDGE
:
222 chameleon_parse_bdd(bus
, cb
, p
);
223 p
+= sizeof(struct chameleon_bdd
);
225 case CHAMELEON_DTYPE_END
:
228 pr_err("Invalid chameleon descriptor type 0x%x\n",
236 if (num_cells
== 0) {
241 table_size
= p
- base
;
242 pr_debug("%d cell(s) found. Chameleon table size: 0x%04x bytes\n", num_cells
, table_size
);
254 EXPORT_SYMBOL_NS_GPL(chameleon_parse_cells
, "MCB");