diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-09-03 20:01:44 +0300 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-09-03 20:01:44 +0300 |
commit | 01b944fe1cd4e21a2a9ed51adbdbafe2d5e905ba (patch) | |
tree | 85f506cf9fce3d8fd47cf624dd8698472bffc13f /drivers/video/fbdev/omap2 | |
parent | e51e38494a8ecc18650efb0c840600637891de2c (diff) | |
parent | 58f1eae48e5372200553de07b5ecc7574803ee91 (diff) | |
download | linux-01b944fe1cd4e21a2a9ed51adbdbafe2d5e905ba.tar.xz |
Merge branch 'next' into for-linus
Prepare first round of input updates for 4.3 merge window.
Diffstat (limited to 'drivers/video/fbdev/omap2')
28 files changed, 715 insertions, 278 deletions
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c index 0cdc97413020..a8ce920fa797 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c @@ -37,7 +37,7 @@ static const struct omap_video_timings dvic_default_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; struct panel_drv_data { diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c index 84a6b3367124..a14d993f719d 100644 --- a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c +++ b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c @@ -201,15 +201,9 @@ static int opa362_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - gpio = devm_gpiod_get(&pdev->dev, "enable"); - if (IS_ERR(gpio)) { - if (PTR_ERR(gpio) != -ENOENT) - return PTR_ERR(gpio); - - gpio = NULL; - } else { - gpiod_direction_output(gpio, 0); - } + gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->enable_gpio = gpio; diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c index 92919a74e715..d9048b3df495 100644 --- a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c +++ b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c @@ -114,12 +114,21 @@ static void tfp410_disable(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } +static void tfp410_fix_timings(struct omap_video_timings *timings) +{ + timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; +} + static void tfp410_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { struct panel_drv_data *ddata = to_panel_data(dssdev); struct omap_dss_device *in = ddata->in; + tfp410_fix_timings(timings); + ddata->timings = *timings; dssdev->panel.timings = *timings; @@ -140,6 +149,8 @@ static int tfp410_check_timings(struct omap_dss_device *dssdev, struct panel_drv_data *ddata = to_panel_data(dssdev); struct omap_dss_device *in = ddata->in; + tfp410_fix_timings(timings); + return in->ops.dpi->check_timings(in, timings); } diff --git a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c index eb8fd8140ad0..f7be3489f744 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c @@ -209,16 +209,9 @@ static int panel_dpi_probe_of(struct platform_device *pdev) struct videomode vm; struct gpio_desc *gpio; - gpio = devm_gpiod_get(&pdev->dev, "enable"); - - if (IS_ERR(gpio)) { - if (PTR_ERR(gpio) != -ENOENT) - return PTR_ERR(gpio); - else - gpio = NULL; - } else { - gpiod_direction_output(gpio, 0); - } + gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); ddata->enable_gpio = gpio; diff --git a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c index 27d4fcfa1824..6a1b6a89a928 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c @@ -37,7 +37,7 @@ static struct omap_video_timings lb035q02_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; struct panel_drv_data { @@ -285,15 +285,14 @@ static int lb035q02_probe_of(struct spi_device *spi) struct omap_dss_device *in; struct gpio_desc *gpio; - gpio = devm_gpiod_get(&spi->dev, "enable"); + gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(gpio)) { dev_err(&spi->dev, "failed to parse enable gpio\n"); return PTR_ERR(gpio); - } else { - gpiod_direction_output(gpio, 0); - ddata->enable_gpio = gpio; } + ddata->enable_gpio = gpio; + ddata->backlight_gpio = -ENOENT; in = omapdss_of_find_source_for_first_ep(node); diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c index 18b19b6e1ac2..abfd1f6e3327 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c @@ -54,7 +54,7 @@ static const struct omap_video_timings sharp_ls_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) @@ -268,17 +268,12 @@ static int sharp_ls_get_gpio_of(struct device *dev, int index, int val, const char *desc, struct gpio_desc **gpiod) { struct gpio_desc *gd; - int r; *gpiod = NULL; - gd = devm_gpiod_get_index(dev, desc, index); + gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW); if (IS_ERR(gd)) - return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd); - - r = gpiod_direction_output(gd, val); - if (r) - return r; + return PTR_ERR(gd); *gpiod = gd; return 0; diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c index 337ccc5c0f5e..90cbc4c3406c 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c @@ -108,7 +108,7 @@ static const struct omap_video_timings acx565akm_panel_timings = { .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c index fbba0b8ca871..9edc51133c59 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c @@ -58,7 +58,7 @@ static struct omap_video_timings td028ttec1_panel_timings = { .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, }; #define JBT_COMMAND 0x000 diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c index 5aba76bca25a..79e4a029aab9 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c @@ -91,7 +91,7 @@ static const struct omap_video_timings tpo_td043_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c index d5d92124e019..54eeb507f9b3 100644 --- a/drivers/video/fbdev/omap2/dss/core.c +++ b/drivers/video/fbdev/omap2/dss/core.c @@ -50,8 +50,6 @@ static char *def_disp_name; module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp, "default display name"); -static bool dss_initialized; - const char *omapdss_get_default_display_name(void) { return core.default_display_name; @@ -65,12 +63,6 @@ enum omapdss_version omapdss_get_version(void) } EXPORT_SYMBOL(omapdss_get_version); -bool omapdss_is_initialized(void) -{ - return dss_initialized; -} -EXPORT_SYMBOL(omapdss_is_initialized); - struct platform_device *dss_get_core_pdev(void) { return core.pdev; @@ -179,10 +171,14 @@ static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) switch (v) { case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: DSSDBG("suspending displays\n"); return dss_suspend_all_devices(); case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: DSSDBG("resuming displays\n"); return dss_resume_all_devices(); @@ -249,6 +245,8 @@ static struct platform_driver omap_dss_driver = { /* INIT */ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { + dss_init_platform_driver, + dispc_init_platform_driver, #ifdef CONFIG_OMAP2_DSS_DSI dsi_init_platform_driver, #endif @@ -272,32 +270,32 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { #endif }; -static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_uninit_platform_driver, +static void (*dss_output_drv_unreg_funcs[])(void) = { +#ifdef CONFIG_OMAP5_DSS_HDMI + hdmi5_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_DPI - dpi_uninit_platform_driver, +#ifdef CONFIG_OMAP4_DSS_HDMI + hdmi4_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_SDI - sdi_uninit_platform_driver, +#ifdef CONFIG_OMAP2_DSS_VENC + venc_uninit_platform_driver, #endif #ifdef CONFIG_OMAP2_DSS_RFBI rfbi_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_VENC - venc_uninit_platform_driver, +#ifdef CONFIG_OMAP2_DSS_SDI + sdi_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP4_DSS_HDMI - hdmi4_uninit_platform_driver, +#ifdef CONFIG_OMAP2_DSS_DPI + dpi_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP5_DSS_HDMI - hdmi5_uninit_platform_driver, +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_uninit_platform_driver, #endif + dispc_uninit_platform_driver, + dss_uninit_platform_driver, }; -static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; - static int __init omap_dss_init(void) { int r; @@ -307,35 +305,20 @@ static int __init omap_dss_init(void) if (r) return r; - r = dss_init_platform_driver(); - if (r) { - DSSERR("Failed to initialize DSS platform driver\n"); - goto err_dss; - } - - r = dispc_init_platform_driver(); - if (r) { - DSSERR("Failed to initialize dispc platform driver\n"); - goto err_dispc; - } - - /* - * It's ok if the output-driver register fails. It happens, for example, - * when there is no output-device (e.g. SDI for OMAP4). - */ for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { r = dss_output_drv_reg_funcs[i](); - if (r == 0) - dss_output_drv_loaded[i] = true; + if (r) + goto err_reg; } - dss_initialized = true; - return 0; -err_dispc: - dss_uninit_platform_driver(); -err_dss: +err_reg: + for (i = ARRAY_SIZE(dss_output_drv_reg_funcs) - i; + i < ARRAY_SIZE(dss_output_drv_reg_funcs); + ++i) + dss_output_drv_unreg_funcs[i](); + platform_driver_unregister(&omap_dss_driver); return r; @@ -345,13 +328,8 @@ static void __exit omap_dss_exit(void) { int i; - for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { - if (dss_output_drv_loaded[i]) - dss_output_drv_unreg_funcs[i](); - } - - dispc_uninit_platform_driver(); - dss_uninit_platform_driver(); + for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) + dss_output_drv_unreg_funcs[i](); platform_driver_unregister(&omap_dss_driver); } diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index 31b743c70272..be716c9ffb88 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c @@ -39,6 +39,7 @@ #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/of.h> +#include <linux/component.h> #include <video/omapdss.h> @@ -95,6 +96,9 @@ struct dispc_features { bool mstandby_workaround:1; bool set_max_preload:1; + + /* PIXEL_INC is not added to the last pixel of a line */ + bool last_pixel_inc_missing:1; }; #define DISPC_MAX_NR_FIFOS 5 @@ -123,6 +127,9 @@ static struct { struct regmap *syscon_pol; u32 syscon_pol_offset; + + /* DISPC_CONTROL & DISPC_CONFIG lock*/ + spinlock_t control_lock; } dispc; enum omap_color_component { @@ -261,7 +268,16 @@ static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld) static void mgr_fld_write(enum omap_channel channel, enum mgr_reg_fields regfld, int val) { const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; + const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG; + unsigned long flags; + + if (need_lock) + spin_lock_irqsave(&dispc.control_lock, flags); + REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low); + + if (need_lock) + spin_unlock_irqrestore(&dispc.control_lock, flags); } #define SR(reg) \ @@ -1126,6 +1142,7 @@ static void dispc_init_fifos(void) int fifo; u8 start, end; u32 unit; + int i; unit = dss_feat_get_buffer_size_unit(); @@ -1165,6 +1182,20 @@ static void dispc_init_fifos(void) dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; } + + /* + * Setup default fifo thresholds. + */ + for (i = 0; i < dss_feat_get_num_ovls(); ++i) { + u32 low, high; + const bool use_fifomerge = false; + const bool manual_update = false; + + dispc_ovl_compute_fifo_thresholds(i, &low, &high, + use_fifomerge, manual_update); + + dispc_ovl_set_fifo_threshold(i, low, high); + } } static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) @@ -1278,6 +1309,63 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, } EXPORT_SYMBOL(dispc_ovl_compute_fifo_thresholds); +static void dispc_ovl_set_mflag(enum omap_plane plane, bool enable) +{ + int bit; + + if (plane == OMAP_DSS_GFX) + bit = 14; + else + bit = 23; + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); +} + +static void dispc_ovl_set_mflag_threshold(enum omap_plane plane, + int low, int high) +{ + dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane), + FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); +} + +static void dispc_init_mflag(void) +{ + int i; + + /* + * HACK: NV12 color format and MFLAG seem to have problems working + * together: using two displays, and having an NV12 overlay on one of + * the displays will cause underflows/synclosts when MFLAG_CTRL=2. + * Changing MFLAG thresholds and PRELOAD to certain values seem to + * remove the errors, but there doesn't seem to be a clear logic on + * which values work and which not. + * + * As a work-around, set force MFLAG to always on. + */ + dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE, + (1 << 0) | /* MFLAG_CTRL = force always on */ + (0 << 2)); /* MFLAG_START = disable */ + + for (i = 0; i < dss_feat_get_num_ovls(); ++i) { + u32 size = dispc_ovl_get_fifo_size(i); + u32 unit = dss_feat_get_buffer_size_unit(); + u32 low, high; + + dispc_ovl_set_mflag(i, true); + + /* + * Simulation team suggests below thesholds: + * HT = fifosize * 5 / 8; + * LT = fifosize * 4 / 8; + */ + + low = size * 4 / 8 / unit; + high = size * 5 / 8 / unit; + + dispc_ovl_set_mflag_threshold(i, low, high); + } +} + static void dispc_ovl_set_fir(enum omap_plane plane, int hinc, int vinc, enum omap_color_component color_comp) @@ -1657,6 +1745,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, row_repeat = false; } + /* + * OMAP4/5 Errata i631: + * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra + * rows beyond the framebuffer, which may cause OCP error. + */ + if (color_mode == OMAP_DSS_COLOR_NV12 && + rotation_type != OMAP_DSS_ROT_TILER) + vidrot = 1; + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); if (dss_has_feature(FEAT_ROWREPEATENABLE)) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), @@ -2070,7 +2167,7 @@ static unsigned long calc_core_clk_five_taps(unsigned long pclk, if (height > out_height) { unsigned int ppl = mgr_timings->x_res; - tmp = pclk * height * out_width; + tmp = (u64)pclk * height * out_width; do_div(tmp, 2 * out_height * ppl); core_clk = tmp; @@ -2078,14 +2175,14 @@ static unsigned long calc_core_clk_five_taps(unsigned long pclk, if (ppl == out_width) return 0; - tmp = pclk * (height - 2 * out_height) * out_width; + tmp = (u64)pclk * (height - 2 * out_height) * out_width; do_div(tmp, 2 * out_height * (ppl - out_width)); core_clk = max_t(u32, core_clk, tmp); } } if (width > out_width) { - tmp = pclk * width; + tmp = (u64)pclk * width; do_div(tmp, out_width); core_clk = max_t(u32, core_clk, tmp); @@ -2183,6 +2280,11 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, } } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + if (error) { + DSSERR("failed to find scaling settings\n"); + return -EINVAL; + } + if (in_width > maxsinglelinewidth) { DSSERR("Cannot scale max input width exceeded"); return -EINVAL; @@ -2199,7 +2301,6 @@ static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, { int error; u16 in_width, in_height; - int min_factor = min(*decim_x, *decim_y); const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); @@ -2233,20 +2334,32 @@ again: error = (error || in_width > maxsinglelinewidth * 2 || (in_width > maxsinglelinewidth && *five_taps) || !*core_clk || *core_clk > dispc_core_clk_rate()); - if (error) { - if (*decim_x == *decim_y) { - *decim_x = min_factor; - ++*decim_y; + + if (!error) { + /* verify that we're inside the limits of scaler */ + if (in_width / 4 > out_width) + error = 1; + + if (*five_taps) { + if (in_height / 4 > out_height) + error = 1; } else { - swap(*decim_x, *decim_y); - if (*decim_x < *decim_y) - ++*decim_x; + if (in_height / 2 > out_height) + error = 1; } } + + if (error) + ++*decim_y; } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); - if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width, - height, out_width, out_height, *five_taps)) { + if (error) { + DSSERR("failed to find scaling settings\n"); + return -EINVAL; + } + + if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, in_width, + in_height, out_width, out_height, *five_taps)) { DSSERR("horizontal timing too tight\n"); return -EINVAL; } @@ -2306,6 +2419,9 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, return 0; } +#define DIV_FRAC(dividend, divisor) \ + ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) + static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, enum omap_overlay_caps caps, const struct omap_video_timings *mgr_timings, @@ -2322,6 +2438,11 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, if (width == out_width && height == out_height) return 0; + if (pclk == 0 || mgr_timings->pixelclock == 0) { + DSSERR("cannot calculate scaling settings: pclk is zero\n"); + return -EINVAL; + } + if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) return -EINVAL; @@ -2360,8 +2481,19 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, if (ret) return ret; - DSSDBG("required core clk rate = %lu Hz\n", core_clk); - DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); + DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n", + width, height, + out_width, out_height, + out_width / width, DIV_FRAC(out_width, width), + out_height / height, DIV_FRAC(out_height, height), + + decim_x, decim_y, + width / decim_x, height / decim_y, + out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x), + out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y), + + *five_taps ? 5 : 3, + core_clk, dispc_core_clk_rate()); if (!core_clk || core_clk > dispc_core_clk_rate()) { DSSERR("failed to set up scaling, " @@ -2441,9 +2573,24 @@ static int dispc_ovl_setup_common(enum omap_plane plane, unsigned long pclk = dispc_plane_pclk_rate(plane); unsigned long lclk = dispc_plane_lclk_rate(plane); - if (paddr == 0) + if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) return -EINVAL; + switch (color_mode) { + case OMAP_DSS_COLOR_YUV2: + case OMAP_DSS_COLOR_UYVY: + case OMAP_DSS_COLOR_NV12: + if (in_width & 1) { + DSSERR("input width %d is not even for YUV format\n", + in_width); + return -EINVAL; + } + break; + + default: + break; + } + out_width = out_width == 0 ? width : out_width; out_height = out_height == 0 ? height : out_height; @@ -2474,6 +2621,27 @@ static int dispc_ovl_setup_common(enum omap_plane plane, in_width = in_width / x_predecim; in_height = in_height / y_predecim; + if (x_predecim > 1 || y_predecim > 1) + DSSDBG("predecimation %d x %x, new input size %d x %d\n", + x_predecim, y_predecim, in_width, in_height); + + switch (color_mode) { + case OMAP_DSS_COLOR_YUV2: + case OMAP_DSS_COLOR_UYVY: + case OMAP_DSS_COLOR_NV12: + if (in_width & 1) { + DSSDBG("predecimated input width is not even for YUV format\n"); + DSSDBG("adjusting input width %d -> %d\n", + in_width, in_width & ~1); + + in_width &= ~1; + } + break; + + default: + break; + } + if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY || color_mode == OMAP_DSS_COLOR_NV12) @@ -2543,6 +2711,9 @@ static int dispc_ovl_setup_common(enum omap_plane plane, dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); } + if (dispc.feat->last_pixel_inc_missing) + row_inc += pix_inc - 1; + dispc_ovl_set_row_inc(plane, row_inc); dispc_ovl_set_pix_inc(plane, pix_inc); @@ -2915,7 +3086,7 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, { u32 timing_h, timing_v, l; - bool onoff, rf, ipc; + bool onoff, rf, ipc, vs, hs, de; timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | @@ -2927,6 +3098,39 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); + switch (vsync_level) { + case OMAPDSS_SIG_ACTIVE_LOW: + vs = true; + break; + case OMAPDSS_SIG_ACTIVE_HIGH: + vs = false; + break; + default: + BUG(); + } + + switch (hsync_level) { + case OMAPDSS_SIG_ACTIVE_LOW: + hs = true; + break; + case OMAPDSS_SIG_ACTIVE_HIGH: + hs = false; + break; + default: + BUG(); + } + + switch (de_level) { + case OMAPDSS_SIG_ACTIVE_LOW: + de = true; + break; + case OMAPDSS_SIG_ACTIVE_HIGH: + de = false; + break; + default: + BUG(); + } + switch (data_pclk_edge) { case OMAPDSS_DRIVE_SIG_RISING_EDGE: ipc = false; @@ -2934,22 +3138,18 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, case OMAPDSS_DRIVE_SIG_FALLING_EDGE: ipc = true; break; - case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: default: BUG(); } + /* always use the 'rf' setting */ + onoff = true; + switch (sync_pclk_edge) { - case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: - onoff = false; - rf = false; - break; case OMAPDSS_DRIVE_SIG_FALLING_EDGE: - onoff = true; rf = false; break; case OMAPDSS_DRIVE_SIG_RISING_EDGE: - onoff = true; rf = true; break; default: @@ -2958,10 +3158,10 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, l = FLD_VAL(onoff, 17, 17) | FLD_VAL(rf, 16, 16) | - FLD_VAL(de_level, 15, 15) | + FLD_VAL(de, 15, 15) | FLD_VAL(ipc, 14, 14) | - FLD_VAL(hsync_level, 13, 13) | - FLD_VAL(vsync_level, 12, 12); + FLD_VAL(hs, 13, 13) | + FLD_VAL(vs, 12, 12); dispc_write_reg(DISPC_POL_FREQ(channel), l); @@ -3569,9 +3769,12 @@ static void _omap_dispc_initial_config(void) if (dispc.feat->mstandby_workaround) REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0); + + if (dss_has_feature(FEAT_MFLAG)) + dispc_init_mflag(); } -static const struct dispc_features omap24xx_dispc_feats __initconst = { +static const struct dispc_features omap24xx_dispc_feats = { .sw_start = 5, .fp_start = 15, .bp_start = 27, @@ -3588,9 +3791,10 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = { .num_fifos = 3, .no_framedone_tv = true, .set_max_preload = false, + .last_pixel_inc_missing = true, }; -static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { +static const struct dispc_features omap34xx_rev1_0_dispc_feats = { .sw_start = 5, .fp_start = 15, .bp_start = 27, @@ -3608,9 +3812,10 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { .num_fifos = 3, .no_framedone_tv = true, .set_max_preload = false, + .last_pixel_inc_missing = true, }; -static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { +static const struct dispc_features omap34xx_rev3_0_dispc_feats = { .sw_start = 7, .fp_start = 19, .bp_start = 31, @@ -3628,9 +3833,10 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { .num_fifos = 3, .no_framedone_tv = true, .set_max_preload = false, + .last_pixel_inc_missing = true, }; -static const struct dispc_features omap44xx_dispc_feats __initconst = { +static const struct dispc_features omap44xx_dispc_feats = { .sw_start = 7, .fp_start = 19, .bp_start = 31, @@ -3650,7 +3856,7 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { .set_max_preload = true, }; -static const struct dispc_features omap54xx_dispc_feats __initconst = { +static const struct dispc_features omap54xx_dispc_feats = { .sw_start = 7, .fp_start = 19, .bp_start = 31, @@ -3671,7 +3877,7 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = { .set_max_preload = true, }; -static int __init dispc_init_features(struct platform_device *pdev) +static int dispc_init_features(struct platform_device *pdev) { const struct dispc_features *src; struct dispc_features *dst; @@ -3761,8 +3967,9 @@ void dispc_free_irq(void *dev_id) EXPORT_SYMBOL(dispc_free_irq); /* DISPC HW IP initialisation */ -static int __init omap_dispchw_probe(struct platform_device *pdev) +static int dispc_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); u32 rev; int r = 0; struct resource *dispc_mem; @@ -3770,6 +3977,8 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dispc.pdev = pdev; + spin_lock_init(&dispc.control_lock); + r = dispc_init_features(dispc.pdev); if (r) return r; @@ -3832,12 +4041,27 @@ err_runtime_get: return r; } -static int __exit omap_dispchw_remove(struct platform_device *pdev) +static void dispc_unbind(struct device *dev, struct device *master, + void *data) { - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); dss_uninit_overlay_managers(); +} + +static const struct component_ops dispc_component_ops = { + .bind = dispc_bind, + .unbind = dispc_unbind, +}; +static int dispc_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &dispc_component_ops); +} + +static int dispc_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dispc_component_ops); return 0; } @@ -3890,7 +4114,8 @@ static const struct of_device_id dispc_of_match[] = { }; static struct platform_driver omap_dispchw_driver = { - .remove = __exit_p(omap_dispchw_remove), + .probe = dispc_probe, + .remove = dispc_remove, .driver = { .name = "omapdss_dispc", .pm = &dispc_pm_ops, @@ -3901,10 +4126,10 @@ static struct platform_driver omap_dispchw_driver = { int __init dispc_init_platform_driver(void) { - return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe); + return platform_driver_register(&omap_dispchw_driver); } -void __exit dispc_uninit_platform_driver(void) +void dispc_uninit_platform_driver(void) { platform_driver_unregister(&omap_dispchw_driver); } diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c b/drivers/video/fbdev/omap2/dss/display-sysfs.c index 12186557a9d4..6ad0991f8259 100644 --- a/drivers/video/fbdev/omap2/dss/display-sysfs.c +++ b/drivers/video/fbdev/omap2/dss/display-sysfs.c @@ -324,7 +324,7 @@ int display_init_sysfs(struct platform_device *pdev) for_each_dss_dev(dssdev) { r = kobject_init_and_add(&dssdev->kobj, &display_ktype, - &pdev->dev.kobj, dssdev->alias); + &pdev->dev.kobj, "%s", dssdev->alias); if (r) { DSSERR("failed to create sysfs files\n"); omap_dss_put_device(dssdev); diff --git a/drivers/video/fbdev/omap2/dss/display.c b/drivers/video/fbdev/omap2/dss/display.c index 2412a0dd0c13..ef5b9027985d 100644 --- a/drivers/video/fbdev/omap2/dss/display.c +++ b/drivers/video/fbdev/omap2/dss/display.c @@ -295,7 +295,7 @@ void videomode_to_omap_video_timings(const struct videomode *vm, OMAPDSS_DRIVE_SIG_RISING_EDGE : OMAPDSS_DRIVE_SIG_FALLING_EDGE; - ovt->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + ovt->sync_pclk_edge = ovt->data_pclk_edge; } EXPORT_SYMBOL(videomode_to_omap_video_timings); diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c index f83e7b030249..fb45b6432968 100644 --- a/drivers/video/fbdev/omap2/dss/dpi.c +++ b/drivers/video/fbdev/omap2/dss/dpi.c @@ -32,6 +32,7 @@ #include <linux/string.h> #include <linux/of.h> #include <linux/clk.h> +#include <linux/component.h> #include <video/omapdss.h> @@ -731,7 +732,7 @@ static void dpi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void __exit dpi_uninit_output(struct platform_device *pdev) +static void dpi_uninit_output(struct platform_device *pdev) { struct dpi_data *dpi = dpi_get_data_from_pdev(pdev); struct omap_dss_device *out = &dpi->output; @@ -775,7 +776,7 @@ static void dpi_init_output_port(struct platform_device *pdev, omapdss_register_output(out); } -static void __exit dpi_uninit_output_port(struct device_node *port) +static void dpi_uninit_output_port(struct device_node *port) { struct dpi_data *dpi = port->data; struct omap_dss_device *out = &dpi->output; @@ -783,8 +784,9 @@ static void __exit dpi_uninit_output_port(struct device_node *port) omapdss_unregister_output(out); } -static int omap_dpi_probe(struct platform_device *pdev) +static int dpi_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); struct dpi_data *dpi; dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL); @@ -802,16 +804,32 @@ static int omap_dpi_probe(struct platform_device *pdev) return 0; } -static int __exit omap_dpi_remove(struct platform_device *pdev) +static void dpi_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + dpi_uninit_output(pdev); +} + +static const struct component_ops dpi_component_ops = { + .bind = dpi_bind, + .unbind = dpi_unbind, +}; +static int dpi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &dpi_component_ops); +} + +static int dpi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dpi_component_ops); return 0; } static struct platform_driver omap_dpi_driver = { - .probe = omap_dpi_probe, - .remove = __exit_p(omap_dpi_remove), + .probe = dpi_probe, + .remove = dpi_remove, .driver = { .name = "omapdss_dpi", .suppress_bind_attrs = true, @@ -823,12 +841,12 @@ int __init dpi_init_platform_driver(void) return platform_driver_register(&omap_dpi_driver); } -void __exit dpi_uninit_platform_driver(void) +void dpi_uninit_platform_driver(void) { platform_driver_unregister(&omap_dpi_driver); } -int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) +int dpi_init_port(struct platform_device *pdev, struct device_node *port) { struct dpi_data *dpi; struct device_node *ep; @@ -870,7 +888,7 @@ err_datalines: return r; } -void __exit dpi_uninit_port(struct device_node *port) +void dpi_uninit_port(struct device_node *port) { struct dpi_data *dpi = port->data; diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 5081f6fb1737..b3606def5b7b 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c @@ -40,6 +40,7 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/component.h> #include <video/omapdss.h> #include <video/mipi_display.h> @@ -4137,7 +4138,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; dss_mgr_set_timings(mgr, &dsi->timings); @@ -5274,8 +5275,9 @@ static int dsi_init_pll_data(struct platform_device *dsidev) } /* DSI1 HW IP initialisation */ -static int omap_dsihw_probe(struct platform_device *dsidev) +static int dsi_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *dsidev = to_platform_device(dev); u32 rev; int r, i; struct dsi_data *dsi; @@ -5484,8 +5486,9 @@ err_runtime_get: return r; } -static int __exit omap_dsihw_remove(struct platform_device *dsidev) +static void dsi_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *dsidev = to_platform_device(dev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); of_platform_depopulate(&dsidev->dev); @@ -5502,7 +5505,21 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) regulator_disable(dsi->vdds_dsi_reg); dsi->vdds_dsi_enabled = false; } +} + +static const struct component_ops dsi_component_ops = { + .bind = dsi_bind, + .unbind = dsi_unbind, +}; +static int dsi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &dsi_component_ops); +} + +static int dsi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dsi_component_ops); return 0; } @@ -5569,8 +5586,8 @@ static const struct of_device_id dsi_of_match[] = { }; static struct platform_driver omap_dsihw_driver = { - .probe = omap_dsihw_probe, - .remove = __exit_p(omap_dsihw_remove), + .probe = dsi_probe, + .remove = dsi_remove, .driver = { .name = "omapdss_dsi", .pm = &dsi_pm_ops, @@ -5584,7 +5601,7 @@ int __init dsi_init_platform_driver(void) return platform_driver_register(&omap_dsihw_driver); } -void __exit dsi_uninit_platform_driver(void) +void dsi_uninit_platform_driver(void) { platform_driver_unregister(&omap_dsihw_driver); } diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c index a6d10d4279f3..9200a8668b49 100644 --- a/drivers/video/fbdev/omap2/dss/dss.c +++ b/drivers/video/fbdev/omap2/dss/dss.c @@ -38,6 +38,8 @@ #include <linux/regmap.h> #include <linux/of.h> #include <linux/regulator/consumer.h> +#include <linux/suspend.h> +#include <linux/component.h> #include <video/omapdss.h> @@ -110,6 +112,14 @@ static const char * const dss_generic_clk_source_names[] = { [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI", }; +static bool dss_initialized; + +bool omapdss_is_initialized(void) +{ + return dss_initialized; +} +EXPORT_SYMBOL(omapdss_is_initialized); + static inline void dss_write_reg(const struct dss_reg idx, u32 val) { __raw_writel(val, dss.base + idx.idx); @@ -810,7 +820,7 @@ static const enum omap_display_type dra7xx_ports[] = { OMAP_DISPLAY_TYPE_DPI, }; -static const struct dss_features omap24xx_dss_feats __initconst = { +static const struct dss_features omap24xx_dss_feats = { /* * fck div max is really 16, but the divider range has gaps. The range * from 1 to 6 has no gaps, so let's use that as a max. @@ -823,7 +833,7 @@ static const struct dss_features omap24xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap2plus_ports), }; -static const struct dss_features omap34xx_dss_feats __initconst = { +static const struct dss_features omap34xx_dss_feats = { .fck_div_max = 16, .dss_fck_multiplier = 2, .parent_clk_name = "dpll4_ck", @@ -832,7 +842,7 @@ static const struct dss_features omap34xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap34xx_ports), }; -static const struct dss_features omap3630_dss_feats __initconst = { +static const struct dss_features omap3630_dss_feats = { .fck_div_max = 32, .dss_fck_multiplier = 1, .parent_clk_name = "dpll4_ck", @@ -841,7 +851,7 @@ static const struct dss_features omap3630_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap2plus_ports), }; -static const struct dss_features omap44xx_dss_feats __initconst = { +static const struct dss_features omap44xx_dss_feats = { .fck_div_max = 32, .dss_fck_multiplier = 1, .parent_clk_name = "dpll_per_x2_ck", @@ -850,7 +860,7 @@ static const struct dss_features omap44xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap2plus_ports), }; -static const struct dss_features omap54xx_dss_feats __initconst = { +static const struct dss_features omap54xx_dss_feats = { .fck_div_max = 64, .dss_fck_multiplier = 1, .parent_clk_name = "dpll_per_x2_ck", @@ -859,7 +869,7 @@ static const struct dss_features omap54xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap2plus_ports), }; -static const struct dss_features am43xx_dss_feats __initconst = { +static const struct dss_features am43xx_dss_feats = { .fck_div_max = 0, .dss_fck_multiplier = 0, .parent_clk_name = NULL, @@ -868,7 +878,7 @@ static const struct dss_features am43xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(omap2plus_ports), }; -static const struct dss_features dra7xx_dss_feats __initconst = { +static const struct dss_features dra7xx_dss_feats = { .fck_div_max = 64, .dss_fck_multiplier = 1, .parent_clk_name = "dpll_per_x2_ck", @@ -877,7 +887,7 @@ static const struct dss_features dra7xx_dss_feats __initconst = { .num_ports = ARRAY_SIZE(dra7xx_ports), }; -static int __init dss_init_features(struct platform_device *pdev) +static int dss_init_features(struct platform_device *pdev) { const struct dss_features *src; struct dss_features *dst; @@ -931,7 +941,7 @@ static int __init dss_init_features(struct platform_device *pdev) return 0; } -static int __init dss_init_ports(struct platform_device *pdev) +static int dss_init_ports(struct platform_device *pdev) { struct device_node *parent = pdev->dev.of_node; struct device_node *port; @@ -975,7 +985,7 @@ static int __init dss_init_ports(struct platform_device *pdev) return 0; } -static void __exit dss_uninit_ports(struct platform_device *pdev) +static void dss_uninit_ports(struct platform_device *pdev) { struct device_node *parent = pdev->dev.of_node; struct device_node *port; @@ -1017,14 +1027,74 @@ static void __exit dss_uninit_ports(struct platform_device *pdev) } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); } +static int dss_video_pll_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct regulator *pll_regulator; + int r; + + if (!np) + return 0; + + if (of_property_read_bool(np, "syscon-pll-ctrl")) { + dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, + "syscon-pll-ctrl"); + if (IS_ERR(dss.syscon_pll_ctrl)) { + dev_err(&pdev->dev, + "failed to get syscon-pll-ctrl regmap\n"); + return PTR_ERR(dss.syscon_pll_ctrl); + } + + if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1, + &dss.syscon_pll_ctrl_offset)) { + dev_err(&pdev->dev, + "failed to get syscon-pll-ctrl offset\n"); + return -EINVAL; + } + } + + pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video"); + if (IS_ERR(pll_regulator)) { + r = PTR_ERR(pll_regulator); + + switch (r) { + case -ENOENT: + pll_regulator = NULL; + break; + + case -EPROBE_DEFER: + return -EPROBE_DEFER; + + default: + DSSERR("can't get DPLL VDDA regulator\n"); + return r; + } + } + + if (of_property_match_string(np, "reg-names", "pll1") >= 0) { + dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator); + if (IS_ERR(dss.video1_pll)) + return PTR_ERR(dss.video1_pll); + } + + if (of_property_match_string(np, "reg-names", "pll2") >= 0) { + dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator); + if (IS_ERR(dss.video2_pll)) { + dss_video_pll_uninit(dss.video1_pll); + return PTR_ERR(dss.video2_pll); + } + } + + return 0; +} + /* DSS HW IP initialisation */ -static int __init omap_dsshw_probe(struct platform_device *pdev) +static int dss_bind(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct resource *dss_mem; - struct device_node *np = pdev->dev.of_node; u32 rev; int r; - struct regulator *pll_regulator; dss.pdev = pdev; @@ -1053,6 +1123,14 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) if (r) goto err_setup_clocks; + r = dss_video_pll_probe(pdev); + if (r) + goto err_pll_init; + + r = dss_init_ports(pdev); + if (r) + goto err_init_ports; + pm_runtime_enable(&pdev->dev); r = dss_runtime_get(); @@ -1077,84 +1155,48 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; - dss_init_ports(pdev); - - if (np && of_property_read_bool(np, "syscon-pll-ctrl")) { - dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np, - "syscon-pll-ctrl"); - if (IS_ERR(dss.syscon_pll_ctrl)) { - dev_err(&pdev->dev, - "failed to get syscon-pll-ctrl regmap\n"); - return PTR_ERR(dss.syscon_pll_ctrl); - } - - if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1, - &dss.syscon_pll_ctrl_offset)) { - dev_err(&pdev->dev, - "failed to get syscon-pll-ctrl offset\n"); - return -EINVAL; - } - } - - pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video"); - if (IS_ERR(pll_regulator)) { - r = PTR_ERR(pll_regulator); - - switch (r) { - case -ENOENT: - pll_regulator = NULL; - break; - - case -EPROBE_DEFER: - return -EPROBE_DEFER; - - default: - DSSERR("can't get DPLL VDDA regulator\n"); - return r; - } - } - - if (of_property_match_string(np, "reg-names", "pll1") >= 0) { - dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator); - if (IS_ERR(dss.video1_pll)) { - r = PTR_ERR(dss.video1_pll); - goto err_pll_init; - } - } - - if (of_property_match_string(np, "reg-names", "pll2") >= 0) { - dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator); - if (IS_ERR(dss.video2_pll)) { - r = PTR_ERR(dss.video2_pll); - goto err_pll_init; - } - } - rev = dss_read_reg(DSS_REVISION); printk(KERN_INFO "OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); dss_runtime_put(); + r = component_bind_all(&pdev->dev, NULL); + if (r) + goto err_component; + dss_debugfs_create_file("dss", dss_dump_regs); + pm_set_vt_switch(0); + + dss_initialized = true; + return 0; -err_pll_init: +err_component: +err_runtime_get: + pm_runtime_disable(&pdev->dev); + dss_uninit_ports(pdev); +err_init_ports: if (dss.video1_pll) dss_video_pll_uninit(dss.video1_pll); if (dss.video2_pll) dss_video_pll_uninit(dss.video2_pll); -err_runtime_get: - pm_runtime_disable(&pdev->dev); +err_pll_init: err_setup_clocks: dss_put_clocks(); return r; } -static int __exit omap_dsshw_remove(struct platform_device *pdev) +static void dss_unbind(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + + dss_initialized = false; + + component_unbind_all(&pdev->dev, NULL); + if (dss.video1_pll) dss_video_pll_uninit(dss.video1_pll); @@ -1166,7 +1208,55 @@ static int __exit omap_dsshw_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); dss_put_clocks(); +} + +static const struct component_master_ops dss_component_ops = { + .bind = dss_bind, + .unbind = dss_unbind, +}; +static int dss_component_compare(struct device *dev, void *data) +{ + struct device *child = data; + return dev == child; +} + +static int dss_add_child_component(struct device *dev, void *data) +{ + struct component_match **match = data; + + /* + * HACK + * We don't have a working driver for rfbi, so skip it here always. + * Otherwise dss will never get probed successfully, as it will wait + * for rfbi to get probed. + */ + if (strstr(dev_name(dev), "rfbi")) + return 0; + + component_match_add(dev->parent, match, dss_component_compare, dev); + + return 0; +} + +static int dss_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + int r; + + /* add all the child devices as components */ + device_for_each_child(&pdev->dev, &match, dss_add_child_component); + + r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); + if (r) + return r; + + return 0; +} + +static int dss_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &dss_component_ops); return 0; } @@ -1212,7 +1302,8 @@ static const struct of_device_id dss_of_match[] = { MODULE_DEVICE_TABLE(of, dss_of_match); static struct platform_driver omap_dsshw_driver = { - .remove = __exit_p(omap_dsshw_remove), + .probe = dss_probe, + .remove = dss_remove, .driver = { .name = "omapdss_dss", .pm = &dss_pm_ops, @@ -1223,7 +1314,7 @@ static struct platform_driver omap_dsshw_driver = { int __init dss_init_platform_driver(void) { - return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe); + return platform_driver_register(&omap_dsshw_driver); } void dss_uninit_platform_driver(void) diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h index 4812eee2622a..2406bcdb831a 100644 --- a/drivers/video/fbdev/omap2/dss/dss.h +++ b/drivers/video/fbdev/omap2/dss/dss.h @@ -309,18 +309,18 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, /* SDI */ int sdi_init_platform_driver(void) __init; -void sdi_uninit_platform_driver(void) __exit; +void sdi_uninit_platform_driver(void); #ifdef CONFIG_OMAP2_DSS_SDI -int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init; -void sdi_uninit_port(struct device_node *port) __exit; +int sdi_init_port(struct platform_device *pdev, struct device_node *port); +void sdi_uninit_port(struct device_node *port); #else -static inline int __init sdi_init_port(struct platform_device *pdev, +static inline int sdi_init_port(struct platform_device *pdev, struct device_node *port) { return 0; } -static inline void __exit sdi_uninit_port(struct device_node *port) +static inline void sdi_uninit_port(struct device_node *port) { } #endif @@ -333,7 +333,7 @@ struct dentry; struct file_operations; int dsi_init_platform_driver(void) __init; -void dsi_uninit_platform_driver(void) __exit; +void dsi_uninit_platform_driver(void); void dsi_dump_clocks(struct seq_file *s); @@ -350,25 +350,25 @@ static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) /* DPI */ int dpi_init_platform_driver(void) __init; -void dpi_uninit_platform_driver(void) __exit; +void dpi_uninit_platform_driver(void); #ifdef CONFIG_OMAP2_DSS_DPI -int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init; -void dpi_uninit_port(struct device_node *port) __exit; +int dpi_init_port(struct platform_device *pdev, struct device_node *port); +void dpi_uninit_port(struct device_node *port); #else -static inline int __init dpi_init_port(struct platform_device *pdev, +static inline int dpi_init_port(struct platform_device *pdev, struct device_node *port) { return 0; } -static inline void __exit dpi_uninit_port(struct device_node *port) +static inline void dpi_uninit_port(struct device_node *port) { } #endif /* DISPC */ int dispc_init_platform_driver(void) __init; -void dispc_uninit_platform_driver(void) __exit; +void dispc_uninit_platform_driver(void); void dispc_dump_clocks(struct seq_file *s); void dispc_enable_sidle(void); @@ -418,18 +418,18 @@ int dispc_wb_setup(const struct omap_dss_writeback_info *wi, /* VENC */ int venc_init_platform_driver(void) __init; -void venc_uninit_platform_driver(void) __exit; +void venc_uninit_platform_driver(void); /* HDMI */ int hdmi4_init_platform_driver(void) __init; -void hdmi4_uninit_platform_driver(void) __exit; +void hdmi4_uninit_platform_driver(void); int hdmi5_init_platform_driver(void) __init; -void hdmi5_uninit_platform_driver(void) __exit; +void hdmi5_uninit_platform_driver(void); /* RFBI */ int rfbi_init_platform_driver(void) __init; -void rfbi_uninit_platform_driver(void) __exit; +void rfbi_uninit_platform_driver(void); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c index 376270b777f8..b0b6dfd657bf 100644 --- a/drivers/video/fbdev/omap2/dss/dss_features.c +++ b/drivers/video/fbdev/omap2/dss/dss_features.c @@ -440,7 +440,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { static const struct dss_param_range am43xx_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, - [FEAT_PARAM_DSS_PCD] = { 2, 255 }, + [FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, }; diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 916d47978f41..6d3aa3f51c20 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -32,6 +32,7 @@ #include <linux/clk.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/component.h> #include <video/omapdss.h> #include <sound/omap-hdmi-audio.h> @@ -229,9 +230,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) err_mgr_enable: hdmi_wp_video_stop(&hdmi.wp); err_vid_enable: -err_phy_cfg: hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); err_phy_pwr: +err_phy_cfg: err_pll_cfg: dss_pll_disable(&hdmi.pll.pll); err_pll_enable: @@ -646,8 +647,9 @@ static int hdmi_audio_register(struct device *dev) } /* HDMI HW IP initialisation */ -static int omapdss_hdmihw_probe(struct platform_device *pdev) +static int hdmi4_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); int r; int irq; @@ -713,8 +715,10 @@ err: return r; } -static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) +static void hdmi4_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + if (hdmi.audio_pdev) platform_device_unregister(hdmi.audio_pdev); @@ -723,7 +727,21 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) hdmi_pll_uninit(&hdmi.pll); pm_runtime_disable(&pdev->dev); +} + +static const struct component_ops hdmi4_component_ops = { + .bind = hdmi4_bind, + .unbind = hdmi4_unbind, +}; +static int hdmi4_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi4_component_ops); +} + +static int hdmi4_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &hdmi4_component_ops); return 0; } @@ -756,8 +774,8 @@ static const struct of_device_id hdmi_of_match[] = { }; static struct platform_driver omapdss_hdmihw_driver = { - .probe = omapdss_hdmihw_probe, - .remove = __exit_p(omapdss_hdmihw_remove), + .probe = hdmi4_probe, + .remove = hdmi4_remove, .driver = { .name = "omapdss_hdmi", .pm = &hdmi_pm_ops, @@ -771,7 +789,7 @@ int __init hdmi4_init_platform_driver(void) return platform_driver_register(&omapdss_hdmihw_driver); } -void __exit hdmi4_uninit_platform_driver(void) +void hdmi4_uninit_platform_driver(void) { platform_driver_unregister(&omapdss_hdmihw_driver); } diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c index 7eafea5b8e19..fa72e735dad2 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c @@ -654,6 +654,13 @@ static void hdmi_core_audio_infoframe_cfg(struct hdmi_core_data *core, hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3); sum += info_aud->db3; + /* + * The OMAP HDMI IP requires to use the 8-channel channel code when + * transmitting more than two channels. + */ + if (info_aud->db4_ca != 0x00) + info_aud->db4_ca = 0x13; + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca); sum += info_aud->db4_ca; @@ -795,7 +802,9 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, /* * the HDMI IP needs to enable four stereo channels when transmitting - * more than 2 audio channels + * more than 2 audio channels. Similarly, the channel count in the + * Audio InfoFrame has to match the sample_present bits (some channels + * are padded with zeroes) */ if (channel_count == 2) { audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; @@ -807,6 +816,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | HDMI_AUDIO_I2S_SD3_EN; acore.layout = HDMI_AUDIO_LAYOUT_8CH; + audio->cea->db1_ct_cc = 7; } acore.en_spdif = false; diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c index 3f0b34a7031a..7f875788edbc 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5.c @@ -37,6 +37,7 @@ #include <linux/clk.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/component.h> #include <video/omapdss.h> #include <sound/omap-hdmi-audio.h> @@ -681,8 +682,9 @@ static int hdmi_audio_register(struct device *dev) } /* HDMI HW IP initialisation */ -static int omapdss_hdmihw_probe(struct platform_device *pdev) +static int hdmi5_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); int r; int irq; @@ -748,8 +750,10 @@ err: return r; } -static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) +static void hdmi5_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + if (hdmi.audio_pdev) platform_device_unregister(hdmi.audio_pdev); @@ -758,7 +762,21 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) hdmi_pll_uninit(&hdmi.pll); pm_runtime_disable(&pdev->dev); +} + +static const struct component_ops hdmi5_component_ops = { + .bind = hdmi5_bind, + .unbind = hdmi5_unbind, +}; +static int hdmi5_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi5_component_ops); +} + +static int hdmi5_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &hdmi5_component_ops); return 0; } @@ -792,8 +810,8 @@ static const struct of_device_id hdmi_of_match[] = { }; static struct platform_driver omapdss_hdmihw_driver = { - .probe = omapdss_hdmihw_probe, - .remove = __exit_p(omapdss_hdmihw_remove), + .probe = hdmi5_probe, + .remove = hdmi5_remove, .driver = { .name = "omapdss_hdmi5", .pm = &hdmi_pm_ops, @@ -807,7 +825,7 @@ int __init hdmi5_init_platform_driver(void) return platform_driver_register(&omapdss_hdmihw_driver); } -void __exit hdmi5_uninit_platform_driver(void) +void hdmi5_uninit_platform_driver(void) { platform_driver_unregister(&omapdss_hdmihw_driver); } diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c index a3cfe3d708f7..8ea531d2652c 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c @@ -55,7 +55,7 @@ static void hdmi_core_ddc_init(struct hdmi_core_data *core) const unsigned ss_scl_low = 4700; /* ns */ const unsigned fs_scl_high = 600; /* ns */ const unsigned fs_scl_low = 1300; /* ns */ - const unsigned sda_hold = 300; /* ns */ + const unsigned sda_hold = 1000; /* ns */ const unsigned sfr_div = 10; unsigned long long sfr; unsigned v; @@ -790,7 +790,9 @@ static void hdmi5_core_audio_infoframe_cfg(struct hdmi_core_data *core, hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF1, info_aud->db2_sf_ss); hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF2, info_aud->db4_ca); - hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3, info_aud->db5_dminh_lsv); + hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3, + (info_aud->db5_dminh_lsv & CEA861_AUDIO_INFOFRAME_DB5_DM_INH) >> 3 | + (info_aud->db5_dminh_lsv & CEA861_AUDIO_INFOFRAME_DB5_LSV)); } int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, @@ -870,6 +872,7 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; + audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; /* only LPCM atm */ audio_format.type = HDMI_AUDIO_TYPE_LPCM; diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c index c15377e242cc..7c544bc56fb5 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c @@ -110,7 +110,23 @@ int hdmi_wp_video_start(struct hdmi_wp_data *wp) void hdmi_wp_video_stop(struct hdmi_wp_data *wp) { + int i; + + hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE); + REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31); + + for (i = 0; i < 50; ++i) { + u32 v; + + msleep(20); + + v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW); + if (v & HDMI_IRQ_VIDEO_FRAME_DONE) + return; + } + + DSSERR("no HDMI FRAMEDONE when disabling output\n"); } void hdmi_wp_video_config_format(struct hdmi_wp_data *wp, diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c index 42b87f95267c..8b6f6d5fdd68 100644 --- a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c +++ b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c @@ -164,20 +164,15 @@ static void __init omapdss_walk_device(struct device_node *node, bool root) pn = of_graph_get_remote_port_parent(n); - if (!pn) { - of_node_put(n); + if (!pn) continue; - } if (!of_device_is_available(pn) || omapdss_list_contains(pn)) { of_node_put(pn); - of_node_put(n); continue; } omapdss_walk_device(pn, false); - - of_node_put(n); } } diff --git a/drivers/video/fbdev/omap2/dss/rfbi.c b/drivers/video/fbdev/omap2/dss/rfbi.c index 28e694b11ff9..1525a494d057 100644 --- a/drivers/video/fbdev/omap2/dss/rfbi.c +++ b/drivers/video/fbdev/omap2/dss/rfbi.c @@ -36,6 +36,7 @@ #include <linux/semaphore.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/component.h> #include <video/omapdss.h> #include "dss.h" @@ -869,7 +870,7 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; dss_mgr_set_timings(mgr, &rfbi.timings); } @@ -938,7 +939,7 @@ static void rfbi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void __exit rfbi_uninit_output(struct platform_device *pdev) +static void rfbi_uninit_output(struct platform_device *pdev) { struct omap_dss_device *out = &rfbi.output; @@ -946,8 +947,9 @@ static void __exit rfbi_uninit_output(struct platform_device *pdev) } /* RFBI HW IP initialisation */ -static int omap_rfbihw_probe(struct platform_device *pdev) +static int rfbi_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); u32 rev; struct resource *rfbi_mem; struct clk *clk; @@ -1005,8 +1007,10 @@ err_runtime_get: return r; } -static int __exit omap_rfbihw_remove(struct platform_device *pdev) +static void rfbi_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + rfbi_uninit_output(pdev); pm_runtime_disable(&pdev->dev); @@ -1014,6 +1018,22 @@ static int __exit omap_rfbihw_remove(struct platform_device *pdev) return 0; } +static const struct component_ops rfbi_component_ops = { + .bind = rfbi_bind, + .unbind = rfbi_unbind, +}; + +static int rfbi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &rfbi_component_ops); +} + +static int rfbi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &rfbi_component_ops); + return 0; +} + static int rfbi_runtime_suspend(struct device *dev) { dispc_runtime_put(); @@ -1038,8 +1058,8 @@ static const struct dev_pm_ops rfbi_pm_ops = { }; static struct platform_driver omap_rfbihw_driver = { - .probe = omap_rfbihw_probe, - .remove = __exit_p(omap_rfbihw_remove), + .probe = rfbi_probe, + .remove = rfbi_remove, .driver = { .name = "omapdss_rfbi", .pm = &rfbi_pm_ops, @@ -1052,7 +1072,7 @@ int __init rfbi_init_platform_driver(void) return platform_driver_register(&omap_rfbihw_driver); } -void __exit rfbi_uninit_platform_driver(void) +void rfbi_uninit_platform_driver(void) { platform_driver_unregister(&omap_rfbihw_driver); } diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/video/fbdev/omap2/dss/sdi.c index 5c2ccab5a958..5843580a1deb 100644 --- a/drivers/video/fbdev/omap2/dss/sdi.c +++ b/drivers/video/fbdev/omap2/dss/sdi.c @@ -27,6 +27,7 @@ #include <linux/platform_device.h> #include <linux/string.h> #include <linux/of.h> +#include <linux/component.h> #include <video/omapdss.h> #include "dss.h" @@ -350,15 +351,17 @@ static void sdi_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void __exit sdi_uninit_output(struct platform_device *pdev) +static void sdi_uninit_output(struct platform_device *pdev) { struct omap_dss_device *out = &sdi.output; omapdss_unregister_output(out); } -static int omap_sdi_probe(struct platform_device *pdev) +static int sdi_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + sdi.pdev = pdev; sdi_init_output(pdev); @@ -366,16 +369,32 @@ static int omap_sdi_probe(struct platform_device *pdev) return 0; } -static int __exit omap_sdi_remove(struct platform_device *pdev) +static void sdi_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + sdi_uninit_output(pdev); +} + +static const struct component_ops sdi_component_ops = { + .bind = sdi_bind, + .unbind = sdi_unbind, +}; +static int sdi_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &sdi_component_ops); +} + +static int sdi_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &sdi_component_ops); return 0; } static struct platform_driver omap_sdi_driver = { - .probe = omap_sdi_probe, - .remove = __exit_p(omap_sdi_remove), + .probe = sdi_probe, + .remove = sdi_remove, .driver = { .name = "omapdss_sdi", .suppress_bind_attrs = true, @@ -387,12 +406,12 @@ int __init sdi_init_platform_driver(void) return platform_driver_register(&omap_sdi_driver); } -void __exit sdi_uninit_platform_driver(void) +void sdi_uninit_platform_driver(void) { platform_driver_unregister(&omap_sdi_driver); } -int __init sdi_init_port(struct platform_device *pdev, struct device_node *port) +int sdi_init_port(struct platform_device *pdev, struct device_node *port) { struct device_node *ep; u32 datapairs; @@ -426,7 +445,7 @@ err_datapairs: return r; } -void __exit sdi_uninit_port(struct device_node *port) +void sdi_uninit_port(struct device_node *port) { if (!sdi.port_initialized) return; diff --git a/drivers/video/fbdev/omap2/dss/venc.c b/drivers/video/fbdev/omap2/dss/venc.c index ef7fd925e7f2..99ca268c1cdd 100644 --- a/drivers/video/fbdev/omap2/dss/venc.c +++ b/drivers/video/fbdev/omap2/dss/venc.c @@ -35,6 +35,7 @@ #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/component.h> #include <video/omapdss.h> @@ -802,7 +803,7 @@ static void venc_init_output(struct platform_device *pdev) omapdss_register_output(out); } -static void __exit venc_uninit_output(struct platform_device *pdev) +static void venc_uninit_output(struct platform_device *pdev) { struct omap_dss_device *out = &venc.output; @@ -852,8 +853,9 @@ err: } /* VENC HW IP initialisation */ -static int omap_venchw_probe(struct platform_device *pdev) +static int venc_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); u8 rev_id; struct resource *venc_mem; int r; @@ -912,12 +914,28 @@ err_runtime_get: return r; } -static int __exit omap_venchw_remove(struct platform_device *pdev) +static void venc_unbind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); + venc_uninit_output(pdev); pm_runtime_disable(&pdev->dev); +} +static const struct component_ops venc_component_ops = { + .bind = venc_bind, + .unbind = venc_unbind, +}; + +static int venc_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &venc_component_ops); +} + +static int venc_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &venc_component_ops); return 0; } @@ -950,7 +968,6 @@ static const struct dev_pm_ops venc_pm_ops = { .runtime_resume = venc_runtime_resume, }; - static const struct of_device_id venc_of_match[] = { { .compatible = "ti,omap2-venc", }, { .compatible = "ti,omap3-venc", }, @@ -959,8 +976,8 @@ static const struct of_device_id venc_of_match[] = { }; static struct platform_driver omap_venchw_driver = { - .probe = omap_venchw_probe, - .remove = __exit_p(omap_venchw_remove), + .probe = venc_probe, + .remove = venc_remove, .driver = { .name = "omapdss_venc", .pm = &venc_pm_ops, @@ -974,7 +991,7 @@ int __init venc_init_platform_driver(void) return platform_driver_register(&omap_venchw_driver); } -void __exit venc_uninit_platform_driver(void) +void venc_uninit_platform_driver(void) { platform_driver_unregister(&omap_venchw_driver); } diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index 22f07f88bc40..4f0cbb54d4db 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -2073,7 +2073,7 @@ static int omapfb_mode_to_timings(const char *mode_str, } else { timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; } timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000; @@ -2223,7 +2223,7 @@ static void fb_videomode_to_omap_timings(struct fb_videomode *m, } else { t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; t->de_level = OMAPDSS_SIG_ACTIVE_HIGH; - t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; } t->x_res = m->xres; |