From d936cae7ba6ab3ae4665ac889bcef4c90354c36b Mon Sep 17 00:00:00 2001 From: sw.multimedia Date: Sat, 9 Oct 2021 18:09:44 +0800 Subject: [PATCH 01/10] add starfive pipeline --- include/libcamera/internal/v4l2_subdevice.h | 1 + include/linux/v4l2-subdev.h | 9 + meson_options.txt | 2 +- src/gstreamer/gstlibcamera-utils.cpp | 7 + src/gstreamer/gstlibcamerasrc.cpp | 16 +- src/libcamera/pipeline/starfive/meson.build | 5 + src/libcamera/pipeline/starfive/starfive.cpp | 940 +++++++++++++++++++ src/libcamera/v4l2_subdevice.cpp | 12 + 8 files changed, 990 insertions(+), 2 deletions(-) create mode 100644 src/libcamera/pipeline/starfive/meson.build create mode 100644 src/libcamera/pipeline/starfive/starfive.cpp diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index 97b89fb9..fe8835bd 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -63,6 +63,7 @@ public: static std::unique_ptr fromEntityName(const MediaDevice *media, const std::string &entity); + int ioctlPrivate(unsigned long request, void *argp); protected: std::string logPrefix() const override; diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h index a38454d9..4c9af64d 100644 --- a/include/linux/v4l2-subdev.h +++ b/include/linux/v4l2-subdev.h @@ -206,4 +206,13 @@ struct v4l2_subdev_capability { #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS _IOR('V', 99, struct v4l2_dv_timings) #define VIDIOC_SUBDEV_DV_TIMINGS_CAP _IOWR('V', 100, struct v4l2_dv_timings_cap) +#define STF_ISPFW_FILENAME_MAX_LEN 30 + +struct stfisp_fw_info { + char filename[STF_ISPFW_FILENAME_MAX_LEN]; +}; + +#define VIDIOC_STFISP_LOAD_FW \ + _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct stfisp_fw_info) + #endif diff --git a/meson_options.txt b/meson_options.txt index 2c80ad8b..14baa7ef 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -37,7 +37,7 @@ option('lc-compliance', option('pipelines', type : 'array', - choices : ['ipu3', 'raspberrypi', 'rkisp1', 'simple', 'uvcvideo', 'vimc'], + choices : ['ipu3', 'raspberrypi', 'rkisp1', 'simple', 'uvcvideo', 'vimc', 'starfive'], description : 'Select which pipeline handlers to include') option('qcam', diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp index 3f242286..bce4960a 100644 --- a/src/gstreamer/gstlibcamera-utils.cpp +++ b/src/gstreamer/gstlibcamera-utils.cpp @@ -139,6 +139,12 @@ gst_libcamera_stream_configuration_to_caps(const StreamConfiguration &stream_cfg "width", G_TYPE_INT, stream_cfg.size.width, "height", G_TYPE_INT, stream_cfg.size.height, nullptr); + + // Add framerate negotiation support + // the range will be [ 0/1, 2147483647/1 ] as there is not any args + // required from driver for the time being. + gst_structure_set(s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + gst_caps_append_structure(caps, s); return caps; @@ -230,6 +236,7 @@ gst_libcamera_resume_task(GstTask *task) /* We only want to resume the task if it's paused. */ GLibLocker lock(GST_OBJECT(task)); if (GST_TASK_STATE(task) == GST_TASK_PAUSED) { + GST_DEBUG("gst_libcamera_resume_task"); GST_TASK_STATE(task) = GST_TASK_STARTED; GST_TASK_SIGNAL(task); } diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 812ba7a2..1dd0e807 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -46,6 +46,7 @@ using namespace libcamera; GST_DEBUG_CATEGORY_STATIC(source_debug); #define GST_CAT_DEFAULT source_debug +#define TASK_PAUSE_COUNT_MAX 2 struct RequestWrap { RequestWrap(std::unique_ptr request); @@ -125,6 +126,7 @@ struct _GstLibcameraSrc { GstLibcameraSrcState *state; GstLibcameraAllocator *allocator; GstFlowCombiner *flow_combiner; + guint task_pause_count; }; enum { @@ -340,8 +342,20 @@ gst_libcamera_src_task_run(gpointer user_data) } } - if (do_pause) + if (do_pause){ + self->task_pause_count ++; + GST_DEBUG_OBJECT(self, "task_pause_count: %d'", self->task_pause_count); + } else { + self->task_pause_count = 0; + GST_DEBUG_OBJECT(self, "reset task_pause_count "); + } + + if ( self->task_pause_count > TASK_PAUSE_COUNT_MAX) + { + GST_DEBUG_OBJECT(self, "gst_task_pause"); gst_task_pause(self->task); + } + } } diff --git a/src/libcamera/pipeline/starfive/meson.build b/src/libcamera/pipeline/starfive/meson.build new file mode 100644 index 00000000..2f2d2a75 --- /dev/null +++ b/src/libcamera/pipeline/starfive/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_sources += files([ + 'starfive.cpp', +]) diff --git a/src/libcamera/pipeline/starfive/starfive.cpp b/src/libcamera/pipeline/starfive/starfive.cpp new file mode 100644 index 00000000..8797bdcb --- /dev/null +++ b/src/libcamera/pipeline/starfive/starfive.cpp @@ -0,0 +1,940 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * starfive.cpp - Pipeline handler for starfive devices + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "libcamera/internal/camera.h" +#include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/ipa_manager.h" +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/pipeline_handler.h" +// #include "libcamera/internal/utils.h" +// #include "libcamera/internal/v4l2_controls.h" +#include "libcamera/internal/v4l2_videodevice.h" + +#define STF_MAX_CAMERAS 3 + +namespace libcamera { + +LOG_DEFINE_CATEGORY(STARFIVE) + +static constexpr unsigned int BUFFER_COUNT = 4; +static constexpr unsigned int MAX_STREAMS = 2; +static const Size OUTPUT_MIN_SIZE = { 8, 8 }; +static const Size OUTPUT_MAX_SIZE = { 8192, 8192 }; + +namespace { + +typedef enum { + DVP_YUV = 0, + MIPICSI0_YUV, + MIPICSI1_YUV, + DVP_ISP0, // ISP0 + MIPICSI0_ISP0, + MIPICSI1_ISP0, + DVP_ISP1, // ISP1 + MIPICSI0_ISP1, + MIPICSI1_ISP1, + SENSORTYPE_MAX +} SensorType; + +typedef struct { + std::string sensorEntityName_; + std::string sensorFwImageName_; + SensorType sensorType_; +} SensorConfig; + +const std::vector sensorConfigs = { + { "imx219 0-0010", "stf_isp0_fw_dump.bin", MIPICSI0_ISP0 }, + { "imx219 2-0010", "stf_isp0_fw_dump.bin", MIPICSI1_ISP1 }, +}; + +typedef struct { + std::string source; + std::string link; +} PipelineConfigLink; + +const std::vector dvpyuvConfig = { + {"stf_dvp0", "stf_vin0_wr"}, +}; + +const std::vector mipicsi0yuvConfig = { + {"stf_csiphy0", "stf_csi0"}, + {"stf_csi0", "stf_vin0_wr"} +}; + +const std::vector mipicsi1yuvConfig = { + {"stf_csiphy1", "stf_csi1"}, + {"stf_csi1", "stf_vin0_wr"} +}; + +const std::vector dvpraw0Config = { + {"stf_dvp0", "stf_isp0"}, + {"stf_isp0", "stf_vin0_isp0"} +}; + +const std::vector mipicsi0raw0Config = { + {"stf_csiphy0", "stf_csi0"}, + {"stf_csi0", "stf_isp0"}, + {"stf_isp0", "stf_vin0_isp0"} +}; + +const std::vector mipicsi1raw0Config = { + {"stf_csiphy1", "stf_csi1"}, + {"stf_csi1", "stf_isp0"}, + {"stf_isp0", "stf_vin0_isp0"} +}; + +const std::vector dvpraw1Config = { + {"stf_dvp0", "stf_isp1"}, + {"stf_isp1", "stf_vin0_isp1"} +}; + +const std::vector mipicsi0raw1Config = { + {"stf_csiphy0", "stf_csi0"}, + {"stf_csi0", "stf_isp1"}, + {"stf_isp1", "stf_vin0_isp1"} +}; + +const std::vector mipicsi1raw1Config = { + {"stf_csiphy1", "stf_csi1"}, + {"stf_csi1", "stf_isp1"}, + {"stf_isp1", "stf_vin0_isp1"} +}; + +const std::vector pipelineConfigs[SENSORTYPE_MAX] = { + dvpyuvConfig, + mipicsi0yuvConfig, + mipicsi1yuvConfig, + dvpraw0Config, + mipicsi0raw0Config, + mipicsi1raw0Config, + dvpraw1Config, + mipicsi0raw1Config, + mipicsi1raw1Config, +}; + +const std::map mbusCodesToPixelFormat = { + { MEDIA_BUS_FMT_SBGGR10_1X10, formats::SBGGR12 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, formats::SGBRG12 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, formats::SGRBG12 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, formats::SRGGB12 }, +}; + +} /* namespace */ + +class StarFiveCameraData : public Camera::Private +{ +public: + StarFiveCameraData(PipelineHandler *pipe, MediaDevice *media, + std::string entityName, + std::string sensorEntityName) + : Camera::Private(pipe), media_(media) + { + LOG(STARFIVE, Debug) << __func__; + sensorEntityName_ = sensorEntityName; + videoEntityName_ = entityName; + if ( videoEntityName_ == "stf_vin0_isp0_video1") + ispEntityName_ = "stf_isp0"; + else if (videoEntityName_ == "stf_vin0_isp1_video2") + ispEntityName_ = "stf_isp1"; + else + ispEntityName_ = "unknow"; + + video_ = nullptr; + raw_ = nullptr; + sensor_ = nullptr; + ispSubDev_ = nullptr; + haveRaw_ = false; + rawActive_= false; + } + + ~StarFiveCameraData() + { + LOG(STARFIVE, Debug) << __func__; + delete sensor_; + delete video_; + if (raw_ != nullptr) + delete raw_; + if (ispSubDev_ != nullptr) + delete ispSubDev_; + } + + int init(); + void bufferReady(FrameBuffer *buffer); + bool haveRaw() const { return haveRaw_; } + bool rawActive() const { return rawActive_; } + void setRawActive(bool val) { rawActive_ = val; } + std::vector sensorSizes() const; + std::vector sensorFormats() const; + std::vector videoFormats() const; + + MediaDevice *media_; + V4L2VideoDevice *video_; + V4L2VideoDevice *raw_; + V4L2Subdevice *ispSubDev_; + CameraSensor *sensor_; + Stream outStream_; + Stream rawStream_; + +private: + bool haveRaw_; + bool rawActive_; + std::string videoEntityName_; + std::string sensorEntityName_; + std::string ispEntityName_; + std::string getRawVideoEntityName() + { + LOG(STARFIVE, Debug) << __func__; + if ( videoEntityName_ == "stf_vin0_isp0_video1") + return "stf_vin0_isp0_raw_video3"; + else if (videoEntityName_ == "stf_vin0_isp1_video2") + return "stf_vin0_isp1_raw_video4"; + else + return "unknow"; + } + int ispLoadFW(const char *filename); +}; + +std::vector StarFiveCameraData::videoFormats() const +{ + if (!video_) + return {}; + + std::vector formats; + for (auto it : video_->formats()) { + formats.push_back(it.first.toPixelFormat()); + } + + return formats; +} + +std::vector StarFiveCameraData::sensorFormats() const +{ + if (!sensor_) + return {}; + + std::vector formats; + for (unsigned int code : sensor_->mbusCodes()) { + auto it = mbusCodesToPixelFormat.find(code); + if (it != mbusCodesToPixelFormat.end()) + formats.push_back(it->second); + } + + return formats; +} + +std::vector StarFiveCameraData::sensorSizes() const +{ + if (!sensor_) + return {}; + + std::vector sizes; + for (const Size &size : sensor_->sizes(sensor_->mbusCodes().at(0))) + sizes.emplace_back(size, size); + + return sizes; +} + +int StarFiveCameraData::ispLoadFW(const char *filename) +{ + struct stfisp_fw_info fw_info = {0}; + + if (!ispSubDev_) + return -ENODEV; + + if (filename && (strlen(filename) < STF_ISPFW_FILENAME_MAX_LEN)) + memcpy(fw_info.filename, filename, strlen(filename) + 1); + else + return -EINVAL; + + LOG(STARFIVE, Debug) + << "VIDIOC_STFISP_LOAD_FW: " << VIDIOC_STFISP_LOAD_FW + << " filename: " << filename + << " struct size: " << sizeof(struct stfisp_fw_info); + + if (ispSubDev_->ioctlPrivate(VIDIOC_STFISP_LOAD_FW, &fw_info) < 0) + LOG(STARFIVE, Error) << "Load ISP fw failed" ; + + return 0; +} + +class StarFiveCameraConfiguration : public CameraConfiguration +{ +public: + StarFiveCameraConfiguration(StarFiveCameraData *data); + + Status validate() override; + +private: + StarFiveCameraData *data_; +}; + +int StarFiveCameraData::init() +{ + int ret; + + LOG(STARFIVE, Debug) << __func__; + if (sensorEntityName_ != "unknow") { + sensor_ = + new CameraSensor(media_->getEntityByName(sensorEntityName_)); + ret = sensor_->init(); + if (ret) + return ret; + LOG(STARFIVE, Debug) << "sensor id: " << sensor_->id(); + } else { + LOG(STARFIVE, Debug) << " Can't find sensorEntityName!"; + return -ENODEV; + } + + if (ispEntityName_ != "unknow") { + ispSubDev_ = + new V4L2Subdevice(media_->getEntityByName(ispEntityName_)); + LOG(STARFIVE, Debug) << "ispEntityName: " << ispEntityName_; + if (ispSubDev_->open()) + return -ENODEV; + + for (SensorConfig it : sensorConfigs) { + if (it.sensorEntityName_ == sensorEntityName_) { + ispLoadFW(it.sensorFwImageName_.c_str()); + break; + } + } + } + + video_ = new V4L2VideoDevice(media_->getEntityByName(videoEntityName_)); + LOG(STARFIVE, Debug) << "videoEntityName: " << videoEntityName_; + if (video_->open()) + return -ENODEV; + + video_->bufferReady.connect(this, &StarFiveCameraData::bufferReady); + LOG(STARFIVE, Debug) << "driverName: " << video_->driverName(); + + std::string rawVideoEntityName = getRawVideoEntityName(); + if (rawVideoEntityName != "unknow") { + raw_ = + new V4L2VideoDevice(media_->getEntityByName(rawVideoEntityName)); + LOG(STARFIVE, Debug) + << "rawEntityName: " << rawVideoEntityName; + if (raw_->open()) { + LOG(STARFIVE, Debug) << "No raw data capture!!!"; + haveRaw_ = false; + } else { + haveRaw_ = true; + raw_->bufferReady.connect(this, + &StarFiveCameraData::bufferReady); + } + } + + return 0; +} + +class PipelineHandlerStarFive : public PipelineHandler +{ +public: + PipelineHandlerStarFive(CameraManager *manager); + + CameraConfiguration *generateConfiguration(Camera *camera, + const StreamRoles &roles) override; + int configure(Camera *camera, CameraConfiguration *config) override; + + int exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) override; + + int start(Camera *camera, const ControlList *controls) override; + void stop(Camera *camera) override; + + int queueRequestDevice(Camera *camera, Request *request) override; + + bool match(DeviceEnumerator *enumerator) override; + +private: + int processControls(StarFiveCameraData *data, Request *request); + + StarFiveCameraData *cameraData(Camera *camera) + { + return static_cast(camera->_d()); + } + + int registerCameras(); + std::string getVideoEntityNameById(unsigned int id); + std::string findSensorEntityName(std::string entityName); + int enableLinks(std::vector config); + + MediaDevice *starFiveMediaDev_; +}; + +StarFiveCameraConfiguration::StarFiveCameraConfiguration(StarFiveCameraData *data) + : CameraConfiguration(), data_(data) +{ + LOG(STARFIVE, Debug) << __func__; +} + +CameraConfiguration::Status StarFiveCameraConfiguration::validate() +{ + LOG(STARFIVE, Debug) << __func__; + Status status = Valid; + + if (config_.empty()) + return Invalid; + + LOG(STARFIVE, Debug) << "config_.size " << config_.size(); + /* Cap the number of entries to the available streams. */ + if (config_.size() > MAX_STREAMS) { + config_.resize(MAX_STREAMS); + status = Adjusted; + } + + for (unsigned int i = 0; i < config_.size(); ++i) { + const PixelFormatInfo &info = + PixelFormatInfo::info(config_[i].pixelFormat); + StreamConfiguration &cfg = config_[i]; + + LOG(STARFIVE, Debug) + << "Validating stream: " << config_[i].toString(); + + const Size size = cfg.size; + + cfg.size.width = std::max(OUTPUT_MIN_SIZE.width, + std::min(OUTPUT_MAX_SIZE.width, cfg.size.width)); + cfg.size.height = std::max(OUTPUT_MIN_SIZE.height, + std::min(OUTPUT_MAX_SIZE.height, cfg.size.height)); + + if (cfg.size != size) { + LOG(STARFIVE, Debug) + << "Adjusting size to " << cfg.size.toString(); + status = Adjusted; + } + + cfg.bufferCount = BUFFER_COUNT; + + if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW + && data_->haveRaw()) { + V4L2DeviceFormat format = {}; + format.fourcc = + data_->raw_->toV4L2PixelFormat(cfg.pixelFormat); + format.size = cfg.size; + + int ret = data_->raw_->tryFormat(&format); + if (ret) + return Invalid; + + cfg.stride = format.planes[0].bpl; + cfg.frameSize = format.planes[0].size; + + cfg.setStream(&data_->rawStream_); + } else { + V4L2DeviceFormat format = {}; + format.fourcc = + data_->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.size = cfg.size; + + int ret = data_->video_->tryFormat(&format); + if (ret) + return Invalid; + + cfg.stride = format.planes[0].bpl; + cfg.frameSize = format.planes[0].size; + + cfg.setStream(&data_->outStream_); + } + } + + return status; +} + +PipelineHandlerStarFive::PipelineHandlerStarFive(CameraManager *manager) + : PipelineHandler(manager) +{ + LOG(STARFIVE, Debug) << __func__; +} + +CameraConfiguration * +PipelineHandlerStarFive::generateConfiguration(Camera *camera, + const StreamRoles &roles) +{ + LOG(STARFIVE, Debug) << __func__; + StarFiveCameraData *data = cameraData(camera); + StarFiveCameraConfiguration *config = + new StarFiveCameraConfiguration(data); + + if (roles.empty()) + return config; + + for (const StreamRole role : roles) { + std::map> streamFormats; + unsigned int bufferCount; + PixelFormat pixelFormat; + Size size; + + LOG(STARFIVE, Debug) << "role: " << role; + size = data->sensor_->resolution(); + switch (role) { + case StreamRole::StillCapture: + case StreamRole::Viewfinder: + case StreamRole::VideoRecording: + for (const auto &pixelformat : data->videoFormats()) { + streamFormats[pixelformat] = data->sensorSizes(); + } + pixelFormat = data->videoFormats().at(0); + bufferCount = BUFFER_COUNT; + + break; + + case StreamRole::Raw: { + std::vector mbusCodes = + utils::map_keys(mbusCodesToPixelFormat); + + V4L2SubdeviceFormat sensorFormat = + data->sensor_->getFormat(mbusCodes, size); + if (!sensorFormat.mbus_code) { + LOG(STARFIVE, Error) + << "Sensor does not support mbus code"; + break; + } + + pixelFormat = + mbusCodesToPixelFormat.at(sensorFormat.mbus_code); + size = sensorFormat.size; + bufferCount = BUFFER_COUNT; + + streamFormats[pixelFormat] = data->sensorSizes(); + + break; + } + default: + LOG(STARFIVE, Error) + << "Requested stream role not supported: " + << role; + break; + } + + StreamFormats formats(streamFormats); + StreamConfiguration cfg(formats); + cfg.size = size; + cfg.pixelFormat = pixelFormat; + cfg.bufferCount = bufferCount; + config->addConfiguration(cfg); + } + + if (config->validate() == CameraConfiguration::Invalid) + return {}; + + return config; +} + +int PipelineHandlerStarFive::configure(Camera *camera, CameraConfiguration *c) +{ + StarFiveCameraConfiguration *config = + static_cast(c); + StarFiveCameraData *data = cameraData(camera); + int ret; + + LOG(STARFIVE, Debug) << __func__ + << " config->size: " << config->size(); + + for (unsigned int i = 0; i < config->size(); ++i) { + StreamConfiguration &cfg = (*config)[i]; + Stream *stream = cfg.stream(); + + LOG(STARFIVE, Debug) + << "config stream: " << cfg.toString(); + + if (stream == &data->rawStream_) { + V4L2DeviceFormat format = {}; + format.fourcc = + data->raw_->toV4L2PixelFormat(cfg.pixelFormat); + format.size = cfg.size; + + ret = data->raw_->setFormat(&format); + if (ret) + return ret; + + if (format.size != cfg.size || + format.fourcc != + data->raw_->toV4L2PixelFormat(cfg.pixelFormat)) + return -EINVAL; + + } else if (stream == &data->outStream_) { + V4L2DeviceFormat format = {}; + format.fourcc = + data->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.size = cfg.size; + + ret = data->video_->setFormat(&format); + if (ret) + return ret; + + if (format.size != cfg.size || + format.fourcc != + data->video_->toV4L2PixelFormat(cfg.pixelFormat)) + return -EINVAL; + } + } + + return 0; +} + +int PipelineHandlerStarFive::exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) +{ + StarFiveCameraData *data = cameraData(camera); + unsigned int count = stream->configuration().bufferCount; + + LOG(STARFIVE, Debug) << __func__ << " bufferCount: " << count; + + if (stream == &data->outStream_) + return data->video_->exportBuffers(count, buffers); + else if (stream == &data->rawStream_) + return data->raw_->exportBuffers(count, buffers); + + return -EINVAL; +} + +int PipelineHandlerStarFive::start(Camera *camera, const ControlList *controls) +{ + StarFiveCameraData *data = cameraData(camera); + unsigned int count = data->outStream_.configuration().bufferCount; + int ret = -EINVAL; + + LOG(STARFIVE, Debug) << __func__ << " bufferCount: " << count; + + ret = data->video_->importBuffers(count); + if (ret < 0) + return ret; + + ret = data->video_->streamOn(); + if (ret < 0) + goto error; + + if (data->haveRaw()) { + count = data->rawStream_.configuration().bufferCount; + + LOG(STARFIVE, Debug) << "rawbufferCount: " << count; + if (count) { + ret = data->raw_->importBuffers(count); + if (ret < 0) { + data->setRawActive(false); + LOG(STARFIVE, Debug) + << "raw video importBuffers failed!"; + goto error; + } + ret = data->raw_->streamOn(); + if (ret < 0) { + data->setRawActive(false); + data->raw_->releaseBuffers(); + LOG(STARFIVE, Debug) + << "raw video streamOn failed!"; + goto error; + } + data->setRawActive(true); + } + } + + return ret; +error: + data->video_->releaseBuffers(); + return ret; +} + +void PipelineHandlerStarFive::stop(Camera *camera) +{ + LOG(STARFIVE, Debug) << __func__; + + StarFiveCameraData *data = cameraData(camera); + data->video_->streamOff(); + data->video_->releaseBuffers(); + if (data->rawActive()) { + data->raw_->streamOff(); + data->raw_->releaseBuffers(); + data->setRawActive(false); + } +} + +int PipelineHandlerStarFive::processControls(StarFiveCameraData *data, Request *request) +{ + LOG(STARFIVE, Debug) << __func__; + + ControlList controls(data->sensor_->controls()); + + for (auto it : request->controls()) { + unsigned int id = it.first; + unsigned int offset; + uint32_t cid; + + if (id == controls::Brightness) { + cid = V4L2_CID_BRIGHTNESS; + offset = 128; + } else if (id == controls::Contrast) { + cid = V4L2_CID_CONTRAST; + offset = 0; + } else if (id == controls::Saturation) { + cid = V4L2_CID_SATURATION; + offset = 0; + } else { + continue; + } + + int32_t value = lroundf(it.second.get() * 128 + offset); + controls.set(cid, std::clamp(value, 0, 255)); + } + + for (const auto &ctrl : controls) + LOG(STARFIVE, Debug) + << "Setting control " << utils::hex(ctrl.first) + << " to " << ctrl.second.toString(); + + int ret = data->sensor_->setControls(&controls); + if (ret) { + LOG(STARFIVE, Debug) + << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + +int PipelineHandlerStarFive::queueRequestDevice(Camera *camera, Request *request) +{ + StarFiveCameraData *data = cameraData(camera); + int error = 0; + + LOG(STARFIVE, Debug) << __func__; + int ret = processControls(data, request); + if (ret < 0) + return ret; + + for (auto it : request->buffers()) { + const Stream *stream = it.first; + FrameBuffer *buffer = it.second; + int ret; + + LOG(STARFIVE, Debug) + << "stream queueBuffer : " << stream->configuration().toString(); + + if (stream == &data->outStream_) + ret = data->video_->queueBuffer(buffer); + else if (stream == &data->rawStream_) + ret = data->raw_->queueBuffer(buffer); + else + continue; + + if (ret < 0) + error = ret; + } + + return error; +} + +std::string PipelineHandlerStarFive::getVideoEntityNameById(unsigned int id) +{ + LOG(STARFIVE, Debug) << __func__; + switch (id) { + case 0: + return "stf_vin0_wr_video0"; + case 1: + return "stf_vin0_isp0_video1"; + case 2: + return "stf_vin0_isp1_video2"; + case 3: + return "stf_vin0_isp0_raw_video3"; + case 4: + return "stf_vin0_isp1_raw_video4"; + default: + return "unknow"; + } + + return "unknow"; +} + +std::string PipelineHandlerStarFive::findSensorEntityName(std::string entityName) +{ + std::string sensorEntityName; + bool found = false; + MediaEntity *sensorEntity = starFiveMediaDev_->getEntityByName(entityName); + + while (1) { + LOG(STARFIVE, Debug) << "findSensorEntityName: " << sensorEntity->name(); + const std::vector &pads = sensorEntity->pads(); + + if (pads.empty()) + break; + + MediaPad *sink = pads[0]; + MediaLink *link; + bool found_enable_link = false; + + for (MediaLink *it : sink->links()) { + if (it->flags() & MEDIA_LNK_FL_ENABLED) { + found_enable_link = true; + link = it; + break; + } + } + + if (!found_enable_link) + break; + + sensorEntity = link->source()->entity(); + if (sensorEntity->function() == MEDIA_ENT_F_CAM_SENSOR) { + found = true; + break; + } + } + + if (found) + sensorEntityName = sensorEntity->name(); + else + sensorEntityName = "unknow"; + + LOG(STARFIVE, Debug) << "sensorEntityName: " << sensorEntityName; + return sensorEntityName; +} + +int PipelineHandlerStarFive::registerCameras() +{ + unsigned int numCameras = 0; + + LOG(STARFIVE, Debug) << __func__; + for (unsigned int id = 0; + id < STF_MAX_CAMERAS + && numCameras < STF_MAX_CAMERAS; ++id) { + std::string videoEntiryName; + videoEntiryName = getVideoEntityNameById(id); + if (videoEntiryName == "unknow") + continue; + + std::string sensorEntityName; + sensorEntityName = findSensorEntityName(videoEntiryName); + if (sensorEntityName == "unknow") + continue; + + std::unique_ptr data = + std::make_unique(this, starFiveMediaDev_, + videoEntiryName, sensorEntityName); + + /* Locate and open the capture video node. */ + if (data->init()) + continue; + + /* Create and register the camera. */ + LOG(STARFIVE, Debug) << "register deviceName: " + << videoEntiryName; + if (data->haveRaw()) { + std::set streams{ &data->outStream_, + &data->rawStream_ }; + std::shared_ptr camera = + Camera::create(std::move(data), videoEntiryName, streams); + registerCamera(std::move(camera)); + } else { + std::set streams{ &data->outStream_ }; + std::shared_ptr camera = + Camera::create(std::move(data), videoEntiryName, streams); + registerCamera(std::move(camera)); + } + numCameras++; + } + + return numCameras; +} + +int PipelineHandlerStarFive::enableLinks(std::vector config) +{ + int ret = 0; + + LOG(STARFIVE, Debug) << __func__; + for (PipelineConfigLink it : config) { + MediaLink *link = starFiveMediaDev_->link(it.source, 1, it.link, 0); + if (!link) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret < 0) + return ret; + } + + return ret; +} + +bool PipelineHandlerStarFive::match(DeviceEnumerator *enumerator) +{ + int numCameras = 0; + + DeviceMatch dm("stf-vin"); + dm.add("stf_vin0_wr_video0"); + dm.add("stf_vin0_isp0_video1"); + dm.add("stf_vin0_isp1_video2"); + + LOG(STARFIVE, Debug) << __func__; + starFiveMediaDev_ = acquireMediaDevice(enumerator, dm); + if (!starFiveMediaDev_) + return false; + + if (starFiveMediaDev_->disableLinks()) + return false; + + for (SensorConfig it : sensorConfigs) { + MediaEntity *sensorEntity = + starFiveMediaDev_->getEntityByName(it.sensorEntityName_); + int ret; + + if (sensorEntity != nullptr) { + if (it.sensorType_ < DVP_YUV + || it.sensorType_ >= SENSORTYPE_MAX) + continue; + ret = enableLinks(pipelineConfigs[it.sensorType_]); + if (ret < 0) { + LOG(STARFIVE, Error) + << it.sensorEntityName_ + << " enableLinks failed!"; + continue; + } + } + } + + numCameras = registerCameras(); + if (numCameras) + LOG(STARFIVE, Debug) + << "StarFive " << numCameras + << " Device Identified"; + + return numCameras != 0; +} + +void StarFiveCameraData::bufferReady(FrameBuffer *buffer) +{ + LOG(STARFIVE, Debug) << __func__; + PipelineHandlerStarFive *pipe = + static_cast(this->pipe()); + Request *request = buffer->request(); + + if (!pipe->completeBuffer(request, buffer)) + return; + + pipe->completeRequest(request); +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerStarFive) + +} /* namespace libcamera */ diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 023e2328..bc7cbfec 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -525,4 +525,16 @@ std::vector V4L2Subdevice::enumPadSizes(unsigned int pad, return sizes; } +int V4L2Subdevice::ioctlPrivate(unsigned long request, void *argp) +{ + /* + * Printing out an error message is usually better performed + * in the caller, which can provide more context. + */ + if (V4L2Device::ioctl(request, argp) < 0) + return -errno; + + return 0; +} + } /* namespace libcamera */ -- 2.25.1