static int init_cc_resources()

in ccree/cc_driver.c [307:581]


static int init_cc_resources(struct platform_device *plat_dev)
{
	struct resource *req_mem_cc_regs = NULL;
	struct cc_drvdata *new_drvdata;
	struct device *dev = &plat_dev->dev;
	struct device_node *np = dev->of_node;
	u32 val, hw_rev_pidr, sig_cidr;
	u64 dma_mask;
	const struct cc_hw_data *hw_rev;
	struct clk *clk;
	int irq;
	int rc = 0;

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

	hw_rev = of_device_get_match_data(dev);
	new_drvdata->hw_rev_name = hw_rev->name;
	new_drvdata->hw_rev = hw_rev->rev;
	new_drvdata->std_bodies = hw_rev->std_bodies;

	if (hw_rev->rev >= CC_HW_REV_712) {
		new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP);
		new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_712);
		new_drvdata->ver_offset = CC_REG(HOST_VERSION_712);
	} else {
		new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP8);
		new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_630);
		new_drvdata->ver_offset = CC_REG(HOST_VERSION_630);
	}

	new_drvdata->comp_mask = CC_COMP_IRQ_MASK;

	platform_set_drvdata(plat_dev, new_drvdata);
	new_drvdata->plat_dev = plat_dev;

	clk = devm_clk_get_optional(dev, NULL);
	if (IS_ERR(clk))
		return dev_err_probe(dev, PTR_ERR(clk), "Error getting clock\n");
	new_drvdata->clk = clk;

	new_drvdata->coherent = of_dma_is_coherent(np);

	/* Get device resources */
	/* First CC registers space */
	req_mem_cc_regs = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
	/* Map registers space */
	new_drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs);
	if (IS_ERR(new_drvdata->cc_base))
		return PTR_ERR(new_drvdata->cc_base);

	dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name,
		req_mem_cc_regs);
	dev_dbg(dev, "CC registers mapped from %pa to 0x%p\n",
		&req_mem_cc_regs->start, new_drvdata->cc_base);

	/* Then IRQ */
	irq = platform_get_irq(plat_dev, 0);
	if (irq < 0)
		return irq;

	init_completion(&new_drvdata->hw_queue_avail);

	if (!dev->dma_mask)
		dev->dma_mask = &dev->coherent_dma_mask;

	dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN);
	while (dma_mask > 0x7fffffffUL) {
		if (dma_supported(dev, dma_mask)) {
			rc = dma_set_coherent_mask(dev, dma_mask);
			if (!rc)
				break;
		}
		dma_mask >>= 1;
	}

	if (rc) {
		dev_err(dev, "Failed in dma_set_mask, mask=%llx\n", dma_mask);
		return rc;
	}

	rc = clk_prepare_enable(new_drvdata->clk);
	if (rc) {
		dev_err(dev, "Failed to enable clock");
		return rc;
	}

	new_drvdata->sec_disabled = cc_sec_disable;

	pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT);
	pm_runtime_use_autosuspend(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	rc = pm_runtime_get_sync(dev);
	if (rc < 0) {
		dev_err(dev, "pm_runtime_get_sync() failed: %d\n", rc);
		goto post_pm_err;
	}

	/* Wait for Cryptocell reset completion */
	if (!cc_wait_for_reset_completion(new_drvdata)) {
		dev_err(dev, "Cryptocell reset not completed");
	}

	if (hw_rev->rev <= CC_HW_REV_712) {
		/* Verify correct mapping */
		val = cc_ioread(new_drvdata, new_drvdata->sig_offset);
		if (val != hw_rev->sig) {
			dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n",
				val, hw_rev->sig);
			rc = -EINVAL;
			goto post_pm_err;
		}
		sig_cidr = val;
		hw_rev_pidr = cc_ioread(new_drvdata, new_drvdata->ver_offset);
	} else {
		/* Verify correct mapping */
		val = cc_read_idr(new_drvdata, pidr_0124_offsets);
		if (val != hw_rev->pidr_0124) {
			dev_err(dev, "Invalid CC PIDR: PIDR0124=0x%08X != expected=0x%08X\n",
				val,  hw_rev->pidr_0124);
			rc = -EINVAL;
			goto post_pm_err;
		}
		hw_rev_pidr = val;

		val = cc_read_idr(new_drvdata, cidr_0123_offsets);
		if (val != hw_rev->cidr_0123) {
			dev_err(dev, "Invalid CC CIDR: CIDR0123=0x%08X != expected=0x%08X\n",
			val,  hw_rev->cidr_0123);
			rc = -EINVAL;
			goto post_pm_err;
		}
		sig_cidr = val;

		/* Check HW engine configuration */
		val = cc_ioread(new_drvdata, CC_REG(HOST_REMOVE_INPUT_PINS));
		switch (val) {
		case CC_PINS_FULL:
			/* This is fine */
			break;
		case CC_PINS_SLIM:
			if (new_drvdata->std_bodies & CC_STD_NIST) {
				dev_warn(dev, "703 mode forced due to HW configuration.\n");
				new_drvdata->std_bodies = CC_STD_OSCCA;
			}
			break;
		default:
			dev_err(dev, "Unsupported engines configuration.\n");
			rc = -EINVAL;
			goto post_pm_err;
		}

		/* Check security disable state */
		val = cc_ioread(new_drvdata, CC_REG(SECURITY_DISABLED));
		val &= CC_SECURITY_DISABLED_MASK;
		new_drvdata->sec_disabled |= !!val;

		if (!new_drvdata->sec_disabled) {
			new_drvdata->comp_mask |= CC_CPP_SM4_ABORT_MASK;
			if (new_drvdata->std_bodies & CC_STD_NIST)
				new_drvdata->comp_mask |= CC_CPP_AES_ABORT_MASK;
		}
	}

	if (new_drvdata->sec_disabled)
		dev_info(dev, "Security Disabled mode is in effect. Security functions disabled.\n");

	/* Display HW versions */
	dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X/0x%8X, Driver version %s\n",
		 hw_rev->name, hw_rev_pidr, sig_cidr, DRV_MODULE_VERSION);
	/* register the driver isr function */
	rc = devm_request_irq(dev, irq, cc_isr, IRQF_SHARED, "ccree",
			      new_drvdata);
	if (rc) {
		dev_err(dev, "Could not register to interrupt %d\n", irq);
		goto post_pm_err;
	}
	dev_dbg(dev, "Registered to IRQ: %d\n", irq);

	init_cc_cache_params(new_drvdata);

	rc = init_cc_regs(new_drvdata);
	if (rc) {
		dev_err(dev, "init_cc_regs failed\n");
		goto post_pm_err;
	}

	rc = cc_debugfs_init(new_drvdata);
	if (rc) {
		dev_err(dev, "Failed registering debugfs interface\n");
		goto post_regs_err;
	}

	rc = cc_fips_init(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_fips_init failed 0x%x\n", rc);
		goto post_debugfs_err;
	}
	rc = cc_sram_mgr_init(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_sram_mgr_init failed\n");
		goto post_fips_init_err;
	}

	new_drvdata->mlli_sram_addr =
		cc_sram_alloc(new_drvdata, MAX_MLLI_BUFF_SIZE);
	if (new_drvdata->mlli_sram_addr == NULL_SRAM_ADDR) {
		rc = -ENOMEM;
		goto post_fips_init_err;
	}

	rc = cc_req_mgr_init(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_req_mgr_init failed\n");
		goto post_fips_init_err;
	}

	rc = cc_buffer_mgr_init(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_buffer_mgr_init failed\n");
		goto post_req_mgr_err;
	}

	/* Allocate crypto algs */
	rc = cc_cipher_alloc(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_cipher_alloc failed\n");
		goto post_buf_mgr_err;
	}

	/* hash must be allocated before aead since hash exports APIs */
	rc = cc_hash_alloc(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_hash_alloc failed\n");
		goto post_cipher_err;
	}

	rc = cc_aead_alloc(new_drvdata);
	if (rc) {
		dev_err(dev, "cc_aead_alloc failed\n");
		goto post_hash_err;
	}

	/* If we got here and FIPS mode is enabled
	 * it means all FIPS test passed, so let TEE
	 * know we're good.
	 */
	cc_set_ree_fips_status(new_drvdata, true);

	pm_runtime_put(dev);
	return 0;

post_hash_err:
	cc_hash_free(new_drvdata);
post_cipher_err:
	cc_cipher_free(new_drvdata);
post_buf_mgr_err:
	 cc_buffer_mgr_fini(new_drvdata);
post_req_mgr_err:
	cc_req_mgr_fini(new_drvdata);
post_fips_init_err:
	cc_fips_fini(new_drvdata);
post_debugfs_err:
	cc_debugfs_fini(new_drvdata);
post_regs_err:
	fini_cc_regs(new_drvdata);
post_pm_err:
	pm_runtime_put_noidle(dev);
	pm_runtime_disable(dev);
	pm_runtime_set_suspended(dev);
	clk_disable_unprepare(new_drvdata->clk);
	return rc;
}