summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/samsung-dsim.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/samsung-dsim.c')
-rw-r--r--drivers/gpu/drm/bridge/samsung-dsim.c105
1 files changed, 51 insertions, 54 deletions
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index be5914caa17d..0014c497e3fe 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -10,7 +10,7 @@
* Tomasz Figa <t.figa@samsung.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -96,6 +96,7 @@
#define DSIM_MFLUSH_VS BIT(29)
/* This flag is valid only for exynos3250/3472/5260/5430 */
#define DSIM_CLKLANE_STOP BIT(30)
+#define DSIM_NON_CONTINUOUS_CLKLANE BIT(31)
/* DSIM_ESCMODE */
#define DSIM_TX_TRIGGER_RST BIT(4)
@@ -573,8 +574,8 @@ static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi,
u16 _m, best_m;
u8 _s, best_s;
- p_min = DIV_ROUND_UP(fin, (12 * MHZ));
- p_max = fin / (6 * MHZ);
+ p_min = DIV_ROUND_UP(fin, (driver_data->pll_fin_max * MHZ));
+ p_max = fin / (driver_data->pll_fin_min * MHZ);
for (_p = p_min; _p <= p_max; ++_p) {
for (_s = 0; _s <= 5; ++_s) {
@@ -945,8 +946,12 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi)
* power consumption.
*/
if (driver_data->has_clklane_stop &&
- dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+ dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
+ if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
+ reg |= DSIM_NON_CONTINUOUS_CLKLANE;
+
reg |= DSIM_CLKLANE_STOP;
+ }
samsung_dsim_write(dsi, DSIM_CONFIG_REG, reg);
lanes_mask = BIT(dsi->lanes) - 1;
@@ -969,10 +974,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi)
reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
reg &= ~DSIM_STOP_STATE_CNT_MASK;
reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]);
-
- if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
- reg |= DSIM_FORCE_STOP_STATE;
-
samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff);
@@ -1431,18 +1432,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi)
disable_irq(dsi->irq);
}
-static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable)
-{
- u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
-
- if (enable)
- reg |= DSIM_FORCE_STOP_STATE;
- else
- reg &= ~DSIM_FORCE_STOP_STATE;
-
- samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
-}
-
static int samsung_dsim_init(struct samsung_dsim *dsi)
{
const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
@@ -1468,7 +1457,7 @@ static int samsung_dsim_init(struct samsung_dsim *dsi)
}
static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
int ret;
@@ -1492,48 +1481,37 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge,
ret = samsung_dsim_init(dsi);
if (ret)
return;
-
- samsung_dsim_set_display_mode(dsi);
- samsung_dsim_set_display_enable(dsi, true);
}
}
static void samsung_dsim_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
- if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) {
- samsung_dsim_set_display_mode(dsi);
- samsung_dsim_set_display_enable(dsi, true);
- } else {
- samsung_dsim_set_stop_state(dsi, false);
- }
+ samsung_dsim_set_display_mode(dsi);
+ samsung_dsim_set_display_enable(dsi, true);
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
}
static void samsung_dsim_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
if (!(dsi->state & DSIM_STATE_ENABLED))
return;
- if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
- samsung_dsim_set_stop_state(dsi, true);
-
+ samsung_dsim_set_display_enable(dsi, false);
dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
}
static void samsung_dsim_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
- samsung_dsim_set_display_enable(dsi, false);
-
dsi->state &= ~DSIM_STATE_ENABLED;
pm_runtime_put_sync(dsi->dev);
}
@@ -1628,6 +1606,27 @@ static int samsung_dsim_atomic_check(struct drm_bridge *bridge,
adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
}
+ /*
+ * When using video sync pulses, the HFP, HBP, and HSA are divided between
+ * the available lanes if there is more than one lane. For certain
+ * timings and lane configurations, the HFP may not be evenly divisible.
+ * If the HFP is rounded down, it ends up being too small which can cause
+ * some monitors to not sync properly. In these instances, adjust htotal
+ * and hsync to round the HFP up, and recalculate the htotal. Through trial
+ * and error, it appears that the HBP and HSA do not appearto need the same
+ * correction that HFP does.
+ */
+ if (dsi->lanes > 1) {
+ int hfp = adjusted_mode->hsync_start - adjusted_mode->hdisplay;
+ int remainder = hfp % dsi->lanes;
+
+ if (remainder) {
+ adjusted_mode->hsync_start += remainder;
+ adjusted_mode->hsync_end += remainder;
+ adjusted_mode->htotal += remainder;
+ }
+ }
+
return 0;
}
@@ -1641,11 +1640,12 @@ static void samsung_dsim_mode_set(struct drm_bridge *bridge,
}
static int samsung_dsim_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
- return drm_bridge_attach(bridge->encoder, dsi->out_bridge, bridge,
+ return drm_bridge_attach(encoder, dsi->out_bridge, bridge,
flags);
}
@@ -1828,8 +1828,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host,
if (ret)
return ret;
- samsung_dsim_set_stop_state(dsi, false);
-
ret = mipi_dsi_create_packet(&xfer.packet, msg);
if (ret < 0)
return ret;
@@ -1938,9 +1936,9 @@ int samsung_dsim_probe(struct platform_device *pdev)
struct samsung_dsim *dsi;
int ret, i;
- dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
- if (!dsi)
- return -ENOMEM;
+ dsi = devm_drm_bridge_alloc(dev, struct samsung_dsim, bridge, &samsung_dsim_bridge_funcs);
+ if (IS_ERR(dsi))
+ return PTR_ERR(dsi);
init_completion(&dsi->completed);
spin_lock_init(&dsi->transfer_lock);
@@ -2010,7 +2008,6 @@ int samsung_dsim_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
- dsi->bridge.funcs = &samsung_dsim_bridge_funcs;
dsi->bridge.of_node = dev->of_node;
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
@@ -2020,11 +2017,11 @@ int samsung_dsim_probe(struct platform_device *pdev)
else
dsi->bridge.timings = &samsung_dsim_bridge_timings_de_high;
- if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host)
+ if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) {
ret = dsi->plat_data->host_ops->register_host(dsi);
-
- if (ret)
- goto err_disable_runtime;
+ if (ret)
+ goto err_disable_runtime;
+ }
return 0;
@@ -2046,7 +2043,7 @@ void samsung_dsim_remove(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(samsung_dsim_remove);
-static int __maybe_unused samsung_dsim_suspend(struct device *dev)
+static int samsung_dsim_suspend(struct device *dev)
{
struct samsung_dsim *dsi = dev_get_drvdata(dev);
const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
@@ -2076,7 +2073,7 @@ static int __maybe_unused samsung_dsim_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused samsung_dsim_resume(struct device *dev)
+static int samsung_dsim_resume(struct device *dev)
{
struct samsung_dsim *dsi = dev_get_drvdata(dev);
const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
@@ -2111,7 +2108,7 @@ err_clk:
}
const struct dev_pm_ops samsung_dsim_pm_ops = {
- SET_RUNTIME_PM_OPS(samsung_dsim_suspend, samsung_dsim_resume, NULL)
+ RUNTIME_PM_OPS(samsung_dsim_suspend, samsung_dsim_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
@@ -2142,10 +2139,10 @@ MODULE_DEVICE_TABLE(of, samsung_dsim_of_match);
static struct platform_driver samsung_dsim_driver = {
.probe = samsung_dsim_probe,
- .remove_new = samsung_dsim_remove,
+ .remove = samsung_dsim_remove,
.driver = {
.name = "samsung-dsim",
- .pm = &samsung_dsim_pm_ops,
+ .pm = pm_ptr(&samsung_dsim_pm_ops),
.of_match_table = samsung_dsim_of_match,
},
};