Commit a6f6cdef authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave Airlie <airlied@redhat.com>

Link: https://patchwork.freedesktop.org/patch/msgid/1532100583.3438.9.camel@pengutronix.de
parents 50077507 81f2b25a
...@@ -37,7 +37,6 @@ ...@@ -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) ...@@ -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 @@ static int imx_drm_bind(struct device *dev) ...@@ -306,8 +305,8 @@ static int imx_drm_bind(struct device *dev)
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) ...@@ -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; ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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); ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment