diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss')
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/base.c | 144 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/display.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dpi.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dsi.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dss-of.c | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dss.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi4.c | 54 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/hdmi5.c | 54 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/omapdss.h | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/output.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/sdi.c | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/venc.c | 229 |
13 files changed, 421 insertions, 518 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 472f56e3de70..f8dad99013e8 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -19,6 +19,7 @@ #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> #include "dss.h" #include "omapdss.h" @@ -112,13 +113,12 @@ void omapdss_device_put(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omapdss_device_put); -struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, - unsigned int port) +struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node) { struct omap_dss_device *dssdev; list_for_each_entry(dssdev, &omapdss_devices_list, list) { - if (dssdev->dev->of_node == src && dssdev->of_ports & BIT(port)) + if (dssdev->dev->of_node == node) return omapdss_device_get(dssdev); } @@ -126,13 +126,10 @@ struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, } /* - * Search for the next device starting at @from. The type argument specfies - * which device types to consider when searching. Searching for multiple types - * is supported by and'ing their type flags. Release the reference to the @from - * device, and acquire a reference to the returned device if found. + * Search for the next output device starting at @from. Release the reference to + * the @from device, and acquire a reference to the returned device if found. */ -struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from, - enum omap_dss_device_type type) +struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) { struct omap_dss_device *dssdev; struct list_head *list; @@ -160,15 +157,8 @@ struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from, goto done; } - /* - * Accept display entities if the display type is requested, - * and output entities if the output type is requested. - */ - if ((type & OMAP_DSS_DEVICE_TYPE_DISPLAY) && - !dssdev->output_type) - goto done; - if ((type & OMAP_DSS_DEVICE_TYPE_OUTPUT) && dssdev->id && - dssdev->next) + if (dssdev->id && + (dssdev->next || dssdev->bridge || dssdev->panel)) goto done; } @@ -183,7 +173,12 @@ done: mutex_unlock(&omapdss_devices_lock); return dssdev; } -EXPORT_SYMBOL(omapdss_device_get_next); +EXPORT_SYMBOL(omapdss_device_next_output); + +static bool omapdss_device_is_connected(struct omap_dss_device *dssdev) +{ + return dssdev->dss; +} int omapdss_device_connect(struct dss_device *dss, struct omap_dss_device *src, @@ -191,7 +186,19 @@ int omapdss_device_connect(struct dss_device *dss, { int ret; - dev_dbg(dst->dev, "connect\n"); + dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n", + src ? dev_name(src->dev) : "NULL", + dst ? dev_name(dst->dev) : "NULL"); + + if (!dst) { + /* + * The destination is NULL when the source is connected to a + * bridge or panel instead of a DSS device. Stop here, we will + * attach the bridge or panel later when we will have a DRM + * encoder. + */ + return src && (src->bridge || src->panel) ? 0 : -EINVAL; + } if (omapdss_device_is_connected(dst)) return -EBUSY; @@ -204,12 +211,6 @@ int omapdss_device_connect(struct dss_device *dss, return ret; } - if (src) { - WARN_ON(src->dst); - dst->src = src; - src->dst = dst; - } - return 0; } EXPORT_SYMBOL_GPL(omapdss_device_connect); @@ -217,19 +218,20 @@ EXPORT_SYMBOL_GPL(omapdss_device_connect); void omapdss_device_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dev_dbg(dst->dev, "disconnect\n"); + struct dss_device *dss = src ? src->dss : dst->dss; - if (!dst->id && !omapdss_device_is_connected(dst)) { - WARN_ON(dst->output_type); + dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n", + src ? dev_name(src->dev) : "NULL", + dst ? dev_name(dst->dev) : "NULL"); + + if (!dst) { + WARN_ON(!src->bridge && !src->panel); return; } - if (src) { - if (WARN_ON(dst != src->dst)) - return; - - dst->src = NULL; - src->dst = NULL; + if (!dst->id && !omapdss_device_is_connected(dst)) { + WARN_ON(!dst->display); + return; } WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED); @@ -239,6 +241,58 @@ void omapdss_device_disconnect(struct omap_dss_device *src, } EXPORT_SYMBOL_GPL(omapdss_device_disconnect); +void omapdss_device_pre_enable(struct omap_dss_device *dssdev) +{ + if (!dssdev) + return; + + omapdss_device_pre_enable(dssdev->next); + + if (dssdev->ops->pre_enable) + dssdev->ops->pre_enable(dssdev); +} +EXPORT_SYMBOL_GPL(omapdss_device_pre_enable); + +void omapdss_device_enable(struct omap_dss_device *dssdev) +{ + if (!dssdev) + return; + + if (dssdev->ops->enable) + dssdev->ops->enable(dssdev); + + omapdss_device_enable(dssdev->next); + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; +} +EXPORT_SYMBOL_GPL(omapdss_device_enable); + +void omapdss_device_disable(struct omap_dss_device *dssdev) +{ + if (!dssdev) + return; + + omapdss_device_disable(dssdev->next); + + if (dssdev->ops->disable) + dssdev->ops->disable(dssdev); +} +EXPORT_SYMBOL_GPL(omapdss_device_disable); + +void omapdss_device_post_disable(struct omap_dss_device *dssdev) +{ + if (!dssdev) + return; + + if (dssdev->ops->post_disable) + dssdev->ops->post_disable(dssdev); + + omapdss_device_post_disable(dssdev->next); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +} +EXPORT_SYMBOL_GPL(omapdss_device_post_disable); + /* ----------------------------------------------------------------------------- * Components Handling */ @@ -249,6 +303,7 @@ struct omapdss_comp_node { struct list_head list; struct device_node *node; bool dss_core_component; + const char *compat; }; static bool omapdss_list_contains(const struct device_node *node) @@ -266,13 +321,20 @@ static bool omapdss_list_contains(const struct device_node *node) static void omapdss_walk_device(struct device *dev, struct device_node *node, bool dss_core) { + struct omapdss_comp_node *comp; struct device_node *n; - struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp), - GFP_KERNEL); + const char *compat; + int ret; + ret = of_property_read_string(node, "compatible", &compat); + if (ret < 0) + return; + + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (comp) { comp->node = node; comp->dss_core_component = dss_core; + comp->compat = compat; list_add(&comp->list, &omapdss_comp_list); } @@ -312,12 +374,8 @@ void omapdss_gather_components(struct device *dev) omapdss_walk_device(dev, dev->of_node, true); - for_each_available_child_of_node(dev->of_node, child) { - if (!of_find_property(child, "compatible", NULL)) - continue; - + for_each_available_child_of_node(dev->of_node, child) omapdss_walk_device(dev, child, true); - } } EXPORT_SYMBOL(omapdss_gather_components); @@ -325,6 +383,8 @@ static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp) { if (comp->dss_core_component) return true; + if (!strstarts(comp->compat, "omapdss,")) + return true; if (omapdss_device_is_registered(comp->node)) return true; diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 34b2a4ef63a4..e93f61a567a8 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -23,6 +23,9 @@ #include <linux/kernel.h> #include <linux/of.h> +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> + #include "omapdss.h" static int disp_num_counter; @@ -39,8 +42,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev) if (id < 0) id = disp_num_counter++; - dssdev->alias_id = id; - /* Use 'label' property for name, if it exists */ of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name); @@ -58,3 +59,22 @@ struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output) return omapdss_device_get(output); } EXPORT_SYMBOL_GPL(omapdss_display_get); + +int omapdss_display_get_modes(struct drm_connector *connector, + const struct videomode *vm) +{ + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (!mode) + return 0; + + drm_display_mode_from_videomode(vm, mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + return 1; +} +EXPORT_SYMBOL_GPL(omapdss_display_get_modes); diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index ca4f3c4c6318..cc78dfa07f04 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -47,8 +47,8 @@ struct dpi_data { struct mutex lock; - struct videomode vm; struct dss_lcd_mgr_config mgr_config; + unsigned long pixelclock; int data_lines; struct omap_dss_device output; @@ -347,16 +347,15 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, static int dpi_set_mode(struct dpi_data *dpi) { - const struct videomode *vm = &dpi->vm; int lck_div = 0, pck_div = 0; unsigned long fck = 0; int r = 0; if (dpi->pll) r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel, - vm->pixelclock, &fck, &lck_div, &pck_div); + dpi->pixelclock, &fck, &lck_div, &pck_div); else - r = dpi_set_dispc_clk(dpi, vm->pixelclock, &fck, + r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck, &lck_div, &pck_div); if (r) return r; @@ -378,7 +377,7 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config); } -static int dpi_display_enable(struct omap_dss_device *dssdev) +static void dpi_display_enable(struct omap_dss_device *dssdev) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); struct omap_dss_device *out = &dpi->output; @@ -386,12 +385,6 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dpi->lock); - if (!out->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err_no_out_mgr; - } - if (dpi->vdds_dsi_reg) { r = regulator_enable(dpi->vdds_dsi_reg); if (r) @@ -426,7 +419,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) mutex_unlock(&dpi->lock); - return 0; + return; err_mgr_enable: err_set_mode: @@ -439,9 +432,7 @@ err_get_dispc: if (dpi->vdds_dsi_reg) regulator_disable(dpi->vdds_dsi_reg); err_reg_enable: -err_no_out_mgr: mutex_unlock(&dpi->lock); - return r; } static void dpi_display_disable(struct omap_dss_device *dssdev) @@ -467,7 +458,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) } static void dpi_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); @@ -475,13 +466,13 @@ static void dpi_set_timings(struct omap_dss_device *dssdev, mutex_lock(&dpi->lock); - dpi->vm = *vm; + dpi->pixelclock = mode->clock * 1000; mutex_unlock(&dpi->lock); } static int dpi_check_timings(struct omap_dss_device *dssdev, - struct videomode *vm) + struct drm_display_mode *mode) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); int lck_div, pck_div; @@ -490,20 +481,20 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, struct dpi_clk_calc_ctx ctx; bool ok; - if (vm->hactive % 8 != 0) + if (mode->hdisplay % 8 != 0) return -EINVAL; - if (vm->pixelclock == 0) + if (mode->clock == 0) return -EINVAL; if (dpi->pll) { - ok = dpi_pll_clk_calc(dpi, vm->pixelclock, &ctx); + ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx); if (!ok) return -EINVAL; fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; } else { - ok = dpi_dss_clk_calc(dpi, vm->pixelclock, &ctx); + ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx); if (!ok) return -EINVAL; @@ -515,7 +506,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, pck = fck / lck_div / pck_div; - vm->pixelclock = pck; + mode->clock = pck / 1000; return 0; } @@ -596,23 +587,15 @@ static int dpi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { struct dpi_data *dpi = dpi_get_data_from_dssdev(dst); - int r; dpi_init_pll(dpi); - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void dpi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -651,25 +634,15 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port) out->dev = &dpi->pdev->dev; out->id = OMAP_DSS_OUTPUT_DPI; - out->output_type = OMAP_DISPLAY_TYPE_DPI; + out->type = OMAP_DISPLAY_TYPE_DPI; out->dispc_channel = dpi_get_channel(dpi); out->of_ports = BIT(port_num); out->ops = &dpi_ops; out->owner = THIS_MODULE; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -681,9 +654,8 @@ static void dpi_uninit_output_port(struct device_node *port) struct dpi_data *dpi = port->data; struct omap_dss_device *out = &dpi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static const struct soc_device_attribute dpi_soc_devices[] = { diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 64fb788b6647..5202862d89b5 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1342,12 +1342,9 @@ static int dsi_pll_enable(struct dss_pll *pll) */ dsi_enable_scp_clk(dsi); - if (!dsi->vdds_dsi_enabled) { - r = regulator_enable(dsi->vdds_dsi_reg); - if (r) - goto err0; - dsi->vdds_dsi_enabled = true; - } + r = regulator_enable(dsi->vdds_dsi_reg); + if (r) + goto err0; /* XXX PLL does not come out of reset without this... */ dispc_pck_free_enable(dsi->dss->dispc, 1); @@ -1372,36 +1369,25 @@ static int dsi_pll_enable(struct dss_pll *pll) return 0; err1: - if (dsi->vdds_dsi_enabled) { - regulator_disable(dsi->vdds_dsi_reg); - dsi->vdds_dsi_enabled = false; - } + regulator_disable(dsi->vdds_dsi_reg); err0: dsi_disable_scp_clk(dsi); dsi_runtime_put(dsi); return r; } -static void dsi_pll_uninit(struct dsi_data *dsi, bool disconnect_lanes) +static void dsi_pll_disable(struct dss_pll *pll) { + struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); + dsi_pll_power(dsi, DSI_PLL_POWER_OFF); - if (disconnect_lanes) { - WARN_ON(!dsi->vdds_dsi_enabled); - regulator_disable(dsi->vdds_dsi_reg); - dsi->vdds_dsi_enabled = false; - } + + regulator_disable(dsi->vdds_dsi_reg); dsi_disable_scp_clk(dsi); dsi_runtime_put(dsi); - DSSDBG("PLL uninit done\n"); -} - -static void dsi_pll_disable(struct dss_pll *pll) -{ - struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); - - dsi_pll_uninit(dsi, true); + DSSDBG("PLL disable done\n"); } static int dsi_dump_dsi_clocks(struct seq_file *s, void *p) @@ -3753,19 +3739,13 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct dsi_data *dsi = to_dsi_data(dssdev); int bpp = dsi_get_pixel_size(dsi->pix_fmt); - struct omap_dss_device *out = &dsi->output; u8 data_type; u16 word_count; int r; - if (!out->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - return -ENODEV; - } - r = dsi_display_init_dispc(dsi); if (r) - goto err_init_dispc; + return r; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { switch (dsi->pix_fmt) { @@ -3814,7 +3794,6 @@ err_mgr_enable: } err_pix_fmt: dsi_display_uninit_dispc(dsi); -err_init_dispc: return r; } @@ -4096,11 +4075,11 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) r = dss_pll_enable(&dsi->pll); if (r) - goto err0; + return r; r = dsi_configure_dsi_clocks(dsi); if (r) - goto err1; + goto err0; dss_select_dsi_clk_source(dsi->dss, dsi->module_id, dsi->module_id == 0 ? @@ -4108,6 +4087,14 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) DSSDBG("PLL OK\n"); + if (!dsi->vdds_dsi_enabled) { + r = regulator_enable(dsi->vdds_dsi_reg); + if (r) + goto err1; + + dsi->vdds_dsi_enabled = true; + } + r = dsi_cio_init(dsi); if (r) goto err2; @@ -4136,10 +4123,13 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) err3: dsi_cio_uninit(dsi); err2: - dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); + regulator_disable(dsi->vdds_dsi_reg); + dsi->vdds_dsi_enabled = false; err1: - dss_pll_disable(&dsi->pll); + dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); err0: + dss_pll_disable(&dsi->pll); + return r; } @@ -4158,13 +4148,18 @@ static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes, dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); dsi_cio_uninit(dsi); - dsi_pll_uninit(dsi, disconnect_lanes); + dss_pll_disable(&dsi->pll); + + if (disconnect_lanes) { + regulator_disable(dsi->vdds_dsi_reg); + dsi->vdds_dsi_enabled = false; + } } -static int dsi_display_enable(struct omap_dss_device *dssdev) +static void dsi_display_enable(struct omap_dss_device *dssdev) { struct dsi_data *dsi = to_dsi_data(dssdev); - int r = 0; + int r; DSSDBG("dsi_display_enable\n"); @@ -4184,14 +4179,13 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) mutex_unlock(&dsi->lock); - return 0; + return; err_init_dsi: dsi_runtime_put(dsi); err_get_dsi: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); - return r; } static void dsi_display_disable(struct omap_dss_device *dssdev, @@ -4888,21 +4882,12 @@ static int dsi_get_clocks(struct dsi_data *dsi) static int dsi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void dsi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -5138,29 +5123,19 @@ static int dsi_init_output(struct dsi_data *dsi) out->id = dsi->module_id == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; - out->output_type = OMAP_DISPLAY_TYPE_DSI; + out->type = OMAP_DISPLAY_TYPE_DSI; out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; out->dispc_channel = dsi_get_channel(dsi); out->ops = &dsi_ops; out->owner = THIS_MODULE; out->of_ports = BIT(0); - out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE + out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_NEGEDGE; - - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } + | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE; - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -5171,9 +5146,8 @@ static void dsi_uninit_output(struct dsi_data *dsi) { struct omap_dss_device *out = &dsi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static int dsi_probe_of(struct dsi_data *dsi) diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c index 0422597ac6b0..b2094055c5fc 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c @@ -12,71 +12,25 @@ * more details. */ -#include <linux/device.h> #include <linux/err.h> -#include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> -#include <linux/seq_file.h> #include "omapdss.h" -static struct device_node * -dss_of_port_get_parent_device(struct device_node *port) -{ - struct device_node *np; - int i; - - if (!port) - return NULL; - - np = of_get_parent(port); - - for (i = 0; i < 2 && np; ++i) { - struct property *prop; - - prop = of_find_property(np, "compatible", NULL); - - if (prop) - return np; - - np = of_get_next_parent(np); - } - - return NULL; -} - struct omap_dss_device * omapdss_of_find_connected_device(struct device_node *node, unsigned int port) { - struct device_node *src_node; - struct device_node *src_port; - struct device_node *ep; - struct omap_dss_device *src; - u32 port_number = 0; + struct device_node *remote_node; + struct omap_dss_device *dssdev; - /* Get the endpoint... */ - ep = of_graph_get_endpoint_by_regs(node, port, 0); - if (!ep) + remote_node = of_graph_get_remote_node(node, port, 0); + if (!remote_node) return NULL; - /* ... and its remote port... */ - src_port = of_graph_get_remote_port(ep); - of_node_put(ep); - if (!src_port) - return NULL; - - /* ... and the remote port's number and parent... */ - of_property_read_u32(src_port, "reg", &port_number); - src_node = dss_of_port_get_parent_device(src_port); - of_node_put(src_port); - if (!src_node) - return ERR_PTR(-EINVAL); - - /* ... and finally the connected device. */ - src = omapdss_find_device_by_port(src_node, port_number); - of_node_put(src_node); + dssdev = omapdss_find_device_by_node(remote_node); + of_node_put(remote_node); - return src ? src : ERR_PTR(-EPROBE_DEFER); + return dssdev ? dssdev : ERR_PTR(-EPROBE_DEFER); } EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device); diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 7553c7fc1c45..55e68863ef15 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1560,7 +1560,7 @@ static void dss_shutdown(struct platform_device *pdev) DSSDBG("shutdown\n"); - for_each_dss_display(dssdev) { + for_each_dss_output(dssdev) { if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) dssdev->ops->disable(dssdev); } diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index aabdda394c9c..6339e2756b34 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -249,15 +249,15 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) } static void hdmi_display_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); mutex_lock(&hdmi->lock); - hdmi->cfg.vm = *vm; + drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); mutex_unlock(&hdmi->lock); } @@ -312,26 +312,20 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) hdmi_wp_audio_enable(&hd->wp, false); } -static int hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; - int r = 0; + int r; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi->lock); - if (!dssdev->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err0; - } - r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); - goto err0; + goto done; } if (hdmi->audio_configured) { @@ -351,12 +345,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) hdmi->display_enabled = true; spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); +done: mutex_unlock(&hdmi->lock); - return 0; - -err0: - mutex_unlock(&hdmi->lock); - return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) @@ -417,21 +407,12 @@ void hdmi4_core_disable(struct hdmi_core_data *core) static int hdmi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void hdmi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -698,7 +679,7 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; - out->output_type = OMAP_DISPLAY_TYPE_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->ops = &hdmi_ops; @@ -706,19 +687,9 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi) out->of_ports = BIT(0); out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -729,9 +700,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi) { struct omap_dss_device *out = &hdmi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static int hdmi4_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 9e8556f67a29..2955bbad13bb 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -248,15 +248,15 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi) } static void hdmi_display_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); mutex_lock(&hdmi->lock); - hdmi->cfg.vm = *vm; + drm_display_mode_to_videomode(mode, &hdmi->cfg.vm); - dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock); + dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000); mutex_unlock(&hdmi->lock); } @@ -320,26 +320,20 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd) REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); } -static int hdmi_display_enable(struct omap_dss_device *dssdev) +static void hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev); unsigned long flags; - int r = 0; + int r; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi->lock); - if (!dssdev->dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err0; - } - r = hdmi_power_on_full(hdmi); if (r) { DSSERR("failed to power on device\n"); - goto err0; + goto done; } if (hdmi->audio_configured) { @@ -359,12 +353,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) hdmi->display_enabled = true; spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags); +done: mutex_unlock(&hdmi->lock); - return 0; - -err0: - mutex_unlock(&hdmi->lock); - return r; } static void hdmi_display_disable(struct omap_dss_device *dssdev) @@ -422,21 +412,12 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi) static int hdmi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void hdmi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -682,7 +663,7 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->dev = &hdmi->pdev->dev; out->id = OMAP_DSS_OUTPUT_HDMI; - out->output_type = OMAP_DISPLAY_TYPE_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; out->name = "hdmi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->ops = &hdmi_ops; @@ -690,19 +671,9 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi) out->of_ports = BIT(0); out->ops_flags = OMAP_DSS_DEVICE_OP_EDID; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -713,9 +684,8 @@ static void hdmi5_uninit_output(struct omap_hdmi *hdmi) { struct omap_dss_device *out = &hdmi->output; - if (out->next) - omapdss_device_put(out->next); omapdss_device_unregister(out); + omapdss_device_cleanup_output(out); } static int hdmi5_probe_of(struct omap_hdmi *hdmi) diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index 3bfb95d230e0..2b41c75ce988 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -184,6 +184,22 @@ static const struct of_device_id omapdss_of_match[] __initconst = { {}, }; +static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = { + { .compatible = "composite-video-connector" }, + { .compatible = "hdmi-connector" }, + { .compatible = "lgphilips,lb035q02" }, + { .compatible = "nec,nl8048hl11" }, + { .compatible = "panel-dsi-cm" }, + { .compatible = "sharp,ls037v7dw01" }, + { .compatible = "sony,acx565akm" }, + { .compatible = "svideo-connector" }, + { .compatible = "ti,opa362" }, + { .compatible = "ti,tpd12s015" }, + { .compatible = "toppoly,td028ttec1" }, + { .compatible = "tpo,td028ttec1" }, + { .compatible = "tpo,td043mtea1" }, +}; + static int __init omapdss_boot_init(void) { struct device_node *dss, *child; @@ -210,7 +226,7 @@ static int __init omapdss_boot_init(void) n = list_first_entry(&dss_conv_list, struct dss_conv_node, list); - if (!n->root) + if (of_match_node(omapdss_of_fixups_whitelist, n->node)) omapdss_omapify_node(n->node); list_del(&n->list); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 33e15cb77efa..0c734d1f89e1 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -19,7 +19,6 @@ #define __OMAP_DRM_DSS_H #include <linux/list.h> -#include <linux/kobject.h> #include <linux/device.h> #include <linux/interrupt.h> #include <video/videomode.h> @@ -68,6 +67,7 @@ struct dss_lcd_mgr_config; struct snd_aes_iec958; struct snd_cea_861_aud_if; struct hdmi_avi_infoframe; +struct drm_connector; enum omap_display_type { OMAP_DISPLAY_TYPE_NONE = 0, @@ -360,15 +360,15 @@ struct omap_dss_device_ops { void (*disconnect)(struct omap_dss_device *dssdev, struct omap_dss_device *dst); - int (*enable)(struct omap_dss_device *dssdev); + void (*pre_enable)(struct omap_dss_device *dssdev); + void (*enable)(struct omap_dss_device *dssdev); void (*disable)(struct omap_dss_device *dssdev); + void (*post_disable)(struct omap_dss_device *dssdev); int (*check_timings)(struct omap_dss_device *dssdev, - struct videomode *vm); - void (*get_timings)(struct omap_dss_device *dssdev, - struct videomode *vm); + struct drm_display_mode *mode); void (*set_timings)(struct omap_dss_device *dssdev, - const struct videomode *vm); + const struct drm_display_mode *mode); bool (*detect)(struct omap_dss_device *dssdev); @@ -380,6 +380,9 @@ struct omap_dss_device_ops { int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); + int (*get_modes)(struct omap_dss_device *dssdev, + struct drm_connector *connector); + union { const struct omapdss_hdmi_ops hdmi; const struct omapdss_dsi_ops dsi; @@ -390,42 +393,40 @@ struct omap_dss_device_ops { * enum omap_dss_device_ops_flag - Indicates which device ops are supported * @OMAP_DSS_DEVICE_OP_DETECT: The device supports output connection detection * @OMAP_DSS_DEVICE_OP_HPD: The device supports all hot-plug-related operations - * @OMAP_DSS_DEVICE_OP_EDID: The device supports readind EDID + * @OMAP_DSS_DEVICE_OP_EDID: The device supports reading EDID + * @OMAP_DSS_DEVICE_OP_MODES: The device supports reading modes */ enum omap_dss_device_ops_flag { OMAP_DSS_DEVICE_OP_DETECT = BIT(0), OMAP_DSS_DEVICE_OP_HPD = BIT(1), OMAP_DSS_DEVICE_OP_EDID = BIT(2), -}; - -enum omap_dss_device_type { - OMAP_DSS_DEVICE_TYPE_OUTPUT = (1 << 0), - OMAP_DSS_DEVICE_TYPE_DISPLAY = (1 << 1), + OMAP_DSS_DEVICE_OP_MODES = BIT(3), }; struct omap_dss_device { - struct kobject kobj; struct device *dev; struct module *owner; struct dss_device *dss; - struct omap_dss_device *src; - struct omap_dss_device *dst; struct omap_dss_device *next; + struct drm_bridge *bridge; + struct drm_panel *panel; struct list_head list; - unsigned int alias_id; - + /* + * DSS type that this device generates (for DSS internal devices) or + * requires (for external encoders, connectors and panels). Must be a + * non-zero (different than OMAP_DISPLAY_TYPE_NONE) value. + */ enum omap_display_type type; + /* - * DSS output type that this device generates (for DSS internal devices) - * or requires (for external encoders). Must be OMAP_DISPLAY_TYPE_NONE - * for display devices (connectors and panels) and to non-zero value for - * all other devices. + * True if the device is a display (panel or connector) at the end of + * the pipeline, false otherwise. */ - enum omap_display_type output_type; + bool display; const char *name; @@ -434,9 +435,6 @@ struct omap_dss_device { unsigned long ops_flags; u32 bus_flags; - /* helper variable for driver suspend/resume */ - bool activate_after_resume; - enum omap_display_caps caps; enum omap_dss_display_state state; @@ -445,7 +443,6 @@ struct omap_dss_device { /* DISPC channel for this output */ enum omap_channel dispc_channel; - bool dispc_channel_connected; /* output instance */ enum omap_dss_output_id id; @@ -465,9 +462,6 @@ struct omap_dss_driver { int (*memory_read)(struct omap_dss_device *dssdev, void *buf, size_t size, u16 x, u16 y, u16 w, u16 h); - - void (*get_size)(struct omap_dss_device *dssdev, - unsigned int *width, unsigned int *height); }; struct dss_device *omapdss_get_dss(void); @@ -477,32 +471,35 @@ static inline bool omapdss_is_initialized(void) return !!omapdss_get_dss(); } -#define for_each_dss_display(d) \ - while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL) void omapdss_display_init(struct omap_dss_device *dssdev); struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output); +int omapdss_display_get_modes(struct drm_connector *connector, + const struct videomode *vm); void omapdss_device_register(struct omap_dss_device *dssdev); void omapdss_device_unregister(struct omap_dss_device *dssdev); struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev); void omapdss_device_put(struct omap_dss_device *dssdev); -struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, - unsigned int port); -struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from, - enum omap_dss_device_type type); +struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node); int omapdss_device_connect(struct dss_device *dss, struct omap_dss_device *src, struct omap_dss_device *dst); void omapdss_device_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst); +void omapdss_device_pre_enable(struct omap_dss_device *dssdev); +void omapdss_device_enable(struct omap_dss_device *dssdev); +void omapdss_device_disable(struct omap_dss_device *dssdev); +void omapdss_device_post_disable(struct omap_dss_device *dssdev); int omap_dss_get_num_overlay_managers(void); int omap_dss_get_num_overlays(void); #define for_each_dss_output(d) \ - while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_OUTPUT)) != NULL) -int omapdss_output_validate(struct omap_dss_device *out); + while ((d = omapdss_device_next_output(d)) != NULL) +struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from); +int omapdss_device_init_output(struct omap_dss_device *out); +void omapdss_device_cleanup_output(struct omap_dss_device *out); typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); @@ -511,11 +508,6 @@ int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); int omapdss_compat_init(void); void omapdss_compat_uninit(void); -static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev) -{ - return dssdev->src; -} - static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) { return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 18505bc70f7e..10a9ee5cdc61 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -20,20 +20,48 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_graph.h> + +#include <drm/drm_panel.h> #include "dss.h" #include "omapdss.h" -int omapdss_output_validate(struct omap_dss_device *out) +int omapdss_device_init_output(struct omap_dss_device *out) { - if (out->next && out->output_type != out->next->type) { + struct device_node *remote_node; + + remote_node = of_graph_get_remote_node(out->dev->of_node, 0, 0); + if (!remote_node) { + dev_dbg(out->dev, "failed to find video sink\n"); + return 0; + } + + out->next = omapdss_find_device_by_node(remote_node); + out->bridge = of_drm_find_bridge(remote_node); + out->panel = of_drm_find_panel(remote_node); + if (IS_ERR(out->panel)) + out->panel = NULL; + + of_node_put(remote_node); + + if (out->next && out->type != out->next->type) { dev_err(out->dev, "output type and display type don't match\n"); + omapdss_device_put(out->next); + out->next = NULL; return -EINVAL; } - return 0; + return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; +} +EXPORT_SYMBOL(omapdss_device_init_output); + +void omapdss_device_cleanup_output(struct omap_dss_device *out) +{ + if (out->next) + omapdss_device_put(out->next); } -EXPORT_SYMBOL(omapdss_output_validate); +EXPORT_SYMBOL(omapdss_device_cleanup_output); int dss_install_mgr_ops(struct dss_device *dss, const struct dss_mgr_ops *mgr_ops, diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index b2fe2387037a..7aae52984fed 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -37,7 +37,7 @@ struct sdi_device { struct regulator *vdds_sdi_reg; struct dss_lcd_mgr_config mgr_config; - struct videomode vm; + unsigned long pixelclock; int datapairs; struct omap_dss_device output; @@ -129,27 +129,22 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi) dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config); } -static int sdi_display_enable(struct omap_dss_device *dssdev) +static void sdi_display_enable(struct omap_dss_device *dssdev) { struct sdi_device *sdi = dssdev_to_sdi(dssdev); struct dispc_clock_info dispc_cinfo; unsigned long fck; int r; - if (!sdi->output.dispc_channel_connected) { - DSSERR("failed to enable display: no output/manager\n"); - return -ENODEV; - } - r = regulator_enable(sdi->vdds_sdi_reg); if (r) - goto err_reg_enable; + return; r = dispc_runtime_get(sdi->dss->dispc); if (r) goto err_get_dispc; - r = sdi_calc_clock_div(sdi, sdi->vm.pixelclock, &fck, &dispc_cinfo); + r = sdi_calc_clock_div(sdi, sdi->pixelclock, &fck, &dispc_cinfo); if (r) goto err_calc_clock_div; @@ -185,7 +180,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_mgr_enable; - return 0; + return; err_mgr_enable: dss_sdi_disable(sdi->dss); @@ -195,8 +190,6 @@ err_calc_clock_div: dispc_runtime_put(sdi->dss->dispc); err_get_dispc: regulator_disable(sdi->vdds_sdi_reg); -err_reg_enable: - return r; } static void sdi_display_disable(struct omap_dss_device *dssdev) @@ -213,36 +206,37 @@ static void sdi_display_disable(struct omap_dss_device *dssdev) } static void sdi_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct sdi_device *sdi = dssdev_to_sdi(dssdev); - sdi->vm = *vm; + sdi->pixelclock = mode->clock * 1000; } static int sdi_check_timings(struct omap_dss_device *dssdev, - struct videomode *vm) + struct drm_display_mode *mode) { struct sdi_device *sdi = dssdev_to_sdi(dssdev); struct dispc_clock_info dispc_cinfo; + unsigned long pixelclock = mode->clock * 1000; unsigned long fck; unsigned long pck; int r; - if (vm->pixelclock == 0) + if (pixelclock == 0) return -EINVAL; - r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo); + r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo); if (r) return r; pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; - if (pck != vm->pixelclock) { + if (pck != pixelclock) { DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n", - vm->pixelclock, pck); + pixelclock, pck); - vm->pixelclock = pck; + mode->clock = pck / 1000; } return 0; @@ -251,21 +245,12 @@ static int sdi_check_timings(struct omap_dss_device *dssdev, static int sdi_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void sdi_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -287,29 +272,19 @@ static int sdi_init_output(struct sdi_device *sdi) out->dev = &sdi->pdev->dev; out->id = OMAP_DSS_OUTPUT_SDI; - out->output_type = OMAP_DISPLAY_TYPE_SDI; + out->type = OMAP_DISPLAY_TYPE_SDI; out->name = "sdi.0"; out->dispc_channel = OMAP_DSS_CHANNEL_LCD; /* We have SDI only on OMAP3, where it's on port 1 */ out->of_ports = BIT(1); out->ops = &sdi_ops; out->owner = THIS_MODULE; - out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE /* 15.5.9.1.2 */ - | DRM_BUS_FLAG_SYNC_POSEDGE; - - out->next = omapdss_of_find_connected_device(out->dev->of_node, 1); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } + out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */ + | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE; - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -318,9 +293,8 @@ static int sdi_init_output(struct sdi_device *sdi) static void sdi_uninit_output(struct sdi_device *sdi) { - if (sdi->output.next) - omapdss_device_put(sdi->output.next); omapdss_device_unregister(&sdi->output); + omapdss_device_cleanup_output(&sdi->output); } int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index b5f52727f8b1..da43b865d973 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -267,63 +267,40 @@ enum venc_videomode { VENC_MODE_NTSC, }; -static const struct videomode omap_dss_pal_vm = { - .hactive = 720, - .vactive = 574, - .pixelclock = 13500000, - .hsync_len = 64, - .hfront_porch = 12, - .hback_porch = 68, - .vsync_len = 5, - .vfront_porch = 5, - .vback_porch = 41, - - .flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW | - DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH | - DISPLAY_FLAGS_PIXDATA_POSEDGE | - DISPLAY_FLAGS_SYNC_NEGEDGE, +static const struct drm_display_mode omap_dss_pal_mode = { + .hdisplay = 720, + .hsync_start = 732, + .hsync_end = 796, + .htotal = 864, + .vdisplay = 574, + .vsync_start = 579, + .vsync_end = 584, + .vtotal = 625, + .clock = 13500, + + .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_NVSYNC, }; -static const struct videomode omap_dss_ntsc_vm = { - .hactive = 720, - .vactive = 482, - .pixelclock = 13500000, - .hsync_len = 64, - .hfront_porch = 16, - .hback_porch = 58, - .vsync_len = 6, - .vfront_porch = 6, - .vback_porch = 31, - - .flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW | - DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH | - DISPLAY_FLAGS_PIXDATA_POSEDGE | - DISPLAY_FLAGS_SYNC_NEGEDGE, +static const struct drm_display_mode omap_dss_ntsc_mode = { + .hdisplay = 720, + .hsync_start = 736, + .hsync_end = 800, + .htotal = 858, + .vdisplay = 482, + .vsync_start = 488, + .vsync_end = 494, + .vtotal = 525, + .clock = 13500, + + .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_NVSYNC, }; -static enum venc_videomode venc_get_videomode(const struct videomode *vm) -{ - if (!(vm->flags & DISPLAY_FLAGS_INTERLACED)) - return VENC_MODE_UNKNOWN; - - if (vm->pixelclock == omap_dss_pal_vm.pixelclock && - vm->hactive == omap_dss_pal_vm.hactive && - vm->vactive == omap_dss_pal_vm.vactive) - return VENC_MODE_PAL; - - if (vm->pixelclock == omap_dss_ntsc_vm.pixelclock && - vm->hactive == omap_dss_ntsc_vm.hactive && - vm->vactive == omap_dss_ntsc_vm.vactive) - return VENC_MODE_NTSC; - - return VENC_MODE_UNKNOWN; -} - struct venc_device { struct platform_device *pdev; void __iomem *base; struct mutex venc_lock; - u32 wss_data; struct regulator *vdda_dac_reg; struct dss_device *dss; @@ -331,7 +308,7 @@ struct venc_device { struct clk *tv_dac_clk; - struct videomode vm; + const struct venc_config *config; enum omap_dss_venc_type type; bool invert_polarity; bool requires_tv_dac_clk; @@ -367,8 +344,7 @@ static void venc_write_config(struct venc_device *venc, venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level); venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level); venc_write_reg(venc, VENC_M_CONTROL, config->m_control); - venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data | - venc->wss_data); + venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data); venc_write_reg(venc, VENC_S_CARR, config->s_carr); venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl); venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid); @@ -452,18 +428,6 @@ static void venc_runtime_put(struct venc_device *venc) WARN_ON(r < 0 && r != -ENOSYS); } -static const struct venc_config *venc_timings_to_config(const struct videomode *vm) -{ - switch (venc_get_videomode(vm)) { - default: - WARN_ON_ONCE(1); - case VENC_MODE_PAL: - return &venc_config_pal_trm; - case VENC_MODE_NTSC: - return &venc_config_ntsc_trm; - } -} - static int venc_power_on(struct venc_device *venc) { u32 l; @@ -474,7 +438,7 @@ static int venc_power_on(struct venc_device *venc) goto err0; venc_reset(venc); - venc_write_config(venc, venc_timings_to_config(&venc->vm)); + venc_write_config(venc, venc->config); dss_set_venc_output(venc->dss, venc->type); dss_set_dac_pwrdn_bgz(venc->dss, 1); @@ -524,33 +488,17 @@ static void venc_power_off(struct venc_device *venc) venc_runtime_put(venc); } -static int venc_display_enable(struct omap_dss_device *dssdev) +static void venc_display_enable(struct omap_dss_device *dssdev) { struct venc_device *venc = dssdev_to_venc(dssdev); - int r; DSSDBG("venc_display_enable\n"); mutex_lock(&venc->venc_lock); - if (!dssdev->dispc_channel_connected) { - DSSERR("Failed to enable display: no output/manager\n"); - r = -ENODEV; - goto err0; - } - - r = venc_power_on(venc); - if (r) - goto err0; - - venc->wss_data = 0; + venc_power_on(venc); mutex_unlock(&venc->venc_lock); - - return 0; -err0: - mutex_unlock(&venc->venc_lock); - return r; } static void venc_display_disable(struct omap_dss_device *dssdev) @@ -566,30 +514,70 @@ static void venc_display_disable(struct omap_dss_device *dssdev) mutex_unlock(&venc->venc_lock); } -static void venc_get_timings(struct omap_dss_device *dssdev, - struct videomode *vm) +static int venc_get_modes(struct omap_dss_device *dssdev, + struct drm_connector *connector) { - struct venc_device *venc = dssdev_to_venc(dssdev); + static const struct drm_display_mode *modes[] = { + &omap_dss_pal_mode, + &omap_dss_ntsc_mode, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(modes); ++i) { + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, modes[i]); + if (!mode) + return i; + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + } - mutex_lock(&venc->venc_lock); - *vm = venc->vm; - mutex_unlock(&venc->venc_lock); + return ARRAY_SIZE(modes); +} + +static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode) +{ + if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) + return VENC_MODE_UNKNOWN; + + if (mode->clock == omap_dss_pal_mode.clock && + mode->hdisplay == omap_dss_pal_mode.hdisplay && + mode->vdisplay == omap_dss_pal_mode.vdisplay) + return VENC_MODE_PAL; + + if (mode->clock == omap_dss_ntsc_mode.clock && + mode->hdisplay == omap_dss_ntsc_mode.hdisplay && + mode->vdisplay == omap_dss_ntsc_mode.vdisplay) + return VENC_MODE_NTSC; + + return VENC_MODE_UNKNOWN; } static void venc_set_timings(struct omap_dss_device *dssdev, - const struct videomode *vm) + const struct drm_display_mode *mode) { struct venc_device *venc = dssdev_to_venc(dssdev); + enum venc_videomode venc_mode = venc_get_videomode(mode); DSSDBG("venc_set_timings\n"); mutex_lock(&venc->venc_lock); - /* Reset WSS data when the TV standard changes. */ - if (memcmp(&venc->vm, vm, sizeof(*vm))) - venc->wss_data = 0; + switch (venc_mode) { + default: + WARN_ON_ONCE(1); + /* Fall-through */ + case VENC_MODE_PAL: + venc->config = &venc_config_pal_trm; + break; - venc->vm = *vm; + case VENC_MODE_NTSC: + venc->config = &venc_config_ntsc_trm; + break; + } dispc_set_tv_pclk(venc->dss->dispc, 13500000); @@ -597,22 +585,26 @@ static void venc_set_timings(struct omap_dss_device *dssdev, } static int venc_check_timings(struct omap_dss_device *dssdev, - struct videomode *vm) + struct drm_display_mode *mode) { DSSDBG("venc_check_timings\n"); - switch (venc_get_videomode(vm)) { + switch (venc_get_videomode(mode)) { case VENC_MODE_PAL: - *vm = omap_dss_pal_vm; - return 0; + drm_mode_copy(mode, &omap_dss_pal_mode); + break; case VENC_MODE_NTSC: - *vm = omap_dss_ntsc_vm; - return 0; + drm_mode_copy(mode, &omap_dss_ntsc_mode); + break; default: return -EINVAL; } + + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_set_name(mode); + return 0; } static int venc_dump_regs(struct seq_file *s, void *p) @@ -695,21 +687,12 @@ static int venc_get_clocks(struct venc_device *venc) static int venc_connect(struct omap_dss_device *src, struct omap_dss_device *dst) { - int r; - - r = omapdss_device_connect(dst->dss, dst, dst->next); - if (r) - return r; - - dst->dispc_channel_connected = true; - return 0; + return omapdss_device_connect(dst->dss, dst, dst->next); } static void venc_disconnect(struct omap_dss_device *src, struct omap_dss_device *dst) { - dst->dispc_channel_connected = false; - omapdss_device_disconnect(dst, dst->next); } @@ -721,8 +704,9 @@ static const struct omap_dss_device_ops venc_ops = { .disable = venc_display_disable, .check_timings = venc_check_timings, - .get_timings = venc_get_timings, .set_timings = venc_set_timings, + + .get_modes = venc_get_modes, }; /* ----------------------------------------------------------------------------- @@ -776,26 +760,17 @@ static int venc_init_output(struct venc_device *venc) out->dev = &venc->pdev->dev; out->id = OMAP_DSS_OUTPUT_VENC; - out->output_type = OMAP_DISPLAY_TYPE_VENC; + out->type = OMAP_DISPLAY_TYPE_VENC; out->name = "venc.0"; out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; out->ops = &venc_ops; out->owner = THIS_MODULE; out->of_ports = BIT(0); + out->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - out->next = omapdss_of_find_connected_device(out->dev->of_node, 0); - if (IS_ERR(out->next)) { - if (PTR_ERR(out->next) != -EPROBE_DEFER) - dev_err(out->dev, "failed to find video sink\n"); - return PTR_ERR(out->next); - } - - r = omapdss_output_validate(out); - if (r) { - omapdss_device_put(out->next); - out->next = NULL; + r = omapdss_device_init_output(out); + if (r < 0) return r; - } omapdss_device_register(out); @@ -804,9 +779,8 @@ static int venc_init_output(struct venc_device *venc) static void venc_uninit_output(struct venc_device *venc) { - if (venc->output.next) - omapdss_device_put(venc->output.next); omapdss_device_unregister(&venc->output); + omapdss_device_cleanup_output(&venc->output); } static int venc_probe_of(struct venc_device *venc) @@ -878,8 +852,7 @@ static int venc_probe(struct platform_device *pdev) mutex_init(&venc->venc_lock); - venc->wss_data = 0; - venc->vm = omap_dss_pal_vm; + venc->config = &venc_config_pal_trm; venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0); venc->base = devm_ioremap_resource(&pdev->dev, venc_mem); |