Commit 5a394f19 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'imx-drm-next-2020-07-20' of git://git.pengutronix.de/pza/linux into drm-next

drm/imx: error path fixes and cleanups

- Fix use after free issue in component bind error path by keeping
  memory allocated as long as the driver is bound. This will be replaced
  with drm managed memory in the next round.
- Fix bus_flags overriding logic in parallel-display.
- Disable regulator in imx-tve bind error path.
- Drop unnecessary best_encoder callback.
- Remove an unused enum in imx-ldb.
- Bail out early on missing panel or bridge in parallel-display to speed
  up -EPROBE_DEFER path.
- Disable both LDB channels in split mode.
- Restore RGB32, BGR32 format support.
- Fix tiled image conversion in case of out of order interrupts.
- Remove a superfluous error message in imx-tve.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/ac4452eb3a989bf5d85b65fd30840a21f15ec301.camel@pengutronix.de
parents fa07634d 408a85e3
...@@ -211,9 +211,8 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, ...@@ -211,9 +211,8 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
if (!pdev->dev.of_node) if (!pdev->dev.of_node)
return -ENODEV; return -ENODEV;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); hdmi = dev_get_drvdata(dev);
if (!hdmi) memset(hdmi, 0, sizeof(*hdmi));
return -ENOMEM;
match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node); match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
plat_data = match->data; plat_data = match->data;
...@@ -237,8 +236,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, ...@@ -237,8 +236,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs); drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
platform_set_drvdata(pdev, hdmi);
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
/* /*
...@@ -268,6 +265,14 @@ static const struct component_ops dw_hdmi_imx_ops = { ...@@ -268,6 +265,14 @@ static const struct component_ops dw_hdmi_imx_ops = {
static int dw_hdmi_imx_probe(struct platform_device *pdev) static int dw_hdmi_imx_probe(struct platform_device *pdev)
{ {
struct imx_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
platform_set_drvdata(pdev, hdmi);
return component_add(&pdev->dev, &dw_hdmi_imx_ops); return component_add(&pdev->dev, &dw_hdmi_imx_ops);
} }
......
...@@ -265,9 +265,10 @@ static void imx_drm_unbind(struct device *dev) ...@@ -265,9 +265,10 @@ static void imx_drm_unbind(struct device *dev)
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
component_unbind_all(drm->dev, drm);
drm_mode_config_cleanup(drm); drm_mode_config_cleanup(drm);
component_unbind_all(drm->dev, drm);
dev_set_drvdata(dev, NULL); dev_set_drvdata(dev, NULL);
drm_dev_put(drm); drm_dev_put(drm);
......
...@@ -156,14 +156,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) ...@@ -156,14 +156,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
return num_modes; return num_modes;
} }
static struct drm_encoder *imx_ldb_connector_best_encoder(
struct drm_connector *connector)
{
struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
return &imx_ldb_ch->encoder;
}
static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
unsigned long serial_clk, unsigned long di_clk) unsigned long serial_clk, unsigned long di_clk)
{ {
...@@ -304,18 +296,19 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) ...@@ -304,18 +296,19 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
{ {
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb; struct imx_ldb *ldb = imx_ldb_ch->ldb;
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
int mux, ret; int mux, ret;
drm_panel_disable(imx_ldb_ch->panel); drm_panel_disable(imx_ldb_ch->panel);
if (imx_ldb_ch == &ldb->channel[0]) if (imx_ldb_ch == &ldb->channel[0] || dual)
ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
else if (imx_ldb_ch == &ldb->channel[1]) if (imx_ldb_ch == &ldb->channel[1] || dual)
ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { if (dual) {
clk_disable_unprepare(ldb->clk[0]); clk_disable_unprepare(ldb->clk[0]);
clk_disable_unprepare(ldb->clk[1]); clk_disable_unprepare(ldb->clk[1]);
} }
...@@ -391,7 +384,6 @@ static const struct drm_connector_funcs imx_ldb_connector_funcs = { ...@@ -391,7 +384,6 @@ static const struct drm_connector_funcs imx_ldb_connector_funcs = {
static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
.get_modes = imx_ldb_connector_get_modes, .get_modes = imx_ldb_connector_get_modes,
.best_encoder = imx_ldb_connector_best_encoder,
}; };
static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
...@@ -473,11 +465,6 @@ static int imx_ldb_register(struct drm_device *drm, ...@@ -473,11 +465,6 @@ static int imx_ldb_register(struct drm_device *drm,
return 0; return 0;
} }
enum {
LVDS_BIT_MAP_SPWG,
LVDS_BIT_MAP_JEIDA
};
struct imx_ldb_bit_mapping { struct imx_ldb_bit_mapping {
u32 bus_format; u32 bus_format;
u32 datawidth; u32 datawidth;
...@@ -590,9 +577,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -590,9 +577,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
int ret; int ret;
int i; int i;
imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL); imx_ldb = dev_get_drvdata(dev);
if (!imx_ldb) memset(imx_ldb, 0, sizeof(*imx_ldb));
return -ENOMEM;
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(imx_ldb->regmap)) { if (IS_ERR(imx_ldb->regmap)) {
...@@ -700,8 +686,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -700,8 +686,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
} }
} }
dev_set_drvdata(dev, imx_ldb);
return 0; return 0;
free_child: free_child:
...@@ -733,6 +717,14 @@ static const struct component_ops imx_ldb_ops = { ...@@ -733,6 +717,14 @@ static const struct component_ops imx_ldb_ops = {
static int imx_ldb_probe(struct platform_device *pdev) static int imx_ldb_probe(struct platform_device *pdev)
{ {
struct imx_ldb *imx_ldb;
imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
if (!imx_ldb)
return -ENOMEM;
platform_set_drvdata(pdev, imx_ldb);
return component_add(&pdev->dev, &imx_ldb_ops); return component_add(&pdev->dev, &imx_ldb_ops);
} }
......
...@@ -260,14 +260,6 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector, ...@@ -260,14 +260,6 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
return MODE_BAD; return MODE_BAD;
} }
static struct drm_encoder *imx_tve_connector_best_encoder(
struct drm_connector *connector)
{
struct imx_tve *tve = con_to_tve(connector);
return &tve->encoder;
}
static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *orig_mode, struct drm_display_mode *orig_mode,
struct drm_display_mode *mode) struct drm_display_mode *mode)
...@@ -345,7 +337,6 @@ static const struct drm_connector_funcs imx_tve_connector_funcs = { ...@@ -345,7 +337,6 @@ static const struct drm_connector_funcs imx_tve_connector_funcs = {
static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
.get_modes = imx_tve_connector_get_modes, .get_modes = imx_tve_connector_get_modes,
.best_encoder = imx_tve_connector_best_encoder,
.mode_valid = imx_tve_connector_mode_valid, .mode_valid = imx_tve_connector_mode_valid,
}; };
...@@ -490,6 +481,13 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) ...@@ -490,6 +481,13 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
return 0; return 0;
} }
static void imx_tve_disable_regulator(void *data)
{
struct imx_tve *tve = data;
regulator_disable(tve->dac_reg);
}
static bool imx_tve_readable_reg(struct device *dev, unsigned int reg) static bool imx_tve_readable_reg(struct device *dev, unsigned int reg)
{ {
return (reg % 4 == 0) && (reg <= 0xdc); return (reg % 4 == 0) && (reg <= 0xdc);
...@@ -542,9 +540,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) ...@@ -542,9 +540,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
int irq; int irq;
int ret; int ret;
tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL); tve = dev_get_drvdata(dev);
if (!tve) memset(tve, 0, sizeof(*tve));
return -ENOMEM;
tve->dev = dev; tve->dev = dev;
spin_lock_init(&tve->lock); spin_lock_init(&tve->lock);
...@@ -594,10 +591,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) ...@@ -594,10 +591,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
} }
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
dev_err(dev, "failed to get irq\n");
return irq; return irq;
}
ret = devm_request_threaded_irq(dev, irq, NULL, ret = devm_request_threaded_irq(dev, irq, NULL,
imx_tve_irq_handler, IRQF_ONESHOT, imx_tve_irq_handler, IRQF_ONESHOT,
...@@ -614,6 +609,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) ...@@ -614,6 +609,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
ret = regulator_enable(tve->dac_reg); ret = regulator_enable(tve->dac_reg);
if (ret) if (ret)
return ret; return ret;
ret = devm_add_action_or_reset(dev, imx_tve_disable_regulator, tve);
if (ret)
return ret;
} }
tve->clk = devm_clk_get(dev, "tve"); tve->clk = devm_clk_get(dev, "tve");
...@@ -655,27 +653,23 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) ...@@ -655,27 +653,23 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
if (ret) if (ret)
return ret; return ret;
dev_set_drvdata(dev, tve);
return 0; return 0;
} }
static void imx_tve_unbind(struct device *dev, struct device *master,
void *data)
{
struct imx_tve *tve = dev_get_drvdata(dev);
if (!IS_ERR(tve->dac_reg))
regulator_disable(tve->dac_reg);
}
static const struct component_ops imx_tve_ops = { static const struct component_ops imx_tve_ops = {
.bind = imx_tve_bind, .bind = imx_tve_bind,
.unbind = imx_tve_unbind,
}; };
static int imx_tve_probe(struct platform_device *pdev) static int imx_tve_probe(struct platform_device *pdev)
{ {
struct imx_tve *tve;
tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
if (!tve)
return -ENOMEM;
platform_set_drvdata(pdev, tve);
return component_add(&pdev->dev, &imx_tve_ops); return component_add(&pdev->dev, &imx_tve_ops);
} }
......
...@@ -433,21 +433,13 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data) ...@@ -433,21 +433,13 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
struct ipu_client_platformdata *pdata = dev->platform_data; struct ipu_client_platformdata *pdata = dev->platform_data;
struct drm_device *drm = data; struct drm_device *drm = data;
struct ipu_crtc *ipu_crtc; struct ipu_crtc *ipu_crtc;
int ret;
ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL); ipu_crtc = dev_get_drvdata(dev);
if (!ipu_crtc) memset(ipu_crtc, 0, sizeof(*ipu_crtc));
return -ENOMEM;
ipu_crtc->dev = dev; ipu_crtc->dev = dev;
ret = ipu_crtc_init(ipu_crtc, pdata, drm); return ipu_crtc_init(ipu_crtc, pdata, drm);
if (ret)
return ret;
dev_set_drvdata(dev, ipu_crtc);
return 0;
} }
static void ipu_drm_unbind(struct device *dev, struct device *master, static void ipu_drm_unbind(struct device *dev, struct device *master,
...@@ -469,6 +461,7 @@ static const struct component_ops ipu_crtc_ops = { ...@@ -469,6 +461,7 @@ static const struct component_ops ipu_crtc_ops = {
static int ipu_drm_probe(struct platform_device *pdev) static int ipu_drm_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ipu_crtc *ipu_crtc;
int ret; int ret;
if (!dev->platform_data) if (!dev->platform_data)
...@@ -478,6 +471,12 @@ static int ipu_drm_probe(struct platform_device *pdev) ...@@ -478,6 +471,12 @@ static int ipu_drm_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
if (!ipu_crtc)
return -ENOMEM;
dev_set_drvdata(dev, ipu_crtc);
return component_add(dev, &ipu_crtc_ops); return component_add(dev, &ipu_crtc_ops);
} }
......
...@@ -88,14 +88,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) ...@@ -88,14 +88,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return num_modes; return num_modes;
} }
static struct drm_encoder *imx_pd_connector_best_encoder(
struct drm_connector *connector)
{
struct imx_parallel_display *imxpd = con_to_imxpd(connector);
return &imxpd->encoder;
}
static void imx_pd_bridge_enable(struct drm_bridge *bridge) static void imx_pd_bridge_enable(struct drm_bridge *bridge)
{ {
struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
...@@ -217,7 +209,7 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, ...@@ -217,7 +209,7 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
if (next_bridge_state) if (next_bridge_state)
bus_flags = next_bridge_state->input_bus_cfg.flags; bus_flags = next_bridge_state->input_bus_cfg.flags;
else if (!imxpd->bus_format && di->num_bus_formats) else if (di->num_bus_formats)
bus_flags = di->bus_flags; bus_flags = di->bus_flags;
else else
bus_flags = imxpd->bus_flags; bus_flags = imxpd->bus_flags;
...@@ -254,7 +246,6 @@ static const struct drm_connector_funcs imx_pd_connector_funcs = { ...@@ -254,7 +246,6 @@ static const struct drm_connector_funcs imx_pd_connector_funcs = {
static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
.get_modes = imx_pd_connector_get_modes, .get_modes = imx_pd_connector_get_modes,
.best_encoder = imx_pd_connector_best_encoder,
}; };
static const struct drm_bridge_funcs imx_pd_bridge_funcs = { static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
...@@ -326,9 +317,14 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -326,9 +317,14 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
u32 bus_format = 0; u32 bus_format = 0;
const char *fmt; const char *fmt;
imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); imxpd = dev_get_drvdata(dev);
if (!imxpd) memset(imxpd, 0, sizeof(*imxpd));
return -ENOMEM;
/* port@1 is the output port */
ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
&imxpd->next_bridge);
if (ret && ret != -ENODEV)
return ret;
edidp = of_get_property(np, "edid", &imxpd->edid_len); edidp = of_get_property(np, "edid", &imxpd->edid_len);
if (edidp) if (edidp)
...@@ -347,20 +343,12 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -347,20 +343,12 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
} }
imxpd->bus_format = bus_format; imxpd->bus_format = bus_format;
/* port@1 is the output port */
ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
&imxpd->next_bridge);
if (ret && ret != -ENODEV)
return ret;
imxpd->dev = dev; imxpd->dev = dev;
ret = imx_pd_register(drm, imxpd); ret = imx_pd_register(drm, imxpd);
if (ret) if (ret)
return ret; return ret;
dev_set_drvdata(dev, imxpd);
return 0; return 0;
} }
...@@ -382,6 +370,14 @@ static const struct component_ops imx_pd_ops = { ...@@ -382,6 +370,14 @@ static const struct component_ops imx_pd_ops = {
static int imx_pd_probe(struct platform_device *pdev) static int imx_pd_probe(struct platform_device *pdev)
{ {
struct imx_parallel_display *imxpd;
imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
if (!imxpd)
return -ENOMEM;
platform_set_drvdata(pdev, imxpd);
return component_add(&pdev->dev, &imx_pd_ops); return component_add(&pdev->dev, &imx_pd_ops);
} }
......
...@@ -124,6 +124,8 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) ...@@ -124,6 +124,8 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
case V4L2_PIX_FMT_RGBX32: case V4L2_PIX_FMT_RGBX32:
case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ARGB32:
case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_XRGB32:
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
return IPUV3_COLORSPACE_RGB; return IPUV3_COLORSPACE_RGB;
default: default:
return IPUV3_COLORSPACE_UNKNOWN; return IPUV3_COLORSPACE_UNKNOWN;
......
...@@ -137,6 +137,17 @@ struct ipu_image_convert_ctx; ...@@ -137,6 +137,17 @@ struct ipu_image_convert_ctx;
struct ipu_image_convert_chan; struct ipu_image_convert_chan;
struct ipu_image_convert_priv; struct ipu_image_convert_priv;
enum eof_irq_mask {
EOF_IRQ_IN = BIT(0),
EOF_IRQ_ROT_IN = BIT(1),
EOF_IRQ_OUT = BIT(2),
EOF_IRQ_ROT_OUT = BIT(3),
};
#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT | \
EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
struct ipu_image_convert_ctx { struct ipu_image_convert_ctx {
struct ipu_image_convert_chan *chan; struct ipu_image_convert_chan *chan;
...@@ -173,6 +184,9 @@ struct ipu_image_convert_ctx { ...@@ -173,6 +184,9 @@ struct ipu_image_convert_ctx {
/* where to place converted tile in dest image */ /* where to place converted tile in dest image */
unsigned int out_tile_map[MAX_TILES]; unsigned int out_tile_map[MAX_TILES];
/* mask of completed EOF irqs at every tile conversion */
enum eof_irq_mask eof_mask;
struct list_head list; struct list_head list;
}; };
...@@ -189,6 +203,8 @@ struct ipu_image_convert_chan { ...@@ -189,6 +203,8 @@ struct ipu_image_convert_chan {
struct ipuv3_channel *rotation_out_chan; struct ipuv3_channel *rotation_out_chan;
/* the IPU end-of-frame irqs */ /* the IPU end-of-frame irqs */
int in_eof_irq;
int rot_in_eof_irq;
int out_eof_irq; int out_eof_irq;
int rot_out_eof_irq; int rot_out_eof_irq;
...@@ -1380,6 +1396,9 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile) ...@@ -1380,6 +1396,9 @@ static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n", dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
__func__, chan->ic_task, ctx, run, tile, dst_tile); __func__, chan->ic_task, ctx, run, tile, dst_tile);
/* clear EOF irq mask */
ctx->eof_mask = 0;
if (ipu_rot_mode_is_irt(ctx->rot_mode)) { if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
/* swap width/height for resizer */ /* swap width/height for resizer */
dest_width = d_image->tile[dst_tile].height; dest_width = d_image->tile[dst_tile].height;
...@@ -1615,7 +1634,7 @@ static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx) ...@@ -1615,7 +1634,7 @@ static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
} }
/* hold irqlock when calling */ /* hold irqlock when calling */
static irqreturn_t do_irq(struct ipu_image_convert_run *run) static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
{ {
struct ipu_image_convert_ctx *ctx = run->ctx; struct ipu_image_convert_ctx *ctx = run->ctx;
struct ipu_image_convert_chan *chan = ctx->chan; struct ipu_image_convert_chan *chan = ctx->chan;
...@@ -1700,6 +1719,7 @@ static irqreturn_t do_irq(struct ipu_image_convert_run *run) ...@@ -1700,6 +1719,7 @@ static irqreturn_t do_irq(struct ipu_image_convert_run *run)
ctx->cur_buf_num ^= 1; ctx->cur_buf_num ^= 1;
} }
ctx->eof_mask = 0; /* clear EOF irq mask for next tile */
ctx->next_tile++; ctx->next_tile++;
return IRQ_HANDLED; return IRQ_HANDLED;
done: done:
...@@ -1709,13 +1729,15 @@ static irqreturn_t do_irq(struct ipu_image_convert_run *run) ...@@ -1709,13 +1729,15 @@ static irqreturn_t do_irq(struct ipu_image_convert_run *run)
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
} }
static irqreturn_t norotate_irq(int irq, void *data) static irqreturn_t eof_irq(int irq, void *data)
{ {
struct ipu_image_convert_chan *chan = data; struct ipu_image_convert_chan *chan = data;
struct ipu_image_convert_priv *priv = chan->priv;
struct ipu_image_convert_ctx *ctx; struct ipu_image_convert_ctx *ctx;
struct ipu_image_convert_run *run; struct ipu_image_convert_run *run;
irqreturn_t ret = IRQ_HANDLED;
bool tile_complete = false;
unsigned long flags; unsigned long flags;
irqreturn_t ret;
spin_lock_irqsave(&chan->irqlock, flags); spin_lock_irqsave(&chan->irqlock, flags);
...@@ -1728,46 +1750,33 @@ static irqreturn_t norotate_irq(int irq, void *data) ...@@ -1728,46 +1750,33 @@ static irqreturn_t norotate_irq(int irq, void *data)
ctx = run->ctx; ctx = run->ctx;
if (ipu_rot_mode_is_irt(ctx->rot_mode)) { if (irq == chan->in_eof_irq) {
/* this is a rotation operation, just ignore */ ctx->eof_mask |= EOF_IRQ_IN;
spin_unlock_irqrestore(&chan->irqlock, flags); } else if (irq == chan->out_eof_irq) {
return IRQ_HANDLED; ctx->eof_mask |= EOF_IRQ_OUT;
} } else if (irq == chan->rot_in_eof_irq ||
irq == chan->rot_out_eof_irq) {
ret = do_irq(run); if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
out: /* this was NOT a rotation op, shouldn't happen */
spin_unlock_irqrestore(&chan->irqlock, flags); dev_err(priv->ipu->dev,
return ret; "Unexpected rotation interrupt\n");
} goto out;
}
static irqreturn_t rotate_irq(int irq, void *data) ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
{ EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT;
struct ipu_image_convert_chan *chan = data; } else {
struct ipu_image_convert_priv *priv = chan->priv; dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
struct ipu_image_convert_ctx *ctx;
struct ipu_image_convert_run *run;
unsigned long flags;
irqreturn_t ret;
spin_lock_irqsave(&chan->irqlock, flags);
/* get current run and its context */
run = chan->current_run;
if (!run) {
ret = IRQ_NONE; ret = IRQ_NONE;
goto out; goto out;
} }
ctx = run->ctx; if (ipu_rot_mode_is_irt(ctx->rot_mode))
tile_complete = (ctx->eof_mask == EOF_IRQ_ROT_COMPLETE);
if (!ipu_rot_mode_is_irt(ctx->rot_mode)) { else
/* this was NOT a rotation operation, shouldn't happen */ tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE);
dev_err(priv->ipu->dev, "Unexpected rotation interrupt\n");
spin_unlock_irqrestore(&chan->irqlock, flags);
return IRQ_HANDLED;
}
ret = do_irq(run); if (tile_complete)
ret = do_tile_complete(run);
out: out:
spin_unlock_irqrestore(&chan->irqlock, flags); spin_unlock_irqrestore(&chan->irqlock, flags);
return ret; return ret;
...@@ -1801,6 +1810,10 @@ static void force_abort(struct ipu_image_convert_ctx *ctx) ...@@ -1801,6 +1810,10 @@ static void force_abort(struct ipu_image_convert_ctx *ctx)
static void release_ipu_resources(struct ipu_image_convert_chan *chan) static void release_ipu_resources(struct ipu_image_convert_chan *chan)
{ {
if (chan->in_eof_irq >= 0)
free_irq(chan->in_eof_irq, chan);
if (chan->rot_in_eof_irq >= 0)
free_irq(chan->rot_in_eof_irq, chan);
if (chan->out_eof_irq >= 0) if (chan->out_eof_irq >= 0)
free_irq(chan->out_eof_irq, chan); free_irq(chan->out_eof_irq, chan);
if (chan->rot_out_eof_irq >= 0) if (chan->rot_out_eof_irq >= 0)
...@@ -1819,7 +1832,27 @@ static void release_ipu_resources(struct ipu_image_convert_chan *chan) ...@@ -1819,7 +1832,27 @@ static void release_ipu_resources(struct ipu_image_convert_chan *chan)
chan->in_chan = chan->out_chan = chan->rotation_in_chan = chan->in_chan = chan->out_chan = chan->rotation_in_chan =
chan->rotation_out_chan = NULL; chan->rotation_out_chan = NULL;
chan->out_eof_irq = chan->rot_out_eof_irq = -1; chan->in_eof_irq = -1;
chan->rot_in_eof_irq = -1;
chan->out_eof_irq = -1;
chan->rot_out_eof_irq = -1;
}
static int get_eof_irq(struct ipu_image_convert_chan *chan,
struct ipuv3_channel *channel)
{
struct ipu_image_convert_priv *priv = chan->priv;
int ret, irq;
irq = ipu_idmac_channel_irq(priv->ipu, channel, IPU_IRQ_EOF);
ret = request_threaded_irq(irq, eof_irq, do_bh, 0, "ipu-ic", chan);
if (ret < 0) {
dev_err(priv->ipu->dev, "could not acquire irq %d\n", irq);
return ret;
}
return irq;
} }
static int get_ipu_resources(struct ipu_image_convert_chan *chan) static int get_ipu_resources(struct ipu_image_convert_chan *chan)
...@@ -1855,31 +1888,33 @@ static int get_ipu_resources(struct ipu_image_convert_chan *chan) ...@@ -1855,31 +1888,33 @@ static int get_ipu_resources(struct ipu_image_convert_chan *chan)
} }
/* acquire the EOF interrupts */ /* acquire the EOF interrupts */
chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu, ret = get_eof_irq(chan, chan->in_chan);
chan->out_chan, if (ret < 0) {
IPU_IRQ_EOF); chan->in_eof_irq = -1;
goto err;
}
chan->in_eof_irq = ret;
ret = request_threaded_irq(chan->out_eof_irq, norotate_irq, do_bh, ret = get_eof_irq(chan, chan->rotation_in_chan);
0, "ipu-ic", chan);
if (ret < 0) { if (ret < 0) {
dev_err(priv->ipu->dev, "could not acquire irq %d\n", chan->rot_in_eof_irq = -1;
chan->out_eof_irq);
chan->out_eof_irq = -1;
goto err; goto err;
} }
chan->rot_in_eof_irq = ret;
chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu, ret = get_eof_irq(chan, chan->out_chan);
chan->rotation_out_chan, if (ret < 0) {
IPU_IRQ_EOF); chan->out_eof_irq = -1;
goto err;
}
chan->out_eof_irq = ret;
ret = request_threaded_irq(chan->rot_out_eof_irq, rotate_irq, do_bh, ret = get_eof_irq(chan, chan->rotation_out_chan);
0, "ipu-ic", chan);
if (ret < 0) { if (ret < 0) {
dev_err(priv->ipu->dev, "could not acquire irq %d\n",
chan->rot_out_eof_irq);
chan->rot_out_eof_irq = -1; chan->rot_out_eof_irq = -1;
goto err; goto err;
} }
chan->rot_out_eof_irq = ret;
return 0; return 0;
err: err:
...@@ -2458,6 +2493,8 @@ int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev) ...@@ -2458,6 +2493,8 @@ int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
chan->ic_task = i; chan->ic_task = i;
chan->priv = priv; chan->priv = priv;
chan->dma_ch = &image_convert_dma_chan[i]; chan->dma_ch = &image_convert_dma_chan[i];
chan->in_eof_irq = -1;
chan->rot_in_eof_irq = -1;
chan->out_eof_irq = -1; chan->out_eof_irq = -1;
chan->rot_out_eof_irq = -1; chan->rot_out_eof_irq = -1;
......
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