1175 lines
30 KiB
C

/*
* Rockchip isp1 driver
*
* Copyright (C) 2017 Rockchip Electronics Co., Ltd.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <media/videobuf2-dma-contig.h>
#include <soc/rockchip/rockchip-system-status.h>
#include "regs.h"
#include "rkisp1.h"
#include "common.h"
#include "version.h"
#define RKISP_VERNO_LEN 10
struct isp_irqs_data {
const char *name;
irqreturn_t (*irq_hdl)(int irq, void *ctx);
};
struct isp_match_data {
const char * const *clks;
int num_clks;
enum rkisp1_isp_ver isp_ver;
const unsigned int *clk_rate_tbl;
int num_clk_rate_tbl;
struct isp_irqs_data *irqs;
int num_irqs;
};
int rkisp1_debug;
module_param_named(debug, rkisp1_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
static char rkisp1_version[RKISP_VERNO_LEN];
module_param_string(version, rkisp1_version, RKISP_VERNO_LEN, 0444);
MODULE_PARM_DESC(version, "version number");
static DEFINE_MUTEX(rkisp1_dev_mutex);
static LIST_HEAD(rkisp1_device_list);
static int __maybe_unused __rkisp1_clr_unready_dev(void)
{
struct rkisp1_device *isp_dev;
mutex_lock(&rkisp1_dev_mutex);
list_for_each_entry(isp_dev, &rkisp1_device_list, list)
v4l2_async_notifier_clr_unready_dev(&isp_dev->notifier);
mutex_unlock(&rkisp1_dev_mutex);
return 0;
}
static int rkisp1_clr_unready_dev_param_set(const char *val, const struct kernel_param *kp)
{
#ifdef MODULE
__rkisp1_clr_unready_dev();
#endif
return 0;
}
module_param_call(clr_unready_dev, rkisp1_clr_unready_dev_param_set, NULL, NULL, 0200);
MODULE_PARM_DESC(clr_unready_dev, "clear unready devices");
/**************************** pipeline operations *****************************/
static int __isp_pipeline_prepare(struct rkisp1_pipeline *p,
struct media_entity *me)
{
struct rkisp1_device *dev = container_of(p, struct rkisp1_device, pipe);
struct v4l2_subdev *sd;
int i;
p->num_subdevs = 0;
memset(p->subdevs, 0, sizeof(p->subdevs));
if (dev->isp_inp == INP_DMARX_ISP)
return 0;
while (1) {
struct media_pad *pad = NULL;
/* Find remote source pad */
for (i = 0; i < me->num_pads; i++) {
struct media_pad *spad = &me->pads[i];
if (!(spad->flags & MEDIA_PAD_FL_SINK))
continue;
pad = media_pad_remote_pad_first(spad);
if (pad)
break;
}
if (!pad)
break;
sd = media_entity_to_v4l2_subdev(pad->entity);
if (sd != &dev->isp_sdev.sd)
p->subdevs[p->num_subdevs++] = sd;
me = &sd->entity;
if (me->num_pads == 1)
break;
}
if (!p->num_subdevs)
return -EINVAL;
return 0;
}
static int __isp_pipeline_s_isp_clk(struct rkisp1_pipeline *p)
{
struct rkisp1_device *dev = container_of(p, struct rkisp1_device, pipe);
struct v4l2_subdev *sd;
struct v4l2_ctrl *ctrl;
u64 data_rate;
int i;
if (dev->isp_inp == INP_DMARX_ISP) {
clk_set_rate(dev->clks[0], 400 * 1000000UL);
return 0;
}
/* find the subdev of active sensor */
sd = p->subdevs[0];
for (i = 0; i < p->num_subdevs; i++) {
sd = p->subdevs[i];
if (sd->entity.function == MEDIA_ENT_F_CAM_SENSOR)
break;
}
if (i == p->num_subdevs) {
v4l2_warn(sd, "No active sensor\n");
return -EPIPE;
}
ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE);
if (!ctrl) {
v4l2_warn(sd, "No pixel rate control in subdev\n");
return -EPIPE;
}
/* calculate data rate */
data_rate = v4l2_ctrl_g_ctrl_int64(ctrl) *
dev->isp_sdev.in_fmt.bus_width;
data_rate >>= 3;
do_div(data_rate, 1000 * 1000);
/* increase 25% margin */
data_rate += data_rate >> 2;
/* compare with isp clock adjustment table */
for (i = 0; i < dev->num_clk_rate_tbl; i++)
if (data_rate <= dev->clk_rate_tbl[i])
break;
if (i == dev->num_clk_rate_tbl)
i--;
/* set isp clock rate */
clk_set_rate(dev->clks[0], dev->clk_rate_tbl[i] * 1000000UL);
v4l2_dbg(1, rkisp1_debug, sd, "set isp clk = %luHz\n",
clk_get_rate(dev->clks[0]));
return 0;
}
static int rkisp1_pipeline_open(struct rkisp1_pipeline *p,
struct media_entity *me,
bool prepare)
{
int ret;
if (WARN_ON(!p || !me))
return -EINVAL;
if (atomic_inc_return(&p->power_cnt) > 1)
return 0;
/* go through media graphic and get subdevs */
if (prepare) {
ret = __isp_pipeline_prepare(p, me);
if (ret < 0)
return ret;
}
ret = __isp_pipeline_s_isp_clk(p);
if (ret < 0)
return ret;
return 0;
}
static int rkisp1_pipeline_close(struct rkisp1_pipeline *p)
{
atomic_dec(&p->power_cnt);
return 0;
}
/*
* stream-on order: isp_subdev, mipi dphy, sensor
* stream-off order: mipi dphy, sensor, isp_subdev
*/
static int rkisp1_pipeline_set_stream(struct rkisp1_pipeline *p, bool on)
{
struct rkisp1_device *dev = container_of(p, struct rkisp1_device, pipe);
int i, ret;
if ((on && atomic_inc_return(&p->stream_cnt) > 1) ||
(!on && atomic_dec_return(&p->stream_cnt) > 0))
return 0;
if (on) {
if (dev->vs_irq >= 0)
enable_irq(dev->vs_irq);
rockchip_set_system_status(SYS_STATUS_ISP);
v4l2_subdev_call(&dev->isp_sdev.sd, video, s_stream, true);
}
/* phy -> sensor */
for (i = 0; i < p->num_subdevs; ++i) {
ret = v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
if (on && ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
goto err_stream_off;
}
if (!on) {
if (dev->vs_irq >= 0)
disable_irq(dev->vs_irq);
v4l2_subdev_call(&dev->isp_sdev.sd, video, s_stream, false);
rockchip_clear_system_status(SYS_STATUS_ISP);
}
return 0;
err_stream_off:
for (--i; i >= 0; --i)
v4l2_subdev_call(p->subdevs[i], video, s_stream, false);
v4l2_subdev_call(&dev->isp_sdev.sd, video, s_stream, false);
rockchip_clear_system_status(SYS_STATUS_ISP);
return ret;
}
/***************************** media controller *******************************/
/* See http://opensource.rock-chips.com/wiki_Rockchip-isp1 for Topology */
static int rkisp1_create_links(struct rkisp1_device *dev)
{
struct media_entity *source, *sink;
unsigned int flags, s, pad;
int ret;
/* sensor links(or mipi-phy) */
for (s = 0; s < dev->num_sensors; ++s) {
struct rkisp1_sensor_info *sensor = &dev->sensors[s];
for (pad = 0; pad < sensor->sd->entity.num_pads; pad++)
if (sensor->sd->entity.pads[pad].flags &
MEDIA_PAD_FL_SOURCE)
break;
if (pad == sensor->sd->entity.num_pads) {
dev_err(dev->dev,
"failed to find src pad for %s\n",
sensor->sd->name);
return -ENXIO;
}
ret = media_create_pad_link(
&sensor->sd->entity, pad,
&dev->isp_sdev.sd.entity,
RKISP1_ISP_PAD_SINK,
s ? 0 : MEDIA_LNK_FL_ENABLED);
if (ret) {
dev_err(dev->dev,
"failed to create link for %s\n",
sensor->sd->name);
return ret;
}
}
/* params links */
source = &dev->params_vdev.vnode.vdev.entity;
sink = &dev->isp_sdev.sd.entity;
flags = MEDIA_LNK_FL_ENABLED;
ret = media_create_pad_link(source, 0, sink,
RKISP1_ISP_PAD_SINK_PARAMS, flags);
if (ret < 0)
return ret;
/* create isp internal links */
if (dev->isp_ver != ISP_V10_1) {
/* SP links */
source = &dev->isp_sdev.sd.entity;
sink = &dev->stream[RKISP1_STREAM_SP].vnode.vdev.entity;
ret = media_create_pad_link(source,
RKISP1_ISP_PAD_SOURCE_PATH,
sink, 0, flags);
if (ret < 0)
return ret;
}
/* MP links */
source = &dev->isp_sdev.sd.entity;
sink = &dev->stream[RKISP1_STREAM_MP].vnode.vdev.entity;
ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_PATH,
sink, 0, flags);
if (ret < 0)
return ret;
#if RKISP1_RK3326_USE_OLDMIPI
if (dev->isp_ver == ISP_V13) {
#else
if (dev->isp_ver == ISP_V12 ||
dev->isp_ver == ISP_V13) {
#endif
/* MIPI RAW links */
source = &dev->isp_sdev.sd.entity;
sink = &dev->stream[RKISP1_STREAM_RAW].vnode.vdev.entity;
ret = media_create_pad_link(source,
RKISP1_ISP_PAD_SOURCE_PATH, sink, 0, flags);
if (ret < 0)
return ret;
}
/* 3A stats links */
source = &dev->isp_sdev.sd.entity;
sink = &dev->stats_vdev.vnode.vdev.entity;
return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS,
sink, 0, flags);
}
static int _set_pipeline_default_fmt(struct rkisp1_device *dev)
{
struct v4l2_subdev *isp;
struct v4l2_subdev_format fmt;
struct v4l2_subdev_selection sel;
struct v4l2_subdev_state state;
u32 width, height;
u32 ori_width, ori_height, ori_code;
isp = &dev->isp_sdev.sd;
fmt = dev->active_sensor->fmt;
ori_width = fmt.format.width;
ori_height = fmt.format.height;
ori_code = fmt.format.code;
if (dev->isp_ver == ISP_V12) {
fmt.format.width = clamp_t(u32, fmt.format.width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V12);
fmt.format.height = clamp_t(u32, fmt.format.height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V12);
} else if (dev->isp_ver == ISP_V13) {
fmt.format.width = clamp_t(u32, fmt.format.width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX_V13);
fmt.format.height = clamp_t(u32, fmt.format.height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX_V13);
} else {
fmt.format.width = clamp_t(u32, fmt.format.width,
CIF_ISP_INPUT_W_MIN,
CIF_ISP_INPUT_W_MAX);
fmt.format.height = clamp_t(u32, fmt.format.height,
CIF_ISP_INPUT_H_MIN,
CIF_ISP_INPUT_H_MAX);
}
sel.r.left = 0;
sel.r.top = 0;
width = fmt.format.width;
height = fmt.format.height;
sel.r.width = fmt.format.width;
sel.r.height = fmt.format.height;
sel.target = V4L2_SEL_TGT_CROP;
sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
memset(&state, 0, sizeof(state));
/* change fmt&size for RKISP1_ISP_PAD_SINK */
fmt.pad = RKISP1_ISP_PAD_SINK;
sel.pad = RKISP1_ISP_PAD_SINK;
v4l2_subdev_call(isp, pad, set_fmt, &state, &fmt);
v4l2_subdev_call(isp, pad, set_selection, &state, &sel);
/* change fmt&size for RKISP1_ISP_PAD_SOURCE_PATH */
if ((fmt.format.code & RKISP1_MEDIA_BUS_FMT_MASK) ==
RKISP1_MEDIA_BUS_FMT_BAYER)
fmt.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
fmt.pad = RKISP1_ISP_PAD_SOURCE_PATH;
sel.pad = RKISP1_ISP_PAD_SOURCE_PATH;
v4l2_subdev_call(isp, pad, set_fmt, &state, &fmt);
v4l2_subdev_call(isp, pad, set_selection, &state, &sel);
/* change fmt&size of MP/SP */
rkisp1_set_stream_def_fmt(dev, RKISP1_STREAM_MP,
width, height, V4L2_PIX_FMT_YUYV);
if (dev->isp_ver != ISP_V10_1)
rkisp1_set_stream_def_fmt(dev, RKISP1_STREAM_SP,
width, height, V4L2_PIX_FMT_YUYV);
if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13)
rkisp1_set_stream_def_fmt(dev, RKISP1_STREAM_RAW, ori_width,
ori_height, rkisp1_mbus_pixelcode_to_v4l2(ori_code));
return 0;
}
static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct rkisp1_device *dev;
int ret;
dev = container_of(notifier, struct rkisp1_device, notifier);
mutex_lock(&dev->media_dev.graph_mutex);
ret = rkisp1_create_links(dev);
if (ret < 0)
goto unlock;
ret = v4l2_device_register_subdev_nodes(&dev->v4l2_dev);
if (ret < 0)
goto unlock;
ret = rkisp1_update_sensor_info(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "update sensor failed\n");
goto unlock;
}
ret = _set_pipeline_default_fmt(dev);
if (ret < 0)
goto unlock;
v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n");
unlock:
mutex_unlock(&dev->media_dev.graph_mutex);
return ret;
}
struct rkisp1_async_subdev {
struct v4l2_async_subdev asd;
struct v4l2_mbus_config mbus;
};
static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
{
struct rkisp1_device *isp_dev = container_of(notifier,
struct rkisp1_device, notifier);
struct rkisp1_async_subdev *s_asd = container_of(asd,
struct rkisp1_async_subdev, asd);
if (isp_dev->num_sensors == ARRAY_SIZE(isp_dev->sensors))
return -EBUSY;
isp_dev->sensors[isp_dev->num_sensors].mbus = s_asd->mbus;
isp_dev->sensors[isp_dev->num_sensors].sd = subdev;
++isp_dev->num_sensors;
v4l2_dbg(1, rkisp1_debug, subdev, "Async registered subdev\n");
return 0;
}
static int rkisp1_fwnode_parse(struct device *dev,
struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd)
{
struct rkisp1_async_subdev *rk_asd =
container_of(asd, struct rkisp1_async_subdev, asd);
/*
* MIPI sensor is linked with a mipi dphy and its media bus config can
* not be get in here
*/
if (vep->bus_type != V4L2_MBUS_BT656 &&
vep->bus_type != V4L2_MBUS_PARALLEL)
return 0;
rk_asd->mbus.type = vep->bus_type;
return 0;
}
static const struct v4l2_async_notifier_operations subdev_notifier_ops = {
.bound = subdev_notifier_bound,
.complete = subdev_notifier_complete,
};
static int isp_subdev_notifier(struct rkisp1_device *isp_dev)
{
struct v4l2_async_notifier *ntf = &isp_dev->notifier;
struct device *dev = isp_dev->dev;
int ret;
v4l2_async_nf_init(ntf);
ret = v4l2_async_nf_parse_fwnode_endpoints(
dev, ntf, sizeof(struct rkisp1_async_subdev),
rkisp1_fwnode_parse);
if (ret < 0)
return ret;
ntf->ops = &subdev_notifier_ops;
return v4l2_async_nf_register(&isp_dev->v4l2_dev, ntf);
}
/***************************** platform deive *******************************/
static int rkisp1_register_platform_subdevs(struct rkisp1_device *dev)
{
int ret;
ret = rkisp1_register_isp_subdev(dev, &dev->v4l2_dev);
if (ret < 0)
return ret;
ret = rkisp1_register_stream_vdevs(dev);
if (ret < 0)
goto err_unreg_isp_subdev;
ret = rkisp1_register_dmarx_vdev(dev);
if (ret < 0)
goto err_unreg_stream_vdev;
ret = rkisp1_register_stats_vdev(&dev->stats_vdev, &dev->v4l2_dev, dev);
if (ret < 0)
goto err_unreg_dmarx_vdev;
ret = rkisp1_register_params_vdev(&dev->params_vdev, &dev->v4l2_dev,
dev);
if (ret < 0)
goto err_unreg_stats_vdev;
ret = isp_subdev_notifier(dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"Failed to register subdev notifier(%d)\n", ret);
goto err_unreg_params_vdev;
}
return 0;
err_unreg_params_vdev:
rkisp1_unregister_params_vdev(&dev->params_vdev);
err_unreg_stats_vdev:
rkisp1_unregister_stats_vdev(&dev->stats_vdev);
err_unreg_dmarx_vdev:
rkisp1_unregister_dmarx_vdev(dev);
err_unreg_stream_vdev:
rkisp1_unregister_stream_vdevs(dev);
err_unreg_isp_subdev:
rkisp1_unregister_isp_subdev(dev);
return ret;
}
static irqreturn_t rkisp1_irq_handler(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkisp1_device *rkisp1_dev = dev_get_drvdata(dev);
unsigned int mis_val;
mis_val = readl(rkisp1_dev->base_addr + CIF_ISP_MIS);
if (mis_val)
rkisp1_isp_isr(mis_val, rkisp1_dev);
mis_val = readl(rkisp1_dev->base_addr + CIF_MIPI_MIS);
if (mis_val)
rkisp1_mipi_isr(mis_val, rkisp1_dev);
mis_val = readl(rkisp1_dev->base_addr + CIF_MI_MIS);
if (mis_val)
rkisp1_mi_isr(mis_val, rkisp1_dev);
return IRQ_HANDLED;
}
static irqreturn_t rkisp1_isp_irq_hdl(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkisp1_device *rkisp1_dev = dev_get_drvdata(dev);
unsigned int mis_val;
mis_val = readl(rkisp1_dev->base_addr + CIF_ISP_MIS);
if (mis_val)
rkisp1_isp_isr(mis_val, rkisp1_dev);
return IRQ_HANDLED;
}
static irqreturn_t rkisp1_mi_irq_hdl(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkisp1_device *rkisp1_dev = dev_get_drvdata(dev);
unsigned int mis_val;
mis_val = readl(rkisp1_dev->base_addr + CIF_MI_MIS);
if (mis_val)
rkisp1_mi_isr(mis_val, rkisp1_dev);
return IRQ_HANDLED;
}
static irqreturn_t rkisp1_mipi_irq_hdl(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkisp1_device *rkisp1_dev = dev_get_drvdata(dev);
unsigned int mis_val;
unsigned int err1, err2, err3;
#if RKISP1_RK3326_USE_OLDMIPI
if (rkisp1_dev->isp_ver == ISP_V13) {
#else
if (rkisp1_dev->isp_ver == ISP_V13 ||
rkisp1_dev->isp_ver == ISP_V12) {
#endif
err1 = readl(rkisp1_dev->base_addr + CIF_ISP_CSI0_ERR1);
err2 = readl(rkisp1_dev->base_addr + CIF_ISP_CSI0_ERR2);
err3 = readl(rkisp1_dev->base_addr + CIF_ISP_CSI0_ERR3);
if (err3 & 0x1)
rkisp1_mipi_dmatx0_end(err3, rkisp1_dev);
if (err1 || err2 || err3)
rkisp1_mipi_v13_isr(err1, err2, err3, rkisp1_dev);
} else {
mis_val = readl(rkisp1_dev->base_addr + CIF_MIPI_MIS);
if (mis_val)
rkisp1_mipi_isr(mis_val, rkisp1_dev);
/*
* As default interrupt mask for csi_rx are on,
* when resetting isp, interrupt from csi_rx maybe arise,
* we should clear them.
*/
#if RKISP1_RK3326_USE_OLDMIPI
if (rkisp1_dev->isp_ver == ISP_V12) {
/* read error state register to clear interrupt state */
readl(rkisp1_dev->base_addr + CIF_ISP_CSI0_ERR1);
readl(rkisp1_dev->base_addr + CIF_ISP_CSI0_ERR2);
readl(rkisp1_dev->base_addr + CIF_ISP_CSI0_ERR3);
}
#endif
}
return IRQ_HANDLED;
}
static const char * const rk1808_isp_clks[] = {
"clk_isp",
"aclk_isp",
"hclk_isp",
"pclk_isp",
};
static const char * const rk3288_isp_clks[] = {
"clk_isp",
"aclk_isp",
"hclk_isp",
"pclk_isp_in",
"sclk_isp_jpe",
};
static const char * const rk3326_isp_clks[] = {
"clk_isp",
"aclk_isp",
"hclk_isp",
"pclk_isp",
};
static const char * const rk3368_isp_clks[] = {
"clk_isp",
"aclk_isp",
"hclk_isp",
"pclk_isp",
};
static const char * const rk3399_isp_clks[] = {
"clk_isp",
"aclk_isp",
"hclk_isp",
"aclk_isp_wrap",
"hclk_isp_wrap",
"pclk_isp_wrap"
};
/* isp clock adjustment table (MHz) */
static const unsigned int rk1808_isp_clk_rate[] = {
300, 400, 500, 600
};
/* isp clock adjustment table (MHz) */
static const unsigned int rk3288_isp_clk_rate[] = {
150, 384, 500, 594
};
/* isp clock adjustment table (MHz) */
static const unsigned int rk3326_isp_clk_rate[] = {
300, 347, 400, 520, 600
};
/* isp clock adjustment table (MHz) */
static const unsigned int rk3368_isp_clk_rate[] = {
300, 400, 600
};
/* isp clock adjustment table (MHz) */
static const unsigned int rk3399_isp_clk_rate[] = {
300, 400, 600
};
static struct isp_irqs_data rk1808_isp_irqs[] = {
{"isp_irq", rkisp1_isp_irq_hdl},
{"mi_irq", rkisp1_mi_irq_hdl},
{"mipi_irq", rkisp1_mipi_irq_hdl}
};
static struct isp_irqs_data rk3288_isp_irqs[] = {
{"isp_irq", rkisp1_irq_handler}
};
static struct isp_irqs_data rk3326_isp_irqs[] = {
{"isp_irq", rkisp1_isp_irq_hdl},
{"mi_irq", rkisp1_mi_irq_hdl},
{"mipi_irq", rkisp1_mipi_irq_hdl}
};
static struct isp_irqs_data rk3368_isp_irqs[] = {
{"isp_irq", rkisp1_irq_handler}
};
static struct isp_irqs_data rk3399_isp_irqs[] = {
{"isp_irq", rkisp1_irq_handler}
};
static const struct isp_match_data rk1808_isp_match_data = {
.clks = rk1808_isp_clks,
.num_clks = ARRAY_SIZE(rk1808_isp_clks),
.isp_ver = ISP_V13,
.clk_rate_tbl = rk1808_isp_clk_rate,
.num_clk_rate_tbl = ARRAY_SIZE(rk1808_isp_clk_rate),
.irqs = rk1808_isp_irqs,
.num_irqs = ARRAY_SIZE(rk1808_isp_irqs)
};
static const struct isp_match_data rk3288_isp_match_data = {
.clks = rk3288_isp_clks,
.num_clks = ARRAY_SIZE(rk3288_isp_clks),
.isp_ver = ISP_V10,
.clk_rate_tbl = rk3288_isp_clk_rate,
.num_clk_rate_tbl = ARRAY_SIZE(rk3288_isp_clk_rate),
.irqs = rk3288_isp_irqs,
.num_irqs = ARRAY_SIZE(rk3288_isp_irqs)
};
static const struct isp_match_data rk3326_isp_match_data = {
.clks = rk3326_isp_clks,
.num_clks = ARRAY_SIZE(rk3326_isp_clks),
.isp_ver = ISP_V12,
.clk_rate_tbl = rk3326_isp_clk_rate,
.num_clk_rate_tbl = ARRAY_SIZE(rk3326_isp_clk_rate),
.irqs = rk3326_isp_irqs,
.num_irqs = ARRAY_SIZE(rk3326_isp_irqs)
};
static const struct isp_match_data rk3368_isp_match_data = {
.clks = rk3368_isp_clks,
.num_clks = ARRAY_SIZE(rk3368_isp_clks),
.isp_ver = ISP_V10_1,
.clk_rate_tbl = rk3368_isp_clk_rate,
.num_clk_rate_tbl = ARRAY_SIZE(rk3368_isp_clk_rate),
.irqs = rk3368_isp_irqs,
.num_irqs = ARRAY_SIZE(rk3368_isp_irqs)
};
static const struct isp_match_data rk3399_isp_match_data = {
.clks = rk3399_isp_clks,
.num_clks = ARRAY_SIZE(rk3399_isp_clks),
.isp_ver = ISP_V10,
.clk_rate_tbl = rk3399_isp_clk_rate,
.num_clk_rate_tbl = ARRAY_SIZE(rk3399_isp_clk_rate),
.irqs = rk3399_isp_irqs,
.num_irqs = ARRAY_SIZE(rk3399_isp_irqs)
};
static const struct of_device_id rkisp1_plat_of_match[] = {
{
.compatible = "rockchip,rk1808-rkisp1",
.data = &rk1808_isp_match_data,
}, {
.compatible = "rockchip,rk3288-rkisp1",
.data = &rk3288_isp_match_data,
}, {
.compatible = "rockchip,rk3326-rkisp1",
.data = &rk3326_isp_match_data,
}, {
.compatible = "rockchip,rk3368-rkisp1",
.data = &rk3368_isp_match_data,
}, {
.compatible = "rockchip,rk3399-rkisp1",
.data = &rk3399_isp_match_data,
},
{},
};
static void rkisp1_disable_sys_clk(struct rkisp1_device *rkisp1_dev)
{
int i;
for (i = rkisp1_dev->num_clks - 1; i >= 0; i--)
if (!IS_ERR(rkisp1_dev->clks[i]))
clk_disable_unprepare(rkisp1_dev->clks[i]);
}
static int rkisp1_enable_sys_clk(struct rkisp1_device *rkisp1_dev)
{
int i, ret = -EINVAL;
for (i = 0; i < rkisp1_dev->num_clks; i++) {
if (!IS_ERR(rkisp1_dev->clks[i])) {
ret = clk_prepare_enable(rkisp1_dev->clks[i]);
if (ret < 0)
goto err;
}
}
return 0;
err:
for (--i; i >= 0; --i)
if (!IS_ERR(rkisp1_dev->clks[i]))
clk_disable_unprepare(rkisp1_dev->clks[i]);
return ret;
}
static inline bool is_iommu_enable(struct device *dev)
{
struct device_node *iommu;
iommu = of_parse_phandle(dev->of_node, "iommus", 0);
if (!iommu) {
dev_info(dev, "no iommu attached, using non-iommu buffers\n");
return false;
} else if (!of_device_is_available(iommu)) {
dev_info(dev, "iommu is disabled, using non-iommu buffers\n");
of_node_put(iommu);
return false;
}
of_node_put(iommu);
return true;
}
static int rkisp1_vs_irq_parse(struct platform_device *pdev)
{
int ret;
int vs_irq;
unsigned long vs_irq_flags;
struct gpio_desc *vs_irq_gpio;
struct device *dev = &pdev->dev;
struct rkisp1_device *isp_dev = dev_get_drvdata(dev);
/* this irq recevice the message of sensor vs from preisp */
isp_dev->vs_irq = -1;
vs_irq_gpio = devm_gpiod_get(dev, "vsirq", GPIOD_IN);
if (!IS_ERR(vs_irq_gpio)) {
vs_irq_flags = IRQF_TRIGGER_RISING |
IRQF_ONESHOT | IRQF_SHARED;
vs_irq = gpiod_to_irq(vs_irq_gpio);
if (vs_irq < 0) {
dev_err(dev, "GPIO to interrupt failed\n");
return vs_irq;
}
dev_info(dev, "register_irq: %d\n", vs_irq);
ret = devm_request_irq(dev,
vs_irq,
rkisp1_vs_isr_handler,
vs_irq_flags,
"vs_irq_gpio_int",
dev);
if (ret) {
dev_err(dev, "devm_request_irq failed: %d\n", ret);
return ret;
} else {
disable_irq(vs_irq);
isp_dev->vs_irq = vs_irq;
isp_dev->vs_irq_gpio = vs_irq_gpio;
dev_info(dev, "vs_gpio_int interrupt is hooked\n");
}
}
return 0;
}
static const struct media_device_ops rkisp1_media_ops = {
.link_notify = v4l2_pipeline_link_notify,
};
static int rkisp1_plat_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct v4l2_device *v4l2_dev;
struct rkisp1_device *isp_dev;
const struct isp_match_data *match_data;
struct resource *res;
int i, ret, irq;
sprintf(rkisp1_version, "v%02x.%02x.%02x",
RKISP1_DRIVER_VERSION >> 16,
(RKISP1_DRIVER_VERSION & 0xff00) >> 8,
RKISP1_DRIVER_VERSION & 0x00ff);
dev_info(dev, "rkisp1 driver version: %s\n", rkisp1_version);
match = of_match_node(rkisp1_plat_of_match, node);
isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL);
if (!isp_dev)
return -ENOMEM;
dev_set_drvdata(dev, isp_dev);
isp_dev->dev = dev;
isp_dev->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(isp_dev->grf))
dev_warn(dev, "Missing rockchip,grf property\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
isp_dev->base_addr = devm_ioremap_resource(dev, res);
if (IS_ERR(isp_dev->base_addr))
return PTR_ERR(isp_dev->base_addr);
match_data = match->data;
isp_dev->mipi_irq = -1;
/* there are irq names in dts */
for (i = 0; i < match_data->num_irqs; i++) {
irq = platform_get_irq_byname(pdev, match_data->irqs[i].name);
if (irq < 0) {
dev_err(dev, "no irq %s in dts\n",
match_data->irqs[i].name);
return irq;
}
if (!strcmp(match_data->irqs[i].name, "mipi_irq"))
isp_dev->mipi_irq = irq;
ret = devm_request_irq(dev, irq,
match_data->irqs[i].irq_hdl,
IRQF_SHARED,
dev_driver_string(dev),
dev);
if (ret < 0) {
dev_err(dev, "request %s failed: %d\n",
match_data->irqs[i].name,
ret);
return ret;
}
if (isp_dev->mipi_irq == irq)
disable_irq(isp_dev->mipi_irq);
}
for (i = 0; i < match_data->num_clks; i++) {
struct clk *clk = devm_clk_get(dev, match_data->clks[i]);
if (IS_ERR(clk))
dev_dbg(dev, "failed to get %s\n", match_data->clks[i]);
isp_dev->clks[i] = clk;
}
isp_dev->num_clks = match_data->num_clks;
isp_dev->isp_ver = match_data->isp_ver;
isp_dev->clk_rate_tbl = match_data->clk_rate_tbl;
isp_dev->num_clk_rate_tbl = match_data->num_clk_rate_tbl;
mutex_init(&isp_dev->apilock);
mutex_init(&isp_dev->iqlock);
atomic_set(&isp_dev->pipe.power_cnt, 0);
atomic_set(&isp_dev->pipe.stream_cnt, 0);
atomic_set(&isp_dev->open_cnt, 0);
init_waitqueue_head(&isp_dev->sync_onoff);
isp_dev->pipe.open = rkisp1_pipeline_open;
isp_dev->pipe.close = rkisp1_pipeline_close;
isp_dev->pipe.set_stream = rkisp1_pipeline_set_stream;
rkisp1_stream_init(isp_dev, RKISP1_STREAM_SP);
rkisp1_stream_init(isp_dev, RKISP1_STREAM_MP);
rkisp1_stream_init(isp_dev, RKISP1_STREAM_RAW);
strlcpy(isp_dev->media_dev.model, "rkisp1",
sizeof(isp_dev->media_dev.model));
isp_dev->media_dev.dev = &pdev->dev;
isp_dev->media_dev.ops = &rkisp1_media_ops;
v4l2_dev = &isp_dev->v4l2_dev;
v4l2_dev->mdev = &isp_dev->media_dev;
strlcpy(v4l2_dev->name, "rkisp1", sizeof(v4l2_dev->name));
v4l2_ctrl_handler_init(&isp_dev->ctrl_handler, 5);
v4l2_dev->ctrl_handler = &isp_dev->ctrl_handler;
ret = v4l2_device_register(isp_dev->dev, &isp_dev->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2 device: %d\n",
ret);
return ret;
}
media_device_init(&isp_dev->media_dev);
ret = media_device_register(&isp_dev->media_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register media device: %d\n",
ret);
goto err_unreg_v4l2_dev;
}
/* create & register platefom subdev (from of_node) */
ret = rkisp1_register_platform_subdevs(isp_dev);
if (ret < 0)
goto err_unreg_media_dev;
if (!is_iommu_enable(dev)) {
ret = of_reserved_mem_device_init(dev);
if (ret)
v4l2_warn(v4l2_dev,
"No reserved memory region assign to isp\n");
}
pm_runtime_enable(&pdev->dev);
ret = rkisp1_vs_irq_parse(pdev);
if (ret)
goto err_runtime_disable;
mutex_lock(&rkisp1_dev_mutex);
list_add_tail(&isp_dev->list, &rkisp1_device_list);
mutex_unlock(&rkisp1_dev_mutex);
return 0;
err_runtime_disable:
pm_runtime_disable(&pdev->dev);
err_unreg_media_dev:
media_device_unregister(&isp_dev->media_dev);
err_unreg_v4l2_dev:
v4l2_device_unregister(&isp_dev->v4l2_dev);
return ret;
}
static int rkisp1_plat_remove(struct platform_device *pdev)
{
struct rkisp1_device *isp_dev = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
media_device_unregister(&isp_dev->media_dev);
v4l2_device_unregister(&isp_dev->v4l2_dev);
rkisp1_unregister_params_vdev(&isp_dev->params_vdev);
rkisp1_unregister_stats_vdev(&isp_dev->stats_vdev);
rkisp1_unregister_stream_vdevs(isp_dev);
rkisp1_unregister_isp_subdev(isp_dev);
media_device_cleanup(&isp_dev->media_dev);
return 0;
}
static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
{
struct rkisp1_device *isp_dev = dev_get_drvdata(dev);
if (isp_dev->isp_ver == ISP_V12 || isp_dev->isp_ver == ISP_V13) {
if (isp_dev->mipi_irq >= 0)
disable_irq(isp_dev->mipi_irq);
}
rkisp1_disable_sys_clk(isp_dev);
return pinctrl_pm_select_sleep_state(dev);
}
static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
{
struct rkisp1_device *isp_dev = dev_get_drvdata(dev);
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret < 0)
return ret;
rkisp1_enable_sys_clk(isp_dev);
if (isp_dev->isp_ver == ISP_V12 || isp_dev->isp_ver == ISP_V13) {
writel(0, isp_dev->base_addr + CIF_ISP_CSI0_MASK1);
writel(0, isp_dev->base_addr + CIF_ISP_CSI0_MASK2);
writel(0, isp_dev->base_addr + CIF_ISP_CSI0_MASK3);
if (isp_dev->mipi_irq >= 0)
enable_irq(isp_dev->mipi_irq);
}
return 0;
}
#ifndef MODULE
static int __init rkisp1_clr_unready_dev(void)
{
__rkisp1_clr_unready_dev();
return 0;
}
late_initcall_sync(rkisp1_clr_unready_dev);
#endif
static const struct dev_pm_ops rkisp1_plat_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL)
};
static struct platform_driver rkisp1_plat_drv = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(rkisp1_plat_of_match),
.pm = &rkisp1_plat_pm_ops,
},
.probe = rkisp1_plat_probe,
.remove = rkisp1_plat_remove,
};
module_platform_driver(rkisp1_plat_drv);
MODULE_AUTHOR("Rockchip Camera/ISP team");
MODULE_DESCRIPTION("Rockchip ISP1 platform driver");
MODULE_LICENSE("Dual BSD/GPL");