162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR MIT) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Rockchip ISP1 Driver - Base driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. 862306a36Sopenharmony_ci * Copyright (C) 2017 Rockchip Electronics Co., Ltd. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_graph.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1962306a36Sopenharmony_ci#include <media/v4l2-fwnode.h> 2062306a36Sopenharmony_ci#include <media/v4l2-mc.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "rkisp1-common.h" 2362306a36Sopenharmony_ci#include "rkisp1-csi.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * ISP Details 2762306a36Sopenharmony_ci * ----------- 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * ISP Comprises with: 3062306a36Sopenharmony_ci * MIPI serial camera interface 3162306a36Sopenharmony_ci * Image Signal Processing 3262306a36Sopenharmony_ci * Many Image Enhancement Blocks 3362306a36Sopenharmony_ci * Crop 3462306a36Sopenharmony_ci * Resizer 3562306a36Sopenharmony_ci * RBG display ready image 3662306a36Sopenharmony_ci * Image Rotation 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * ISP Block Diagram 3962306a36Sopenharmony_ci * ----------------- 4062306a36Sopenharmony_ci * rkisp1-resizer.c rkisp1-capture.c 4162306a36Sopenharmony_ci * |====================| |=======================| 4262306a36Sopenharmony_ci * rkisp1-isp.c Main Picture Path 4362306a36Sopenharmony_ci * |==========================| |===============================================| 4462306a36Sopenharmony_ci * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ 4562306a36Sopenharmony_ci * | | | | | | | | | | | | | 4662306a36Sopenharmony_ci * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| | 4762306a36Sopenharmony_ci * | MIPI |--->| \ | | | | | | | | | | | | | | 4862306a36Sopenharmony_ci * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory | 4962306a36Sopenharmony_ci * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface | 5062306a36Sopenharmony_ci * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | | 5162306a36Sopenharmony_ci * |Parallel|--->| / | | | | | | | | | | | | | | | | 5262306a36Sopenharmony_ci * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| | 5362306a36Sopenharmony_ci * | | | | | | | | | | | | Rotate | | | 5462306a36Sopenharmony_ci * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+ 5562306a36Sopenharmony_ci * ^ 5662306a36Sopenharmony_ci * +--------+ | |===============================================| 5762306a36Sopenharmony_ci * | DMA |------------------------------------+ Self Picture Path 5862306a36Sopenharmony_ci * +--------+ 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * rkisp1-stats.c rkisp1-params.c 6162306a36Sopenharmony_ci * |===============| |===============| 6262306a36Sopenharmony_ci * +---------------+ +---------------+ 6362306a36Sopenharmony_ci * | | | | 6462306a36Sopenharmony_ci * | ISP | | ISP | 6562306a36Sopenharmony_ci * | | | | 6662306a36Sopenharmony_ci * +---------------+ +---------------+ 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * Media Topology 7062306a36Sopenharmony_ci * -------------- 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * +----------+ +----------+ 7362306a36Sopenharmony_ci * | Sensor 1 | | Sensor X | 7462306a36Sopenharmony_ci * ------------ ... ------------ 7562306a36Sopenharmony_ci * | 0 | | 0 | 7662306a36Sopenharmony_ci * +----------+ +----------+ 7762306a36Sopenharmony_ci * | | 7862306a36Sopenharmony_ci * \----\ /----/ 7962306a36Sopenharmony_ci * | | 8062306a36Sopenharmony_ci * v v 8162306a36Sopenharmony_ci * +-------------+ 8262306a36Sopenharmony_ci * | 0 | 8362306a36Sopenharmony_ci * --------------- 8462306a36Sopenharmony_ci * | CSI-2 RX | 8562306a36Sopenharmony_ci * --------------- +-----------+ 8662306a36Sopenharmony_ci * | 1 | | params | 8762306a36Sopenharmony_ci * +-------------+ | (output) | 8862306a36Sopenharmony_ci * | +-----------+ 8962306a36Sopenharmony_ci * v | 9062306a36Sopenharmony_ci * +------+------+ | 9162306a36Sopenharmony_ci * | 0 | 1 |<---------+ 9262306a36Sopenharmony_ci * |------+------| 9362306a36Sopenharmony_ci * | ISP | 9462306a36Sopenharmony_ci * |------+------| 9562306a36Sopenharmony_ci * +-------------| 2 | 3 |----------+ 9662306a36Sopenharmony_ci * | +------+------+ | 9762306a36Sopenharmony_ci * | | | 9862306a36Sopenharmony_ci * v v v 9962306a36Sopenharmony_ci * +- ---------+ +-----------+ +-----------+ 10062306a36Sopenharmony_ci * | 0 | | 0 | | stats | 10162306a36Sopenharmony_ci * ------------- ------------- | (capture) | 10262306a36Sopenharmony_ci * | Resizer | | Resizer | +-----------+ 10362306a36Sopenharmony_ci * ------------| ------------| 10462306a36Sopenharmony_ci * | 1 | | 1 | 10562306a36Sopenharmony_ci * +-----------+ +-----------+ 10662306a36Sopenharmony_ci * | | 10762306a36Sopenharmony_ci * v v 10862306a36Sopenharmony_ci * +-----------+ +-----------+ 10962306a36Sopenharmony_ci * | selfpath | | mainpath | 11062306a36Sopenharmony_ci * | (capture) | | (capture) | 11162306a36Sopenharmony_ci * +-----------+ +-----------+ 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistruct rkisp1_isr_data { 11562306a36Sopenharmony_ci const char *name; 11662306a36Sopenharmony_ci irqreturn_t (*isr)(int irq, void *ctx); 11762306a36Sopenharmony_ci u32 line_mask; 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* ---------------------------------------------------------------------------- 12162306a36Sopenharmony_ci * Sensor DT bindings 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, 12562306a36Sopenharmony_ci struct v4l2_subdev *sd, 12662306a36Sopenharmony_ci struct v4l2_async_connection *asc) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct rkisp1_device *rkisp1 = 12962306a36Sopenharmony_ci container_of(notifier, struct rkisp1_device, notifier); 13062306a36Sopenharmony_ci struct rkisp1_sensor_async *s_asd = 13162306a36Sopenharmony_ci container_of(asc, struct rkisp1_sensor_async, asd); 13262306a36Sopenharmony_ci int source_pad; 13362306a36Sopenharmony_ci int ret; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci s_asd->sd = sd; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci source_pad = media_entity_get_fwnode_pad(&sd->entity, s_asd->source_ep, 13862306a36Sopenharmony_ci MEDIA_PAD_FL_SOURCE); 13962306a36Sopenharmony_ci if (source_pad < 0) { 14062306a36Sopenharmony_ci dev_err(rkisp1->dev, "failed to find source pad for %s\n", 14162306a36Sopenharmony_ci sd->name); 14262306a36Sopenharmony_ci return source_pad; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (s_asd->port == 0) 14662306a36Sopenharmony_ci return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ret = media_create_pad_link(&sd->entity, source_pad, 14962306a36Sopenharmony_ci &rkisp1->isp.sd.entity, 15062306a36Sopenharmony_ci RKISP1_ISP_PAD_SINK_VIDEO, 15162306a36Sopenharmony_ci !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); 15262306a36Sopenharmony_ci if (ret) { 15362306a36Sopenharmony_ci dev_err(rkisp1->dev, "failed to link source pad of %s\n", 15462306a36Sopenharmony_ci sd->name); 15562306a36Sopenharmony_ci return ret; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct rkisp1_device *rkisp1 = 16462306a36Sopenharmony_ci container_of(notifier, struct rkisp1_device, notifier); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct rkisp1_sensor_async *rk_asd = 17262306a36Sopenharmony_ci container_of(asc, struct rkisp1_sensor_async, asd); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci fwnode_handle_put(rk_asd->source_ep); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { 17862306a36Sopenharmony_ci .bound = rkisp1_subdev_notifier_bound, 17962306a36Sopenharmony_ci .complete = rkisp1_subdev_notifier_complete, 18062306a36Sopenharmony_ci .destroy = rkisp1_subdev_notifier_destroy, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct v4l2_async_notifier *ntf = &rkisp1->notifier; 18662306a36Sopenharmony_ci struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev); 18762306a36Sopenharmony_ci struct fwnode_handle *ep; 18862306a36Sopenharmony_ci unsigned int index = 0; 18962306a36Sopenharmony_ci int ret = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci v4l2_async_nf_init(ntf, &rkisp1->v4l2_dev); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci ntf->ops = &rkisp1_subdev_notifier_ops; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci fwnode_graph_for_each_endpoint(fwnode, ep) { 19662306a36Sopenharmony_ci struct fwnode_handle *port; 19762306a36Sopenharmony_ci struct v4l2_fwnode_endpoint vep = { }; 19862306a36Sopenharmony_ci struct rkisp1_sensor_async *rk_asd; 19962306a36Sopenharmony_ci struct fwnode_handle *source; 20062306a36Sopenharmony_ci u32 reg = 0; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Select the bus type based on the port. */ 20362306a36Sopenharmony_ci port = fwnode_get_parent(ep); 20462306a36Sopenharmony_ci fwnode_property_read_u32(port, "reg", ®); 20562306a36Sopenharmony_ci fwnode_handle_put(port); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci switch (reg) { 20862306a36Sopenharmony_ci case 0: 20962306a36Sopenharmony_ci /* MIPI CSI-2 port */ 21062306a36Sopenharmony_ci if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) { 21162306a36Sopenharmony_ci dev_err(rkisp1->dev, 21262306a36Sopenharmony_ci "internal CSI must be available for port 0\n"); 21362306a36Sopenharmony_ci ret = -EINVAL; 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci vep.bus_type = V4L2_MBUS_CSI2_DPHY; 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci case 1: 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * Parallel port. The bus-type property in DT is 22362306a36Sopenharmony_ci * mandatory for port 1, it will be used to determine if 22462306a36Sopenharmony_ci * it's PARALLEL or BT656. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci vep.bus_type = V4L2_MBUS_UNKNOWN; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Parse the endpoint and validate the bus type. */ 23162306a36Sopenharmony_ci ret = v4l2_fwnode_endpoint_parse(ep, &vep); 23262306a36Sopenharmony_ci if (ret) { 23362306a36Sopenharmony_ci dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n", 23462306a36Sopenharmony_ci ep); 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (vep.base.port == 1) { 23962306a36Sopenharmony_ci if (vep.bus_type != V4L2_MBUS_PARALLEL && 24062306a36Sopenharmony_ci vep.bus_type != V4L2_MBUS_BT656) { 24162306a36Sopenharmony_ci dev_err(rkisp1->dev, 24262306a36Sopenharmony_ci "port 1 must be parallel or BT656\n"); 24362306a36Sopenharmony_ci ret = -EINVAL; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Add the async subdev to the notifier. */ 24962306a36Sopenharmony_ci source = fwnode_graph_get_remote_endpoint(ep); 25062306a36Sopenharmony_ci if (!source) { 25162306a36Sopenharmony_ci dev_err(rkisp1->dev, 25262306a36Sopenharmony_ci "endpoint %pfw has no remote endpoint\n", 25362306a36Sopenharmony_ci ep); 25462306a36Sopenharmony_ci ret = -ENODEV; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci rk_asd = v4l2_async_nf_add_fwnode(ntf, source, 25962306a36Sopenharmony_ci struct rkisp1_sensor_async); 26062306a36Sopenharmony_ci if (IS_ERR(rk_asd)) { 26162306a36Sopenharmony_ci fwnode_handle_put(source); 26262306a36Sopenharmony_ci ret = PTR_ERR(rk_asd); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci rk_asd->index = index++; 26762306a36Sopenharmony_ci rk_asd->source_ep = source; 26862306a36Sopenharmony_ci rk_asd->mbus_type = vep.bus_type; 26962306a36Sopenharmony_ci rk_asd->port = vep.base.port; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) { 27262306a36Sopenharmony_ci rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; 27362306a36Sopenharmony_ci rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci rk_asd->mbus_flags = vep.bus.parallel.flags; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n", 27962306a36Sopenharmony_ci vep.base.id, rk_asd->mbus_type, rk_asd->lanes); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (ret) { 28362306a36Sopenharmony_ci fwnode_handle_put(ep); 28462306a36Sopenharmony_ci v4l2_async_nf_cleanup(ntf); 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!index) 28962306a36Sopenharmony_ci dev_dbg(rkisp1->dev, "no remote subdevice found\n"); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ret = v4l2_async_nf_register(ntf); 29262306a36Sopenharmony_ci if (ret) { 29362306a36Sopenharmony_ci v4l2_async_nf_cleanup(ntf); 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* ---------------------------------------------------------------------------- 30162306a36Sopenharmony_ci * Power 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int __maybe_unused rkisp1_runtime_suspend(struct device *dev) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci rkisp1->irqs_enabled = false; 30962306a36Sopenharmony_ci /* Make sure the IRQ handler will see the above */ 31062306a36Sopenharmony_ci mb(); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * Wait until any running IRQ handler has returned. The IRQ handler 31462306a36Sopenharmony_ci * may get called even after this (as it's a shared interrupt line) 31562306a36Sopenharmony_ci * but the 'irqs_enabled' flag will make the handler return immediately. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { 31862306a36Sopenharmony_ci if (rkisp1->irqs[il] == -1) 31962306a36Sopenharmony_ci continue; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Skip if the irq line is the same as previous */ 32262306a36Sopenharmony_ci if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il]) 32362306a36Sopenharmony_ci synchronize_irq(rkisp1->irqs[il]); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); 32762306a36Sopenharmony_ci return pinctrl_pm_select_sleep_state(dev); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic int __maybe_unused rkisp1_runtime_resume(struct device *dev) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); 33362306a36Sopenharmony_ci int ret; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci ret = pinctrl_pm_select_default_state(dev); 33662306a36Sopenharmony_ci if (ret) 33762306a36Sopenharmony_ci return ret; 33862306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci return ret; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci rkisp1->irqs_enabled = true; 34362306a36Sopenharmony_ci /* Make sure the IRQ handler will see the above */ 34462306a36Sopenharmony_ci mb(); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic const struct dev_pm_ops rkisp1_pm_ops = { 35062306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 35162306a36Sopenharmony_ci pm_runtime_force_resume) 35262306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) 35362306a36Sopenharmony_ci}; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/* ---------------------------------------------------------------------------- 35662306a36Sopenharmony_ci * Core 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int rkisp1_create_links(struct rkisp1_device *rkisp1) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci unsigned int i; 36262306a36Sopenharmony_ci int ret; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { 36562306a36Sopenharmony_ci /* Link the CSI receiver to the ISP. */ 36662306a36Sopenharmony_ci ret = media_create_pad_link(&rkisp1->csi.sd.entity, 36762306a36Sopenharmony_ci RKISP1_CSI_PAD_SRC, 36862306a36Sopenharmony_ci &rkisp1->isp.sd.entity, 36962306a36Sopenharmony_ci RKISP1_ISP_PAD_SINK_VIDEO, 37062306a36Sopenharmony_ci MEDIA_LNK_FL_ENABLED); 37162306a36Sopenharmony_ci if (ret) 37262306a36Sopenharmony_ci return ret; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* create ISP->RSZ->CAP links */ 37662306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 37762306a36Sopenharmony_ci struct media_entity *resizer = 37862306a36Sopenharmony_ci &rkisp1->resizer_devs[i].sd.entity; 37962306a36Sopenharmony_ci struct media_entity *capture = 38062306a36Sopenharmony_ci &rkisp1->capture_devs[i].vnode.vdev.entity; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ret = media_create_pad_link(&rkisp1->isp.sd.entity, 38362306a36Sopenharmony_ci RKISP1_ISP_PAD_SOURCE_VIDEO, 38462306a36Sopenharmony_ci resizer, RKISP1_RSZ_PAD_SINK, 38562306a36Sopenharmony_ci MEDIA_LNK_FL_ENABLED); 38662306a36Sopenharmony_ci if (ret) 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC, 39062306a36Sopenharmony_ci capture, 0, 39162306a36Sopenharmony_ci MEDIA_LNK_FL_ENABLED | 39262306a36Sopenharmony_ci MEDIA_LNK_FL_IMMUTABLE); 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci return ret; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* params links */ 39862306a36Sopenharmony_ci ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0, 39962306a36Sopenharmony_ci &rkisp1->isp.sd.entity, 40062306a36Sopenharmony_ci RKISP1_ISP_PAD_SINK_PARAMS, 40162306a36Sopenharmony_ci MEDIA_LNK_FL_ENABLED | 40262306a36Sopenharmony_ci MEDIA_LNK_FL_IMMUTABLE); 40362306a36Sopenharmony_ci if (ret) 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* 3A stats links */ 40762306a36Sopenharmony_ci return media_create_pad_link(&rkisp1->isp.sd.entity, 40862306a36Sopenharmony_ci RKISP1_ISP_PAD_SOURCE_STATS, 40962306a36Sopenharmony_ci &rkisp1->stats.vnode.vdev.entity, 0, 41062306a36Sopenharmony_ci MEDIA_LNK_FL_ENABLED | 41162306a36Sopenharmony_ci MEDIA_LNK_FL_IMMUTABLE); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) 41762306a36Sopenharmony_ci rkisp1_csi_unregister(rkisp1); 41862306a36Sopenharmony_ci rkisp1_params_unregister(rkisp1); 41962306a36Sopenharmony_ci rkisp1_stats_unregister(rkisp1); 42062306a36Sopenharmony_ci rkisp1_capture_devs_unregister(rkisp1); 42162306a36Sopenharmony_ci rkisp1_resizer_devs_unregister(rkisp1); 42262306a36Sopenharmony_ci rkisp1_isp_unregister(rkisp1); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int rkisp1_entities_register(struct rkisp1_device *rkisp1) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci int ret; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ret = rkisp1_isp_register(rkisp1); 43062306a36Sopenharmony_ci if (ret) 43162306a36Sopenharmony_ci goto error; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ret = rkisp1_resizer_devs_register(rkisp1); 43462306a36Sopenharmony_ci if (ret) 43562306a36Sopenharmony_ci goto error; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ret = rkisp1_capture_devs_register(rkisp1); 43862306a36Sopenharmony_ci if (ret) 43962306a36Sopenharmony_ci goto error; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ret = rkisp1_stats_register(rkisp1); 44262306a36Sopenharmony_ci if (ret) 44362306a36Sopenharmony_ci goto error; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ret = rkisp1_params_register(rkisp1); 44662306a36Sopenharmony_ci if (ret) 44762306a36Sopenharmony_ci goto error; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { 45062306a36Sopenharmony_ci ret = rkisp1_csi_register(rkisp1); 45162306a36Sopenharmony_ci if (ret) 45262306a36Sopenharmony_ci goto error; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci ret = rkisp1_create_links(rkisp1); 45662306a36Sopenharmony_ci if (ret) 45762306a36Sopenharmony_ci goto error; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cierror: 46262306a36Sopenharmony_ci rkisp1_entities_unregister(rkisp1); 46362306a36Sopenharmony_ci return ret; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic irqreturn_t rkisp1_isr(int irq, void *ctx) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* 47162306a36Sopenharmony_ci * Call rkisp1_capture_isr() first to handle the frame that 47262306a36Sopenharmony_ci * potentially completed using the current frame_sequence number before 47362306a36Sopenharmony_ci * it is potentially incremented by rkisp1_isp_isr() in the vertical 47462306a36Sopenharmony_ci * sync. 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED) 47862306a36Sopenharmony_ci ret = IRQ_HANDLED; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED) 48162306a36Sopenharmony_ci ret = IRQ_HANDLED; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED) 48462306a36Sopenharmony_ci ret = IRQ_HANDLED; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic const char * const px30_isp_clks[] = { 49062306a36Sopenharmony_ci "isp", 49162306a36Sopenharmony_ci "aclk", 49262306a36Sopenharmony_ci "hclk", 49362306a36Sopenharmony_ci "pclk", 49462306a36Sopenharmony_ci}; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic const struct rkisp1_isr_data px30_isp_isrs[] = { 49762306a36Sopenharmony_ci { "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) }, 49862306a36Sopenharmony_ci { "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) }, 49962306a36Sopenharmony_ci { "mipi", rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) }, 50062306a36Sopenharmony_ci}; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic const struct rkisp1_info px30_isp_info = { 50362306a36Sopenharmony_ci .clks = px30_isp_clks, 50462306a36Sopenharmony_ci .clk_size = ARRAY_SIZE(px30_isp_clks), 50562306a36Sopenharmony_ci .isrs = px30_isp_isrs, 50662306a36Sopenharmony_ci .isr_size = ARRAY_SIZE(px30_isp_isrs), 50762306a36Sopenharmony_ci .isp_ver = RKISP1_V12, 50862306a36Sopenharmony_ci .features = RKISP1_FEATURE_MIPI_CSI2, 50962306a36Sopenharmony_ci}; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic const char * const rk3399_isp_clks[] = { 51262306a36Sopenharmony_ci "isp", 51362306a36Sopenharmony_ci "aclk", 51462306a36Sopenharmony_ci "hclk", 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct rkisp1_isr_data rk3399_isp_isrs[] = { 51862306a36Sopenharmony_ci { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) }, 51962306a36Sopenharmony_ci}; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic const struct rkisp1_info rk3399_isp_info = { 52262306a36Sopenharmony_ci .clks = rk3399_isp_clks, 52362306a36Sopenharmony_ci .clk_size = ARRAY_SIZE(rk3399_isp_clks), 52462306a36Sopenharmony_ci .isrs = rk3399_isp_isrs, 52562306a36Sopenharmony_ci .isr_size = ARRAY_SIZE(rk3399_isp_isrs), 52662306a36Sopenharmony_ci .isp_ver = RKISP1_V10, 52762306a36Sopenharmony_ci .features = RKISP1_FEATURE_MIPI_CSI2, 52862306a36Sopenharmony_ci}; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic const struct of_device_id rkisp1_of_match[] = { 53162306a36Sopenharmony_ci { 53262306a36Sopenharmony_ci .compatible = "rockchip,px30-cif-isp", 53362306a36Sopenharmony_ci .data = &px30_isp_info, 53462306a36Sopenharmony_ci }, 53562306a36Sopenharmony_ci { 53662306a36Sopenharmony_ci .compatible = "rockchip,rk3399-cif-isp", 53762306a36Sopenharmony_ci .data = &rk3399_isp_info, 53862306a36Sopenharmony_ci }, 53962306a36Sopenharmony_ci {}, 54062306a36Sopenharmony_ci}; 54162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rkisp1_of_match); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int rkisp1_probe(struct platform_device *pdev) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci const struct rkisp1_info *info; 54662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 54762306a36Sopenharmony_ci struct rkisp1_device *rkisp1; 54862306a36Sopenharmony_ci struct v4l2_device *v4l2_dev; 54962306a36Sopenharmony_ci unsigned int i; 55062306a36Sopenharmony_ci int ret, irq; 55162306a36Sopenharmony_ci u32 cif_id; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); 55462306a36Sopenharmony_ci if (!rkisp1) 55562306a36Sopenharmony_ci return -ENOMEM; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci info = of_device_get_match_data(dev); 55862306a36Sopenharmony_ci rkisp1->info = info; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci dev_set_drvdata(dev, rkisp1); 56162306a36Sopenharmony_ci rkisp1->dev = dev; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci mutex_init(&rkisp1->stream_lock); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); 56662306a36Sopenharmony_ci if (IS_ERR(rkisp1->base_addr)) 56762306a36Sopenharmony_ci return PTR_ERR(rkisp1->base_addr); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) 57062306a36Sopenharmony_ci rkisp1->irqs[il] = -1; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci for (i = 0; i < info->isr_size; i++) { 57362306a36Sopenharmony_ci irq = info->isrs[i].name 57462306a36Sopenharmony_ci ? platform_get_irq_byname(pdev, info->isrs[i].name) 57562306a36Sopenharmony_ci : platform_get_irq(pdev, i); 57662306a36Sopenharmony_ci if (irq < 0) 57762306a36Sopenharmony_ci return irq; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { 58062306a36Sopenharmony_ci if (info->isrs[i].line_mask & BIT(il)) 58162306a36Sopenharmony_ci rkisp1->irqs[il] = irq; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, 58562306a36Sopenharmony_ci dev_driver_string(dev), dev); 58662306a36Sopenharmony_ci if (ret) { 58762306a36Sopenharmony_ci dev_err(dev, "request irq failed: %d\n", ret); 58862306a36Sopenharmony_ci return ret; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci for (i = 0; i < info->clk_size; i++) 59362306a36Sopenharmony_ci rkisp1->clks[i].id = info->clks[i]; 59462306a36Sopenharmony_ci ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks); 59562306a36Sopenharmony_ci if (ret) 59662306a36Sopenharmony_ci return ret; 59762306a36Sopenharmony_ci rkisp1->clk_size = info->clk_size; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&pdev->dev); 60262306a36Sopenharmony_ci if (ret) 60362306a36Sopenharmony_ci goto err_pm_runtime_disable; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); 60662306a36Sopenharmony_ci dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci rkisp1->media_dev.hw_revision = info->isp_ver; 61162306a36Sopenharmony_ci strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, 61262306a36Sopenharmony_ci sizeof(rkisp1->media_dev.model)); 61362306a36Sopenharmony_ci rkisp1->media_dev.dev = &pdev->dev; 61462306a36Sopenharmony_ci strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, 61562306a36Sopenharmony_ci sizeof(rkisp1->media_dev.bus_info)); 61662306a36Sopenharmony_ci media_device_init(&rkisp1->media_dev); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci v4l2_dev = &rkisp1->v4l2_dev; 61962306a36Sopenharmony_ci v4l2_dev->mdev = &rkisp1->media_dev; 62062306a36Sopenharmony_ci strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); 62362306a36Sopenharmony_ci if (ret) 62462306a36Sopenharmony_ci goto err_media_dev_cleanup; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci ret = media_device_register(&rkisp1->media_dev); 62762306a36Sopenharmony_ci if (ret) { 62862306a36Sopenharmony_ci dev_err(dev, "Failed to register media device: %d\n", ret); 62962306a36Sopenharmony_ci goto err_unreg_v4l2_dev; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { 63362306a36Sopenharmony_ci ret = rkisp1_csi_init(rkisp1); 63462306a36Sopenharmony_ci if (ret) 63562306a36Sopenharmony_ci goto err_unreg_media_dev; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci ret = rkisp1_entities_register(rkisp1); 63962306a36Sopenharmony_ci if (ret) 64062306a36Sopenharmony_ci goto err_cleanup_csi; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci ret = rkisp1_subdev_notifier_register(rkisp1); 64362306a36Sopenharmony_ci if (ret) 64462306a36Sopenharmony_ci goto err_unreg_entities; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci rkisp1_debug_init(rkisp1); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return 0; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cierr_unreg_entities: 65162306a36Sopenharmony_ci rkisp1_entities_unregister(rkisp1); 65262306a36Sopenharmony_cierr_cleanup_csi: 65362306a36Sopenharmony_ci if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) 65462306a36Sopenharmony_ci rkisp1_csi_cleanup(rkisp1); 65562306a36Sopenharmony_cierr_unreg_media_dev: 65662306a36Sopenharmony_ci media_device_unregister(&rkisp1->media_dev); 65762306a36Sopenharmony_cierr_unreg_v4l2_dev: 65862306a36Sopenharmony_ci v4l2_device_unregister(&rkisp1->v4l2_dev); 65962306a36Sopenharmony_cierr_media_dev_cleanup: 66062306a36Sopenharmony_ci media_device_cleanup(&rkisp1->media_dev); 66162306a36Sopenharmony_cierr_pm_runtime_disable: 66262306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 66362306a36Sopenharmony_ci return ret; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void rkisp1_remove(struct platform_device *pdev) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci v4l2_async_nf_unregister(&rkisp1->notifier); 67162306a36Sopenharmony_ci v4l2_async_nf_cleanup(&rkisp1->notifier); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci rkisp1_entities_unregister(rkisp1); 67462306a36Sopenharmony_ci if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) 67562306a36Sopenharmony_ci rkisp1_csi_cleanup(rkisp1); 67662306a36Sopenharmony_ci rkisp1_debug_cleanup(rkisp1); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci media_device_unregister(&rkisp1->media_dev); 67962306a36Sopenharmony_ci v4l2_device_unregister(&rkisp1->v4l2_dev); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci media_device_cleanup(&rkisp1->media_dev); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic struct platform_driver rkisp1_drv = { 68762306a36Sopenharmony_ci .driver = { 68862306a36Sopenharmony_ci .name = RKISP1_DRIVER_NAME, 68962306a36Sopenharmony_ci .of_match_table = of_match_ptr(rkisp1_of_match), 69062306a36Sopenharmony_ci .pm = &rkisp1_pm_ops, 69162306a36Sopenharmony_ci }, 69262306a36Sopenharmony_ci .probe = rkisp1_probe, 69362306a36Sopenharmony_ci .remove_new = rkisp1_remove, 69462306a36Sopenharmony_ci}; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cimodule_platform_driver(rkisp1_drv); 69762306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip ISP1 platform driver"); 69862306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL"); 699