static int edma_probe()

in ti/edma.c [2339:2597]


static int edma_probe(struct platform_device *pdev)
{
	struct edma_soc_info	*info = pdev->dev.platform_data;
	s8			(*queue_priority_mapping)[2];
	const s16		(*reserved)[2];
	int			i, irq;
	char			*irq_name;
	struct resource		*mem;
	struct device_node	*node = pdev->dev.of_node;
	struct device		*dev = &pdev->dev;
	struct edma_cc		*ecc;
	bool			legacy_mode = true;
	int ret;

	if (node) {
		const struct of_device_id *match;

		match = of_match_node(edma_of_ids, node);
		if (match && (*(u32 *)match->data) == EDMA_BINDING_TPCC)
			legacy_mode = false;

		info = edma_setup_info_from_dt(dev, legacy_mode);
		if (IS_ERR(info)) {
			dev_err(dev, "failed to get DT data\n");
			return PTR_ERR(info);
		}
	}

	if (!info)
		return -ENODEV;

	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
	if (ret)
		return ret;

	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
	if (!ecc)
		return -ENOMEM;

	ecc->dev = dev;
	ecc->id = pdev->id;
	ecc->legacy_mode = legacy_mode;
	/* When booting with DT the pdev->id is -1 */
	if (ecc->id < 0)
		ecc->id = 0;

	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma3_cc");
	if (!mem) {
		dev_dbg(dev, "mem resource not found, using index 0\n");
		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
		if (!mem) {
			dev_err(dev, "no mem resource?\n");
			return -ENODEV;
		}
	}
	ecc->base = devm_ioremap_resource(dev, mem);
	if (IS_ERR(ecc->base))
		return PTR_ERR(ecc->base);

	platform_set_drvdata(pdev, ecc);

	pm_runtime_enable(dev);
	ret = pm_runtime_get_sync(dev);
	if (ret < 0) {
		dev_err(dev, "pm_runtime_get_sync() failed\n");
		pm_runtime_disable(dev);
		return ret;
	}

	/* Get eDMA3 configuration from IP */
	ret = edma_setup_from_hw(dev, info, ecc);
	if (ret)
		goto err_disable_pm;

	/* Allocate memory based on the information we got from the IP */
	ecc->slave_chans = devm_kcalloc(dev, ecc->num_channels,
					sizeof(*ecc->slave_chans), GFP_KERNEL);

	ecc->slot_inuse = devm_kcalloc(dev, BITS_TO_LONGS(ecc->num_slots),
				       sizeof(unsigned long), GFP_KERNEL);

	ecc->channels_mask = devm_kcalloc(dev,
					   BITS_TO_LONGS(ecc->num_channels),
					   sizeof(unsigned long), GFP_KERNEL);
	if (!ecc->slave_chans || !ecc->slot_inuse || !ecc->channels_mask) {
		ret = -ENOMEM;
		goto err_disable_pm;
	}

	/* Mark all channels available initially */
	bitmap_fill(ecc->channels_mask, ecc->num_channels);

	ecc->default_queue = info->default_queue;

	if (info->rsv) {
		/* Set the reserved slots in inuse list */
		reserved = info->rsv->rsv_slots;
		if (reserved) {
			for (i = 0; reserved[i][0] != -1; i++)
				bitmap_set(ecc->slot_inuse, reserved[i][0],
					   reserved[i][1]);
		}

		/* Clear channels not usable for Linux */
		reserved = info->rsv->rsv_chans;
		if (reserved) {
			for (i = 0; reserved[i][0] != -1; i++)
				bitmap_clear(ecc->channels_mask, reserved[i][0],
					     reserved[i][1]);
		}
	}

	for (i = 0; i < ecc->num_slots; i++) {
		/* Reset only unused - not reserved - paRAM slots */
		if (!test_bit(i, ecc->slot_inuse))
			edma_write_slot(ecc, i, &dummy_paramset);
	}

	irq = platform_get_irq_byname(pdev, "edma3_ccint");
	if (irq < 0 && node)
		irq = irq_of_parse_and_map(node, 0);

	if (irq >= 0) {
		irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint",
					  dev_name(dev));
		ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name,
				       ecc);
		if (ret) {
			dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret);
			goto err_disable_pm;
		}
		ecc->ccint = irq;
	}

	irq = platform_get_irq_byname(pdev, "edma3_ccerrint");
	if (irq < 0 && node)
		irq = irq_of_parse_and_map(node, 2);

	if (irq >= 0) {
		irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint",
					  dev_name(dev));
		ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name,
				       ecc);
		if (ret) {
			dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret);
			goto err_disable_pm;
		}
		ecc->ccerrint = irq;
	}

	ecc->dummy_slot = edma_alloc_slot(ecc, EDMA_SLOT_ANY);
	if (ecc->dummy_slot < 0) {
		dev_err(dev, "Can't allocate PaRAM dummy slot\n");
		ret = ecc->dummy_slot;
		goto err_disable_pm;
	}

	queue_priority_mapping = info->queue_priority_mapping;

	if (!ecc->legacy_mode) {
		int lowest_priority = 0;
		unsigned int array_max;
		struct of_phandle_args tc_args;

		ecc->tc_list = devm_kcalloc(dev, ecc->num_tc,
					    sizeof(*ecc->tc_list), GFP_KERNEL);
		if (!ecc->tc_list) {
			ret = -ENOMEM;
			goto err_reg1;
		}

		for (i = 0;; i++) {
			ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs",
							       1, i, &tc_args);
			if (ret || i == ecc->num_tc)
				break;

			ecc->tc_list[i].node = tc_args.np;
			ecc->tc_list[i].id = i;
			queue_priority_mapping[i][1] = tc_args.args[0];
			if (queue_priority_mapping[i][1] > lowest_priority) {
				lowest_priority = queue_priority_mapping[i][1];
				info->default_queue = i;
			}
		}

		/* See if we have optional dma-channel-mask array */
		array_max = DIV_ROUND_UP(ecc->num_channels, BITS_PER_TYPE(u32));
		ret = of_property_read_variable_u32_array(node,
						"dma-channel-mask",
						(u32 *)ecc->channels_mask,
						1, array_max);
		if (ret > 0 && ret != array_max)
			dev_warn(dev, "dma-channel-mask is not complete.\n");
		else if (ret == -EOVERFLOW || ret == -ENODATA)
			dev_warn(dev,
				 "dma-channel-mask is out of range or empty\n");
	}

	/* Event queue priority mapping */
	for (i = 0; queue_priority_mapping[i][0] != -1; i++)
		edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0],
					      queue_priority_mapping[i][1]);

	edma_write_array2(ecc, EDMA_DRAE, 0, 0, 0x0);
	edma_write_array2(ecc, EDMA_DRAE, 0, 1, 0x0);
	edma_write_array(ecc, EDMA_QRAE, 0, 0x0);

	ecc->info = info;

	/* Init the dma device and channels */
	edma_dma_init(ecc, legacy_mode);

	for (i = 0; i < ecc->num_channels; i++) {
		/* Do not touch reserved channels */
		if (!test_bit(i, ecc->channels_mask))
			continue;

		/* Assign all channels to the default queue */
		edma_assign_channel_eventq(&ecc->slave_chans[i],
					   info->default_queue);
		/* Set entry slot to the dummy slot */
		edma_set_chmap(&ecc->slave_chans[i], ecc->dummy_slot);
	}

	ecc->dma_slave.filter.map = info->slave_map;
	ecc->dma_slave.filter.mapcnt = info->slavecnt;
	ecc->dma_slave.filter.fn = edma_filter_fn;

	ret = dma_async_device_register(&ecc->dma_slave);
	if (ret) {
		dev_err(dev, "slave ddev registration failed (%d)\n", ret);
		goto err_reg1;
	}

	if (ecc->dma_memcpy) {
		ret = dma_async_device_register(ecc->dma_memcpy);
		if (ret) {
			dev_err(dev, "memcpy ddev registration failed (%d)\n",
				ret);
			dma_async_device_unregister(&ecc->dma_slave);
			goto err_reg1;
		}
	}

	if (node)
		of_dma_controller_register(node, of_edma_xlate, ecc);

	dev_info(dev, "TI EDMA DMA engine driver\n");

	return 0;

err_reg1:
	edma_free_slot(ecc, ecc->dummy_slot);
err_disable_pm:
	pm_runtime_put_sync(dev);
	pm_runtime_disable(dev);
	return ret;
}