13764e82eSJohannes Thumshirn #include <linux/types.h> 23764e82eSJohannes Thumshirn #include <linux/ioport.h> 33764e82eSJohannes Thumshirn #include <linux/slab.h> 43764e82eSJohannes Thumshirn #include <linux/export.h> 53764e82eSJohannes Thumshirn #include <linux/io.h> 63764e82eSJohannes Thumshirn #include <linux/mcb.h> 73764e82eSJohannes Thumshirn 83764e82eSJohannes Thumshirn #include "mcb-internal.h" 93764e82eSJohannes Thumshirn 103764e82eSJohannes Thumshirn struct mcb_parse_priv { 113764e82eSJohannes Thumshirn phys_addr_t mapbase; 123764e82eSJohannes Thumshirn void __iomem *base; 133764e82eSJohannes Thumshirn }; 143764e82eSJohannes Thumshirn 153764e82eSJohannes Thumshirn #define for_each_chameleon_cell(dtype, p) \ 163764e82eSJohannes Thumshirn for ((dtype) = get_next_dtype((p)); \ 173764e82eSJohannes Thumshirn (dtype) != CHAMELEON_DTYPE_END; \ 183764e82eSJohannes Thumshirn (dtype) = get_next_dtype((p))) 193764e82eSJohannes Thumshirn 203764e82eSJohannes Thumshirn static inline uint32_t get_next_dtype(void __iomem *p) 213764e82eSJohannes Thumshirn { 223764e82eSJohannes Thumshirn uint32_t dtype; 233764e82eSJohannes Thumshirn 243764e82eSJohannes Thumshirn dtype = readl(p); 253764e82eSJohannes Thumshirn return dtype >> 28; 263764e82eSJohannes Thumshirn } 273764e82eSJohannes Thumshirn 283764e82eSJohannes Thumshirn static int chameleon_parse_bdd(struct mcb_bus *bus, 29ffc7bb38SAndreas Werner struct chameleon_bar *cb, 303764e82eSJohannes Thumshirn void __iomem *base) 313764e82eSJohannes Thumshirn { 323764e82eSJohannes Thumshirn return 0; 333764e82eSJohannes Thumshirn } 343764e82eSJohannes Thumshirn 353764e82eSJohannes Thumshirn static int chameleon_parse_gdd(struct mcb_bus *bus, 36ffc7bb38SAndreas Werner struct chameleon_bar *cb, 37ffc7bb38SAndreas Werner void __iomem *base, int bar_count) 383764e82eSJohannes Thumshirn { 393764e82eSJohannes Thumshirn struct chameleon_gdd __iomem *gdd = 403764e82eSJohannes Thumshirn (struct chameleon_gdd __iomem *) base; 413764e82eSJohannes Thumshirn struct mcb_device *mdev; 42ffc7bb38SAndreas Werner u32 dev_mapbase; 433764e82eSJohannes Thumshirn u32 offset; 443764e82eSJohannes Thumshirn u32 size; 453764e82eSJohannes Thumshirn int ret; 463764e82eSJohannes Thumshirn __le32 reg1; 473764e82eSJohannes Thumshirn __le32 reg2; 483764e82eSJohannes Thumshirn 493764e82eSJohannes Thumshirn mdev = mcb_alloc_dev(bus); 503764e82eSJohannes Thumshirn if (!mdev) 513764e82eSJohannes Thumshirn return -ENOMEM; 523764e82eSJohannes Thumshirn 533764e82eSJohannes Thumshirn reg1 = readl(&gdd->reg1); 543764e82eSJohannes Thumshirn reg2 = readl(&gdd->reg2); 553764e82eSJohannes Thumshirn offset = readl(&gdd->offset); 563764e82eSJohannes Thumshirn size = readl(&gdd->size); 573764e82eSJohannes Thumshirn 583764e82eSJohannes Thumshirn mdev->id = GDD_DEV(reg1); 593764e82eSJohannes Thumshirn mdev->rev = GDD_REV(reg1); 603764e82eSJohannes Thumshirn mdev->var = GDD_VAR(reg1); 61f75564d3SAndreas Werner mdev->bar = GDD_BAR(reg2); 623764e82eSJohannes Thumshirn mdev->group = GDD_GRP(reg2); 633764e82eSJohannes Thumshirn mdev->inst = GDD_INS(reg2); 643764e82eSJohannes Thumshirn 65ffc7bb38SAndreas Werner /* 66ffc7bb38SAndreas Werner * If the BAR is missing, dev_mapbase is zero, or if the 67ffc7bb38SAndreas Werner * device is IO mapped we just print a warning and go on with the 68ffc7bb38SAndreas Werner * next device, instead of completely stop the gdd parser 69ffc7bb38SAndreas Werner */ 70ffc7bb38SAndreas Werner if (mdev->bar > bar_count - 1) { 71ffc7bb38SAndreas Werner pr_info("No BAR for 16z%03d\n", mdev->id); 72ffc7bb38SAndreas Werner ret = 0; 73ffc7bb38SAndreas Werner goto err; 74ffc7bb38SAndreas Werner } 75ffc7bb38SAndreas Werner 76ffc7bb38SAndreas Werner dev_mapbase = cb[mdev->bar].addr; 77ffc7bb38SAndreas Werner if (!dev_mapbase) { 78ffc7bb38SAndreas Werner pr_info("BAR not assigned for 16z%03d\n", mdev->id); 79ffc7bb38SAndreas Werner ret = 0; 80ffc7bb38SAndreas Werner goto err; 81ffc7bb38SAndreas Werner } 82ffc7bb38SAndreas Werner 83ffc7bb38SAndreas Werner if (dev_mapbase & 0x01) { 84ffc7bb38SAndreas Werner pr_info("IO mapped Device (16z%03d) not yet supported\n", 85ffc7bb38SAndreas Werner mdev->id); 86ffc7bb38SAndreas Werner ret = 0; 87ffc7bb38SAndreas Werner goto err; 88ffc7bb38SAndreas Werner } 89ffc7bb38SAndreas Werner 903764e82eSJohannes Thumshirn pr_debug("Found a 16z%03d\n", mdev->id); 913764e82eSJohannes Thumshirn 923764e82eSJohannes Thumshirn mdev->irq.start = GDD_IRQ(reg1); 933764e82eSJohannes Thumshirn mdev->irq.end = GDD_IRQ(reg1); 943764e82eSJohannes Thumshirn mdev->irq.flags = IORESOURCE_IRQ; 953764e82eSJohannes Thumshirn 96ffc7bb38SAndreas Werner mdev->mem.start = dev_mapbase + offset; 97ffc7bb38SAndreas Werner 983764e82eSJohannes Thumshirn mdev->mem.end = mdev->mem.start + size - 1; 993764e82eSJohannes Thumshirn mdev->mem.flags = IORESOURCE_MEM; 1003764e82eSJohannes Thumshirn 1013764e82eSJohannes Thumshirn mdev->is_added = false; 1023764e82eSJohannes Thumshirn 1033764e82eSJohannes Thumshirn ret = mcb_device_register(bus, mdev); 1043764e82eSJohannes Thumshirn if (ret < 0) 1053764e82eSJohannes Thumshirn goto err; 1063764e82eSJohannes Thumshirn 1073764e82eSJohannes Thumshirn return 0; 1083764e82eSJohannes Thumshirn 1093764e82eSJohannes Thumshirn err: 1103764e82eSJohannes Thumshirn mcb_free_dev(mdev); 1113764e82eSJohannes Thumshirn 1123764e82eSJohannes Thumshirn return ret; 1133764e82eSJohannes Thumshirn } 1143764e82eSJohannes Thumshirn 115ffc7bb38SAndreas Werner static void chameleon_parse_bar(void __iomem *base, 116ffc7bb38SAndreas Werner struct chameleon_bar *cb, int bar_count) 117ffc7bb38SAndreas Werner { 118ffc7bb38SAndreas Werner char __iomem *p = base; 119ffc7bb38SAndreas Werner int i; 120ffc7bb38SAndreas Werner 121ffc7bb38SAndreas Werner /* skip reg1 */ 122ffc7bb38SAndreas Werner p += sizeof(__le32); 123ffc7bb38SAndreas Werner 124ffc7bb38SAndreas Werner for (i = 0; i < bar_count; i++) { 125ffc7bb38SAndreas Werner cb[i].addr = readl(p); 126ffc7bb38SAndreas Werner cb[i].size = readl(p + 4); 127ffc7bb38SAndreas Werner 128ffc7bb38SAndreas Werner p += sizeof(struct chameleon_bar); 129ffc7bb38SAndreas Werner } 130ffc7bb38SAndreas Werner } 131ffc7bb38SAndreas Werner 132ffc7bb38SAndreas Werner static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase, 133ffc7bb38SAndreas Werner struct chameleon_bar **cb) 134ffc7bb38SAndreas Werner { 135ffc7bb38SAndreas Werner struct chameleon_bar *c; 136ffc7bb38SAndreas Werner int bar_count; 137ffc7bb38SAndreas Werner __le32 reg; 138ffc7bb38SAndreas Werner u32 dtype; 139ffc7bb38SAndreas Werner 140ffc7bb38SAndreas Werner /* 141ffc7bb38SAndreas Werner * For those devices which are not connected 142ffc7bb38SAndreas Werner * to the PCI Bus (e.g. LPC) there is a bar 143ffc7bb38SAndreas Werner * descriptor located directly after the 144ffc7bb38SAndreas Werner * chameleon header. This header is comparable 145ffc7bb38SAndreas Werner * to a PCI header. 146ffc7bb38SAndreas Werner */ 147ffc7bb38SAndreas Werner dtype = get_next_dtype(*base); 148ffc7bb38SAndreas Werner if (dtype == CHAMELEON_DTYPE_BAR) { 149ffc7bb38SAndreas Werner reg = readl(*base); 150ffc7bb38SAndreas Werner 151ffc7bb38SAndreas Werner bar_count = BAR_CNT(reg); 152*c836790aSMichael Moese if (bar_count <= 0 || bar_count > CHAMELEON_BAR_MAX) 153ffc7bb38SAndreas Werner return -ENODEV; 154ffc7bb38SAndreas Werner 155ffc7bb38SAndreas Werner c = kcalloc(bar_count, sizeof(struct chameleon_bar), 156ffc7bb38SAndreas Werner GFP_KERNEL); 157ffc7bb38SAndreas Werner if (!c) 158ffc7bb38SAndreas Werner return -ENOMEM; 159ffc7bb38SAndreas Werner 160ffc7bb38SAndreas Werner chameleon_parse_bar(*base, c, bar_count); 161ffc7bb38SAndreas Werner *base += BAR_DESC_SIZE(bar_count); 162ffc7bb38SAndreas Werner } else { 163ffc7bb38SAndreas Werner c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL); 164ffc7bb38SAndreas Werner if (!c) 165ffc7bb38SAndreas Werner return -ENOMEM; 166ffc7bb38SAndreas Werner 167ffc7bb38SAndreas Werner bar_count = 1; 168ffc7bb38SAndreas Werner c->addr = mapbase; 169ffc7bb38SAndreas Werner } 170ffc7bb38SAndreas Werner 171ffc7bb38SAndreas Werner *cb = c; 172ffc7bb38SAndreas Werner 173ffc7bb38SAndreas Werner return bar_count; 174ffc7bb38SAndreas Werner } 175ffc7bb38SAndreas Werner 1763764e82eSJohannes Thumshirn int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, 1773764e82eSJohannes Thumshirn void __iomem *base) 1783764e82eSJohannes Thumshirn { 1793764e82eSJohannes Thumshirn struct chameleon_fpga_header *header; 180ffc7bb38SAndreas Werner struct chameleon_bar *cb; 181ffc7bb38SAndreas Werner char __iomem *p = base; 1823764e82eSJohannes Thumshirn int num_cells = 0; 183ffc7bb38SAndreas Werner uint32_t dtype; 184ffc7bb38SAndreas Werner int bar_count; 1853764e82eSJohannes Thumshirn int ret = 0; 1863764e82eSJohannes Thumshirn u32 hsize; 1873764e82eSJohannes Thumshirn 1883764e82eSJohannes Thumshirn hsize = sizeof(struct chameleon_fpga_header); 1893764e82eSJohannes Thumshirn 1903764e82eSJohannes Thumshirn header = kzalloc(hsize, GFP_KERNEL); 1913764e82eSJohannes Thumshirn if (!header) 1923764e82eSJohannes Thumshirn return -ENOMEM; 1933764e82eSJohannes Thumshirn 1943764e82eSJohannes Thumshirn /* Extract header information */ 1953764e82eSJohannes Thumshirn memcpy_fromio(header, p, hsize); 1963764e82eSJohannes Thumshirn /* We only support chameleon v2 at the moment */ 1973764e82eSJohannes Thumshirn header->magic = le16_to_cpu(header->magic); 1983764e82eSJohannes Thumshirn if (header->magic != CHAMELEONV2_MAGIC) { 1993764e82eSJohannes Thumshirn pr_err("Unsupported chameleon version 0x%x\n", 2003764e82eSJohannes Thumshirn header->magic); 201ffc7bb38SAndreas Werner ret = -ENODEV; 202ffc7bb38SAndreas Werner goto free_header; 2033764e82eSJohannes Thumshirn } 2043764e82eSJohannes Thumshirn p += hsize; 2053764e82eSJohannes Thumshirn 206803f1ca6SJohannes Thumshirn bus->revision = header->revision; 207803f1ca6SJohannes Thumshirn bus->model = header->model; 208803f1ca6SJohannes Thumshirn bus->minor = header->minor; 209803f1ca6SJohannes Thumshirn snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s", 2103764e82eSJohannes Thumshirn header->filename); 2113764e82eSJohannes Thumshirn 212ffc7bb38SAndreas Werner bar_count = chameleon_get_bar(&p, mapbase, &cb); 213ffc7bb38SAndreas Werner if (bar_count < 0) 214ffc7bb38SAndreas Werner goto free_header; 215ffc7bb38SAndreas Werner 2163764e82eSJohannes Thumshirn for_each_chameleon_cell(dtype, p) { 2173764e82eSJohannes Thumshirn switch (dtype) { 2183764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_GENERAL: 219ffc7bb38SAndreas Werner ret = chameleon_parse_gdd(bus, cb, p, bar_count); 2203764e82eSJohannes Thumshirn if (ret < 0) 221ffc7bb38SAndreas Werner goto free_bar; 2223764e82eSJohannes Thumshirn p += sizeof(struct chameleon_gdd); 2233764e82eSJohannes Thumshirn break; 2243764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_BRIDGE: 225ffc7bb38SAndreas Werner chameleon_parse_bdd(bus, cb, p); 2263764e82eSJohannes Thumshirn p += sizeof(struct chameleon_bdd); 2273764e82eSJohannes Thumshirn break; 2283764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_END: 2293764e82eSJohannes Thumshirn break; 2303764e82eSJohannes Thumshirn default: 2313764e82eSJohannes Thumshirn pr_err("Invalid chameleon descriptor type 0x%x\n", 2323764e82eSJohannes Thumshirn dtype); 233ffc7bb38SAndreas Werner ret = -EINVAL; 234ffc7bb38SAndreas Werner goto free_bar; 2353764e82eSJohannes Thumshirn } 2363764e82eSJohannes Thumshirn num_cells++; 2373764e82eSJohannes Thumshirn } 2383764e82eSJohannes Thumshirn 2393764e82eSJohannes Thumshirn if (num_cells == 0) 2403764e82eSJohannes Thumshirn num_cells = -EINVAL; 2413764e82eSJohannes Thumshirn 242ffc7bb38SAndreas Werner kfree(cb); 2433764e82eSJohannes Thumshirn kfree(header); 2443764e82eSJohannes Thumshirn return num_cells; 2453764e82eSJohannes Thumshirn 246ffc7bb38SAndreas Werner free_bar: 247ffc7bb38SAndreas Werner kfree(cb); 248ffc7bb38SAndreas Werner free_header: 2493764e82eSJohannes Thumshirn kfree(header); 250ffc7bb38SAndreas Werner 2513764e82eSJohannes Thumshirn return ret; 2523764e82eSJohannes Thumshirn } 2533764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(chameleon_parse_cells); 254