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

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
...@@ -250,6 +250,8 @@ static void d71_layer_update(struct komeda_component *c, ...@@ -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, ...@@ -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]));
......
...@@ -517,6 +517,53 @@ static void d71_init_fmt_tbl(struct komeda_dev *mdev) ...@@ -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 = { ...@@ -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 *
......
...@@ -5,6 +5,7 @@ ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -92,6 +92,10 @@ struct komeda_dev_funcs { ...@@ -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 { ...@@ -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;
}; };
......
...@@ -202,6 +202,8 @@ komeda_fb_create(struct drm_device *dev, struct drm_file *file, ...@@ -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:
......
...@@ -21,6 +21,8 @@ struct komeda_fb { ...@@ -21,6 +21,8 @@ struct komeda_fb {
* extends drm_format_info for komeda specific information * extends drm_format_info for komeda specific information
*/ */
const struct komeda_format_caps *format_caps; const struct komeda_format_caps *format_caps;
/** @is_va: if smmu is enabled, it will be true */
bool is_va;
/** @aligned_w: aligned frame buffer width */ /** @aligned_w: aligned frame buffer width */
u32 aligned_w; u32 aligned_w;
/** @aligned_h: aligned frame buffer height */ /** @aligned_h: aligned frame buffer height */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment