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