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