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:
commit
a02b5a155e
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -152,6 +152,7 @@ struct ipu_soc {
|
|||
void __iomem *cm_reg;
|
||||
void __iomem *idmac_reg;
|
||||
|
||||
int id;
|
||||
int usecount;
|
||||
|
||||
struct clk *clk;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue