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, 293764e82eSJohannes Thumshirn phys_addr_t mapbase, 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, 363764e82eSJohannes Thumshirn phys_addr_t mapbase, 373764e82eSJohannes Thumshirn void __iomem *base) 383764e82eSJohannes Thumshirn { 393764e82eSJohannes Thumshirn struct chameleon_gdd __iomem *gdd = 403764e82eSJohannes Thumshirn (struct chameleon_gdd __iomem *) base; 413764e82eSJohannes Thumshirn struct mcb_device *mdev; 423764e82eSJohannes Thumshirn u32 offset; 433764e82eSJohannes Thumshirn u32 size; 443764e82eSJohannes Thumshirn int ret; 453764e82eSJohannes Thumshirn __le32 reg1; 463764e82eSJohannes Thumshirn __le32 reg2; 473764e82eSJohannes Thumshirn 483764e82eSJohannes Thumshirn mdev = mcb_alloc_dev(bus); 493764e82eSJohannes Thumshirn if (!mdev) 503764e82eSJohannes Thumshirn return -ENOMEM; 513764e82eSJohannes Thumshirn 523764e82eSJohannes Thumshirn reg1 = readl(&gdd->reg1); 533764e82eSJohannes Thumshirn reg2 = readl(&gdd->reg2); 543764e82eSJohannes Thumshirn offset = readl(&gdd->offset); 553764e82eSJohannes Thumshirn size = readl(&gdd->size); 563764e82eSJohannes Thumshirn 573764e82eSJohannes Thumshirn mdev->id = GDD_DEV(reg1); 583764e82eSJohannes Thumshirn mdev->rev = GDD_REV(reg1); 593764e82eSJohannes Thumshirn mdev->var = GDD_VAR(reg1); 603764e82eSJohannes Thumshirn mdev->bar = GDD_BAR(reg1); 613764e82eSJohannes Thumshirn mdev->group = GDD_GRP(reg2); 623764e82eSJohannes Thumshirn mdev->inst = GDD_INS(reg2); 633764e82eSJohannes Thumshirn 643764e82eSJohannes Thumshirn pr_debug("Found a 16z%03d\n", mdev->id); 653764e82eSJohannes Thumshirn 663764e82eSJohannes Thumshirn mdev->irq.start = GDD_IRQ(reg1); 673764e82eSJohannes Thumshirn mdev->irq.end = GDD_IRQ(reg1); 683764e82eSJohannes Thumshirn mdev->irq.flags = IORESOURCE_IRQ; 693764e82eSJohannes Thumshirn 703764e82eSJohannes Thumshirn mdev->mem.start = mapbase + offset; 713764e82eSJohannes Thumshirn mdev->mem.end = mdev->mem.start + size - 1; 723764e82eSJohannes Thumshirn mdev->mem.flags = IORESOURCE_MEM; 733764e82eSJohannes Thumshirn 743764e82eSJohannes Thumshirn mdev->is_added = false; 753764e82eSJohannes Thumshirn 763764e82eSJohannes Thumshirn ret = mcb_device_register(bus, mdev); 773764e82eSJohannes Thumshirn if (ret < 0) 783764e82eSJohannes Thumshirn goto err; 793764e82eSJohannes Thumshirn 803764e82eSJohannes Thumshirn return 0; 813764e82eSJohannes Thumshirn 823764e82eSJohannes Thumshirn err: 833764e82eSJohannes Thumshirn mcb_free_dev(mdev); 843764e82eSJohannes Thumshirn 853764e82eSJohannes Thumshirn return ret; 863764e82eSJohannes Thumshirn } 873764e82eSJohannes Thumshirn 883764e82eSJohannes Thumshirn int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, 893764e82eSJohannes Thumshirn void __iomem *base) 903764e82eSJohannes Thumshirn { 913764e82eSJohannes Thumshirn char __iomem *p = base; 923764e82eSJohannes Thumshirn struct chameleon_fpga_header *header; 933764e82eSJohannes Thumshirn uint32_t dtype; 943764e82eSJohannes Thumshirn int num_cells = 0; 953764e82eSJohannes Thumshirn int ret = 0; 963764e82eSJohannes Thumshirn u32 hsize; 973764e82eSJohannes Thumshirn 983764e82eSJohannes Thumshirn hsize = sizeof(struct chameleon_fpga_header); 993764e82eSJohannes Thumshirn 1003764e82eSJohannes Thumshirn header = kzalloc(hsize, GFP_KERNEL); 1013764e82eSJohannes Thumshirn if (!header) 1023764e82eSJohannes Thumshirn return -ENOMEM; 1033764e82eSJohannes Thumshirn 1043764e82eSJohannes Thumshirn /* Extract header information */ 1053764e82eSJohannes Thumshirn memcpy_fromio(header, p, hsize); 1063764e82eSJohannes Thumshirn /* We only support chameleon v2 at the moment */ 1073764e82eSJohannes Thumshirn header->magic = le16_to_cpu(header->magic); 1083764e82eSJohannes Thumshirn if (header->magic != CHAMELEONV2_MAGIC) { 1093764e82eSJohannes Thumshirn pr_err("Unsupported chameleon version 0x%x\n", 1103764e82eSJohannes Thumshirn header->magic); 1113764e82eSJohannes Thumshirn kfree(header); 1123764e82eSJohannes Thumshirn return -ENODEV; 1133764e82eSJohannes Thumshirn } 1143764e82eSJohannes Thumshirn p += hsize; 1153764e82eSJohannes Thumshirn 116*803f1ca6SJohannes Thumshirn bus->revision = header->revision; 117*803f1ca6SJohannes Thumshirn bus->model = header->model; 118*803f1ca6SJohannes Thumshirn bus->minor = header->minor; 119*803f1ca6SJohannes Thumshirn snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s", 1203764e82eSJohannes Thumshirn header->filename); 1213764e82eSJohannes Thumshirn 1223764e82eSJohannes Thumshirn for_each_chameleon_cell(dtype, p) { 1233764e82eSJohannes Thumshirn switch (dtype) { 1243764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_GENERAL: 1253764e82eSJohannes Thumshirn ret = chameleon_parse_gdd(bus, mapbase, p); 1263764e82eSJohannes Thumshirn if (ret < 0) 1273764e82eSJohannes Thumshirn goto out; 1283764e82eSJohannes Thumshirn p += sizeof(struct chameleon_gdd); 1293764e82eSJohannes Thumshirn break; 1303764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_BRIDGE: 1313764e82eSJohannes Thumshirn chameleon_parse_bdd(bus, mapbase, p); 1323764e82eSJohannes Thumshirn p += sizeof(struct chameleon_bdd); 1333764e82eSJohannes Thumshirn break; 1343764e82eSJohannes Thumshirn case CHAMELEON_DTYPE_END: 1353764e82eSJohannes Thumshirn break; 1363764e82eSJohannes Thumshirn default: 1373764e82eSJohannes Thumshirn pr_err("Invalid chameleon descriptor type 0x%x\n", 1383764e82eSJohannes Thumshirn dtype); 1397c735282SChristoph Jaeger kfree(header); 1403764e82eSJohannes Thumshirn return -EINVAL; 1413764e82eSJohannes Thumshirn } 1423764e82eSJohannes Thumshirn num_cells++; 1433764e82eSJohannes Thumshirn } 1443764e82eSJohannes Thumshirn 1453764e82eSJohannes Thumshirn if (num_cells == 0) 1463764e82eSJohannes Thumshirn num_cells = -EINVAL; 1473764e82eSJohannes Thumshirn 1483764e82eSJohannes Thumshirn kfree(header); 1493764e82eSJohannes Thumshirn return num_cells; 1503764e82eSJohannes Thumshirn 1513764e82eSJohannes Thumshirn out: 1523764e82eSJohannes Thumshirn kfree(header); 1533764e82eSJohannes Thumshirn return ret; 1543764e82eSJohannes Thumshirn } 1553764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(chameleon_parse_cells); 156