imx-drm updates and encoder atomic_mode_set helper callback

- add pixel clock and DE polarity configuration from device tree
   using display timing bindings for parallel and LVDS output
 - cleanup/remove trivial functions
 - cleanup and fixes in preparation for capture support
 - add atomic_mode_set helper and use it in imx-ldb - this is an
   alternative to the encoder mode_set callback that passes the
   crtc and connector state instead of just the mode. It allows
   drivers to get information from the attached connector without
   having to iterate over all connectors
 - add drm_bridge support to imx-ldb, for bridges attached via LVDS
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJXrXKYAAoJEFDCiBxwnmDrXocQAJVTaIbgwsq4G5CH3X3M3dRu
 vpIu71k2ww1YLktmE25AkIWKpMAdVQl+DwU3ARwqPtU6QRayolrYNgpmZAUzTy1a
 jk1CBYbhD+mi9uDaWo7HirGdClb0zs6tL1S56VnCA5AD36nix0ho6zkIutzxKFY6
 mFRFcIQPYbSykffyAaeyoVOqKUtQ4mdscMhIutrJABUX4U7PUhYWAWhv5PBvtLGa
 wfL/UA3aoDOK69M9z8ubdKhfKPKUCyU2BIgNdY3T5UunSEhLVAdHsp/1E1nguYQo
 x/ZzcO5+BZpNUeV3XStC4KTr5tl42TwTpXhmV9yVi+EGycRRp51U3GDyh7R3rRbO
 5R5c6iunwRth3R3vmRLLxU89sOfaq5m7qOkOerKtxAwvsAzCizLHyZIQdP1KMHsa
 fC3DmPIJZKdjI0Z5yED8mzEi25aT0rZiTMPwTmSyoKZ5SHH6udfHtraNTJwKsNIY
 Q4+9q21Q/tDV65xgzk/u9VFQl3S4ZuH54gdQ8s3UR0TWEmZyfSQ84qxTNu9Obeq5
 TqjwzJLktJ3yPKR6TEeiT/yRelmTobQGLbdwq+x0dcxfbgh/IE897my3OcsS3MjG
 X0kvNISSbtLZe2ShKX+sVTukQP+88IS84F5skGhkEpityUPkf4fyMo4x/tX/ygpN
 PceRsKJdoCEwoHGgN/jC
 =hj4e
 -----END PGP SIGNATURE-----

Merge tag 'imx-drm-next-2016-08-12' of git://git.pengutronix.de/git/pza/linux into drm-next

imx-drm updates and encoder atomic_mode_set helper callback

- add pixel clock and DE polarity configuration from device tree
  using display timing bindings for parallel and LVDS output
- cleanup/remove trivial functions
- cleanup and fixes in preparation for capture support
- add atomic_mode_set helper and use it in imx-ldb - this is an
  alternative to the encoder mode_set callback that passes the
  crtc and connector state instead of just the mode. It allows
  drivers to get information from the attached connector without
  having to iterate over all connectors
- add drm_bridge support to imx-ldb, for bridges attached via LVDS

* tag 'imx-drm-next-2016-08-12' of git://git.pengutronix.de/git/pza/linux:
  drm/imx-ldb: Add support to drm-bridge
  drm/imx: imx-ldb: use encoder atomic_mode_set callback
  drm/atomic-helper: Add atomic_mode_set helper callback
  drm/imx: Remove imx_drm_handle_vblank()
  gpu: ipu-v3: Add missing IDMAC channel names
  gpu: ipu-v3: rename CSI client device
  gpu: ipu-v3: Fix IRT usage
  gpu: ipu-v3: Fix CSI data format for 16-bit media bus formats
  gpu: ipu-v3: set correct full sensor frame for PAL/NTSC
  gpu: ipu-v3: Add VDI input IDMAC channels
  gpu: ipu-v3: Add ipu_get_num()
  gpu: ipu-cpmem: Add ipu_cpmem_get_burstsize()
  gpu: ipu-cpmem: Add ipu_cpmem_set_uv_offset()
  drm/imx: Remove imx_drm_crtc_id()
  drm/imx: Remove imx_drm_crtc_vblank_get/_put()
  drm/imx: convey the pixelclk-active and de-active flags from DT to the ipu-di driver
  drm: add a helper function to extract 'de-active' and 'pixelclk-active' from DT
