xref: /linux/drivers/mcb/mcb-parse.c (revision 7c7352827343b377446bb59b844d387df665e401)
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 
1163764e82eSJohannes Thumshirn 	pr_debug("header->revision = %d\n", header->revision);
1173764e82eSJohannes Thumshirn 	pr_debug("header->model = 0x%x ('%c')\n", header->model,
1183764e82eSJohannes Thumshirn 		header->model);
1193764e82eSJohannes Thumshirn 	pr_debug("header->minor = %d\n", header->minor);
1203764e82eSJohannes Thumshirn 	pr_debug("header->bus_type = 0x%x\n", header->bus_type);
1213764e82eSJohannes Thumshirn 
1223764e82eSJohannes Thumshirn 
1233764e82eSJohannes Thumshirn 	pr_debug("header->magic = 0x%x\n", header->magic);
1243764e82eSJohannes Thumshirn 	pr_debug("header->filename = \"%.*s\"\n", CHAMELEON_FILENAME_LEN,
1253764e82eSJohannes Thumshirn 		header->filename);
1263764e82eSJohannes Thumshirn 
1273764e82eSJohannes Thumshirn 	for_each_chameleon_cell(dtype, p) {
1283764e82eSJohannes Thumshirn 		switch (dtype) {
1293764e82eSJohannes Thumshirn 		case CHAMELEON_DTYPE_GENERAL:
1303764e82eSJohannes Thumshirn 			ret = chameleon_parse_gdd(bus, mapbase, p);
1313764e82eSJohannes Thumshirn 			if (ret < 0)
1323764e82eSJohannes Thumshirn 				goto out;
1333764e82eSJohannes Thumshirn 			p += sizeof(struct chameleon_gdd);
1343764e82eSJohannes Thumshirn 			break;
1353764e82eSJohannes Thumshirn 		case CHAMELEON_DTYPE_BRIDGE:
1363764e82eSJohannes Thumshirn 			chameleon_parse_bdd(bus, mapbase, p);
1373764e82eSJohannes Thumshirn 			p += sizeof(struct chameleon_bdd);
1383764e82eSJohannes Thumshirn 			break;
1393764e82eSJohannes Thumshirn 		case CHAMELEON_DTYPE_END:
1403764e82eSJohannes Thumshirn 			break;
1413764e82eSJohannes Thumshirn 		default:
1423764e82eSJohannes Thumshirn 			pr_err("Invalid chameleon descriptor type 0x%x\n",
1433764e82eSJohannes Thumshirn 				dtype);
144*7c735282SChristoph Jaeger 			kfree(header);
1453764e82eSJohannes Thumshirn 			return -EINVAL;
1463764e82eSJohannes Thumshirn 		}
1473764e82eSJohannes Thumshirn 		num_cells++;
1483764e82eSJohannes Thumshirn 	}
1493764e82eSJohannes Thumshirn 
1503764e82eSJohannes Thumshirn 	if (num_cells == 0)
1513764e82eSJohannes Thumshirn 		num_cells = -EINVAL;
1523764e82eSJohannes Thumshirn 
1533764e82eSJohannes Thumshirn 	kfree(header);
1543764e82eSJohannes Thumshirn 	return num_cells;
1553764e82eSJohannes Thumshirn 
1563764e82eSJohannes Thumshirn out:
1573764e82eSJohannes Thumshirn 	kfree(header);
1583764e82eSJohannes Thumshirn 	return ret;
1593764e82eSJohannes Thumshirn }
1603764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(chameleon_parse_cells);
161