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, 29*ffc7bb38SAndreas 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, 36*ffc7bb38SAndreas Werner struct chameleon_bar *cb, 37*ffc7bb38SAndreas 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; 42*ffc7bb38SAndreas 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 65*ffc7bb38SAndreas Werner /* 66*ffc7bb38SAndreas Werner * If the BAR is missing, dev_mapbase is zero, or if the 67*ffc7bb38SAndreas Werner * device is IO mapped we just print a warning and go on with the 68*ffc7bb38SAndreas Werner * next device, instead of completely stop the gdd parser 69*ffc7bb38SAndreas Werner */ 70*ffc7bb38SAndreas Werner if (mdev->bar > bar_count - 1) { 71*ffc7bb38SAndreas Werner pr_info("No BAR for 16z%03d\n", mdev->id); 72*ffc7bb38SAndreas Werner ret = 0; 73*ffc7bb38SAndreas Werner goto err; 74*ffc7bb38SAndreas Werner } 75*ffc7bb38SAndreas Werner 76*ffc7bb38SAndreas Werner dev_mapbase = cb[mdev->bar].addr; 77*ffc7bb38SAndreas Werner if (!dev_mapbase) { 78*ffc7bb38SAndreas Werner pr_info("BAR not assigned for 16z%03d\n", mdev->id); 79*ffc7bb38SAndreas Werner ret = 0; 80*ffc7bb38SAndreas Werner goto err; 81*ffc7bb38SAndreas Werner } 82*ffc7bb38SAndreas Werner 83*ffc7bb38SAndreas Werner if (dev_mapbase & 0x01) { 84*ffc7bb38SAndreas Werner pr_info("IO mapped Device (16z%03d) not yet supported\n", 85*ffc7bb38SAndreas Werner mdev->id); 86*ffc7bb38SAndreas Werner ret = 0; 87*ffc7bb38SAndreas Werner goto err; 88*ffc7bb38SAndreas Werner } 89*ffc7bb38SAndreas 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 96*ffc7bb38SAndreas Werner mdev->mem.start = dev_mapbase + offset; 97*ffc7bb38SAndreas 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 115*ffc7bb38SAndreas Werner static void chameleon_parse_bar(void __iomem *base, 116*ffc7bb38SAndreas Werner struct chameleon_bar *cb, int bar_count) 117*ffc7bb38SAndreas Werner { 118*ffc7bb38SAndreas Werner char __iomem *p = base; 119*ffc7bb38SAndreas Werner int i; 120*ffc7bb38SAndreas Werner 121*ffc7bb38SAndreas Werner /* skip reg1 */ 122*ffc7bb38SAndreas Werner p += sizeof(__le32); 123*ffc7bb38SAndreas Werner 124*ffc7bb38SAndreas Werner for (i = 0; i < bar_count; i++) { 125*ffc7bb38SAndreas Werner cb[i].addr = readl(p); 126*ffc7bb38SAndreas Werner cb[i].size = readl(p + 4); 127*ffc7bb38SAndreas Werner 128*ffc7bb38SAndreas Werner p += sizeof(struct chameleon_bar); 129*ffc7bb38SAndreas Werner } 130*ffc7bb38SAndreas Werner } 131*ffc7bb38SAndreas Werner 132*ffc7bb38SAndreas Werner static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase, 133*ffc7bb38SAndreas Werner struct chameleon_bar **cb) 134*ffc7bb38SAndreas Werner { 135*ffc7bb38SAndreas Werner struct chameleon_bar *c; 136*ffc7bb38SAndreas Werner int bar_count; 137*ffc7bb38SAndreas Werner __le32 reg; 138*ffc7bb38SAndreas Werner u32 dtype; 139*ffc7bb38SAndreas Werner 140*ffc7bb38SAndreas Werner /* 141*ffc7bb38SAndreas Werner * For those devices which are not connected 142*ffc7bb38SAndreas Werner * to the PCI Bus (e.g. LPC) there is a bar 143*ffc7bb38SAndreas Werner * descriptor located directly after the 144*ffc7bb38SAndreas Werner * chameleon header. This header is comparable 145*ffc7bb38SAndreas Werner * to a PCI header. 146*ffc7bb38SAndreas Werner */ 147*ffc7bb38SAndreas Werner dtype = get_next_dtype(*base); 148*ffc7bb38SAndreas Werner if (dtype == CHAMELEON_DTYPE_BAR) { 149*ffc7bb38SAndreas Werner reg = readl(*base); 150*ffc7bb38SAndreas Werner 151*ffc7bb38SAndreas Werner bar_count = BAR_CNT(reg); 152*ffc7bb38SAndreas Werner if (bar_count <= 0 && bar_count > CHAMELEON_BAR_MAX) 153*ffc7bb38SAndreas Werner return -ENODEV; 154*ffc7bb38SAndreas Werner 155*ffc7bb38SAndreas Werner c = kcalloc(bar_count, sizeof(struct chameleon_bar), 156*ffc7bb38SAndreas Werner GFP_KERNEL); 157*ffc7bb38SAndreas Werner if (!c) 158*ffc7bb38SAndreas Werner return -ENOMEM; 159*ffc7bb38SAndreas Werner 160*ffc7bb38SAndreas Werner chameleon_parse_bar(*base, c, bar_count); 161*ffc7bb38SAndreas Werner *base += BAR_DESC_SIZE(bar_count); 162*ffc7bb38SAndreas Werner } else { 163*ffc7bb38SAndreas Werner c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL); 164*ffc7bb38SAndreas Werner if (!c) 165*ffc7bb38SAndreas Werner return -ENOMEM; 166*ffc7bb38SAndreas Werner 167*ffc7bb38SAndreas Werner bar_count = 1; 168*ffc7bb38SAndreas Werner c->addr = mapbase; 169*ffc7bb38SAndreas Werner } 170*ffc7bb38SAndreas Werner 171*ffc7bb38SAndreas Werner *cb = c; 172*ffc7bb38SAndreas Werner 173*ffc7bb38SAndreas Werner return bar_count; 174*ffc7bb38SAndreas Werner } 175*ffc7bb38SAndreas 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; 180*ffc7bb38SAndreas Werner struct chameleon_bar *cb; 181*ffc7bb38SAndreas Werner char __iomem *p = base; 1823764e82eSJohannes Thumshirn int num_cells = 0; 183*ffc7bb38SAndreas Werner uint32_t dtype; 184*ffc7bb38SAndreas 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); 201*ffc7bb38SAndreas Werner ret = -ENODEV; 202*ffc7bb38SAndreas 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 212*ffc7bb38SAndreas Werner bar_count = chameleon_get_bar(&p, mapbase, &cb); 213*ffc7bb38SAndreas Werner if (bar_count < 0) 214*ffc7bb38SAndreas Werner goto free_header; 215*ffc7bb38SAndreas Werner 2163764e82eSJohannes Thumshirn for_each_chameleon_cell(dtype, p) { 2173764e82eSJohannes Thumshirn switch (dtype) { 2183764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_GENERAL: 219*ffc7bb38SAndreas Werner ret = chameleon_parse_gdd(bus, cb, p, bar_count); 2203764e82eSJohannes Thumshirn if (ret < 0) 221*ffc7bb38SAndreas Werner goto free_bar; 2223764e82eSJohannes Thumshirn p += sizeof(struct chameleon_gdd); 2233764e82eSJohannes Thumshirn break; 2243764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_BRIDGE: 225*ffc7bb38SAndreas 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); 233*ffc7bb38SAndreas Werner ret = -EINVAL; 234*ffc7bb38SAndreas 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 242*ffc7bb38SAndreas Werner kfree(cb); 2433764e82eSJohannes Thumshirn kfree(header); 2443764e82eSJohannes Thumshirn return num_cells; 2453764e82eSJohannes Thumshirn 246*ffc7bb38SAndreas Werner free_bar: 247*ffc7bb38SAndreas Werner kfree(cb); 248*ffc7bb38SAndreas Werner free_header: 2493764e82eSJohannes Thumshirn kfree(header); 250*ffc7bb38SAndreas Werner 2513764e82eSJohannes Thumshirn return ret; 2523764e82eSJohannes Thumshirn } 2533764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(chameleon_parse_cells); 254