This commit is contained in:
Dave Airlie 2016-08-15 16:41:45 +10:00
commit a02b5a155e
15 changed files with 247 additions and 116 deletions

View File

@ -886,8 +886,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
* Each encoder has at most one connector (since we always steal
* it away), so we won't call mode_set hooks twice.
*/
if (funcs && funcs->mode_set)
if (funcs && funcs->atomic_mode_set) {
funcs->atomic_mode_set(encoder, new_crtc_state,
connector->state);
} else if (funcs && funcs->mode_set) {
funcs->mode_set(encoder, mode, adjusted_mode);
}
drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
}

View File

@ -657,6 +657,21 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
}
EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
{
*bus_flags = 0;
if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
*bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
*bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
if (vm->flags & DISPLAY_FLAGS_DE_LOW)
*bus_flags |= DRM_BUS_FLAG_DE_LOW;
if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
*bus_flags |= DRM_BUS_FLAG_DE_HIGH;
}
EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);
#ifdef CONFIG_OF
/**
* of_get_drm_display_mode - get a drm_display_mode from devicetree
@ -672,7 +687,8 @@ EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
* 0 on success, a negative errno code when no of videomode node was found.
*/
int of_get_drm_display_mode(struct device_node *np,
struct drm_display_mode *dmode, int index)
struct drm_display_mode *dmode, u32 *bus_flags,
int index)
{
struct videomode vm;
int ret;
@ -682,6 +698,8 @@ int of_get_drm_display_mode(struct device_node *np,
return ret;
drm_display_mode_from_videomode(&vm, dmode);
if (bus_flags)
drm_bus_flags_from_videomode(&vm, bus_flags);
pr_debug("%s: got %dx%d display mode from %s\n",
of_node_full_name(np), vm.hactive, vm.vactive, np->name);

View File

@ -58,12 +58,6 @@ static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
#endif
unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
return drm_crtc_index(crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
struct imx_drm_device *imxdrm = drm->dev_private;
@ -90,24 +84,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
return 0;
}
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{
return drm_crtc_vblank_get(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
{
drm_crtc_vblank_put(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
{
drm_crtc_handle_vblank(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
struct imx_drm_device *imxdrm = drm->dev_private;

View File

@ -13,8 +13,6 @@ struct drm_plane;
struct imx_drm_crtc;
struct platform_device;
unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
struct imx_crtc_state {
struct drm_crtc_state base;
u32 bus_format;
@ -44,10 +42,6 @@ int imx_drm_init_drm(struct platform_device *pdev,
int preferred_bpp);
int imx_drm_exit_drm(void);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);

View File

@ -57,7 +57,11 @@ struct imx_ldb_channel {
struct imx_ldb *ldb;
struct drm_connector connector;
struct drm_encoder encoder;
/* Defines what is connected to the ldb, only one at a time */
struct drm_panel *panel;
struct drm_bridge *bridge;
struct device_node *child;
struct i2c_adapter *ddc;
int chno;
@ -66,6 +70,7 @@ struct imx_ldb_channel {
struct drm_display_mode mode;
int mode_valid;
u32 bus_format;
u32 bus_flags;
};
static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c)
@ -251,11 +256,13 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
drm_panel_enable(imx_ldb_ch->panel);
}
static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *orig_mode,
struct drm_display_mode *mode)
static void
imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *connector_state)
{
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
struct imx_ldb *ldb = imx_ldb_ch->ldb;
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
unsigned long serial_clk;
@ -297,17 +304,11 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
}
if (!bus_format) {
struct drm_connector *connector;
struct drm_connector *connector = connector_state->connector;
struct drm_display_info *di = &connector->display_info;
drm_for_each_connector(connector, encoder->dev) {
struct drm_display_info *di = &connector->display_info;
if (connector->encoder == encoder &&
di->num_bus_formats) {
bus_format = di->bus_formats[0];
break;
}
}
if (di->num_bus_formats)
bus_format = di->bus_formats[0];
}
imx_ldb_ch_set_bus_format(imx_ldb_ch, bus_format);
}
@ -379,8 +380,13 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
u32 bus_format = imx_ldb_ch->bus_format;
/* Bus format description in DT overrides connector display info. */
if (!bus_format && di->num_bus_formats)
if (!bus_format && di->num_bus_formats) {
bus_format = di->bus_formats[0];
imx_crtc_state->bus_flags = di->bus_flags;
} else {
bus_format = imx_ldb_ch->bus_format;
imx_crtc_state->bus_flags = imx_ldb_ch->bus_flags;
}
switch (bus_format) {
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
@ -420,7 +426,7 @@ static const struct drm_encoder_funcs imx_ldb_encoder_funcs = {
};
static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
.mode_set = imx_ldb_encoder_mode_set,
.atomic_mode_set = imx_ldb_encoder_atomic_mode_set,
.enable = imx_ldb_encoder_enable,
.disable = imx_ldb_encoder_disable,
.atomic_check = imx_ldb_encoder_atomic_check,
@ -466,10 +472,30 @@ static int imx_ldb_register(struct drm_device *drm,
drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs,
DRM_MODE_ENCODER_LVDS, NULL);
drm_connector_helper_add(&imx_ldb_ch->connector,
&imx_ldb_connector_helper_funcs);
drm_connector_init(drm, &imx_ldb_ch->connector,
&imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
if (imx_ldb_ch->bridge) {
imx_ldb_ch->bridge->encoder = encoder;
imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return ret;
}
} else {
/*
* We want to add the connector whenever there is no bridge
* that brings its own, not only when there is a panel. For
* historical reasons, the ldb driver can also work without
* a panel.
*/
drm_connector_helper_add(&imx_ldb_ch->connector,
&imx_ldb_connector_helper_funcs);
drm_connector_init(drm, &imx_ldb_ch->connector,
&imx_ldb_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
encoder);
}
if (imx_ldb_ch->panel) {
ret = drm_panel_attach(imx_ldb_ch->panel,
@ -478,8 +504,6 @@ static int imx_ldb_register(struct drm_device *drm,
return ret;
}
drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
return 0;
}
@ -548,6 +572,46 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
static int imx_ldb_panel_ddc(struct device *dev,
struct imx_ldb_channel *channel, struct device_node *child)
{
struct device_node *ddc_node;
const u8 *edidp;
int ret;
ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
if (ddc_node) {
channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
if (!channel->ddc) {
dev_warn(dev, "failed to get ddc i2c adapter\n");
return -EPROBE_DEFER;
}
}
if (!channel->ddc) {
/* if no DDC available, fallback to hardcoded EDID */
dev_dbg(dev, "no ddc available\n");
edidp = of_get_property(child, "edid",
&channel->edid_len);
if (edidp) {
channel->edid = kmemdup(edidp,
channel->edid_len,
GFP_KERNEL);
} else if (!channel->panel) {
/* fallback to display-timings node */
ret = of_get_drm_display_mode(child,
&channel->mode,
&channel->bus_flags,
OF_USE_NATIVE_MODE);
if (!ret)
channel->mode_valid = 1;
}
}
return 0;
}
static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
@ -555,7 +619,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
const struct of_device_id *of_id =
of_match_device(imx_ldb_dt_ids, dev);
struct device_node *child;
const u8 *edidp;
struct imx_ldb *imx_ldb;
int dual;
int ret;
@ -605,7 +668,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
for_each_child_of_node(np, child) {
struct imx_ldb_channel *channel;
struct device_node *ddc_node;
struct device_node *ep;
int bus_format;
@ -638,46 +700,25 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
remote = of_graph_get_remote_port_parent(ep);
of_node_put(ep);
if (remote)
if (remote) {
channel->panel = of_drm_find_panel(remote);
else
channel->bridge = of_drm_find_bridge(remote);
} else
return -EPROBE_DEFER;
of_node_put(remote);
if (!channel->panel) {
dev_err(dev, "panel not found: %s\n",
if (!channel->panel && !channel->bridge) {
dev_err(dev, "panel/bridge not found: %s\n",
remote->full_name);
return -EPROBE_DEFER;
}
}
ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
if (ddc_node) {
channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
if (!channel->ddc) {
dev_warn(dev, "failed to get ddc i2c adapter\n");
return -EPROBE_DEFER;
}
}
if (!channel->ddc) {
/* if no DDC available, fallback to hardcoded EDID */
dev_dbg(dev, "no ddc available\n");
edidp = of_get_property(child, "edid",
&channel->edid_len);
if (edidp) {
channel->edid = kmemdup(edidp,
channel->edid_len,
GFP_KERNEL);
} else if (!channel->panel) {
/* fallback to display-timings node */
ret = of_get_drm_display_mode(child,
&channel->mode,
OF_USE_NATIVE_MODE);
if (!ret)
channel->mode_valid = 1;
}
/* panel ddc only if there is no bridge */
if (!channel->bridge) {
ret = imx_ldb_panel_ddc(dev, channel, child);
if (ret)
return ret;
}
bus_format = of_get_bus_format(dev, child);

View File

@ -134,7 +134,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
{
struct ipu_crtc *ipu_crtc = dev_id;
imx_drm_handle_vblank(ipu_crtc->imx_crtc);
drm_crtc_handle_vblank(&ipu_crtc->base);
return IRQ_HANDLED;
}

View File

@ -33,6 +33,7 @@ struct imx_parallel_display {
void *edid;
int edid_len;
u32 bus_format;
u32 bus_flags;
struct drm_display_mode mode;
struct drm_panel *panel;
struct drm_bridge *bridge;
@ -80,6 +81,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return -EINVAL;
ret = of_get_drm_display_mode(np, &imxpd->mode,
&imxpd->bus_flags,
OF_USE_NATIVE_MODE);
if (ret)
return ret;
@ -125,11 +127,13 @@ static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_display_info *di = &conn_state->connector->display_info;
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
imx_crtc_state->bus_flags = di->bus_flags;
if (!imxpd->bus_format && di->num_bus_formats)
if (!imxpd->bus_format && di->num_bus_formats) {
imx_crtc_state->bus_flags = di->bus_flags;
imx_crtc_state->bus_format = di->bus_formats[0];
else
} else {
imx_crtc_state->bus_flags = imxpd->bus_flags;
imx_crtc_state->bus_format = imxpd->bus_format;
}
imx_crtc_state->di_hsync_pin = 2;
imx_crtc_state->di_vsync_pin = 3;

View File

@ -45,6 +45,12 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
writel(value, ipu->cm_reg + offset);
}
int ipu_get_num(struct ipu_soc *ipu)
{
return ipu->id;
}
EXPORT_SYMBOL_GPL(ipu_get_num);
void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
{
u32 val;
@ -1004,14 +1010,14 @@ static struct ipu_platform_reg client_reg[] = {
.dma[0] = IPUV3_CHANNEL_CSI0,
.dma[1] = -EINVAL,
},
.name = "imx-ipuv3-camera",
.name = "imx-ipuv3-csi",
}, {
.pdata = {
.csi = 1,
.dma[0] = IPUV3_CHANNEL_CSI1,
.dma[1] = -EINVAL,
},
.name = "imx-ipuv3-camera",
.name = "imx-ipuv3-csi",
}, {
.pdata = {
.di = 0,
@ -1209,6 +1215,7 @@ static int ipu_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(imx_ipu_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct ipu_soc *ipu;
struct resource *res;
unsigned long ipu_base;
@ -1237,6 +1244,7 @@ static int ipu_probe(struct platform_device *pdev)
ipu->channel[i].ipu = ipu;
ipu->devtype = devtype;
ipu->ipu_type = devtype->type;
ipu->id = of_alias_get_id(np, "ipu");
spin_lock_init(&ipu->lock);
mutex_init(&ipu->channel_lock);

View File

@ -253,6 +253,13 @@ void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
{
ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
{
ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
@ -268,6 +275,12 @@ void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
{
return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
}
EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
{
ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);

View File

@ -258,12 +258,8 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
case MEDIA_BUS_FMT_UYVY8_1X16:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
break;
case MEDIA_BUS_FMT_YUYV8_1X16:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
break;
@ -365,10 +361,14 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
{
struct ipu_csi_bus_config cfg;
unsigned long flags;
u32 data = 0;
u32 width, height, data = 0;
fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
/* set default sensor frame width and height */
width = mbus_fmt->width;
height = mbus_fmt->height;
/* Set the CSI_SENS_CONF register remaining fields */
data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
@ -386,11 +386,6 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
ipu_csi_write(csi, data, CSI_SENS_CONF);
/* Setup sensor frame size */
ipu_csi_write(csi,
(mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16),
CSI_SENS_FRM_SIZE);
/* Set CCIR registers */
switch (cfg.clk_mode) {
@ -408,11 +403,12 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
* Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
* Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
*/
height = 625; /* framelines for PAL */
ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
CSI_CCIR_CODE_1);
ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
} else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) {
/*
* NTSC case
@ -422,6 +418,8 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
* Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
* Field1ActiveEnd = 0x4, Field1ActiveStart = 0
*/
height = 525; /* framelines for NTSC */
ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
CSI_CCIR_CODE_1);
ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
@ -447,6 +445,10 @@ int ipu_csi_init_interface(struct ipu_csi *csi,
break;
}
/* Setup sensor frame size */
ipu_csi_write(csi, (width - 1) | ((height - 1) << 16),
CSI_SENS_FRM_SIZE);
dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
ipu_csi_read(csi, CSI_SENS_CONF));
dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",

View File

@ -160,6 +160,7 @@ struct ipu_ic_priv {
spinlock_t lock;
struct ipu_soc *ipu;
int use_count;
int irt_use_count;
struct ipu_ic task[IC_NUM_TASKS];
};
@ -379,8 +380,6 @@ void ipu_ic_task_disable(struct ipu_ic *ic)
ipu_ic_write(ic, ic_conf, IC_CONF);
ic->rotation = ic->graphics = false;
spin_unlock_irqrestore(&priv->lock, flags);
}
EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
@ -629,22 +628,41 @@ unlock:
}
EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
static void ipu_irt_enable(struct ipu_ic *ic)
{
struct ipu_ic_priv *priv = ic->priv;
if (!priv->irt_use_count)
ipu_module_enable(priv->ipu, IPU_CONF_ROT_EN);
priv->irt_use_count++;
}
static void ipu_irt_disable(struct ipu_ic *ic)
{
struct ipu_ic_priv *priv = ic->priv;
if (priv->irt_use_count) {
if (!--priv->irt_use_count)
ipu_module_disable(priv->ipu, IPU_CONF_ROT_EN);
}
}
int ipu_ic_enable(struct ipu_ic *ic)
{
struct ipu_ic_priv *priv = ic->priv;
unsigned long flags;
u32 module = IPU_CONF_IC_EN;
spin_lock_irqsave(&priv->lock, flags);
if (ic->rotation)
module |= IPU_CONF_ROT_EN;
if (!priv->use_count)
ipu_module_enable(priv->ipu, module);
ipu_module_enable(priv->ipu, IPU_CONF_IC_EN);
priv->use_count++;
if (ic->rotation)
ipu_irt_enable(ic);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
@ -655,18 +673,22 @@ int ipu_ic_disable(struct ipu_ic *ic)
{
struct ipu_ic_priv *priv = ic->priv;
unsigned long flags;
u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN;
spin_lock_irqsave(&priv->lock, flags);
priv->use_count--;
if (!priv->use_count)
ipu_module_disable(priv->ipu, module);
ipu_module_disable(priv->ipu, IPU_CONF_IC_EN);
if (priv->use_count < 0)
priv->use_count = 0;
if (ic->rotation)
ipu_irt_disable(ic);
ic->rotation = ic->graphics = false;
spin_unlock_irqrestore(&priv->lock, flags);
return 0;

View File

@ -152,6 +152,7 @@ struct ipu_soc {
void __iomem *cm_reg;
void __iomem *idmac_reg;
int id;
int usecount;
struct clk *clk;

View File

@ -434,7 +434,7 @@ struct drm_cmdline_mode;
struct drm_display_mode *drm_mode_create(struct drm_device *dev);
void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
const struct drm_display_mode *in);
const struct drm_display_mode *in);
int drm_mode_convert_umode(struct drm_display_mode *out,
const struct drm_mode_modeinfo *in);
void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
@ -457,8 +457,9 @@ void drm_display_mode_from_videomode(const struct videomode *vm,
struct drm_display_mode *dmode);
void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
struct videomode *vm);
void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags);
int of_get_drm_display_mode(struct device_node *np,
struct drm_display_mode *dmode,
struct drm_display_mode *dmode, u32 *bus_flags,
int index);
void drm_mode_set_name(struct drm_display_mode *mode);

View File

@ -523,11 +523,40 @@ struct drm_encoder_helper_funcs {
*
* This callback is used both by the legacy CRTC helpers and the atomic
* modeset helpers. It is optional in the atomic helpers.
*
* NOTE:
*
* If the driver uses the atomic modeset helpers and needs to inspect
* the connector state or connector display info during mode setting,
* @atomic_mode_set can be used instead.
*/
void (*mode_set)(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
/**
* @atomic_mode_set:
*
* This callback is used to update the display mode of an encoder.
*
* Note that the display pipe is completely off when this function is
* called. Drivers which need hardware to be running before they program
* the new display mode (because they implement runtime PM) should not
* use this hook, because the helper library calls it only once and not
* every time the display pipeline is suspended using either DPMS or the
* new "ACTIVE" property. Such drivers should instead move all their
* encoder setup into the ->enable() callback.
*
* This callback is used by the atomic modeset helpers in place of the
* @mode_set callback, if set by the driver. It is optional and should
* be used instead of @mode_set if the driver needs to inspect the
* connector state or display info, since there is no direct way to
* go from the encoder to the current connector.
*/
void (*atomic_mode_set)(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
/**
* @get_crtc:
*

View File

@ -97,20 +97,34 @@ enum ipu_channel_irq {
#define IPUV3_CHANNEL_CSI2 2
#define IPUV3_CHANNEL_CSI3 3
#define IPUV3_CHANNEL_VDI_MEM_IC_VF 5
#define IPUV3_CHANNEL_MEM_VDI_PREV 8
#define IPUV3_CHANNEL_MEM_VDI_CUR 9
#define IPUV3_CHANNEL_MEM_VDI_NEXT 10
#define IPUV3_CHANNEL_MEM_IC_PP 11
#define IPUV3_CHANNEL_MEM_IC_PRP_VF 12
#define IPUV3_CHANNEL_VDI_MEM_RECENT 13
#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14
#define IPUV3_CHANNEL_G_MEM_IC_PP 15
#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF_ALPHA 17
#define IPUV3_CHANNEL_G_MEM_IC_PP_ALPHA 18
#define IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB_ALPHA 19
#define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20
#define IPUV3_CHANNEL_IC_PRP_VF_MEM 21
#define IPUV3_CHANNEL_IC_PP_MEM 22
#define IPUV3_CHANNEL_MEM_BG_SYNC 23
#define IPUV3_CHANNEL_MEM_BG_ASYNC 24
#define IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB 25
#define IPUV3_CHANNEL_MEM_VDI_PLANE3_COMB 26
#define IPUV3_CHANNEL_MEM_FG_SYNC 27
#define IPUV3_CHANNEL_MEM_DC_SYNC 28
#define IPUV3_CHANNEL_MEM_FG_ASYNC 29
#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
#define IPUV3_CHANNEL_MEM_FG_ASYNC_ALPHA 33
#define IPUV3_CHANNEL_DC_MEM_READ 40
#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
#define IPUV3_CHANNEL_MEM_DC_COMMAND 42
#define IPUV3_CHANNEL_MEM_DC_COMMAND2 43
#define IPUV3_CHANNEL_MEM_DC_OUTPUT_MASK 44
#define IPUV3_CHANNEL_MEM_ROT_ENC 45
#define IPUV3_CHANNEL_MEM_ROT_VF 46
#define IPUV3_CHANNEL_MEM_ROT_PP 47
@ -118,6 +132,7 @@ enum ipu_channel_irq {
#define IPUV3_CHANNEL_ROT_VF_MEM 49
#define IPUV3_CHANNEL_ROT_PP_MEM 50
#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
#define IPUV3_CHANNEL_MEM_BG_ASYNC_ALPHA 52
int ipu_map_irq(struct ipu_soc *ipu, int irq);
int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
@ -138,6 +153,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
/*
* IPU Common functions
*/
int ipu_get_num(struct ipu_soc *ipu);
void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
void ipu_dump(struct ipu_soc *ipu);
@ -184,8 +200,10 @@ void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres);
void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off);
void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch);
void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,