mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-26 08:51:13 +00:00
631 lines
16 KiB
Diff
631 lines
16 KiB
Diff
|
From 0dc93c9321ba947ac429baeb58202496e4b0f219 Mon Sep 17 00:00:00 2001
|
||
|
From: Jack Zhu <jack.zhu@starfivetech.com>
|
||
|
Date: Fri, 12 May 2023 18:28:41 +0800
|
||
|
Subject: [PATCH 083/122] media: starfive: Add basic driver
|
||
|
|
||
|
Add basic platform driver for StarFive Camera Subsystem.
|
||
|
|
||
|
Signed-off-by: Jack Zhu <jack.zhu@starfivetech.com>
|
||
|
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
|
||
|
---
|
||
|
drivers/media/platform/Kconfig | 1 +
|
||
|
drivers/media/platform/Makefile | 1 +
|
||
|
drivers/media/platform/starfive/Kconfig | 19 +
|
||
|
drivers/media/platform/starfive/Makefile | 9 +
|
||
|
drivers/media/platform/starfive/stf_camss.c | 372 +++++++++++++++++++
|
||
|
drivers/media/platform/starfive/stf_camss.h | 153 ++++++++
|
||
|
drivers/media/platform/starfive/stf_common.h | 18 +
|
||
|
7 files changed, 573 insertions(+)
|
||
|
create mode 100644 drivers/media/platform/starfive/Kconfig
|
||
|
create mode 100644 drivers/media/platform/starfive/Makefile
|
||
|
create mode 100644 drivers/media/platform/starfive/stf_camss.c
|
||
|
create mode 100644 drivers/media/platform/starfive/stf_camss.h
|
||
|
create mode 100644 drivers/media/platform/starfive/stf_common.h
|
||
|
|
||
|
--- a/drivers/media/platform/Kconfig
|
||
|
+++ b/drivers/media/platform/Kconfig
|
||
|
@@ -79,6 +79,7 @@ source "drivers/media/platform/renesas/K
|
||
|
source "drivers/media/platform/rockchip/Kconfig"
|
||
|
source "drivers/media/platform/samsung/Kconfig"
|
||
|
source "drivers/media/platform/st/Kconfig"
|
||
|
+source "drivers/media/platform/starfive/Kconfig"
|
||
|
source "drivers/media/platform/sunxi/Kconfig"
|
||
|
source "drivers/media/platform/ti/Kconfig"
|
||
|
source "drivers/media/platform/verisilicon/Kconfig"
|
||
|
--- a/drivers/media/platform/Makefile
|
||
|
+++ b/drivers/media/platform/Makefile
|
||
|
@@ -22,6 +22,7 @@ obj-y += renesas/
|
||
|
obj-y += rockchip/
|
||
|
obj-y += samsung/
|
||
|
obj-y += st/
|
||
|
+obj-y += starfive/
|
||
|
obj-y += sunxi/
|
||
|
obj-y += ti/
|
||
|
obj-y += verisilicon/
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/media/platform/starfive/Kconfig
|
||
|
@@ -0,0 +1,19 @@
|
||
|
+# SPDX-License-Identifier: GPL-2.0-only
|
||
|
+
|
||
|
+comment "Starfive media platform drivers"
|
||
|
+
|
||
|
+config VIDEO_STARFIVE_CAMSS
|
||
|
+ tristate "Starfive Camera Subsystem driver"
|
||
|
+ depends on V4L_PLATFORM_DRIVERS
|
||
|
+ depends on VIDEO_DEV && OF
|
||
|
+ depends on DMA_CMA
|
||
|
+ select MEDIA_CONTROLLER
|
||
|
+ select VIDEO_V4L2_SUBDEV_API
|
||
|
+ select VIDEOBUF2_DMA_CONTIG
|
||
|
+ select V4L2_FWNODE
|
||
|
+ help
|
||
|
+ Enable this to support for the Starfive Camera subsystem
|
||
|
+ found on Starfive JH7110 SoC.
|
||
|
+
|
||
|
+ To compile this driver as a module, choose M here: the
|
||
|
+ module will be called stf-camss.
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/media/platform/starfive/Makefile
|
||
|
@@ -0,0 +1,9 @@
|
||
|
+# SPDX-License-Identifier: GPL-2.0
|
||
|
+#
|
||
|
+# Makefile for StarFive camera subsystem driver.
|
||
|
+#
|
||
|
+
|
||
|
+starfive-camss-objs += \
|
||
|
+ stf_camss.o
|
||
|
+
|
||
|
+obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/media/platform/starfive/stf_camss.c
|
||
|
@@ -0,0 +1,372 @@
|
||
|
+// SPDX-License-Identifier: GPL-2.0
|
||
|
+/*
|
||
|
+ * stf_camss.c
|
||
|
+ *
|
||
|
+ * Starfive Camera Subsystem driver
|
||
|
+ *
|
||
|
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
|
||
|
+ */
|
||
|
+#include <linux/module.h>
|
||
|
+#include <linux/of.h>
|
||
|
+#include <linux/of_graph.h>
|
||
|
+#include <linux/platform_device.h>
|
||
|
+#include <linux/pm_runtime.h>
|
||
|
+#include <linux/videodev2.h>
|
||
|
+#include <media/media-device.h>
|
||
|
+#include <media/v4l2-async.h>
|
||
|
+#include <media/v4l2-fwnode.h>
|
||
|
+#include <media/v4l2-mc.h>
|
||
|
+
|
||
|
+#include "stf_camss.h"
|
||
|
+
|
||
|
+static const char * const stfcamss_clocks[] = {
|
||
|
+ "clk_apb_func",
|
||
|
+ "clk_wrapper_clk_c",
|
||
|
+ "clk_dvp_inv",
|
||
|
+ "clk_axiwr",
|
||
|
+ "clk_mipi_rx0_pxl",
|
||
|
+ "clk_ispcore_2x",
|
||
|
+ "clk_isp_axi",
|
||
|
+};
|
||
|
+
|
||
|
+static const char * const stfcamss_resets[] = {
|
||
|
+ "rst_wrapper_p",
|
||
|
+ "rst_wrapper_c",
|
||
|
+ "rst_axird",
|
||
|
+ "rst_axiwr",
|
||
|
+ "rst_isp_top_n",
|
||
|
+ "rst_isp_top_axi",
|
||
|
+};
|
||
|
+
|
||
|
+static int stfcamss_get_mem_res(struct platform_device *pdev,
|
||
|
+ struct stfcamss *stfcamss)
|
||
|
+{
|
||
|
+ stfcamss->syscon_base =
|
||
|
+ devm_platform_ioremap_resource_byname(pdev, "syscon");
|
||
|
+ if (IS_ERR(stfcamss->syscon_base))
|
||
|
+ return PTR_ERR(stfcamss->syscon_base);
|
||
|
+
|
||
|
+ stfcamss->isp_base =
|
||
|
+ devm_platform_ioremap_resource_byname(pdev, "isp");
|
||
|
+ if (IS_ERR(stfcamss->isp_base))
|
||
|
+ return PTR_ERR(stfcamss->isp_base);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * stfcamss_of_parse_endpoint_node - Parse port endpoint node
|
||
|
+ * @dev: Device
|
||
|
+ * @node: Device node to be parsed
|
||
|
+ * @csd: Parsed data from port endpoint node
|
||
|
+ *
|
||
|
+ * Return 0 on success or a negative error code on failure
|
||
|
+ */
|
||
|
+static int stfcamss_of_parse_endpoint_node(struct device *dev,
|
||
|
+ struct device_node *node,
|
||
|
+ struct stfcamss_async_subdev *csd)
|
||
|
+{
|
||
|
+ struct v4l2_fwnode_endpoint vep = { { 0 } };
|
||
|
+
|
||
|
+ v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
|
||
|
+ dev_dbg(dev, "vep.base.port = 0x%x, id = 0x%x\n",
|
||
|
+ vep.base.port, vep.base.id);
|
||
|
+
|
||
|
+ csd->port = vep.base.port;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * stfcamss_of_parse_ports - Parse ports node
|
||
|
+ * @stfcamss: STFCAMSS device
|
||
|
+ *
|
||
|
+ * Return number of "port" nodes found in "ports" node
|
||
|
+ */
|
||
|
+static int stfcamss_of_parse_ports(struct stfcamss *stfcamss)
|
||
|
+{
|
||
|
+ struct device *dev = stfcamss->dev;
|
||
|
+ struct device_node *node = NULL;
|
||
|
+ struct device_node *remote = NULL;
|
||
|
+ int ret, num_subdevs = 0;
|
||
|
+
|
||
|
+ for_each_endpoint_of_node(dev->of_node, node) {
|
||
|
+ struct stfcamss_async_subdev *csd;
|
||
|
+
|
||
|
+ if (!of_device_is_available(node))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ remote = of_graph_get_remote_port_parent(node);
|
||
|
+ if (!remote) {
|
||
|
+ dev_err(dev, "Cannot get remote parent\n");
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto err_cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ csd = v4l2_async_nf_add_fwnode(&stfcamss->notifier,
|
||
|
+ of_fwnode_handle(remote),
|
||
|
+ struct stfcamss_async_subdev);
|
||
|
+ of_node_put(remote);
|
||
|
+ if (IS_ERR(csd)) {
|
||
|
+ ret = PTR_ERR(csd);
|
||
|
+ goto err_cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = stfcamss_of_parse_endpoint_node(dev, node, csd);
|
||
|
+ if (ret < 0)
|
||
|
+ goto err_cleanup;
|
||
|
+
|
||
|
+ num_subdevs++;
|
||
|
+ }
|
||
|
+
|
||
|
+ return num_subdevs;
|
||
|
+
|
||
|
+err_cleanup:
|
||
|
+ of_node_put(node);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async,
|
||
|
+ struct v4l2_subdev *subdev,
|
||
|
+ struct v4l2_async_subdev *asd)
|
||
|
+{
|
||
|
+ struct stfcamss *stfcamss =
|
||
|
+ container_of(async, struct stfcamss, notifier);
|
||
|
+ struct host_data *host_data = &stfcamss->host_data;
|
||
|
+ struct media_entity *source;
|
||
|
+ int i, j;
|
||
|
+
|
||
|
+ source = &subdev->entity;
|
||
|
+
|
||
|
+ for (i = 0; i < source->num_pads; i++) {
|
||
|
+ if (source->pads[i].flags & MEDIA_PAD_FL_SOURCE)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (i == source->num_pads) {
|
||
|
+ dev_err(stfcamss->dev, "No source pad in external entity\n");
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (j = 0; host_data->host_entity[j] && (j < HOST_ENTITY_MAX); j++) {
|
||
|
+ struct media_entity *input;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ input = host_data->host_entity[j];
|
||
|
+
|
||
|
+ ret = media_create_pad_link(
|
||
|
+ source,
|
||
|
+ i,
|
||
|
+ input,
|
||
|
+ STF_PAD_SINK,
|
||
|
+ source->function == MEDIA_ENT_F_CAM_SENSOR ?
|
||
|
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED :
|
||
|
+ 0);
|
||
|
+ if (ret < 0) {
|
||
|
+ dev_err(stfcamss->dev,
|
||
|
+ "Failed to link %s->%s entities: %d\n",
|
||
|
+ source->name, input->name, ret);
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf)
|
||
|
+{
|
||
|
+ struct stfcamss *stfcamss =
|
||
|
+ container_of(ntf, struct stfcamss, notifier);
|
||
|
+
|
||
|
+ return v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev);
|
||
|
+}
|
||
|
+
|
||
|
+static const struct v4l2_async_notifier_operations
|
||
|
+stfcamss_subdev_notifier_ops = {
|
||
|
+ .bound = stfcamss_subdev_notifier_bound,
|
||
|
+ .complete = stfcamss_subdev_notifier_complete,
|
||
|
+};
|
||
|
+
|
||
|
+static const struct media_device_ops stfcamss_media_ops = {
|
||
|
+ .link_notify = v4l2_pipeline_link_notify,
|
||
|
+};
|
||
|
+
|
||
|
+static void stfcamss_mc_init(struct platform_device *pdev,
|
||
|
+ struct stfcamss *stfcamss)
|
||
|
+{
|
||
|
+ stfcamss->media_dev.dev = stfcamss->dev;
|
||
|
+ strscpy(stfcamss->media_dev.model, "Starfive Camera Subsystem",
|
||
|
+ sizeof(stfcamss->media_dev.model));
|
||
|
+ snprintf(stfcamss->media_dev.bus_info,
|
||
|
+ sizeof(stfcamss->media_dev.bus_info),
|
||
|
+ "%s:%s", dev_bus_name(&pdev->dev), pdev->name);
|
||
|
+ stfcamss->media_dev.hw_revision = 0x01;
|
||
|
+ stfcamss->media_dev.ops = &stfcamss_media_ops;
|
||
|
+ media_device_init(&stfcamss->media_dev);
|
||
|
+
|
||
|
+ stfcamss->v4l2_dev.mdev = &stfcamss->media_dev;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * stfcamss_probe - Probe STFCAMSS platform device
|
||
|
+ * @pdev: Pointer to STFCAMSS platform device
|
||
|
+ *
|
||
|
+ * Return 0 on success or a negative error code on failure
|
||
|
+ */
|
||
|
+static int stfcamss_probe(struct platform_device *pdev)
|
||
|
+{
|
||
|
+ struct stfcamss *stfcamss;
|
||
|
+ struct device *dev = &pdev->dev;
|
||
|
+ int ret = 0, i, num_subdevs;
|
||
|
+
|
||
|
+ stfcamss = devm_kzalloc(dev, sizeof(*stfcamss), GFP_KERNEL);
|
||
|
+ if (!stfcamss)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ for (i = 0; i < ARRAY_SIZE(stfcamss->irq); ++i) {
|
||
|
+ stfcamss->irq[i] = platform_get_irq(pdev, i);
|
||
|
+ if (stfcamss->irq[i] < 0)
|
||
|
+ return dev_err_probe(&pdev->dev, stfcamss->irq[i],
|
||
|
+ "Failed to get clock%d", i);
|
||
|
+ }
|
||
|
+
|
||
|
+ stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk);
|
||
|
+ for (i = 0; i < ARRAY_SIZE(stfcamss->sys_clk); ++i)
|
||
|
+ stfcamss->sys_clk[i].id = stfcamss_clocks[i];
|
||
|
+ ret = devm_clk_bulk_get(dev, stfcamss->nclks, stfcamss->sys_clk);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "Failed to get clk controls\n");
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ stfcamss->nrsts = ARRAY_SIZE(stfcamss->sys_rst);
|
||
|
+ for (i = 0; i < ARRAY_SIZE(stfcamss->sys_rst); ++i)
|
||
|
+ stfcamss->sys_rst[i].id = stfcamss_resets[i];
|
||
|
+ ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts,
|
||
|
+ stfcamss->sys_rst);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "Failed to get reset controls\n");
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = stfcamss_get_mem_res(pdev, stfcamss);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "Could not map registers\n");
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ stfcamss->dev = dev;
|
||
|
+ platform_set_drvdata(pdev, stfcamss);
|
||
|
+
|
||
|
+ v4l2_async_nf_init(&stfcamss->notifier);
|
||
|
+
|
||
|
+ num_subdevs = stfcamss_of_parse_ports(stfcamss);
|
||
|
+ if (num_subdevs < 0) {
|
||
|
+ dev_err(dev, "Failed to find subdevices\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ stfcamss_mc_init(pdev, stfcamss);
|
||
|
+
|
||
|
+ ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev);
|
||
|
+ if (ret < 0) {
|
||
|
+ dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
|
||
|
+ goto err_cleanup_notifier;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = media_device_register(&stfcamss->media_dev);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "Failed to register media device: %d\n", ret);
|
||
|
+ goto err_unregister_device;
|
||
|
+ }
|
||
|
+
|
||
|
+ stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops;
|
||
|
+ ret = v4l2_async_nf_register(&stfcamss->v4l2_dev, &stfcamss->notifier);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "Failed to register async subdev nodes: %d\n",
|
||
|
+ ret);
|
||
|
+ goto err_unregister_media_dev;
|
||
|
+ }
|
||
|
+
|
||
|
+ pm_runtime_enable(dev);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+
|
||
|
+err_unregister_media_dev:
|
||
|
+ media_device_unregister(&stfcamss->media_dev);
|
||
|
+err_unregister_device:
|
||
|
+ v4l2_device_unregister(&stfcamss->v4l2_dev);
|
||
|
+err_cleanup_notifier:
|
||
|
+ v4l2_async_nf_cleanup(&stfcamss->notifier);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * stfcamss_remove - Remove STFCAMSS platform device
|
||
|
+ * @pdev: Pointer to STFCAMSS platform device
|
||
|
+ *
|
||
|
+ * Always returns 0.
|
||
|
+ */
|
||
|
+static int stfcamss_remove(struct platform_device *pdev)
|
||
|
+{
|
||
|
+ struct stfcamss *stfcamss = platform_get_drvdata(pdev);
|
||
|
+
|
||
|
+ v4l2_device_unregister(&stfcamss->v4l2_dev);
|
||
|
+ media_device_cleanup(&stfcamss->media_dev);
|
||
|
+ pm_runtime_disable(&pdev->dev);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static const struct of_device_id stfcamss_of_match[] = {
|
||
|
+ { .compatible = "starfive,jh7110-camss" },
|
||
|
+ { /* sentinel */ },
|
||
|
+};
|
||
|
+
|
||
|
+MODULE_DEVICE_TABLE(of, stfcamss_of_match);
|
||
|
+
|
||
|
+static int __maybe_unused stfcamss_runtime_suspend(struct device *dev)
|
||
|
+{
|
||
|
+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
|
||
|
+
|
||
|
+ reset_control_assert(stfcamss->sys_rst[STF_RST_ISP_TOP_AXI].rstc);
|
||
|
+ reset_control_assert(stfcamss->sys_rst[STF_RST_ISP_TOP_N].rstc);
|
||
|
+ clk_disable_unprepare(stfcamss->sys_clk[STF_CLK_ISP_AXI].clk);
|
||
|
+ clk_disable_unprepare(stfcamss->sys_clk[STF_CLK_ISPCORE_2X].clk);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int __maybe_unused stfcamss_runtime_resume(struct device *dev)
|
||
|
+{
|
||
|
+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
|
||
|
+
|
||
|
+ clk_prepare_enable(stfcamss->sys_clk[STF_CLK_ISPCORE_2X].clk);
|
||
|
+ clk_prepare_enable(stfcamss->sys_clk[STF_CLK_ISP_AXI].clk);
|
||
|
+ reset_control_deassert(stfcamss->sys_rst[STF_RST_ISP_TOP_N].rstc);
|
||
|
+ reset_control_deassert(stfcamss->sys_rst[STF_RST_ISP_TOP_AXI].rstc);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static const struct dev_pm_ops stfcamss_pm_ops = {
|
||
|
+ SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend,
|
||
|
+ stfcamss_runtime_resume,
|
||
|
+ NULL)
|
||
|
+};
|
||
|
+
|
||
|
+static struct platform_driver stfcamss_driver = {
|
||
|
+ .probe = stfcamss_probe,
|
||
|
+ .remove = stfcamss_remove,
|
||
|
+ .driver = {
|
||
|
+ .name = DRV_NAME,
|
||
|
+ .pm = &stfcamss_pm_ops,
|
||
|
+ .of_match_table = of_match_ptr(stfcamss_of_match),
|
||
|
+ },
|
||
|
+};
|
||
|
+
|
||
|
+module_platform_driver(stfcamss_driver);
|
||
|
+
|
||
|
+MODULE_AUTHOR("StarFive Corporation");
|
||
|
+MODULE_DESCRIPTION("StarFive Camera Subsystem driver");
|
||
|
+MODULE_LICENSE("GPL");
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/media/platform/starfive/stf_camss.h
|
||
|
@@ -0,0 +1,153 @@
|
||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
+/*
|
||
|
+ * stf_camss.h
|
||
|
+ *
|
||
|
+ * Starfive Camera Subsystem driver
|
||
|
+ *
|
||
|
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef STF_CAMSS_H
|
||
|
+#define STF_CAMSS_H
|
||
|
+
|
||
|
+#include <linux/clk.h>
|
||
|
+#include <linux/delay.h>
|
||
|
+#include <linux/reset.h>
|
||
|
+#include <media/v4l2-device.h>
|
||
|
+
|
||
|
+#include "stf_common.h"
|
||
|
+
|
||
|
+#define DRV_NAME "starfive-camss"
|
||
|
+#define STF_DVP_NAME "stf_dvp"
|
||
|
+#define STF_CSI_NAME "cdns_csi2rx"
|
||
|
+#define STF_ISP_NAME "stf_isp"
|
||
|
+#define STF_VIN_NAME "stf_vin"
|
||
|
+
|
||
|
+#define STF_PAD_SINK 0
|
||
|
+#define STF_PAD_SRC 1
|
||
|
+#define STF_PADS_NUM 2
|
||
|
+
|
||
|
+enum port_num {
|
||
|
+ PORT_NUMBER_DVP_SENSOR = 0,
|
||
|
+ PORT_NUMBER_CSI2RX
|
||
|
+};
|
||
|
+
|
||
|
+enum stf_clk {
|
||
|
+ STF_CLK_APB_FUNC = 0,
|
||
|
+ STF_CLK_WRAPPER_CLK_C,
|
||
|
+ STF_CLK_DVP_INV,
|
||
|
+ STF_CLK_AXIWR,
|
||
|
+ STF_CLK_MIPI_RX0_PXL,
|
||
|
+ STF_CLK_ISPCORE_2X,
|
||
|
+ STF_CLK_ISP_AXI,
|
||
|
+ STF_CLK_NUM
|
||
|
+};
|
||
|
+
|
||
|
+enum stf_rst {
|
||
|
+ STF_RST_WRAPPER_P = 0,
|
||
|
+ STF_RST_WRAPPER_C,
|
||
|
+ STF_RST_AXIRD,
|
||
|
+ STF_RST_AXIWR,
|
||
|
+ STF_RST_ISP_TOP_N,
|
||
|
+ STF_RST_ISP_TOP_AXI,
|
||
|
+ STF_RST_NUM
|
||
|
+};
|
||
|
+
|
||
|
+enum stf_irq {
|
||
|
+ STF_IRQ_VINWR = 0,
|
||
|
+ STF_IRQ_ISP,
|
||
|
+ STF_IRQ_ISPCSIL,
|
||
|
+ STF_IRQ_NUM
|
||
|
+};
|
||
|
+
|
||
|
+#define HOST_ENTITY_MAX 2
|
||
|
+
|
||
|
+struct host_data {
|
||
|
+ struct media_entity *host_entity[HOST_ENTITY_MAX];
|
||
|
+};
|
||
|
+
|
||
|
+struct stfcamss {
|
||
|
+ struct v4l2_device v4l2_dev;
|
||
|
+ struct media_device media_dev;
|
||
|
+ struct media_pipeline pipe;
|
||
|
+ struct device *dev;
|
||
|
+ struct v4l2_async_notifier notifier;
|
||
|
+ struct host_data host_data;
|
||
|
+ void __iomem *syscon_base;
|
||
|
+ void __iomem *isp_base;
|
||
|
+ int irq[STF_IRQ_NUM];
|
||
|
+ struct clk_bulk_data sys_clk[STF_CLK_NUM];
|
||
|
+ int nclks;
|
||
|
+ struct reset_control_bulk_data sys_rst[STF_RST_NUM];
|
||
|
+ int nrsts;
|
||
|
+};
|
||
|
+
|
||
|
+struct stfcamss_async_subdev {
|
||
|
+ struct v4l2_async_subdev asd; /* must be first */
|
||
|
+ enum port_num port;
|
||
|
+};
|
||
|
+
|
||
|
+static inline u32 stf_isp_reg_read(struct stfcamss *stfcamss, u32 reg)
|
||
|
+{
|
||
|
+ return ioread32(stfcamss->isp_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_isp_reg_write(struct stfcamss *stfcamss,
|
||
|
+ u32 reg, u32 val)
|
||
|
+{
|
||
|
+ iowrite32(val, stfcamss->isp_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_isp_reg_write_delay(struct stfcamss *stfcamss,
|
||
|
+ u32 reg, u32 val, u32 delay)
|
||
|
+{
|
||
|
+ iowrite32(val, stfcamss->isp_base + reg);
|
||
|
+ usleep_range(1000 * delay, 1000 * delay + 100);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_isp_reg_set_bit(struct stfcamss *stfcamss,
|
||
|
+ u32 reg, u32 mask, u32 val)
|
||
|
+{
|
||
|
+ u32 value;
|
||
|
+
|
||
|
+ value = ioread32(stfcamss->isp_base + reg) & ~mask;
|
||
|
+ val &= mask;
|
||
|
+ val |= value;
|
||
|
+ iowrite32(val, stfcamss->isp_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_isp_reg_set(struct stfcamss *stfcamss, u32 reg, u32 mask)
|
||
|
+{
|
||
|
+ iowrite32(ioread32(stfcamss->isp_base + reg) | mask,
|
||
|
+ stfcamss->isp_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline u32 stf_syscon_reg_read(struct stfcamss *stfcamss, u32 reg)
|
||
|
+{
|
||
|
+ return ioread32(stfcamss->syscon_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_syscon_reg_write(struct stfcamss *stfcamss,
|
||
|
+ u32 reg, u32 val)
|
||
|
+{
|
||
|
+ iowrite32(val, stfcamss->syscon_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_syscon_reg_set_bit(struct stfcamss *stfcamss,
|
||
|
+ u32 reg, u32 bit_mask)
|
||
|
+{
|
||
|
+ u32 value;
|
||
|
+
|
||
|
+ value = ioread32(stfcamss->syscon_base + reg);
|
||
|
+ iowrite32(value | bit_mask, stfcamss->syscon_base + reg);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void stf_syscon_reg_clear_bit(struct stfcamss *stfcamss,
|
||
|
+ u32 reg, u32 bit_mask)
|
||
|
+{
|
||
|
+ u32 value;
|
||
|
+
|
||
|
+ value = ioread32(stfcamss->syscon_base + reg);
|
||
|
+ iowrite32(value & ~bit_mask, stfcamss->syscon_base + reg);
|
||
|
+}
|
||
|
+#endif /* STF_CAMSS_H */
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/media/platform/starfive/stf_common.h
|
||
|
@@ -0,0 +1,18 @@
|
||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
+/*
|
||
|
+ * stf_common.h
|
||
|
+ *
|
||
|
+ * StarFive Camera Subsystem - Common definitions
|
||
|
+ *
|
||
|
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef STF_COMMON_H
|
||
|
+#define STF_COMMON_H
|
||
|
+
|
||
|
+enum stf_subdev_type {
|
||
|
+ STF_SUBDEV_TYPE_VIN,
|
||
|
+ STF_SUBDEV_TYPE_ISP,
|
||
|
+};
|
||
|
+
|
||
|
+#endif /* STF_COMMON_H */
|