Message ID | 20241120-qcom-video-iris-v6-2-a8cf6704e992@quicinc.com |
---|---|
State | Superseded |
Headers | show |
Series | Qualcomm iris video decoder driver | expand |
On 20/11/2024 15:45, Dikshita Agarwal wrote: > In preparation of adding H264 decode functionality, add probe and remove > functions and platform data to initialize iris resources, which are > clocks, interconnects, power domains, reset clocks, and clock > frequencies used for iris hardware. > > Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl> Regards, Hans > Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com> > --- > drivers/media/platform/qcom/Kconfig | 1 + > drivers/media/platform/qcom/Makefile | 1 + > drivers/media/platform/qcom/iris/Kconfig | 9 + > drivers/media/platform/qcom/iris/Makefile | 4 + > drivers/media/platform/qcom/iris/iris_core.h | 54 +++++ > .../platform/qcom/iris/iris_platform_common.h | 35 +++ > .../platform/qcom/iris/iris_platform_sm8550.c | 37 ++++ > drivers/media/platform/qcom/iris/iris_probe.c | 237 +++++++++++++++++++++ > 8 files changed, 378 insertions(+) > > diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig > index cc5799b9ea00..4f4d3a68e6e5 100644 > --- a/drivers/media/platform/qcom/Kconfig > +++ b/drivers/media/platform/qcom/Kconfig > @@ -3,4 +3,5 @@ > comment "Qualcomm media platform drivers" > > source "drivers/media/platform/qcom/camss/Kconfig" > +source "drivers/media/platform/qcom/iris/Kconfig" > source "drivers/media/platform/qcom/venus/Kconfig" > diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile > index 4f055c396e04..ea2221a202c0 100644 > --- a/drivers/media/platform/qcom/Makefile > +++ b/drivers/media/platform/qcom/Makefile > @@ -1,3 +1,4 @@ > # SPDX-License-Identifier: GPL-2.0-only > obj-y += camss/ > +obj-y += iris/ > obj-y += venus/ > diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig > new file mode 100644 > index 000000000000..34a2f81c5db3 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/Kconfig > @@ -0,0 +1,9 @@ > +config VIDEO_QCOM_IRIS > + tristate "Qualcomm iris V4L2 decoder driver" > + depends on VIDEO_DEV > + depends on ARCH_QCOM || COMPILE_TEST > + help > + This is a V4L2 driver for Qualcomm iris video accelerator > + hardware. It accelerates decoding operations on various > + Qualcomm SoCs. > + To compile this driver as a module choose m here. > diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile > new file mode 100644 > index 000000000000..7e701361492e > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/Makefile > @@ -0,0 +1,4 @@ > +iris-objs += iris_platform_sm8550.o \ > + iris_probe.o \ > + > +obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o > diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h > new file mode 100644 > index 000000000000..27bc2ca71e1b > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_core.h > @@ -0,0 +1,54 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef __IRIS_CORE_H__ > +#define __IRIS_CORE_H__ > + > +#include <linux/types.h> > +#include <media/v4l2-device.h> > + > +#include "iris_platform_common.h" > + > +struct icc_info { > + const char *name; > + u32 bw_min_kbps; > + u32 bw_max_kbps; > +}; > + > +/** > + * struct iris_core - holds core parameters valid for all instances > + * > + * @dev: reference to device structure > + * @reg_base: IO memory base address > + * @irq: iris irq > + * @v4l2_dev: a holder for v4l2 device structure > + * @vdev_dec: iris video device structure for decoder > + * @icc_tbl: table of iris interconnects > + * @icc_count: count of iris interconnects > + * @pmdomain_tbl: table of iris power domains > + * @opp_pmdomain_tbl: table of opp power domains > + * @clock_tbl: table of iris clocks > + * @clk_count: count of iris clocks > + * @resets: table of iris reset clocks > + * @iris_platform_data: a structure for platform data > + */ > + > +struct iris_core { > + struct device *dev; > + void __iomem *reg_base; > + int irq; > + struct v4l2_device v4l2_dev; > + struct video_device *vdev_dec; > + struct icc_bulk_data *icc_tbl; > + u32 icc_count; > + struct dev_pm_domain_list *pmdomain_tbl; > + struct dev_pm_domain_list *opp_pmdomain_tbl; > + struct clk_bulk_data *clock_tbl; > + u32 clk_count; > + struct reset_control_bulk_data *resets; > + const struct iris_platform_data *iris_platform_data; > +}; > + > +#endif > diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h > new file mode 100644 > index 000000000000..31c53dad8136 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h > @@ -0,0 +1,35 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef __IRIS_PLATFORM_COMMON_H__ > +#define __IRIS_PLATFORM_COMMON_H__ > + > +extern struct iris_platform_data sm8550_data; > + > +enum platform_clk_type { > + IRIS_AXI_CLK, > + IRIS_CTRL_CLK, > + IRIS_HW_CLK, > +}; > + > +struct platform_clk_data { > + enum platform_clk_type clk_type; > + const char *clk_name; > +}; > + > +struct iris_platform_data { > + const struct icc_info *icc_tbl; > + unsigned int icc_tbl_size; > + const char * const *pmdomain_tbl; > + unsigned int pmdomain_tbl_size; > + const char * const *opp_pd_tbl; > + unsigned int opp_pd_tbl_size; > + const struct platform_clk_data *clk_tbl; > + unsigned int clk_tbl_size; > + const char * const *clk_rst_tbl; > + unsigned int clk_rst_tbl_size; > +}; > + > +#endif > diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > new file mode 100644 > index 000000000000..3dd91523d783 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > @@ -0,0 +1,37 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include "iris_core.h" > +#include "iris_platform_common.h" > + > +static const struct icc_info sm8550_icc_table[] = { > + { "cpu-cfg", 1000, 1000 }, > + { "video-mem", 1000, 15000000 }, > +}; > + > +static const char * const sm8550_clk_reset_table[] = { "bus" }; > + > +static const char * const sm8550_pmdomain_table[] = { "venus", "vcodec0" }; > + > +static const char * const sm8550_opp_pd_table[] = { "mxc", "mmcx" }; > + > +static const struct platform_clk_data sm8550_clk_table[] = { > + {IRIS_AXI_CLK, "iface" }, > + {IRIS_CTRL_CLK, "core" }, > + {IRIS_HW_CLK, "vcodec0_core" }, > +}; > + > +struct iris_platform_data sm8550_data = { > + .icc_tbl = sm8550_icc_table, > + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), > + .clk_rst_tbl = sm8550_clk_reset_table, > + .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table), > + .pmdomain_tbl = sm8550_pmdomain_table, > + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), > + .opp_pd_tbl = sm8550_opp_pd_table, > + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), > + .clk_tbl = sm8550_clk_table, > + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), > +}; > diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c > new file mode 100644 > index 000000000000..911e3bc1b434 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_probe.c > @@ -0,0 +1,237 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include <linux/clk.h> > +#include <linux/interconnect.h> > +#include <linux/module.h> > +#include <linux/pm_domain.h> > +#include <linux/pm_opp.h> > +#include <linux/reset.h> > + > +#include "iris_core.h" > + > +static int iris_init_icc(struct iris_core *core) > +{ > + const struct icc_info *icc_tbl; > + u32 i = 0; > + > + icc_tbl = core->iris_platform_data->icc_tbl; > + > + core->icc_count = core->iris_platform_data->icc_tbl_size; > + core->icc_tbl = devm_kzalloc(core->dev, > + sizeof(struct icc_bulk_data) * core->icc_count, > + GFP_KERNEL); > + if (!core->icc_tbl) > + return -ENOMEM; > + > + for (i = 0; i < core->icc_count; i++) { > + core->icc_tbl[i].name = icc_tbl[i].name; > + core->icc_tbl[i].avg_bw = icc_tbl[i].bw_min_kbps; > + core->icc_tbl[i].peak_bw = 0; > + } > + > + return devm_of_icc_bulk_get(core->dev, core->icc_count, core->icc_tbl); > +} > + > +static int iris_init_power_domains(struct iris_core *core) > +{ > + const struct platform_clk_data *clk_tbl; > + u32 clk_cnt, i; > + int ret; > + > + struct dev_pm_domain_attach_data iris_pd_data = { > + .pd_names = core->iris_platform_data->pmdomain_tbl, > + .num_pd_names = core->iris_platform_data->pmdomain_tbl_size, > + .pd_flags = PD_FLAG_NO_DEV_LINK, > + }; > + > + struct dev_pm_domain_attach_data iris_opp_pd_data = { > + .pd_names = core->iris_platform_data->opp_pd_tbl, > + .num_pd_names = core->iris_platform_data->opp_pd_tbl_size, > + .pd_flags = PD_FLAG_DEV_LINK_ON, > + }; > + > + ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); > + if (ret < 0) > + return ret; > + > + ret = devm_pm_domain_attach_list(core->dev, &iris_opp_pd_data, &core->opp_pmdomain_tbl); > + if (ret < 0) > + return ret; > + > + clk_tbl = core->iris_platform_data->clk_tbl; > + clk_cnt = core->iris_platform_data->clk_tbl_size; > + > + for (i = 0; i < clk_cnt; i++) { > + if (clk_tbl[i].clk_type == IRIS_HW_CLK) { > + ret = devm_pm_opp_set_clkname(core->dev, clk_tbl[i].clk_name); > + if (ret) > + return ret; > + } > + } > + > + return devm_pm_opp_of_add_table(core->dev); > +} > + > +static int iris_init_clocks(struct iris_core *core) > +{ > + int ret; > + > + ret = devm_clk_bulk_get_all(core->dev, &core->clock_tbl); > + if (ret < 0) > + return ret; > + > + core->clk_count = ret; > + > + return 0; > +} > + > +static int iris_init_resets(struct iris_core *core) > +{ > + const char * const *rst_tbl; > + u32 rst_tbl_size; > + u32 i = 0; > + > + rst_tbl = core->iris_platform_data->clk_rst_tbl; > + rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; > + > + core->resets = devm_kzalloc(core->dev, > + sizeof(*core->resets) * rst_tbl_size, > + GFP_KERNEL); > + if (!core->resets) > + return -ENOMEM; > + > + for (i = 0; i < rst_tbl_size; i++) > + core->resets[i].id = rst_tbl[i]; > + > + return devm_reset_control_bulk_get_exclusive(core->dev, rst_tbl_size, core->resets); > +} > + > +static int iris_init_resources(struct iris_core *core) > +{ > + int ret; > + > + ret = iris_init_icc(core); > + if (ret) > + return ret; > + > + ret = iris_init_power_domains(core); > + if (ret) > + return ret; > + > + ret = iris_init_clocks(core); > + if (ret) > + return ret; > + > + return iris_init_resets(core); > +} > + > +static int iris_register_video_device(struct iris_core *core) > +{ > + struct video_device *vdev; > + int ret; > + > + vdev = video_device_alloc(); > + if (!vdev) > + return -ENOMEM; > + > + strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); > + vdev->release = video_device_release; > + vdev->vfl_dir = VFL_DIR_M2M; > + vdev->v4l2_dev = &core->v4l2_dev; > + vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; > + > + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); > + if (ret) > + goto err_vdev_release; > + > + core->vdev_dec = vdev; > + video_set_drvdata(vdev, core); > + > + return 0; > + > +err_vdev_release: > + video_device_release(vdev); > + > + return ret; > +} > + > +static void iris_remove(struct platform_device *pdev) > +{ > + struct iris_core *core; > + > + core = platform_get_drvdata(pdev); > + if (!core) > + return; > + > + video_unregister_device(core->vdev_dec); > + > + v4l2_device_unregister(&core->v4l2_dev); > +} > + > +static int iris_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct iris_core *core; > + int ret; > + > + core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL); > + if (!core) > + return -ENOMEM; > + core->dev = dev; > + > + core->reg_base = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(core->reg_base)) > + return PTR_ERR(core->reg_base); > + > + core->irq = platform_get_irq(pdev, 0); > + if (core->irq < 0) > + return core->irq; > + > + core->iris_platform_data = of_device_get_match_data(core->dev); > + > + ret = iris_init_resources(core); > + if (ret) > + return ret; > + > + ret = v4l2_device_register(dev, &core->v4l2_dev); > + if (ret) > + return ret; > + > + ret = iris_register_video_device(core); > + if (ret) > + goto err_v4l2_unreg; > + > + platform_set_drvdata(pdev, core); > + > + return 0; > + > +err_v4l2_unreg: > + v4l2_device_unregister(&core->v4l2_dev); > + > + return ret; > +} > + > +static const struct of_device_id iris_dt_match[] = { > + { > + .compatible = "qcom,sm8550-iris", > + .data = &sm8550_data, > + }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, iris_dt_match); > + > +static struct platform_driver qcom_iris_driver = { > + .probe = iris_probe, > + .remove = iris_remove, > + .driver = { > + .name = "qcom-iris", > + .of_match_table = iris_dt_match, > + }, > +}; > + > +module_platform_driver(qcom_iris_driver); > +MODULE_DESCRIPTION("Qualcomm iris video driver"); > +MODULE_LICENSE("GPL"); >
diff --git a/drivers/media/platform/qcom/Kconfig b/drivers/media/platform/qcom/Kconfig index cc5799b9ea00..4f4d3a68e6e5 100644 --- a/drivers/media/platform/qcom/Kconfig +++ b/drivers/media/platform/qcom/Kconfig @@ -3,4 +3,5 @@ comment "Qualcomm media platform drivers" source "drivers/media/platform/qcom/camss/Kconfig" +source "drivers/media/platform/qcom/iris/Kconfig" source "drivers/media/platform/qcom/venus/Kconfig" diff --git a/drivers/media/platform/qcom/Makefile b/drivers/media/platform/qcom/Makefile index 4f055c396e04..ea2221a202c0 100644 --- a/drivers/media/platform/qcom/Makefile +++ b/drivers/media/platform/qcom/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += camss/ +obj-y += iris/ obj-y += venus/ diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig new file mode 100644 index 000000000000..34a2f81c5db3 --- /dev/null +++ b/drivers/media/platform/qcom/iris/Kconfig @@ -0,0 +1,9 @@ +config VIDEO_QCOM_IRIS + tristate "Qualcomm iris V4L2 decoder driver" + depends on VIDEO_DEV + depends on ARCH_QCOM || COMPILE_TEST + help + This is a V4L2 driver for Qualcomm iris video accelerator + hardware. It accelerates decoding operations on various + Qualcomm SoCs. + To compile this driver as a module choose m here. diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile new file mode 100644 index 000000000000..7e701361492e --- /dev/null +++ b/drivers/media/platform/qcom/iris/Makefile @@ -0,0 +1,4 @@ +iris-objs += iris_platform_sm8550.o \ + iris_probe.o \ + +obj-$(CONFIG_VIDEO_QCOM_IRIS) += iris.o diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h new file mode 100644 index 000000000000..27bc2ca71e1b --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_CORE_H__ +#define __IRIS_CORE_H__ + +#include <linux/types.h> +#include <media/v4l2-device.h> + +#include "iris_platform_common.h" + +struct icc_info { + const char *name; + u32 bw_min_kbps; + u32 bw_max_kbps; +}; + +/** + * struct iris_core - holds core parameters valid for all instances + * + * @dev: reference to device structure + * @reg_base: IO memory base address + * @irq: iris irq + * @v4l2_dev: a holder for v4l2 device structure + * @vdev_dec: iris video device structure for decoder + * @icc_tbl: table of iris interconnects + * @icc_count: count of iris interconnects + * @pmdomain_tbl: table of iris power domains + * @opp_pmdomain_tbl: table of opp power domains + * @clock_tbl: table of iris clocks + * @clk_count: count of iris clocks + * @resets: table of iris reset clocks + * @iris_platform_data: a structure for platform data + */ + +struct iris_core { + struct device *dev; + void __iomem *reg_base; + int irq; + struct v4l2_device v4l2_dev; + struct video_device *vdev_dec; + struct icc_bulk_data *icc_tbl; + u32 icc_count; + struct dev_pm_domain_list *pmdomain_tbl; + struct dev_pm_domain_list *opp_pmdomain_tbl; + struct clk_bulk_data *clock_tbl; + u32 clk_count; + struct reset_control_bulk_data *resets; + const struct iris_platform_data *iris_platform_data; +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h new file mode 100644 index 000000000000..31c53dad8136 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_PLATFORM_COMMON_H__ +#define __IRIS_PLATFORM_COMMON_H__ + +extern struct iris_platform_data sm8550_data; + +enum platform_clk_type { + IRIS_AXI_CLK, + IRIS_CTRL_CLK, + IRIS_HW_CLK, +}; + +struct platform_clk_data { + enum platform_clk_type clk_type; + const char *clk_name; +}; + +struct iris_platform_data { + const struct icc_info *icc_tbl; + unsigned int icc_tbl_size; + const char * const *pmdomain_tbl; + unsigned int pmdomain_tbl_size; + const char * const *opp_pd_tbl; + unsigned int opp_pd_tbl_size; + const struct platform_clk_data *clk_tbl; + unsigned int clk_tbl_size; + const char * const *clk_rst_tbl; + unsigned int clk_rst_tbl_size; +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c new file mode 100644 index 000000000000..3dd91523d783 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "iris_core.h" +#include "iris_platform_common.h" + +static const struct icc_info sm8550_icc_table[] = { + { "cpu-cfg", 1000, 1000 }, + { "video-mem", 1000, 15000000 }, +}; + +static const char * const sm8550_clk_reset_table[] = { "bus" }; + +static const char * const sm8550_pmdomain_table[] = { "venus", "vcodec0" }; + +static const char * const sm8550_opp_pd_table[] = { "mxc", "mmcx" }; + +static const struct platform_clk_data sm8550_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_CLK, "vcodec0_core" }, +}; + +struct iris_platform_data sm8550_data = { + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8550_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8550_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), +}; diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c new file mode 100644 index 000000000000..911e3bc1b434 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/interconnect.h> +#include <linux/module.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/reset.h> + +#include "iris_core.h" + +static int iris_init_icc(struct iris_core *core) +{ + const struct icc_info *icc_tbl; + u32 i = 0; + + icc_tbl = core->iris_platform_data->icc_tbl; + + core->icc_count = core->iris_platform_data->icc_tbl_size; + core->icc_tbl = devm_kzalloc(core->dev, + sizeof(struct icc_bulk_data) * core->icc_count, + GFP_KERNEL); + if (!core->icc_tbl) + return -ENOMEM; + + for (i = 0; i < core->icc_count; i++) { + core->icc_tbl[i].name = icc_tbl[i].name; + core->icc_tbl[i].avg_bw = icc_tbl[i].bw_min_kbps; + core->icc_tbl[i].peak_bw = 0; + } + + return devm_of_icc_bulk_get(core->dev, core->icc_count, core->icc_tbl); +} + +static int iris_init_power_domains(struct iris_core *core) +{ + const struct platform_clk_data *clk_tbl; + u32 clk_cnt, i; + int ret; + + struct dev_pm_domain_attach_data iris_pd_data = { + .pd_names = core->iris_platform_data->pmdomain_tbl, + .num_pd_names = core->iris_platform_data->pmdomain_tbl_size, + .pd_flags = PD_FLAG_NO_DEV_LINK, + }; + + struct dev_pm_domain_attach_data iris_opp_pd_data = { + .pd_names = core->iris_platform_data->opp_pd_tbl, + .num_pd_names = core->iris_platform_data->opp_pd_tbl_size, + .pd_flags = PD_FLAG_DEV_LINK_ON, + }; + + ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); + if (ret < 0) + return ret; + + ret = devm_pm_domain_attach_list(core->dev, &iris_opp_pd_data, &core->opp_pmdomain_tbl); + if (ret < 0) + return ret; + + clk_tbl = core->iris_platform_data->clk_tbl; + clk_cnt = core->iris_platform_data->clk_tbl_size; + + for (i = 0; i < clk_cnt; i++) { + if (clk_tbl[i].clk_type == IRIS_HW_CLK) { + ret = devm_pm_opp_set_clkname(core->dev, clk_tbl[i].clk_name); + if (ret) + return ret; + } + } + + return devm_pm_opp_of_add_table(core->dev); +} + +static int iris_init_clocks(struct iris_core *core) +{ + int ret; + + ret = devm_clk_bulk_get_all(core->dev, &core->clock_tbl); + if (ret < 0) + return ret; + + core->clk_count = ret; + + return 0; +} + +static int iris_init_resets(struct iris_core *core) +{ + const char * const *rst_tbl; + u32 rst_tbl_size; + u32 i = 0; + + rst_tbl = core->iris_platform_data->clk_rst_tbl; + rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + + core->resets = devm_kzalloc(core->dev, + sizeof(*core->resets) * rst_tbl_size, + GFP_KERNEL); + if (!core->resets) + return -ENOMEM; + + for (i = 0; i < rst_tbl_size; i++) + core->resets[i].id = rst_tbl[i]; + + return devm_reset_control_bulk_get_exclusive(core->dev, rst_tbl_size, core->resets); +} + +static int iris_init_resources(struct iris_core *core) +{ + int ret; + + ret = iris_init_icc(core); + if (ret) + return ret; + + ret = iris_init_power_domains(core); + if (ret) + return ret; + + ret = iris_init_clocks(core); + if (ret) + return ret; + + return iris_init_resets(core); +} + +static int iris_register_video_device(struct iris_core *core) +{ + struct video_device *vdev; + int ret; + + vdev = video_device_alloc(); + if (!vdev) + return -ENOMEM; + + strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); + vdev->release = video_device_release; + vdev->vfl_dir = VFL_DIR_M2M; + vdev->v4l2_dev = &core->v4l2_dev; + vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) + goto err_vdev_release; + + core->vdev_dec = vdev; + video_set_drvdata(vdev, core); + + return 0; + +err_vdev_release: + video_device_release(vdev); + + return ret; +} + +static void iris_remove(struct platform_device *pdev) +{ + struct iris_core *core; + + core = platform_get_drvdata(pdev); + if (!core) + return; + + video_unregister_device(core->vdev_dec); + + v4l2_device_unregister(&core->v4l2_dev); +} + +static int iris_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iris_core *core; + int ret; + + core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + core->dev = dev; + + core->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(core->reg_base)) + return PTR_ERR(core->reg_base); + + core->irq = platform_get_irq(pdev, 0); + if (core->irq < 0) + return core->irq; + + core->iris_platform_data = of_device_get_match_data(core->dev); + + ret = iris_init_resources(core); + if (ret) + return ret; + + ret = v4l2_device_register(dev, &core->v4l2_dev); + if (ret) + return ret; + + ret = iris_register_video_device(core); + if (ret) + goto err_v4l2_unreg; + + platform_set_drvdata(pdev, core); + + return 0; + +err_v4l2_unreg: + v4l2_device_unregister(&core->v4l2_dev); + + return ret; +} + +static const struct of_device_id iris_dt_match[] = { + { + .compatible = "qcom,sm8550-iris", + .data = &sm8550_data, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, iris_dt_match); + +static struct platform_driver qcom_iris_driver = { + .probe = iris_probe, + .remove = iris_remove, + .driver = { + .name = "qcom-iris", + .of_match_table = iris_dt_match, + }, +}; + +module_platform_driver(qcom_iris_driver); +MODULE_DESCRIPTION("Qualcomm iris video driver"); +MODULE_LICENSE("GPL");