diff --git a/drivers/video/rockchip/mpp/mpp_av1dec.c b/drivers/video/rockchip/mpp/mpp_av1dec.c index e5dfb373207b..cb7e9e4f6a36 100644 --- a/drivers/video/rockchip/mpp/mpp_av1dec.c +++ b/drivers/video/rockchip/mpp/mpp_av1dec.c @@ -7,6 +7,8 @@ * */ +#define pr_fmt(fmt) "mpp_av1dec: " fmt + #include #include #include @@ -16,8 +18,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -28,7 +31,7 @@ #include "mpp_common.h" #include "mpp_iommu.h" -#define AV1DEC_DRIVER_NAME "mpp_av1dec" +#define AV1DEC_DRIVER_NAME "mpp_av1dec" #define AV1DEC_SESSION_MAX_BUFFERS 40 @@ -1098,7 +1101,7 @@ static int av1_of_device_add(struct platform_device *ofdev) return device_add(&ofdev->dev); } -struct platform_device *av1dec_device_create(void) +static struct platform_device *av1dec_device_create(void) { int ret = -ENODEV; struct device_node *root, *child; @@ -1134,6 +1137,35 @@ struct platform_device *av1dec_device_create(void) return ERR_PTR(ret); } +static void av1dec_device_destory(void) +{ + struct platform_device *pdev; + struct device *dev; + + dev = bus_find_device_by_name(&av1dec_bus, NULL, "av1d-master"); + pdev = dev ? to_platform_device(dev) : NULL; + if (!pdev) { + pr_err("cannot find platform device\n"); + return; + } + + pr_info("destroy device %s\n", dev_name(&pdev->dev)); + platform_device_del(pdev); + platform_device_put(pdev); +} + +void av1dec_driver_unregister(struct platform_driver *drv) +{ + /* 1. unregister av1 driver */ + driver_unregister(&drv->driver); + /* 2. release device */ + av1dec_device_destory(); + /* 3. unregister iommu driver */ + platform_driver_unregister(&rockchip_av1_iommu_driver); + /* 4. unregister bus */ + bus_unregister(&av1dec_bus); +} + int av1dec_driver_register(struct platform_driver *drv) { int ret; diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index cc673096c5fe..7c365850dff3 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -837,8 +837,8 @@ extern struct platform_driver rockchip_rkvenc2_driver; extern struct platform_driver rockchip_av1dec_driver; extern struct platform_driver rockchip_av1_iommu_driver; -extern struct platform_device *av1dec_device_create(void); extern int av1dec_driver_register(struct platform_driver *drv); +extern void av1dec_driver_unregister(struct platform_driver *drv); extern struct bus_type av1dec_bus; #endif diff --git a/drivers/video/rockchip/mpp/mpp_iommu_av1d.c b/drivers/video/rockchip/mpp/mpp_iommu_av1d.c index 0e10b3966efb..e09ce4cdf96a 100644 --- a/drivers/video/rockchip/mpp/mpp_iommu_av1d.c +++ b/drivers/video/rockchip/mpp/mpp_iommu_av1d.c @@ -713,6 +713,10 @@ static struct iommu_device *av1_iommu_probe_device(struct device *dev) pr_info("%s,%d, consumer : %s, supplier : %s\n", __func__, __LINE__, dev_name(dev), dev_name(iommu->dev)); + /* + * link will free by platform_device_del(master) via + * BUS_NOTIFY_REMOVED_DEVICE + */ data->link = device_link_add(dev, iommu->dev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME); @@ -729,9 +733,10 @@ static struct iommu_device *av1_iommu_probe_device(struct device *dev) static void av1_iommu_release_device(struct device *dev) { - struct av1_iommudata *data = dev_iommu_priv_get(dev); + const struct iommu_ops *ops = dev->bus->iommu_ops; - device_link_del(data->link); + /* hack for rmmod */ + __module_get(ops->owner); } static struct iommu_group *av1_iommu_device_group(struct device *dev) @@ -765,6 +770,14 @@ static int av1_iommu_of_xlate(struct device *dev, return 0; } +static void av1_iommu_probe_finalize(struct device *dev) +{ + const struct iommu_ops *ops = dev->bus->iommu_ops; + + /* hack for rmmod */ + module_put(ops->owner); +} + static struct iommu_ops av1_iommu_ops = { .domain_alloc = av1_iommu_domain_alloc, .domain_free = av1_iommu_domain_free, @@ -780,6 +793,7 @@ static struct iommu_ops av1_iommu_ops = { .device_group = av1_iommu_device_group, .pgsize_bitmap = AV1_IOMMU_PGSIZE_BITMAP, .of_xlate = av1_iommu_of_xlate, + .probe_finalize = av1_iommu_probe_finalize, }; static const struct of_device_id av1_iommu_dt_ids[] = { @@ -891,6 +905,17 @@ err_unprepare_clocks: return err; } +static int av1_iommu_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct av1_iommu *iommu = platform_get_drvdata(pdev); + + iommu_device_unregister(&iommu->iommu); + iommu_device_sysfs_remove(&iommu->iommu); + pm_runtime_disable(dev); + return 0; +} + static void av1_iommu_shutdown(struct platform_device *pdev) { struct av1_iommu *iommu = platform_get_drvdata(pdev); @@ -934,6 +959,7 @@ static const struct dev_pm_ops av1_iommu_pm_ops = { struct platform_driver rockchip_av1_iommu_driver = { .probe = av1_iommu_probe, + .remove = av1_iommu_remove, .shutdown = av1_iommu_shutdown, .driver = { .name = "av1_iommu", diff --git a/drivers/video/rockchip/mpp/mpp_service.c b/drivers/video/rockchip/mpp/mpp_service.c index e58a7df934fc..c9f858e3904b 100644 --- a/drivers/video/rockchip/mpp/mpp_service.c +++ b/drivers/video/rockchip/mpp/mpp_service.c @@ -113,8 +113,14 @@ static int mpp_add_driver(struct mpp_service *srv, static int mpp_remove_driver(struct mpp_service *srv, int i) { if (srv && srv->sub_drivers[i]) { - mpp_set_grf(&srv->grf_infos[i]); - platform_driver_unregister(srv->sub_drivers[i]); + if (i != MPP_DRIVER_AV1DEC) { + mpp_set_grf(&srv->grf_infos[i]); + platform_driver_unregister(srv->sub_drivers[i]); + } +#if IS_ENABLED(CONFIG_ROCKCHIP_MPP_AV1DEC) + else + av1dec_driver_unregister(srv->sub_drivers[i]); +#endif srv->sub_drivers[i] = NULL; }