drm/imx: cleanup and csi improvements
- Remove the unused struct imx_drm_crtc and the unused pipes field from imx_drm_device and replace drm_dev_unref with drm_dev_put. - Extend CSI configuration to support RGB888 and BGR888 capture, as well as 16-bit RGB565 capture via a parallel bus. - Add CPMEM support for negative interlace offsets, which is necessary to support writing captured bottom-top interlaced fields to memory with interleaved lines. -----BEGIN PGP SIGNATURE----- iI4EABYIADYWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCW1G7LxgccGhpbGlwcC56 YWJlbEBnbWFpbC5jb20ACgkQ1YWnJRg3YsBNlQD9FofVPjKCFW79jy/H2bf+hWVB uGhLAxfSsHmLLUSi7Z8A/jFtafSMQDU8uNNbTTHNjofKiFqdjpUljCUgTuA1paUC =oPJE -----END PGP SIGNATURE----- Merge tag 'imx-drm-next-2018-07-20' of git://git.pengutronix.de/git/pza/linux into drm-next drm/imx: cleanup and csi improvements - Remove the unused struct imx_drm_crtc and the unused pipes field from imx_drm_device and replace drm_dev_unref with drm_dev_put. - Extend CSI configuration to support RGB888 and BGR888 capture, as well as 16-bit RGB565 capture via a parallel bus. - Add CPMEM support for negative interlace offsets, which is necessary to support writing captured bottom-top interlaced fields to memory with interleaved lines. Signed-off-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/1532100583.3438.9.camel@pengutronix.de
This commit is contained in:
commit
a6f6cdefd4
@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
struct imx_drm_device {
|
struct imx_drm_device {
|
||||||
struct drm_device *drm;
|
struct drm_device *drm;
|
||||||
unsigned int pipes;
|
|
||||||
struct drm_atomic_state *state;
|
struct drm_atomic_state *state;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -229,7 +228,7 @@ static int imx_drm_bind(struct device *dev)
|
|||||||
imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
|
imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
|
||||||
if (!imxdrm) {
|
if (!imxdrm) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_unref;
|
goto err_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
imxdrm->drm = drm;
|
imxdrm->drm = drm;
|
||||||
@ -306,8 +305,8 @@ err_unbind:
|
|||||||
component_unbind_all(drm->dev, drm);
|
component_unbind_all(drm->dev, drm);
|
||||||
err_kms:
|
err_kms:
|
||||||
drm_mode_config_cleanup(drm);
|
drm_mode_config_cleanup(drm);
|
||||||
err_unref:
|
err_put:
|
||||||
drm_dev_unref(drm);
|
drm_dev_put(drm);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -327,7 +326,7 @@ static void imx_drm_unbind(struct device *dev)
|
|||||||
component_unbind_all(drm->dev, drm);
|
component_unbind_all(drm->dev, drm);
|
||||||
dev_set_drvdata(dev, NULL);
|
dev_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
drm_dev_unref(drm);
|
drm_dev_put(drm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_master_ops imx_drm_ops = {
|
static const struct component_master_ops imx_drm_ops = {
|
||||||
|
@ -10,7 +10,6 @@ struct drm_display_mode;
|
|||||||
struct drm_encoder;
|
struct drm_encoder;
|
||||||
struct drm_framebuffer;
|
struct drm_framebuffer;
|
||||||
struct drm_plane;
|
struct drm_plane;
|
||||||
struct imx_drm_crtc;
|
|
||||||
struct platform_device;
|
struct platform_device;
|
||||||
|
|
||||||
struct imx_crtc_state {
|
struct imx_crtc_state {
|
||||||
|
@ -611,6 +611,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
|
|||||||
return PTR_ERR(imx_ldb->regmap);
|
return PTR_ERR(imx_ldb->regmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* disable LDB by resetting the control register to POR default */
|
||||||
|
regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0);
|
||||||
|
|
||||||
imx_ldb->dev = dev;
|
imx_ldb->dev = dev;
|
||||||
|
|
||||||
if (of_id)
|
if (of_id)
|
||||||
@ -651,14 +654,14 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
|
|||||||
if (ret || i < 0 || i > 1)
|
if (ret || i < 0 || i > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!of_device_is_available(child))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (dual && i > 0) {
|
if (dual && i > 0) {
|
||||||
dev_warn(dev, "dual-channel mode, ignoring second output\n");
|
dev_warn(dev, "dual-channel mode, ignoring second output\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!of_device_is_available(child))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
channel = &imx_ldb->channel[i];
|
channel = &imx_ldb->channel[i];
|
||||||
channel->ldb = imx_ldb;
|
channel->ldb = imx_ldb;
|
||||||
channel->chno = i;
|
channel->chno = i;
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
struct ipu_crtc {
|
struct ipu_crtc {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct drm_crtc base;
|
struct drm_crtc base;
|
||||||
struct imx_drm_crtc *imx_crtc;
|
|
||||||
|
|
||||||
/* plane[0] is the full plane, plane[1] is the partial plane */
|
/* plane[0] is the full plane, plane[1] is the partial plane */
|
||||||
struct ipu_plane *plane[2];
|
struct ipu_plane *plane[2];
|
||||||
|
@ -269,9 +269,20 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
|
|||||||
|
|
||||||
void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
|
void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
|
||||||
{
|
{
|
||||||
|
u32 ilo, sly;
|
||||||
|
|
||||||
|
if (stride < 0) {
|
||||||
|
stride = -stride;
|
||||||
|
ilo = 0x100000 - (stride / 8);
|
||||||
|
} else {
|
||||||
|
ilo = stride / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
sly = (stride * 2) - 1;
|
||||||
|
|
||||||
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
|
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
|
||||||
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8);
|
ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
|
||||||
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1);
|
ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
|
EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
|
||||||
|
|
||||||
|
@ -224,14 +224,18 @@ static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
|
|||||||
* Find the CSI data format and data width for the given V4L2 media
|
* Find the CSI data format and data width for the given V4L2 media
|
||||||
* bus pixel format code.
|
* bus pixel format code.
|
||||||
*/
|
*/
|
||||||
static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
|
static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code,
|
||||||
|
enum v4l2_mbus_type mbus_type)
|
||||||
{
|
{
|
||||||
switch (mbus_code) {
|
switch (mbus_code) {
|
||||||
case MEDIA_BUS_FMT_BGR565_2X8_BE:
|
case MEDIA_BUS_FMT_BGR565_2X8_BE:
|
||||||
case MEDIA_BUS_FMT_BGR565_2X8_LE:
|
case MEDIA_BUS_FMT_BGR565_2X8_LE:
|
||||||
case MEDIA_BUS_FMT_RGB565_2X8_BE:
|
case MEDIA_BUS_FMT_RGB565_2X8_BE:
|
||||||
case MEDIA_BUS_FMT_RGB565_2X8_LE:
|
case MEDIA_BUS_FMT_RGB565_2X8_LE:
|
||||||
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
|
if (mbus_type == V4L2_MBUS_CSI2)
|
||||||
|
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
|
||||||
|
else
|
||||||
|
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
|
||||||
cfg->mipi_dt = MIPI_DT_RGB565;
|
cfg->mipi_dt = MIPI_DT_RGB565;
|
||||||
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
|
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
|
||||||
break;
|
break;
|
||||||
@ -247,6 +251,12 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
|
|||||||
cfg->mipi_dt = MIPI_DT_RGB555;
|
cfg->mipi_dt = MIPI_DT_RGB555;
|
||||||
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
|
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
|
||||||
break;
|
break;
|
||||||
|
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||||
|
case MEDIA_BUS_FMT_BGR888_1X24:
|
||||||
|
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
|
||||||
|
cfg->mipi_dt = MIPI_DT_RGB888;
|
||||||
|
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
|
||||||
|
break;
|
||||||
case MEDIA_BUS_FMT_UYVY8_2X8:
|
case MEDIA_BUS_FMT_UYVY8_2X8:
|
||||||
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
|
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
|
||||||
cfg->mipi_dt = MIPI_DT_YUV422;
|
cfg->mipi_dt = MIPI_DT_YUV422;
|
||||||
@ -318,13 +328,17 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
|
|||||||
/*
|
/*
|
||||||
* Fill a CSI bus config struct from mbus_config and mbus_framefmt.
|
* Fill a CSI bus config struct from mbus_config and mbus_framefmt.
|
||||||
*/
|
*/
|
||||||
static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
|
static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
|
||||||
struct v4l2_mbus_config *mbus_cfg,
|
struct v4l2_mbus_config *mbus_cfg,
|
||||||
struct v4l2_mbus_framefmt *mbus_fmt)
|
struct v4l2_mbus_framefmt *mbus_fmt)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(csicfg, 0, sizeof(*csicfg));
|
memset(csicfg, 0, sizeof(*csicfg));
|
||||||
|
|
||||||
mbus_code_to_bus_cfg(csicfg, mbus_fmt->code);
|
ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
switch (mbus_cfg->type) {
|
switch (mbus_cfg->type) {
|
||||||
case V4L2_MBUS_PARALLEL:
|
case V4L2_MBUS_PARALLEL:
|
||||||
@ -339,7 +353,8 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
|
|||||||
break;
|
break;
|
||||||
case V4L2_MBUS_BT656:
|
case V4L2_MBUS_BT656:
|
||||||
csicfg->ext_vsync = 0;
|
csicfg->ext_vsync = 0;
|
||||||
if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field))
|
if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
|
||||||
|
mbus_fmt->field == V4L2_FIELD_ALTERNATE)
|
||||||
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
|
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
|
||||||
else
|
else
|
||||||
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
|
csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
|
||||||
@ -355,6 +370,8 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
|
|||||||
/* will never get here, keep compiler quiet */
|
/* will never get here, keep compiler quiet */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipu_csi_init_interface(struct ipu_csi *csi,
|
int ipu_csi_init_interface(struct ipu_csi *csi,
|
||||||
@ -364,8 +381,11 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
|
|||||||
struct ipu_csi_bus_config cfg;
|
struct ipu_csi_bus_config cfg;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 width, height, data = 0;
|
u32 width, height, data = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
|
ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* set default sensor frame width and height */
|
/* set default sensor frame width and height */
|
||||||
width = mbus_fmt->width;
|
width = mbus_fmt->width;
|
||||||
@ -586,11 +606,14 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
|
|||||||
struct ipu_csi_bus_config cfg;
|
struct ipu_csi_bus_config cfg;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 temp;
|
u32 temp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (vc > 3)
|
if (vc > 3)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mbus_code_to_bus_cfg(&cfg, mbus_fmt->code);
|
ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&csi->lock, flags);
|
spin_lock_irqsave(&csi->lock, flags);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user