Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e87cae37 authored by Lowry Li (Arm Technology China)'s avatar Lowry Li (Arm Technology China) Committed by Liviu Dudau
Browse files

drm/komeda: Adds SMMU support



Adds iommu_connect and disconnect for SMMU support, and configures
TBU translation once SMMU has been attached to the display device.

Signed-off-by: default avatarLowry Li (Arm Technology China) <lowry.li@arm.com>
[fixed checking of error code returned by dp_wait_cond() and removed
extraneous DRM_ERROR() calls]
Signed-off-by: default avatarLiviu Dudau <liviu.dudau@arm.com>
parent 9682dee9
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -250,6 +250,8 @@ static void d71_layer_update(struct komeda_component *c,
	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));


	if (kfb->is_va)
		ctrl |= L_TBU_EN;
	malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
	malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
}
}


@@ -383,6 +385,9 @@ static void d71_wb_layer_update(struct komeda_component *c,
			       fb->pitches[i] & 0xFFFF);
			       fb->pitches[i] & 0xFFFF);
	}
	}


	if (kfb->is_va)
		ctrl |= LW_TBU_EN;

	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
+49 −0
Original line number Original line Diff line number Diff line
@@ -517,6 +517,53 @@ static void d71_init_fmt_tbl(struct komeda_dev *mdev)
	table->n_formats = ARRAY_SIZE(d71_format_caps_table);
	table->n_formats = ARRAY_SIZE(d71_format_caps_table);
}
}


static int d71_connect_iommu(struct komeda_dev *mdev)
{
	struct d71_dev *d71 = mdev->chip_data;
	u32 __iomem *reg = d71->gcu_addr;
	u32 check_bits = (d71->num_pipelines == 2) ?
			 GCU_STATUS_TCS0 | GCU_STATUS_TCS1 : GCU_STATUS_TCS0;
	int i, ret;

	if (!d71->integrates_tbu)
		return -1;

	malidp_write32_mask(reg, BLK_CONTROL, 0x7, TBU_CONNECT_MODE);

	ret = dp_wait_cond(has_bits(check_bits, malidp_read32(reg, BLK_STATUS)),
			100, 1000, 1000);
	if (ret < 0) {
		DRM_ERROR("timed out connecting to TCU!\n");
		malidp_write32_mask(reg, BLK_CONTROL, 0x7, INACTIVE_MODE);
		return ret;
	}

	for (i = 0; i < d71->num_pipelines; i++)
		malidp_write32_mask(d71->pipes[i]->lpu_addr, LPU_TBU_CONTROL,
				    LPU_TBU_CTRL_TLBPEN, LPU_TBU_CTRL_TLBPEN);
	return 0;
}

static int d71_disconnect_iommu(struct komeda_dev *mdev)
{
	struct d71_dev *d71 = mdev->chip_data;
	u32 __iomem *reg = d71->gcu_addr;
	u32 check_bits = (d71->num_pipelines == 2) ?
			 GCU_STATUS_TCS0 | GCU_STATUS_TCS1 : GCU_STATUS_TCS0;
	int ret;

	malidp_write32_mask(reg, BLK_CONTROL, 0x7, TBU_DISCONNECT_MODE);

	ret = dp_wait_cond(((malidp_read32(reg, BLK_STATUS) & check_bits) == 0),
			100, 1000, 1000);
	if (ret < 0) {
		DRM_ERROR("timed out disconnecting from TCU!\n");
		malidp_write32_mask(reg, BLK_CONTROL, 0x7, INACTIVE_MODE);
	}

	return ret;
}

static const struct komeda_dev_funcs d71_chip_funcs = {
static const struct komeda_dev_funcs d71_chip_funcs = {
	.init_format_table = d71_init_fmt_tbl,
	.init_format_table = d71_init_fmt_tbl,
	.enum_resources	= d71_enum_resources,
	.enum_resources	= d71_enum_resources,
@@ -527,6 +574,8 @@ static const struct komeda_dev_funcs d71_chip_funcs = {
	.on_off_vblank	= d71_on_off_vblank,
	.on_off_vblank	= d71_on_off_vblank,
	.change_opmode	= d71_change_opmode,
	.change_opmode	= d71_change_opmode,
	.flush		= d71_flush,
	.flush		= d71_flush,
	.connect_iommu	= d71_connect_iommu,
	.disconnect_iommu = d71_disconnect_iommu,
};
};


const struct komeda_dev_funcs *
const struct komeda_dev_funcs *
+17 −0
Original line number Original line Diff line number Diff line
@@ -5,6 +5,7 @@
 *
 *
 */
 */
#include <linux/io.h>
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/of_device.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
@@ -253,6 +254,18 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
	dev->dma_parms = &mdev->dma_parms;
	dev->dma_parms = &mdev->dma_parms;
	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));


	mdev->iommu = iommu_get_domain_for_dev(mdev->dev);
	if (!mdev->iommu)
		DRM_INFO("continue without IOMMU support!\n");

	if (mdev->iommu && mdev->funcs->connect_iommu) {
		err = mdev->funcs->connect_iommu(mdev);
		if (err) {
			mdev->iommu = NULL;
			goto err_cleanup;
		}
	}

	err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
	err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
	if (err) {
	if (err) {
		DRM_ERROR("create sysfs group failed.\n");
		DRM_ERROR("create sysfs group failed.\n");
@@ -282,6 +295,10 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
	debugfs_remove_recursive(mdev->debugfs_root);
	debugfs_remove_recursive(mdev->debugfs_root);
#endif
#endif


	if (mdev->iommu && mdev->funcs->disconnect_iommu)
		mdev->funcs->disconnect_iommu(mdev);
	mdev->iommu = NULL;

	for (i = 0; i < mdev->n_pipelines; i++) {
	for (i = 0; i < mdev->n_pipelines; i++) {
		komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
		komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
		mdev->pipelines[i] = NULL;
		mdev->pipelines[i] = NULL;
+7 −0
Original line number Original line Diff line number Diff line
@@ -92,6 +92,10 @@ struct komeda_dev_funcs {
	int (*enum_resources)(struct komeda_dev *mdev);
	int (*enum_resources)(struct komeda_dev *mdev);
	/** @cleanup: call to chip to cleanup komeda_dev->chip data */
	/** @cleanup: call to chip to cleanup komeda_dev->chip data */
	void (*cleanup)(struct komeda_dev *mdev);
	void (*cleanup)(struct komeda_dev *mdev);
	/** @connect_iommu: Optional, connect to external iommu */
	int (*connect_iommu)(struct komeda_dev *mdev);
	/** @disconnect_iommu: Optional, disconnect to external iommu */
	int (*disconnect_iommu)(struct komeda_dev *mdev);
	/**
	/**
	 * @irq_handler:
	 * @irq_handler:
	 *
	 *
@@ -184,6 +188,9 @@ struct komeda_dev {
	 */
	 */
	void *chip_data;
	void *chip_data;


	/** @iommu: iommu domain */
	struct iommu_domain *iommu;

	/** @debugfs_root: root directory of komeda debugfs */
	/** @debugfs_root: root directory of komeda debugfs */
	struct dentry *debugfs_root;
	struct dentry *debugfs_root;
};
};
+2 −0
Original line number Original line Diff line number Diff line
@@ -202,6 +202,8 @@ komeda_fb_create(struct drm_device *dev, struct drm_file *file,
		goto err_cleanup;
		goto err_cleanup;
	}
	}


	kfb->is_va = mdev->iommu ? true : false;

	return &kfb->base;
	return &kfb->base;


err_cleanup:
err_cleanup:
Loading