Commit | Line | Data |
---|---|---|
3764e82e JT |
1 | #include <linux/types.h> |
2 | #include <linux/ioport.h> | |
3 | #include <linux/slab.h> | |
4 | #include <linux/export.h> | |
5 | #include <linux/io.h> | |
6 | #include <linux/mcb.h> | |
7 | ||
8 | #include "mcb-internal.h" | |
9 | ||
10 | struct mcb_parse_priv { | |
11 | phys_addr_t mapbase; | |
12 | void __iomem *base; | |
13 | }; | |
14 | ||
15 | #define for_each_chameleon_cell(dtype, p) \ | |
16 | for ((dtype) = get_next_dtype((p)); \ | |
17 | (dtype) != CHAMELEON_DTYPE_END; \ | |
18 | (dtype) = get_next_dtype((p))) | |
19 | ||
20 | static inline uint32_t get_next_dtype(void __iomem *p) | |
21 | { | |
22 | uint32_t dtype; | |
23 | ||
24 | dtype = readl(p); | |
25 | return dtype >> 28; | |
26 | } | |
27 | ||
28 | static int chameleon_parse_bdd(struct mcb_bus *bus, | |
29 | phys_addr_t mapbase, | |
30 | void __iomem *base) | |
31 | { | |
32 | return 0; | |
33 | } | |
34 | ||
35 | static int chameleon_parse_gdd(struct mcb_bus *bus, | |
36 | phys_addr_t mapbase, | |
37 | void __iomem *base) | |
38 | { | |
39 | struct chameleon_gdd __iomem *gdd = | |
40 | (struct chameleon_gdd __iomem *) base; | |
41 | struct mcb_device *mdev; | |
42 | u32 offset; | |
43 | u32 size; | |
44 | int ret; | |
45 | __le32 reg1; | |
46 | __le32 reg2; | |
47 | ||
48 | mdev = mcb_alloc_dev(bus); | |
49 | if (!mdev) | |
50 | return -ENOMEM; | |
51 | ||
52 | reg1 = readl(&gdd->reg1); | |
53 | reg2 = readl(&gdd->reg2); | |
54 | offset = readl(&gdd->offset); | |
55 | size = readl(&gdd->size); | |
56 | ||
57 | mdev->id = GDD_DEV(reg1); | |
58 | mdev->rev = GDD_REV(reg1); | |
59 | mdev->var = GDD_VAR(reg1); | |
f75564d3 | 60 | mdev->bar = GDD_BAR(reg2); |
3764e82e JT |
61 | mdev->group = GDD_GRP(reg2); |
62 | mdev->inst = GDD_INS(reg2); | |
63 | ||
64 | pr_debug("Found a 16z%03d\n", mdev->id); | |
65 | ||
66 | mdev->irq.start = GDD_IRQ(reg1); | |
67 | mdev->irq.end = GDD_IRQ(reg1); | |
68 | mdev->irq.flags = IORESOURCE_IRQ; | |
69 | ||
70 | mdev->mem.start = mapbase + offset; | |
71 | mdev->mem.end = mdev->mem.start + size - 1; | |
72 | mdev->mem.flags = IORESOURCE_MEM; | |
73 | ||
74 | mdev->is_added = false; | |
75 | ||
76 | ret = mcb_device_register(bus, mdev); | |
77 | if (ret < 0) | |
78 | goto err; | |
79 | ||
80 | return 0; | |
81 | ||
82 | err: | |
83 | mcb_free_dev(mdev); | |
84 | ||
85 | return ret; | |
86 | } | |
87 | ||
88 | int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, | |
89 | void __iomem *base) | |
90 | { | |
91 | char __iomem *p = base; | |
92 | struct chameleon_fpga_header *header; | |
93 | uint32_t dtype; | |
94 | int num_cells = 0; | |
95 | int ret = 0; | |
96 | u32 hsize; | |
97 | ||
98 | hsize = sizeof(struct chameleon_fpga_header); | |
99 | ||
100 | header = kzalloc(hsize, GFP_KERNEL); | |
101 | if (!header) | |
102 | return -ENOMEM; | |
103 | ||
104 | /* Extract header information */ | |
105 | memcpy_fromio(header, p, hsize); | |
106 | /* We only support chameleon v2 at the moment */ | |
107 | header->magic = le16_to_cpu(header->magic); | |
108 | if (header->magic != CHAMELEONV2_MAGIC) { | |
109 | pr_err("Unsupported chameleon version 0x%x\n", | |
110 | header->magic); | |
111 | kfree(header); | |
112 | return -ENODEV; | |
113 | } | |
114 | p += hsize; | |
115 | ||
803f1ca6 JT |
116 | bus->revision = header->revision; |
117 | bus->model = header->model; | |
118 | bus->minor = header->minor; | |
119 | snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s", | |
120 | header->filename); | |
3764e82e JT |
121 | |
122 | for_each_chameleon_cell(dtype, p) { | |
123 | switch (dtype) { | |
124 | case CHAMELEON_DTYPE_GENERAL: | |
125 | ret = chameleon_parse_gdd(bus, mapbase, p); | |
126 | if (ret < 0) | |
127 | goto out; | |
128 | p += sizeof(struct chameleon_gdd); | |
129 | break; | |
130 | case CHAMELEON_DTYPE_BRIDGE: | |
131 | chameleon_parse_bdd(bus, mapbase, p); | |
132 | p += sizeof(struct chameleon_bdd); | |
133 | break; | |
134 | case CHAMELEON_DTYPE_END: | |
135 | break; | |
136 | default: | |
137 | pr_err("Invalid chameleon descriptor type 0x%x\n", | |
138 | dtype); | |
7c735282 | 139 | kfree(header); |
3764e82e JT |
140 | return -EINVAL; |
141 | } | |
142 | num_cells++; | |
143 | } | |
144 | ||
145 | if (num_cells == 0) | |
146 | num_cells = -EINVAL; | |
147 | ||
148 | kfree(header); | |
149 | return num_cells; | |
150 | ||
151 | out: | |
152 | kfree(header); | |
153 | return ret; | |
154 | } | |
155 | EXPORT_SYMBOL_GPL(chameleon_parse_cells); |