media: staging: Drop starfive-camss from staging

The starfive-camss driver is no longer being worked upon for destaging,
as confirmed by the maintainer, so drop it.

Link: https://lore.kernel.org/all/ZQ0PR01MB13024A92926C415C187D2C18F29F2@ZQ0PR01MB1302.CHNPR01.prod.partner.outlook.cn/
Acked-by: Changhuang Liang <changhuang.liang@starfivetech.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Jai Luthra
2026-03-11 01:05:30 +01:00
committed by Mauro Carvalho Chehab
parent 64ad2497e6
commit 70eaeee95f
20 changed files with 0 additions and 3324 deletions
@@ -1,72 +0,0 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>
================================
Starfive Camera Subsystem driver
================================
Introduction
------------
This file documents the driver for the Starfive Camera Subsystem found on
Starfive JH7110 SoC. The driver is located under drivers/staging/media/starfive/
camss.
The driver implements V4L2, Media controller and v4l2_subdev interfaces. Camera
sensor using V4L2 subdev interface in the kernel is supported.
The driver has been successfully used on the Gstreamer 1.18.5 with v4l2src
plugin.
Starfive Camera Subsystem hardware
----------------------------------
The Starfive Camera Subsystem hardware consists of::
|\ +---------------+ +-----------+
+----------+ | \ | | | |
| | | | | | | |
| MIPI |----->| |----->| ISP |----->| |
| | | | | | | |
+----------+ | | | | | Memory |
|MUX| +---------------+ | Interface |
+----------+ | | | |
| | | |---------------------------->| |
| Parallel |----->| | | |
| | | | | |
+----------+ | / | |
|/ +-----------+
- MIPI: The MIPI interface, receiving data from a MIPI CSI-2 camera sensor.
- Parallel: The parallel interface, receiving data from a parallel sensor.
- ISP: The ISP, processing raw Bayer data from an image sensor and producing
YUV frames.
Topology
--------
The media controller pipeline graph is as follows:
.. _starfive_camss_graph:
.. kernel-figure:: starfive_camss_graph.dot
:alt: starfive_camss_graph.dot
:align: center
The driver has 2 video devices:
- capture_raw: The capture device, capturing image data directly from a sensor.
- capture_yuv: The capture device, capturing YUV frame data processed by the
ISP module
The driver has 3 subdevices:
- stf_isp: is responsible for all the isp operations, outputs YUV frames.
- cdns_csi2rx: a CSI-2 bridge supporting up to 4 CSI lanes in input, and 4
different pixel streams in output.
- imx219: an image sensor, image data is sent through MIPI CSI-2.
@@ -1,12 +0,0 @@
digraph board {
rankdir=TB
n00000001 [label="{{<port0> 0} | stf_isp\n/dev/v4l-subdev0 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000001:port1 -> n00000008 [style=dashed]
n00000004 [label="capture_raw\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
n00000008 [label="capture_yuv\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
n0000000e [label="{{<port0> 0} | cdns_csi2rx.19800000.csi-bridge\n | {<port1> 1 | <port2> 2 | <port3> 3 | <port4> 4}}", shape=Mrecord, style=filled, fillcolor=green]
n0000000e:port1 -> n00000001:port0 [style=dashed]
n0000000e:port1 -> n00000004 [style=dashed]
n00000018 [label="{{} | imx219 6-0010\n/dev/v4l-subdev1 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
n00000018:port0 -> n0000000e:port0 [style=bold]
}
@@ -33,7 +33,6 @@ Video4Linux (V4L) driver-specific documentation
si470x
si4713
si476x
starfive_camss
vimc
visl
vivid
-9
View File
@@ -25158,15 +25158,6 @@ M: Ion Badulescu <ionut@badula.org>
S: Odd Fixes
F: drivers/net/ethernet/adaptec/starfire*
STARFIVE CAMERA SUBSYSTEM DRIVER
M: Jack Zhu <jack.zhu@starfivetech.com>
M: Changhuang Liang <changhuang.liang@starfivetech.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/admin-guide/media/starfive_camss.rst
F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
F: drivers/staging/media/starfive/camss
STARFIVE CRYPTO DRIVER
M: Jia Jie Ho <jiajie.ho@starfivetech.com>
M: William Qiu <william.qiu@starfivetech.com>
-2
View File
@@ -34,8 +34,6 @@ source "drivers/staging/media/max96712/Kconfig"
source "drivers/staging/media/meson/vdec/Kconfig"
source "drivers/staging/media/starfive/Kconfig"
source "drivers/staging/media/sunxi/Kconfig"
source "drivers/staging/media/tegra-video/Kconfig"
-1
View File
@@ -4,7 +4,6 @@ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/
obj-$(CONFIG_VIDEO_MAX96712) += max96712/
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/
obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
-5
View File
@@ -1,5 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
comment "StarFive media platform drivers"
source "drivers/staging/media/starfive/camss/Kconfig"
-2
View File
@@ -1,2 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += camss/
@@ -1,18 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_STARFIVE_CAMSS
tristate "Starfive Camera Subsystem driver"
depends on V4L_PLATFORM_DRIVERS
depends on VIDEO_DEV && OF
depends on HAS_DMA
depends on PM
depends on ARCH_STARFIVE || COMPILE_TEST
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 starfive-camss.
@@ -1,13 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for StarFive Camera Subsystem driver
#
starfive-camss-objs += \
stf-camss.o \
stf-capture.o \
stf-isp.o \
stf-isp-hw-ops.o \
stf-video.o
obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o
@@ -1,4 +0,0 @@
Unstaging requirements:
- Add userspace support which demonstrates the ability to receive statistics and
adapt hardware modules configuration accordingly;
- Add documentation for description of the statistics data structures;
@@ -1,438 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* stf_camss.c
*
* Starfive Camera Subsystem driver
*
* Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
*
* Author: Jack Zhu <jack.zhu@starfivetech.com>
* Author: Changhuang Liang <changhuang.liang@starfivetech.com>
*
*/
#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/v4l2-fwnode.h>
#include <media/v4l2-mc.h>
#include "stf-camss.h"
static const char * const stfcamss_clocks[] = {
"wrapper_clk_c",
"ispcore_2x",
"isp_axi",
};
static const char * const stfcamss_resets[] = {
"wrapper_p",
"wrapper_c",
"axiwr",
"isp_top_n",
"isp_top_axi",
};
static const struct stf_isr_data stf_isrs[] = {
{"wr_irq", stf_wr_irq_handler},
{"isp_irq", stf_isp_irq_handler},
{"line_irq", stf_line_irq_handler},
};
static int stfcamss_get_mem_res(struct stfcamss *stfcamss)
{
struct platform_device *pdev = to_platform_device(stfcamss->dev);
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 stfcamss *stfcamss,
struct device_node *node,
struct stfcamss_async_subdev *csd)
{
struct v4l2_fwnode_endpoint vep = { { 0 } };
int ret;
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
if (ret) {
dev_err(stfcamss->dev, "endpoint not defined at %pOF\n", node);
return ret;
}
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_node *node = NULL;
int ret, num_subdevs = 0;
for_each_endpoint_of_node(stfcamss->dev->of_node, node) {
struct stfcamss_async_subdev *csd;
if (!of_device_is_available(node))
continue;
csd = v4l2_async_nf_add_fwnode_remote(&stfcamss->notifier,
of_fwnode_handle(node),
struct stfcamss_async_subdev);
if (IS_ERR(csd)) {
ret = PTR_ERR(csd);
dev_err(stfcamss->dev, "failed to add async notifier\n");
goto err_cleanup;
}
ret = stfcamss_of_parse_endpoint_node(stfcamss, node, csd);
if (ret)
goto err_cleanup;
num_subdevs++;
}
return num_subdevs;
err_cleanup:
of_node_put(node);
return ret;
}
static int stfcamss_register_devs(struct stfcamss *stfcamss)
{
struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV];
struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
int ret;
ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev);
if (ret < 0) {
dev_err(stfcamss->dev,
"failed to register stf isp%d entity: %d\n", 0, ret);
return ret;
}
ret = stf_capture_register(stfcamss, &stfcamss->v4l2_dev);
if (ret < 0) {
dev_err(stfcamss->dev,
"failed to register capture: %d\n", ret);
goto err_isp_unregister;
}
ret = media_create_pad_link(&isp_dev->subdev.entity, STF_ISP_PAD_SRC,
&cap_yuv->video.vdev.entity, 0, 0);
if (ret)
goto err_cap_unregister;
cap_yuv->video.source_subdev = &isp_dev->subdev;
return ret;
err_cap_unregister:
stf_capture_unregister(stfcamss);
err_isp_unregister:
stf_isp_unregister(&stfcamss->isp_dev);
return ret;
}
static void stfcamss_unregister_devs(struct stfcamss *stfcamss)
{
struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV];
struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
media_entity_remove_links(&isp_dev->subdev.entity);
media_entity_remove_links(&cap_yuv->video.vdev.entity);
stf_isp_unregister(&stfcamss->isp_dev);
stf_capture_unregister(stfcamss);
}
static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async,
struct v4l2_subdev *subdev,
struct v4l2_async_connection *asc)
{
struct stfcamss *stfcamss =
container_of(async, struct stfcamss, notifier);
struct stfcamss_async_subdev *csd =
container_of(asc, struct stfcamss_async_subdev, asd);
enum stf_port_num port = csd->port;
struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
struct stf_capture *cap_raw = &stfcamss->captures[STF_CAPTURE_RAW];
struct media_pad *pad;
int ret;
if (port == STF_PORT_CSI2RX) {
pad = &isp_dev->pads[STF_ISP_PAD_SINK];
} else {
dev_err(stfcamss->dev, "not support port %d\n", port);
return -EPERM;
}
ret = v4l2_create_fwnode_links_to_pad(subdev, pad, 0);
if (ret)
return ret;
ret = media_create_pad_link(&subdev->entity, 1,
&cap_raw->video.vdev.entity, 0, 0);
if (ret)
return ret;
isp_dev->source_subdev = subdev;
cap_raw->video.source_subdev = subdev;
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 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));
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, num_subdevs;
unsigned int i;
stfcamss = devm_kzalloc(dev, sizeof(*stfcamss), GFP_KERNEL);
if (!stfcamss)
return -ENOMEM;
stfcamss->dev = dev;
for (i = 0; i < ARRAY_SIZE(stf_isrs); ++i) {
int irq;
irq = platform_get_irq(pdev, i);
if (irq < 0)
return irq;
ret = devm_request_irq(stfcamss->dev, irq, stf_isrs[i].isr, 0,
stf_isrs[i].name, stfcamss);
if (ret) {
dev_err(dev, "request irq failed: %d\n", ret);
return ret;
}
}
stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk);
for (i = 0; i < stfcamss->nclks; ++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 < stfcamss->nrsts; ++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(stfcamss);
if (ret) {
dev_err(dev, "Could not map registers\n");
return ret;
}
platform_set_drvdata(pdev, stfcamss);
v4l2_async_nf_init(&stfcamss->notifier, &stfcamss->v4l2_dev);
num_subdevs = stfcamss_of_parse_ports(stfcamss);
if (num_subdevs < 0) {
ret = -ENODEV;
dev_err(dev, "Failed to get sub devices: %d\n", ret);
goto err_cleanup_notifier;
}
ret = stf_isp_init(stfcamss);
if (ret < 0) {
dev_err(dev, "Failed to init isp: %d\n", ret);
goto err_cleanup_notifier;
}
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_media_device;
}
ret = media_device_register(&stfcamss->media_dev);
if (ret) {
dev_err(dev, "Failed to register media device: %d\n", ret);
goto err_unregister_device;
}
ret = stfcamss_register_devs(stfcamss);
if (ret < 0) {
dev_err(dev, "Failed to register subdevice: %d\n", ret);
goto err_unregister_media_dev;
}
pm_runtime_enable(dev);
stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops;
ret = v4l2_async_nf_register(&stfcamss->notifier);
if (ret) {
dev_err(dev, "Failed to register async subdev nodes: %d\n",
ret);
pm_runtime_disable(dev);
goto err_unregister_subdevs;
}
return 0;
err_unregister_subdevs:
stfcamss_unregister_devs(stfcamss);
err_unregister_media_dev:
media_device_unregister(&stfcamss->media_dev);
err_unregister_device:
v4l2_device_unregister(&stfcamss->v4l2_dev);
err_cleanup_media_device:
media_device_cleanup(&stfcamss->media_dev);
err_cleanup_notifier:
v4l2_async_nf_cleanup(&stfcamss->notifier);
return ret;
}
/*
* stfcamss_remove - Remove STFCAMSS platform device
* @pdev: Pointer to STFCAMSS platform device
*/
static void stfcamss_remove(struct platform_device *pdev)
{
struct stfcamss *stfcamss = platform_get_drvdata(pdev);
stfcamss_unregister_devs(stfcamss);
v4l2_device_unregister(&stfcamss->v4l2_dev);
media_device_cleanup(&stfcamss->media_dev);
v4l2_async_nf_cleanup(&stfcamss->notifier);
pm_runtime_disable(&pdev->dev);
}
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);
int ret;
ret = reset_control_bulk_assert(stfcamss->nrsts, stfcamss->sys_rst);
if (ret) {
dev_err(dev, "reset assert failed\n");
return ret;
}
clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk);
return 0;
}
static int __maybe_unused stfcamss_runtime_resume(struct device *dev)
{
struct stfcamss *stfcamss = dev_get_drvdata(dev);
int ret;
ret = clk_bulk_prepare_enable(stfcamss->nclks, stfcamss->sys_clk);
if (ret) {
dev_err(dev, "clock prepare enable failed\n");
return ret;
}
ret = reset_control_bulk_deassert(stfcamss->nrsts, stfcamss->sys_rst);
if (ret < 0) {
dev_err(dev, "cannot deassert resets\n");
clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk);
return ret;
}
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 = "starfive-camss",
.pm = &stfcamss_pm_ops,
.of_match_table = stfcamss_of_match,
},
};
module_platform_driver(stfcamss_driver);
MODULE_AUTHOR("Jack Zhu <jack.zhu@starfivetech.com>");
MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>");
MODULE_DESCRIPTION("StarFive Camera Subsystem driver");
MODULE_LICENSE("GPL");
@@ -1,134 +0,0 @@
/* 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/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include "stf-isp.h"
#include "stf-capture.h"
enum stf_port_num {
STF_PORT_DVP = 0,
STF_PORT_CSI2RX
};
enum stf_clk {
STF_CLK_WRAPPER_CLK_C = 0,
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_AXIWR,
STF_RST_ISP_TOP_N,
STF_RST_ISP_TOP_AXI,
STF_RST_NUM
};
struct stf_isr_data {
const char *name;
irqreturn_t (*isr)(int irq, void *priv);
};
struct stfcamss {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
struct media_pipeline pipe;
struct device *dev;
struct stf_isp_dev isp_dev;
struct stf_capture captures[STF_CAPTURE_NUM];
struct v4l2_async_notifier notifier;
void __iomem *syscon_base;
void __iomem *isp_base;
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_connection asd; /* must be first */
enum stf_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 */
File diff suppressed because it is too large Load Diff
@@ -1,86 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* stf_capture.h
*
* Starfive Camera Subsystem driver
*
* Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
*/
#ifndef STF_CAPTURE_H
#define STF_CAPTURE_H
#include "stf-video.h"
#define VIN_CHANNEL_SEL_EN 0x14
#define VIN_START_ADDR_N 0x18
#define VIN_INRT_PIX_CFG 0x1c
#define VIN_START_ADDR_O 0x20
#define VIN_CFG_REG 0x24
#define U0_VIN_CNFG_AXI_DVP_EN BIT(2)
#define U0_VIN_CHANNEL_SEL_MASK GENMASK(3, 0)
#define U0_VIN_AXIWR0_EN BIT(4)
#define CHANNEL(x) ((x) << 0)
#define U0_VIN_INTR_CLEAN BIT(0)
#define U0_VIN_INTR_M BIT(1)
#define U0_VIN_PIX_CNT_END_MASK GENMASK(12, 2)
#define U0_VIN_PIX_CT_MASK GENMASK(14, 13)
#define U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS GENMASK(16, 15)
#define PIX_CNT_END(x) ((x) << 2)
#define PIX_CT(x) ((x) << 13)
#define PIXEL_HEIGH_BIT_SEL(x) ((x) << 15)
#define U0_VIN_CNFG_DVP_HS_POS BIT(1)
#define U0_VIN_CNFG_DVP_SWAP_EN BIT(2)
#define U0_VIN_CNFG_DVP_VS_POS BIT(3)
#define U0_VIN_CNFG_GEN_EN_AXIRD BIT(4)
#define U0_VIN_CNFG_ISP_DVP_EN0 BIT(5)
#define U0_VIN_MIPI_BYTE_EN_ISP0(n) ((n) << 6)
#define U0_VIN_MIPI_CHANNEL_SEL0(n) ((n) << 8)
#define U0_VIN_P_I_MIPI_HAEDER_EN0(n) ((n) << 12)
#define U0_VIN_PIX_NUM(n) ((n) << 13)
#define U0_VIN_MIPI_BYTE_EN_ISP0_MASK GENMASK(7, 6)
#define U0_VIN_MIPI_CHANNEL_SEL0_MASK GENMASK(11, 8)
#define U0_VIN_P_I_MIPI_HAEDER_EN0_MASK BIT(12)
#define U0_VIN_PIX_NUM_MASK GENMASK(16, 13)
enum stf_v_state {
STF_OUTPUT_OFF,
STF_OUTPUT_RESERVED,
STF_OUTPUT_SINGLE,
STF_OUTPUT_CONTINUOUS,
STF_OUTPUT_IDLE,
STF_OUTPUT_STOPPING
};
struct stf_v_buf {
int active_buf;
struct stfcamss_buffer *buf[2];
struct stfcamss_buffer *last_buffer;
struct list_head pending_bufs;
struct list_head ready_bufs;
enum stf_v_state state;
unsigned int sequence;
/* protects the above member variables */
spinlock_t lock;
atomic_t frame_skip;
};
struct stf_capture {
struct stfcamss_video video;
struct stf_v_buf buffers;
enum stf_capture_type type;
};
irqreturn_t stf_wr_irq_handler(int irq, void *priv);
irqreturn_t stf_isp_irq_handler(int irq, void *priv);
irqreturn_t stf_line_irq_handler(int irq, void *priv);
int stf_capture_register(struct stfcamss *stfcamss,
struct v4l2_device *v4l2_dev);
void stf_capture_unregister(struct stfcamss *stfcamss);
#endif
@@ -1,445 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* stf_isp_hw_ops.c
*
* Register interface file for StarFive ISP driver
*
* Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
*
*/
#include "stf-camss.h"
static void stf_isp_config_obc(struct stfcamss *stfcamss)
{
u32 reg_val, reg_add;
stf_isp_reg_write(stfcamss, ISP_REG_OBC_CFG, OBC_W_H(11) | OBC_W_W(11));
reg_val = GAIN_D_POINT(0x40) | GAIN_C_POINT(0x40) |
GAIN_B_POINT(0x40) | GAIN_A_POINT(0x40);
for (reg_add = ISP_REG_OBCG_CFG_0; reg_add <= ISP_REG_OBCG_CFG_3;) {
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
}
reg_val = OFFSET_D_POINT(0) | OFFSET_C_POINT(0) |
OFFSET_B_POINT(0) | OFFSET_A_POINT(0);
for (reg_add = ISP_REG_OBCO_CFG_0; reg_add <= ISP_REG_OBCO_CFG_3;) {
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
}
}
static void stf_isp_config_oecf(struct stfcamss *stfcamss)
{
u32 reg_add, par_val;
u16 par_h, par_l;
par_h = 0x10; par_l = 0;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG0; reg_add <= ISP_REG_OECF_Y3_CFG0;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x40; par_l = 0x20;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG1; reg_add <= ISP_REG_OECF_Y3_CFG1;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x80; par_l = 0x60;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG2; reg_add <= ISP_REG_OECF_Y3_CFG2;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0xc0; par_l = 0xa0;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG3; reg_add <= ISP_REG_OECF_Y3_CFG3;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x100; par_l = 0xe0;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG4; reg_add <= ISP_REG_OECF_Y3_CFG4;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x200; par_l = 0x180;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG5; reg_add <= ISP_REG_OECF_Y3_CFG5;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x300; par_l = 0x280;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG6; reg_add <= ISP_REG_OECF_Y3_CFG6;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x3fe; par_l = 0x380;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_X0_CFG7; reg_add <= ISP_REG_OECF_Y3_CFG7;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 0x20;
}
par_h = 0x80; par_l = 0x80;
par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
for (reg_add = ISP_REG_OECF_S0_CFG0; reg_add <= ISP_REG_OECF_S3_CFG7;) {
stf_isp_reg_write(stfcamss, reg_add, par_val);
reg_add += 4;
}
}
static void stf_isp_config_lccf(struct stfcamss *stfcamss)
{
u32 reg_add;
stf_isp_reg_write(stfcamss, ISP_REG_LCCF_CFG_0,
Y_DISTANCE(0x21C) | X_DISTANCE(0x3C0));
stf_isp_reg_write(stfcamss, ISP_REG_LCCF_CFG_1, LCCF_MAX_DIS(0xb));
for (reg_add = ISP_REG_LCCF_CFG_2; reg_add <= ISP_REG_LCCF_CFG_5;) {
stf_isp_reg_write(stfcamss, reg_add,
LCCF_F2_PAR(0x0) | LCCF_F1_PAR(0x0));
reg_add += 4;
}
}
static void stf_isp_config_awb(struct stfcamss *stfcamss)
{
u32 reg_val, reg_add;
u16 symbol_h, symbol_l;
symbol_h = 0x0; symbol_l = 0x0;
reg_val = AWB_X_SYMBOL_H(symbol_h) | AWB_X_SYMBOL_L(symbol_l);
for (reg_add = ISP_REG_AWB_X0_CFG_0; reg_add <= ISP_REG_AWB_X3_CFG_1;) {
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
}
symbol_h = 0x0, symbol_l = 0x0;
reg_val = AWB_Y_SYMBOL_H(symbol_h) | AWB_Y_SYMBOL_L(symbol_l);
for (reg_add = ISP_REG_AWB_Y0_CFG_0; reg_add <= ISP_REG_AWB_Y3_CFG_1;) {
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
}
symbol_h = 0x80, symbol_l = 0x80;
reg_val = AWB_S_SYMBOL_H(symbol_h) | AWB_S_SYMBOL_L(symbol_l);
for (reg_add = ISP_REG_AWB_S0_CFG_0; reg_add <= ISP_REG_AWB_S3_CFG_1;) {
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
}
}
static void stf_isp_config_grgb(struct stfcamss *stfcamss)
{
stf_isp_reg_write(stfcamss, ISP_REG_ICTC,
GF_MODE(1) | MAXGT(0x140) | MINGT(0x40));
stf_isp_reg_write(stfcamss, ISP_REG_IDBC, BADGT(0x200) | BADXT(0x200));
}
static void stf_isp_config_cfa(struct stfcamss *stfcamss)
{
stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG,
SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | SMY3(2) |
SMY2(3) | SMY1(2) | SMY0(3));
stf_isp_reg_write(stfcamss, ISP_REG_ICFAM, CROSS_COV(3) | HV_W(2));
}
static void stf_isp_config_ccm(struct stfcamss *stfcamss)
{
u32 reg_add;
stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_0, DNRM_F(6) | CCM_M_DAT(0));
for (reg_add = ISP_REG_ICAMD_12; reg_add <= ISP_REG_ICAMD_20;) {
stf_isp_reg_write(stfcamss, reg_add, CCM_M_DAT(0x80));
reg_add += 0x10;
}
stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_24, CCM_M_DAT(0x700));
stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_25, CCM_M_DAT(0x200));
}
static void stf_isp_config_gamma(struct stfcamss *stfcamss)
{
u32 reg_val, reg_add;
u16 gamma_slope_v, gamma_v;
gamma_slope_v = 0x2400; gamma_v = 0x0;
reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL0, reg_val);
gamma_slope_v = 0x800; gamma_v = 0x20;
for (reg_add = ISP_REG_GAMMA_VAL1; reg_add <= ISP_REG_GAMMA_VAL7;) {
reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
gamma_v += 0x20;
}
gamma_v = 0x100;
for (reg_add = ISP_REG_GAMMA_VAL8; reg_add <= ISP_REG_GAMMA_VAL13;) {
reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
stf_isp_reg_write(stfcamss, reg_add, reg_val);
reg_add += 4;
gamma_v += 0x80;
}
gamma_v = 0x3fe;
reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL14, reg_val);
}
static void stf_isp_config_r2y(struct stfcamss *stfcamss)
{
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_0, 0x4C);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_1, 0x97);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_2, 0x1d);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_3, 0x1d5);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_4, 0x1ac);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_5, 0x80);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_6, 0x80);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_7, 0x194);
stf_isp_reg_write(stfcamss, ISP_REG_R2Y_8, 0x1ec);
}
static void stf_isp_config_y_curve(struct stfcamss *stfcamss)
{
u32 reg_add;
u16 y_curve;
y_curve = 0x0;
for (reg_add = ISP_REG_YCURVE_0; reg_add <= ISP_REG_YCURVE_63;) {
stf_isp_reg_write(stfcamss, reg_add, y_curve);
reg_add += 4;
y_curve += 0x10;
}
}
static void stf_isp_config_sharpen(struct stfcamss *sc)
{
u32 reg_add;
stf_isp_reg_write(sc, ISP_REG_SHARPEN0, S_DELTA(0x7) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN1, S_DELTA(0x18) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN2, S_DELTA(0x80) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN3, S_DELTA(0x100) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN4, S_DELTA(0x10) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN5, S_DELTA(0x60) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN6, S_DELTA(0x100) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN7, S_DELTA(0x190) | S_WEIGHT(0xf));
stf_isp_reg_write(sc, ISP_REG_SHARPEN8, S_DELTA(0x0) | S_WEIGHT(0xf));
for (reg_add = ISP_REG_SHARPEN9; reg_add <= ISP_REG_SHARPEN14;) {
stf_isp_reg_write(sc, reg_add, S_WEIGHT(0xf));
reg_add += 4;
}
for (reg_add = ISP_REG_SHARPEN_FS0; reg_add <= ISP_REG_SHARPEN_FS5;) {
stf_isp_reg_write(sc, reg_add, S_FACTOR(0x10) | S_SLOPE(0x0));
reg_add += 4;
}
stf_isp_reg_write(sc, ISP_REG_SHARPEN_WN,
PDIRF(0x8) | NDIRF(0x8) | WSUM(0xd7c));
stf_isp_reg_write(sc, ISP_REG_IUVS1, UVDIFF2(0xC0) | UVDIFF1(0x40));
stf_isp_reg_write(sc, ISP_REG_IUVS2, UVF(0xff) | UVSLOPE(0x0));
stf_isp_reg_write(sc, ISP_REG_IUVCKS1,
UVCKDIFF2(0xa0) | UVCKDIFF1(0x40));
}
static void stf_isp_config_dnyuv(struct stfcamss *stfcamss)
{
u32 reg_val;
reg_val = YUVSW5(7) | YUVSW4(7) | YUVSW3(7) | YUVSW2(7) |
YUVSW1(7) | YUVSW0(7);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR0, reg_val);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR0, reg_val);
reg_val = YUVSW3(7) | YUVSW2(7) | YUVSW1(7) | YUVSW0(7);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR1, reg_val);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR1, reg_val);
reg_val = CURVE_D_H(0x60) | CURVE_D_L(0x40);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR0, reg_val);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR0, reg_val);
reg_val = CURVE_D_H(0xd8) | CURVE_D_L(0x90);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR1, reg_val);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR1, reg_val);
reg_val = CURVE_D_H(0x1e6) | CURVE_D_L(0x144);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR2, reg_val);
stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR2, reg_val);
}
static void stf_isp_config_sat(struct stfcamss *stfcamss)
{
stf_isp_reg_write(stfcamss, ISP_REG_CS_GAIN, CMAD(0x0) | CMAB(0x100));
stf_isp_reg_write(stfcamss, ISP_REG_CS_THRESHOLD, CMD(0x1f) | CMB(0x1));
stf_isp_reg_write(stfcamss, ISP_REG_CS_OFFSET, VOFF(0x0) | UOFF(0x0));
stf_isp_reg_write(stfcamss, ISP_REG_CS_HUE_F, SIN(0x0) | COS(0x100));
stf_isp_reg_write(stfcamss, ISP_REG_CS_SCALE, 0x8);
stf_isp_reg_write(stfcamss, ISP_REG_YADJ0, YOIR(0x401) | YIMIN(0x1));
stf_isp_reg_write(stfcamss, ISP_REG_YADJ1, YOMAX(0x3ff) | YOMIN(0x1));
}
int stf_isp_reset(struct stf_isp_dev *isp_dev)
{
stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0,
ISPC_RST_MASK, ISPC_RST);
stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0,
ISPC_RST_MASK, 0);
return 0;
}
void stf_isp_init_cfg(struct stf_isp_dev *isp_dev)
{
stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DC_CFG_1, DC_AXI_ID(0x0));
stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DEC_CFG,
DEC_V_KEEP(0x0) |
DEC_V_PERIOD(0x0) |
DEC_H_KEEP(0x0) |
DEC_H_PERIOD(0x0));
stf_isp_config_obc(isp_dev->stfcamss);
stf_isp_config_oecf(isp_dev->stfcamss);
stf_isp_config_lccf(isp_dev->stfcamss);
stf_isp_config_awb(isp_dev->stfcamss);
stf_isp_config_grgb(isp_dev->stfcamss);
stf_isp_config_cfa(isp_dev->stfcamss);
stf_isp_config_ccm(isp_dev->stfcamss);
stf_isp_config_gamma(isp_dev->stfcamss);
stf_isp_config_r2y(isp_dev->stfcamss);
stf_isp_config_y_curve(isp_dev->stfcamss);
stf_isp_config_sharpen(isp_dev->stfcamss);
stf_isp_config_dnyuv(isp_dev->stfcamss);
stf_isp_config_sat(isp_dev->stfcamss);
stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_CSI_MODULE_CFG,
CSI_DUMP_EN | CSI_SC_EN | CSI_AWB_EN |
CSI_LCCF_EN | CSI_OECF_EN | CSI_OBC_EN | CSI_DEC_EN);
stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_ISP_CTRL_1,
CTRL_SAT(1) | CTRL_DBC | CTRL_CTC | CTRL_YHIST |
CTRL_YCURVE | CTRL_BIYUV | CTRL_SCE | CTRL_EE |
CTRL_CCE | CTRL_RGE | CTRL_CME | CTRL_AE | CTRL_CE);
}
static void stf_isp_config_crop(struct stfcamss *stfcamss,
struct v4l2_rect *crop)
{
u32 bpp = stfcamss->isp_dev.current_fmt->bpp;
u32 val;
val = VSTART_CAP(crop->top) | HSTART_CAP(crop->left);
stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_START_CFG, val);
val = VEND_CAP(crop->height + crop->top - 1) |
HEND_CAP(crop->width + crop->left - 1);
stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_END_CFG, val);
val = H_ACT_CAP(crop->height) | W_ACT_CAP(crop->width);
stf_isp_reg_write(stfcamss, ISP_REG_PIPELINE_XY_SIZE, val);
val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
stf_isp_reg_write(stfcamss, ISP_REG_STRIDE, val);
}
static void stf_isp_config_raw_fmt(struct stfcamss *stfcamss, u32 mcode)
{
u32 val, val1;
switch (mcode) {
case MEDIA_BUS_FMT_SRGGB10_1X10:
case MEDIA_BUS_FMT_SRGGB8_1X8:
/* 3 2 3 2 1 0 1 0 B Gb B Gb Gr R Gr R */
val = SMY13(3) | SMY12(2) | SMY11(3) | SMY10(2) |
SMY3(1) | SMY2(0) | SMY1(1) | SMY0(0);
val1 = CTRL_SAT(0x0);
break;
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SGRBG8_1X8:
/* 2 3 2 3 0 1 0 1, Gb B Gb B R Gr R Gr */
val = SMY13(2) | SMY12(3) | SMY11(2) | SMY10(3) |
SMY3(0) | SMY2(1) | SMY1(0) | SMY0(1);
val1 = CTRL_SAT(0x2);
break;
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGBRG8_1X8:
/* 1 0 1 0 3 2 3 2, Gr R Gr R B Gb B Gb */
val = SMY13(1) | SMY12(0) | SMY11(1) | SMY10(0) |
SMY3(3) | SMY2(2) | SMY1(3) | SMY0(2);
val1 = CTRL_SAT(0x3);
break;
case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SBGGR8_1X8:
/* 0 1 0 1 2 3 2 3 R Gr R Gr Gb B Gb B */
val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) |
SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3);
val1 = CTRL_SAT(0x1);
break;
default:
val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) |
SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3);
val1 = CTRL_SAT(0x1);
break;
}
stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG, val);
stf_isp_reg_set_bit(stfcamss, ISP_REG_ISP_CTRL_1, CTRL_SAT_MASK, val1);
}
void stf_isp_settings(struct stf_isp_dev *isp_dev,
struct v4l2_rect *crop, u32 mcode)
{
struct stfcamss *stfcamss = isp_dev->stfcamss;
stf_isp_config_crop(stfcamss, crop);
stf_isp_config_raw_fmt(stfcamss, mcode);
stf_isp_reg_set_bit(stfcamss, ISP_REG_DUMP_CFG_1,
DUMP_BURST_LEN_MASK | DUMP_SD_MASK,
DUMP_BURST_LEN(3));
stf_isp_reg_write(stfcamss, ISP_REG_ITIIWSR,
ITI_HSIZE(IMAGE_MAX_HEIGH) |
ITI_WSIZE(IMAGE_MAX_WIDTH));
stf_isp_reg_write(stfcamss, ISP_REG_ITIDWLSR, 0x960);
stf_isp_reg_write(stfcamss, ISP_REG_ITIDRLSR, 0x960);
stf_isp_reg_write(stfcamss, ISP_REG_SENSOR, IMAGER_SEL(1));
}
void stf_isp_stream_set(struct stf_isp_dev *isp_dev)
{
struct stfcamss *stfcamss = isp_dev->stfcamss;
stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0,
ISPC_ENUO | ISPC_ENLS | ISPC_RST, 10);
stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0,
ISPC_ENUO | ISPC_ENLS, 10);
stf_isp_reg_write(stfcamss, ISP_REG_IESHD, SHAD_UP_M);
stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0,
ISPC_ENUO | ISPC_ENLS | ISPC_EN, 10);
stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS,
CSI_INTS(1) | CSI_SHA_M(4), 10);
stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS,
CSI_INTS(2) | CSI_SHA_M(4), 10);
stf_isp_reg_write_delay(stfcamss, ISP_REG_CSI_INPUT_EN_AND_STATUS,
CSI_EN_S, 10);
}
@@ -1,379 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* stf_isp.c
*
* StarFive Camera Subsystem - ISP Module
*
* Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
*/
#include <media/v4l2-rect.h>
#include "stf-camss.h"
static int isp_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel);
static const struct stf_isp_format isp_formats_sink[] = {
{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
};
static const struct stf_isp_format isp_formats_source[] = {
{ MEDIA_BUS_FMT_YUYV8_1_5X8, 8 },
};
static const struct stf_isp_format_table isp_formats_st7110[] = {
{ isp_formats_sink, ARRAY_SIZE(isp_formats_sink) },
{ isp_formats_source, ARRAY_SIZE(isp_formats_source) },
};
static const struct stf_isp_format *
stf_g_fmt_by_mcode(const struct stf_isp_format_table *fmt_table, u32 mcode)
{
unsigned int i;
for (i = 0; i < fmt_table->nfmts; i++) {
if (fmt_table->fmts[i].code == mcode)
return &fmt_table->fmts[i];
}
return NULL;
}
int stf_isp_init(struct stfcamss *stfcamss)
{
struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
isp_dev->stfcamss = stfcamss;
isp_dev->formats = isp_formats_st7110;
isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110);
isp_dev->current_fmt = &isp_formats_source[0];
return 0;
}
static int isp_set_stream(struct v4l2_subdev *sd, int enable)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
struct v4l2_subdev_state *sd_state;
struct v4l2_mbus_framefmt *fmt;
struct v4l2_rect *crop;
sd_state = v4l2_subdev_lock_and_get_active_state(sd);
fmt = v4l2_subdev_state_get_format(sd_state, STF_ISP_PAD_SINK);
crop = v4l2_subdev_state_get_crop(sd_state, STF_ISP_PAD_SRC);
if (enable) {
stf_isp_reset(isp_dev);
stf_isp_init_cfg(isp_dev);
stf_isp_settings(isp_dev, crop, fmt->code);
stf_isp_stream_set(isp_dev);
}
v4l2_subdev_call(isp_dev->source_subdev, video, s_stream, enable);
v4l2_subdev_unlock_state(sd_state);
return 0;
}
static void isp_try_format(struct stf_isp_dev *isp_dev,
struct v4l2_subdev_state *state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt)
{
const struct stf_isp_format_table *formats;
if (pad >= STF_ISP_PAD_MAX) {
fmt->colorspace = V4L2_COLORSPACE_SRGB;
return;
}
formats = &isp_dev->formats[pad];
fmt->width = clamp_t(u32, fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
STFCAMSS_FRAME_MAX_WIDTH);
fmt->height = clamp_t(u32, fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
STFCAMSS_FRAME_MAX_HEIGHT);
fmt->height &= ~0x1;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
fmt->flags = 0;
if (!stf_g_fmt_by_mcode(formats, fmt->code))
fmt->code = formats->fmts[0].code;
}
static int isp_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
const struct stf_isp_format_table *formats;
if (code->pad == STF_ISP_PAD_SINK) {
if (code->index >= ARRAY_SIZE(isp_formats_sink))
return -EINVAL;
formats = &isp_dev->formats[code->pad];
code->code = formats->fmts[code->index].code;
} else {
struct v4l2_mbus_framefmt *sink_fmt;
if (code->index >= ARRAY_SIZE(isp_formats_source))
return -EINVAL;
sink_fmt = v4l2_subdev_state_get_format(state,
STF_ISP_PAD_SRC);
code->code = sink_fmt->code;
if (!code->code)
return -EINVAL;
}
code->flags = 0;
return 0;
}
static int isp_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *fmt)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
format = v4l2_subdev_state_get_format(state, fmt->pad);
if (!format)
return -EINVAL;
isp_try_format(isp_dev, state, fmt->pad, &fmt->format);
*format = fmt->format;
isp_dev->current_fmt = stf_g_fmt_by_mcode(&isp_dev->formats[fmt->pad],
fmt->format.code);
/* Propagate to in crop */
if (fmt->pad == STF_ISP_PAD_SINK) {
struct v4l2_subdev_selection sel = { 0 };
/* Reset sink pad compose selection */
sel.which = fmt->which;
sel.pad = STF_ISP_PAD_SINK;
sel.target = V4L2_SEL_TGT_CROP;
sel.r.width = fmt->format.width;
sel.r.height = fmt->format.height;
isp_set_selection(sd, state, &sel);
}
return 0;
}
static const struct v4l2_rect stf_frame_min_crop = {
.width = STFCAMSS_FRAME_MIN_WIDTH,
.height = STFCAMSS_FRAME_MIN_HEIGHT,
.top = 0,
.left = 0,
};
static void isp_try_crop(struct stf_isp_dev *isp_dev,
struct v4l2_subdev_state *state,
struct v4l2_rect *crop)
{
struct v4l2_mbus_framefmt *fmt =
v4l2_subdev_state_get_format(state, STF_ISP_PAD_SINK);
const struct v4l2_rect bounds = {
.width = fmt->width,
.height = fmt->height,
.left = 0,
.top = 0,
};
v4l2_rect_set_min_size(crop, &stf_frame_min_crop);
v4l2_rect_map_inside(crop, &bounds);
}
static int isp_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
struct v4l2_subdev_format fmt = { 0 };
struct v4l2_rect *rect;
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
if (sel->pad == STF_ISP_PAD_SINK) {
fmt.format = *v4l2_subdev_state_get_format(state,
sel->pad);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = fmt.format.width;
sel->r.height = fmt.format.height;
} else if (sel->pad == STF_ISP_PAD_SRC) {
rect = v4l2_subdev_state_get_crop(state, sel->pad);
sel->r = *rect;
}
break;
case V4L2_SEL_TGT_CROP:
rect = v4l2_subdev_state_get_crop(state, sel->pad);
if (!rect)
return -EINVAL;
sel->r = *rect;
break;
default:
return -EINVAL;
}
return 0;
}
static int isp_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
struct v4l2_rect *rect;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
if (sel->target == V4L2_SEL_TGT_CROP &&
sel->pad == STF_ISP_PAD_SINK) {
struct v4l2_subdev_selection crop = { 0 };
rect = v4l2_subdev_state_get_crop(state, sel->pad);
if (!rect)
return -EINVAL;
isp_try_crop(isp_dev, state, &sel->r);
*rect = sel->r;
/* Reset source crop selection */
crop.which = sel->which;
crop.pad = STF_ISP_PAD_SRC;
crop.target = V4L2_SEL_TGT_CROP;
crop.r = *rect;
isp_set_selection(sd, state, &crop);
} else if (sel->target == V4L2_SEL_TGT_CROP &&
sel->pad == STF_ISP_PAD_SRC) {
struct v4l2_subdev_format fmt = { 0 };
rect = v4l2_subdev_state_get_crop(state, sel->pad);
if (!rect)
return -EINVAL;
isp_try_crop(isp_dev, state, &sel->r);
*rect = sel->r;
/* Reset source pad format width and height */
fmt.which = sel->which;
fmt.pad = STF_ISP_PAD_SRC;
fmt.format.width = rect->width;
fmt.format.height = rect->height;
isp_set_format(sd, state, &fmt);
}
dev_dbg(isp_dev->stfcamss->dev, "pad: %d sel(%d,%d)/%ux%u\n",
sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
return 0;
}
static int isp_init_formats(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format format = {
.pad = STF_ISP_PAD_SINK,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
.format = {
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
.width = 1920,
.height = 1080
}
};
return isp_set_format(sd, sd_state, &format);
}
static const struct v4l2_subdev_video_ops isp_video_ops = {
.s_stream = isp_set_stream,
};
static const struct v4l2_subdev_pad_ops isp_pad_ops = {
.enum_mbus_code = isp_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = isp_set_format,
.get_selection = isp_get_selection,
.set_selection = isp_set_selection,
};
static const struct v4l2_subdev_ops isp_v4l2_ops = {
.video = &isp_video_ops,
.pad = &isp_pad_ops,
};
static const struct v4l2_subdev_internal_ops isp_internal_ops = {
.init_state = isp_init_formats,
};
static const struct media_entity_operations isp_media_ops = {
.link_validate = v4l2_subdev_link_validate,
};
int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev)
{
struct v4l2_subdev *sd = &isp_dev->subdev;
struct media_pad *pads = isp_dev->pads;
int ret;
v4l2_subdev_init(sd, &isp_v4l2_ops);
sd->internal_ops = &isp_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, ARRAY_SIZE(sd->name), "stf_isp");
v4l2_set_subdevdata(sd, isp_dev);
pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP;
sd->entity.ops = &isp_media_ops;
ret = media_entity_pads_init(&sd->entity, STF_ISP_PAD_MAX, pads);
if (ret) {
dev_err(isp_dev->stfcamss->dev,
"Failed to init media entity: %d\n", ret);
return ret;
}
ret = v4l2_subdev_init_finalize(sd);
if (ret)
goto err_entity_cleanup;
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret) {
dev_err(isp_dev->stfcamss->dev,
"Failed to register subdev: %d\n", ret);
goto err_subdev_cleanup;
}
return 0;
err_subdev_cleanup:
v4l2_subdev_cleanup(sd);
err_entity_cleanup:
media_entity_cleanup(&sd->entity);
return ret;
}
int stf_isp_unregister(struct stf_isp_dev *isp_dev)
{
v4l2_device_unregister_subdev(&isp_dev->subdev);
v4l2_subdev_cleanup(&isp_dev->subdev);
media_entity_cleanup(&isp_dev->subdev.entity);
return 0;
}
@@ -1,428 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* stf_isp.h
*
* StarFive Camera Subsystem - ISP Module
*
* Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
*/
#ifndef STF_ISP_H
#define STF_ISP_H
#include <media/v4l2-subdev.h>
#include "stf-video.h"
#define ISP_RAW_DATA_BITS 12
#define SCALER_RATIO_MAX 1
#define STF_ISP_REG_OFFSET_MAX 0x0fff
#define STF_ISP_REG_DELAY_MAX 100
/* isp registers */
#define ISP_REG_CSI_INPUT_EN_AND_STATUS 0x000
#define CSI_SCD_ERR BIT(6)
#define CSI_ITU656_ERR BIT(4)
#define CSI_ITU656_F BIT(3)
#define CSI_SCD_DONE BIT(2)
#define CSI_BUSY_S BIT(1)
#define CSI_EN_S BIT(0)
#define ISP_REG_CSIINTS 0x008
#define CSI_INTS(n) ((n) << 16)
#define CSI_SHA_M(n) ((n) << 0)
#define CSI_INTS_MASK GENMASK(17, 16)
#define ISP_REG_CSI_MODULE_CFG 0x010
#define CSI_DUMP_EN BIT(19)
#define CSI_VS_EN BIT(18)
#define CSI_SC_EN BIT(17)
#define CSI_OBA_EN BIT(16)
#define CSI_AWB_EN BIT(7)
#define CSI_LCCF_EN BIT(6)
#define CSI_OECFHM_EN BIT(5)
#define CSI_OECF_EN BIT(4)
#define CSI_LCBQ_EN BIT(3)
#define CSI_OBC_EN BIT(2)
#define CSI_DEC_EN BIT(1)
#define CSI_DC_EN BIT(0)
#define ISP_REG_SENSOR 0x014
#define DVP_SYNC_POL(n) ((n) << 2)
#define ITU656_EN(n) ((n) << 1)
#define IMAGER_SEL(n) ((n) << 0)
#define ISP_REG_RAW_FORMAT_CFG 0x018
#define SMY13(n) ((n) << 14)
#define SMY12(n) ((n) << 12)
#define SMY11(n) ((n) << 10)
#define SMY10(n) ((n) << 8)
#define SMY3(n) ((n) << 6)
#define SMY2(n) ((n) << 4)
#define SMY1(n) ((n) << 2)
#define SMY0(n) ((n) << 0)
#define ISP_REG_PIC_CAPTURE_START_CFG 0x01c
#define VSTART_CAP(n) ((n) << 16)
#define HSTART_CAP(n) ((n) << 0)
#define ISP_REG_PIC_CAPTURE_END_CFG 0x020
#define VEND_CAP(n) ((n) << 16)
#define HEND_CAP(n) ((n) << 0)
#define ISP_REG_DUMP_CFG_0 0x024
#define ISP_REG_DUMP_CFG_1 0x028
#define DUMP_ID(n) ((n) << 24)
#define DUMP_SHT(n) ((n) << 20)
#define DUMP_BURST_LEN(n) ((n) << 16)
#define DUMP_SD(n) ((n) << 0)
#define DUMP_BURST_LEN_MASK GENMASK(17, 16)
#define DUMP_SD_MASK GENMASK(15, 0)
#define ISP_REG_DEC_CFG 0x030
#define DEC_V_KEEP(n) ((n) << 24)
#define DEC_V_PERIOD(n) ((n) << 16)
#define DEC_H_KEEP(n) ((n) << 8)
#define DEC_H_PERIOD(n) ((n) << 0)
#define ISP_REG_OBC_CFG 0x034
#define OBC_W_H(y) ((y) << 4)
#define OBC_W_W(x) ((x) << 0)
#define ISP_REG_DC_CFG_1 0x044
#define DC_AXI_ID(n) ((n) << 0)
#define ISP_REG_LCCF_CFG_0 0x050
#define Y_DISTANCE(y) ((y) << 16)
#define X_DISTANCE(x) ((x) << 0)
#define ISP_REG_LCCF_CFG_1 0x058
#define LCCF_MAX_DIS(n) ((n) << 0)
#define ISP_REG_LCBQ_CFG_0 0x074
#define H_LCBQ(y) ((y) << 12)
#define W_LCBQ(x) ((x) << 8)
#define ISP_REG_LCBQ_CFG_1 0x07c
#define Y_COOR(y) ((y) << 16)
#define X_COOR(x) ((x) << 0)
#define ISP_REG_LCCF_CFG_2 0x0e0
#define ISP_REG_LCCF_CFG_3 0x0e4
#define ISP_REG_LCCF_CFG_4 0x0e8
#define ISP_REG_LCCF_CFG_5 0x0ec
#define LCCF_F2_PAR(n) ((n) << 16)
#define LCCF_F1_PAR(n) ((n) << 0)
#define ISP_REG_OECF_X0_CFG0 0x100
#define ISP_REG_OECF_X0_CFG1 0x104
#define ISP_REG_OECF_X0_CFG2 0x108
#define ISP_REG_OECF_X0_CFG3 0x10c
#define ISP_REG_OECF_X0_CFG4 0x110
#define ISP_REG_OECF_X0_CFG5 0x114
#define ISP_REG_OECF_X0_CFG6 0x118
#define ISP_REG_OECF_X0_CFG7 0x11c
#define ISP_REG_OECF_Y3_CFG0 0x1e0
#define ISP_REG_OECF_Y3_CFG1 0x1e4
#define ISP_REG_OECF_Y3_CFG2 0x1e8
#define ISP_REG_OECF_Y3_CFG3 0x1ec
#define ISP_REG_OECF_Y3_CFG4 0x1f0
#define ISP_REG_OECF_Y3_CFG5 0x1f4
#define ISP_REG_OECF_Y3_CFG6 0x1f8
#define ISP_REG_OECF_Y3_CFG7 0x1fc
#define ISP_REG_OECF_S0_CFG0 0x200
#define ISP_REG_OECF_S3_CFG7 0x27c
#define OCEF_PAR_H(n) ((n) << 16)
#define OCEF_PAR_L(n) ((n) << 0)
#define ISP_REG_AWB_X0_CFG_0 0x280
#define ISP_REG_AWB_X0_CFG_1 0x284
#define ISP_REG_AWB_X1_CFG_0 0x288
#define ISP_REG_AWB_X1_CFG_1 0x28c
#define ISP_REG_AWB_X2_CFG_0 0x290
#define ISP_REG_AWB_X2_CFG_1 0x294
#define ISP_REG_AWB_X3_CFG_0 0x298
#define ISP_REG_AWB_X3_CFG_1 0x29c
#define AWB_X_SYMBOL_H(n) ((n) << 16)
#define AWB_X_SYMBOL_L(n) ((n) << 0)
#define ISP_REG_AWB_Y0_CFG_0 0x2a0
#define ISP_REG_AWB_Y0_CFG_1 0x2a4
#define ISP_REG_AWB_Y1_CFG_0 0x2a8
#define ISP_REG_AWB_Y1_CFG_1 0x2ac
#define ISP_REG_AWB_Y2_CFG_0 0x2b0
#define ISP_REG_AWB_Y2_CFG_1 0x2b4
#define ISP_REG_AWB_Y3_CFG_0 0x2b8
#define ISP_REG_AWB_Y3_CFG_1 0x2bc
#define AWB_Y_SYMBOL_H(n) ((n) << 16)
#define AWB_Y_SYMBOL_L(n) ((n) << 0)
#define ISP_REG_AWB_S0_CFG_0 0x2c0
#define ISP_REG_AWB_S0_CFG_1 0x2c4
#define ISP_REG_AWB_S1_CFG_0 0x2c8
#define ISP_REG_AWB_S1_CFG_1 0x2cc
#define ISP_REG_AWB_S2_CFG_0 0x2d0
#define ISP_REG_AWB_S2_CFG_1 0x2d4
#define ISP_REG_AWB_S3_CFG_0 0x2d8
#define ISP_REG_AWB_S3_CFG_1 0x2dc
#define AWB_S_SYMBOL_H(n) ((n) << 16)
#define AWB_S_SYMBOL_L(n) ((n) << 0)
#define ISP_REG_OBCG_CFG_0 0x2e0
#define ISP_REG_OBCG_CFG_1 0x2e4
#define ISP_REG_OBCG_CFG_2 0x2e8
#define ISP_REG_OBCG_CFG_3 0x2ec
#define ISP_REG_OBCO_CFG_0 0x2f0
#define ISP_REG_OBCO_CFG_1 0x2f4
#define ISP_REG_OBCO_CFG_2 0x2f8
#define ISP_REG_OBCO_CFG_3 0x2fc
#define GAIN_D_POINT(x) ((x) << 24)
#define GAIN_C_POINT(x) ((x) << 16)
#define GAIN_B_POINT(x) ((x) << 8)
#define GAIN_A_POINT(x) ((x) << 0)
#define OFFSET_D_POINT(x) ((x) << 24)
#define OFFSET_C_POINT(x) ((x) << 16)
#define OFFSET_B_POINT(x) ((x) << 8)
#define OFFSET_A_POINT(x) ((x) << 0)
#define ISP_REG_ISP_CTRL_0 0xa00
#define ISPC_LINE BIT(27)
#define ISPC_SC BIT(26)
#define ISPC_CSI BIT(25)
#define ISPC_ISP BIT(24)
#define ISPC_ENUO BIT(20)
#define ISPC_ENLS BIT(17)
#define ISPC_ENSS1 BIT(12)
#define ISPC_ENSS0 BIT(11)
#define ISPC_RST BIT(1)
#define ISPC_EN BIT(0)
#define ISPC_RST_MASK BIT(1)
#define ISPC_INT_ALL_MASK GENMASK(27, 24)
#define ISP_REG_ISP_CTRL_1 0xa08
#define CTRL_SAT(n) ((n) << 28)
#define CTRL_DBC BIT(22)
#define CTRL_CTC BIT(21)
#define CTRL_YHIST BIT(20)
#define CTRL_YCURVE BIT(19)
#define CTRL_CTM BIT(18)
#define CTRL_BIYUV BIT(17)
#define CTRL_SCE BIT(8)
#define CTRL_EE BIT(7)
#define CTRL_CCE BIT(5)
#define CTRL_RGE BIT(4)
#define CTRL_CME BIT(3)
#define CTRL_AE BIT(2)
#define CTRL_CE BIT(1)
#define CTRL_SAT_MASK GENMASK(31, 28)
#define ISP_REG_PIPELINE_XY_SIZE 0xa0c
#define H_ACT_CAP(n) ((n) << 16)
#define W_ACT_CAP(n) ((n) << 0)
#define ISP_REG_ICTC 0xa10
#define GF_MODE(n) ((n) << 30)
#define MAXGT(n) ((n) << 16)
#define MINGT(n) ((n) << 0)
#define ISP_REG_IDBC 0xa14
#define BADGT(n) ((n) << 16)
#define BADXT(n) ((n) << 0)
#define ISP_REG_ICFAM 0xa1c
#define CROSS_COV(n) ((n) << 4)
#define HV_W(n) ((n) << 0)
#define ISP_REG_CS_GAIN 0xa30
#define CMAD(n) ((n) << 16)
#define CMAB(n) ((n) << 0)
#define ISP_REG_CS_THRESHOLD 0xa34
#define CMD(n) ((n) << 16)
#define CMB(n) ((n) << 0)
#define ISP_REG_CS_OFFSET 0xa38
#define VOFF(n) ((n) << 16)
#define UOFF(n) ((n) << 0)
#define ISP_REG_CS_HUE_F 0xa3c
#define SIN(n) ((n) << 16)
#define COS(n) ((n) << 0)
#define ISP_REG_CS_SCALE 0xa40
#define ISP_REG_IESHD 0xa50
#define SHAD_UP_M BIT(1)
#define SHAD_UP_EN BIT(0)
#define ISP_REG_YADJ0 0xa54
#define YOIR(n) ((n) << 16)
#define YIMIN(n) ((n) << 0)
#define ISP_REG_YADJ1 0xa58
#define YOMAX(n) ((n) << 16)
#define YOMIN(n) ((n) << 0)
#define ISP_REG_Y_PLANE_START_ADDR 0xa80
#define ISP_REG_UV_PLANE_START_ADDR 0xa84
#define ISP_REG_STRIDE 0xa88
#define ISP_REG_ITIIWSR 0xb20
#define ITI_HSIZE(n) ((n) << 16)
#define ITI_WSIZE(n) ((n) << 0)
#define ISP_REG_ITIDWLSR 0xb24
#define ISP_REG_ITIPDFR 0xb38
#define ISP_REG_ITIDRLSR 0xb3C
#define ISP_REG_DNYUV_YSWR0 0xc00
#define ISP_REG_DNYUV_YSWR1 0xc04
#define ISP_REG_DNYUV_CSWR0 0xc08
#define ISP_REG_DNYUV_CSWR1 0xc0c
#define YUVSW5(n) ((n) << 20)
#define YUVSW4(n) ((n) << 16)
#define YUVSW3(n) ((n) << 12)
#define YUVSW2(n) ((n) << 8)
#define YUVSW1(n) ((n) << 4)
#define YUVSW0(n) ((n) << 0)
#define ISP_REG_DNYUV_YDR0 0xc10
#define ISP_REG_DNYUV_YDR1 0xc14
#define ISP_REG_DNYUV_YDR2 0xc18
#define ISP_REG_DNYUV_CDR0 0xc1c
#define ISP_REG_DNYUV_CDR1 0xc20
#define ISP_REG_DNYUV_CDR2 0xc24
#define CURVE_D_H(n) ((n) << 16)
#define CURVE_D_L(n) ((n) << 0)
#define ISP_REG_ICAMD_0 0xc40
#define ISP_REG_ICAMD_12 0xc70
#define ISP_REG_ICAMD_20 0xc90
#define ISP_REG_ICAMD_24 0xca0
#define ISP_REG_ICAMD_25 0xca4
#define DNRM_F(n) ((n) << 16)
#define CCM_M_DAT(n) ((n) << 0)
#define ISP_REG_GAMMA_VAL0 0xe00
#define ISP_REG_GAMMA_VAL1 0xe04
#define ISP_REG_GAMMA_VAL2 0xe08
#define ISP_REG_GAMMA_VAL3 0xe0c
#define ISP_REG_GAMMA_VAL4 0xe10
#define ISP_REG_GAMMA_VAL5 0xe14
#define ISP_REG_GAMMA_VAL6 0xe18
#define ISP_REG_GAMMA_VAL7 0xe1c
#define ISP_REG_GAMMA_VAL8 0xe20
#define ISP_REG_GAMMA_VAL9 0xe24
#define ISP_REG_GAMMA_VAL10 0xe28
#define ISP_REG_GAMMA_VAL11 0xe2c
#define ISP_REG_GAMMA_VAL12 0xe30
#define ISP_REG_GAMMA_VAL13 0xe34
#define ISP_REG_GAMMA_VAL14 0xe38
#define GAMMA_S_VAL(n) ((n) << 16)
#define GAMMA_VAL(n) ((n) << 0)
#define ISP_REG_R2Y_0 0xe40
#define ISP_REG_R2Y_1 0xe44
#define ISP_REG_R2Y_2 0xe48
#define ISP_REG_R2Y_3 0xe4c
#define ISP_REG_R2Y_4 0xe50
#define ISP_REG_R2Y_5 0xe54
#define ISP_REG_R2Y_6 0xe58
#define ISP_REG_R2Y_7 0xe5c
#define ISP_REG_R2Y_8 0xe60
#define ISP_REG_SHARPEN0 0xe80
#define ISP_REG_SHARPEN1 0xe84
#define ISP_REG_SHARPEN2 0xe88
#define ISP_REG_SHARPEN3 0xe8c
#define ISP_REG_SHARPEN4 0xe90
#define ISP_REG_SHARPEN5 0xe94
#define ISP_REG_SHARPEN6 0xe98
#define ISP_REG_SHARPEN7 0xe9c
#define ISP_REG_SHARPEN8 0xea0
#define ISP_REG_SHARPEN9 0xea4
#define ISP_REG_SHARPEN10 0xea8
#define ISP_REG_SHARPEN11 0xeac
#define ISP_REG_SHARPEN12 0xeb0
#define ISP_REG_SHARPEN13 0xeb4
#define ISP_REG_SHARPEN14 0xeb8
#define S_DELTA(n) ((n) << 16)
#define S_WEIGHT(n) ((n) << 8)
#define ISP_REG_SHARPEN_FS0 0xebc
#define ISP_REG_SHARPEN_FS1 0xec0
#define ISP_REG_SHARPEN_FS2 0xec4
#define ISP_REG_SHARPEN_FS3 0xec8
#define ISP_REG_SHARPEN_FS4 0xecc
#define ISP_REG_SHARPEN_FS5 0xed0
#define S_FACTOR(n) ((n) << 24)
#define S_SLOPE(n) ((n) << 0)
#define ISP_REG_SHARPEN_WN 0xed4
#define PDIRF(n) ((n) << 28)
#define NDIRF(n) ((n) << 24)
#define WSUM(n) ((n) << 0)
#define ISP_REG_IUVS1 0xed8
#define UVDIFF2(n) ((n) << 16)
#define UVDIFF1(n) ((n) << 0)
#define ISP_REG_IUVS2 0xedc
#define UVF(n) ((n) << 24)
#define UVSLOPE(n) ((n) << 0)
#define ISP_REG_IUVCKS1 0xee0
#define UVCKDIFF2(n) ((n) << 16)
#define UVCKDIFF1(n) ((n) << 0)
#define ISP_REG_IUVCKS2 0xee4
#define ISP_REG_ISHRPET 0xee8
#define TH(n) ((n) << 8)
#define EN(n) ((n) << 0)
#define ISP_REG_YCURVE_0 0xf00
#define ISP_REG_YCURVE_63 0xffc
#define IMAGE_MAX_WIDTH 1920
#define IMAGE_MAX_HEIGH 1080
/* pad id for media framework */
enum stf_isp_pad_id {
STF_ISP_PAD_SINK = 0,
STF_ISP_PAD_SRC,
STF_ISP_PAD_MAX
};
struct stf_isp_format {
u32 code;
u8 bpp;
};
struct stf_isp_format_table {
const struct stf_isp_format *fmts;
int nfmts;
};
struct stf_isp_dev {
struct stfcamss *stfcamss;
struct v4l2_subdev subdev;
struct media_pad pads[STF_ISP_PAD_MAX];
const struct stf_isp_format_table *formats;
unsigned int nformats;
struct v4l2_subdev *source_subdev;
const struct stf_isp_format *current_fmt;
};
int stf_isp_reset(struct stf_isp_dev *isp_dev);
void stf_isp_init_cfg(struct stf_isp_dev *isp_dev);
void stf_isp_settings(struct stf_isp_dev *isp_dev,
struct v4l2_rect *crop, u32 mcode);
void stf_isp_stream_set(struct stf_isp_dev *isp_dev);
int stf_isp_init(struct stfcamss *stfcamss);
int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev);
int stf_isp_unregister(struct stf_isp_dev *isp_dev);
#endif /* STF_ISP_H */
File diff suppressed because it is too large Load Diff
@@ -1,100 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* stf_video.h
*
* StarFive Camera Subsystem - V4L2 device node
*
* Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
*/
#ifndef STF_VIDEO_H
#define STF_VIDEO_H
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#define STFCAMSS_FRAME_MIN_WIDTH 64
#define STFCAMSS_FRAME_MAX_WIDTH 1920
#define STFCAMSS_FRAME_MIN_HEIGHT 64
#define STFCAMSS_FRAME_MAX_HEIGHT 1080
#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8
#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128
#define STFCAMSS_MIN_BUFFERS 2
#define STFCAMSS_MAX_ENTITY_NAME_LEN 27
enum stf_v_line_id {
STF_V_LINE_WR = 0,
STF_V_LINE_ISP,
STF_V_LINE_MAX,
};
enum stf_capture_type {
STF_CAPTURE_RAW = 0,
STF_CAPTURE_YUV,
STF_CAPTURE_NUM,
};
struct stfcamss_buffer {
struct vb2_v4l2_buffer vb;
dma_addr_t addr[2];
struct list_head queue;
};
struct fract {
u8 numerator;
u8 denominator;
};
/*
* struct stfcamss_format_info - ISP media bus format information
* @code: V4L2 media bus format code
* @pixelformat: V4L2 pixel format FCC identifier
* @planes: Number of planes
* @vsub: Vertical subsampling (for each plane)
* @bpp: Bits per pixel when stored in memory (for each plane)
*/
struct stfcamss_format_info {
u32 code;
u32 pixelformat;
u8 planes;
u8 vsub[3];
u8 bpp;
};
struct stfcamss_video {
struct stfcamss *stfcamss;
struct vb2_queue vb2_q;
struct video_device vdev;
struct media_pad pad;
struct v4l2_format active_fmt;
enum v4l2_buf_type type;
const struct stfcamss_video_ops *ops;
struct mutex lock; /* serialize device access */
struct mutex q_lock; /* protects the queue */
unsigned int bpl_alignment;
const struct stfcamss_format_info *formats;
unsigned int nformats;
struct v4l2_subdev *source_subdev;
};
struct stfcamss_video_ops {
int (*queue_buffer)(struct stfcamss_video *video,
struct stfcamss_buffer *buf);
int (*flush_buffers)(struct stfcamss_video *video,
enum vb2_buffer_state state);
void (*start_streaming)(struct stfcamss_video *video);
void (*stop_streaming)(struct stfcamss_video *video);
};
int stf_video_register(struct stfcamss_video *video,
struct v4l2_device *v4l2_dev, const char *name);
void stf_video_unregister(struct stfcamss_video *video);
#endif /* STF_VIDEO_H */