summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/nwl-dsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/nwl-dsi.c')
-rw-r--r--drivers/gpu/drm/bridge/nwl-dsi.c155
1 files changed, 84 insertions, 71 deletions
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index 873995f0a741..2f7429b24fc2 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -7,15 +7,17 @@
*/
#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/math64.h>
#include <linux/mfd/syscon.h>
+#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/mux/consumer.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/sys_soc.h>
@@ -25,7 +27,6 @@
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <video/mipi_display.h>
@@ -48,12 +49,6 @@ enum transfer_direction {
#define NWL_DSI_ENDPOINT_LCDIF 0
#define NWL_DSI_ENDPOINT_DCSS 1
-struct nwl_dsi_plat_clk_config {
- const char *id;
- struct clk *clk;
- bool present;
-};
-
struct nwl_dsi_transfer {
const struct mipi_dsi_msg *msg;
struct mipi_dsi_packet packet;
@@ -71,7 +66,6 @@ struct nwl_dsi_transfer {
struct nwl_dsi {
struct drm_bridge bridge;
struct mipi_dsi_host dsi_host;
- struct drm_bridge *panel_bridge;
struct device *dev;
struct phy *phy;
union phy_configure_opts phy_cfg;
@@ -196,18 +190,15 @@ static u32 ps2bc(struct nwl_dsi *dsi, unsigned long long ps)
u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
return DIV64_U64_ROUND_UP(ps * dsi->mode.clock * bpp,
- dsi->lanes * 8 * NSEC_PER_SEC);
+ dsi->lanes * 8ULL * NSEC_PER_SEC);
}
/*
* ui2bc - UI time periods to byte clock cycles
*/
-static u32 ui2bc(struct nwl_dsi *dsi, unsigned long long ui)
+static u32 ui2bc(unsigned int ui)
{
- u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
-
- return DIV64_U64_ROUND_UP(ui * dsi->lanes,
- dsi->mode.clock * 1000 * bpp);
+ return DIV_ROUND_UP(ui, BITS_PER_BYTE);
}
/*
@@ -238,12 +229,12 @@ static int nwl_dsi_config_host(struct nwl_dsi *dsi)
}
/* values in byte clock cycles */
- cycles = ui2bc(dsi, cfg->clk_pre);
+ cycles = ui2bc(cfg->clk_pre);
DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_pre: 0x%x\n", cycles);
nwl_dsi_write(dsi, NWL_DSI_CFG_T_PRE, cycles);
cycles = ps2bc(dsi, cfg->lpx + cfg->clk_prepare + cfg->clk_zero);
DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap (pre): 0x%x\n", cycles);
- cycles += ui2bc(dsi, cfg->clk_pre);
+ cycles += ui2bc(cfg->clk_pre);
DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_post: 0x%x\n", cycles);
nwl_dsi_write(dsi, NWL_DSI_CFG_T_POST, cycles);
cycles = ps2bc(dsi, cfg->hs_exit);
@@ -298,13 +289,13 @@ static int nwl_dsi_config_dpi(struct nwl_dsi *dsi)
nwl_dsi_write(dsi, NWL_DSI_INTERFACE_COLOR_CODING, NWL_DSI_DPI_24_BIT);
nwl_dsi_write(dsi, NWL_DSI_PIXEL_FORMAT, color_format);
- /*
- * Adjusting input polarity based on the video mode results in
- * a black screen so always pick active low:
- */
nwl_dsi_write(dsi, NWL_DSI_VSYNC_POLARITY,
+ dsi->mode.flags & DRM_MODE_FLAG_PVSYNC ?
+ NWL_DSI_VSYNC_POLARITY_ACTIVE_HIGH :
NWL_DSI_VSYNC_POLARITY_ACTIVE_LOW);
nwl_dsi_write(dsi, NWL_DSI_HSYNC_POLARITY,
+ dsi->mode.flags & DRM_MODE_FLAG_PHSYNC ?
+ NWL_DSI_HSYNC_POLARITY_ACTIVE_HIGH :
NWL_DSI_HSYNC_POLARITY_ACTIVE_LOW);
burst_mode = (dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
@@ -341,17 +332,13 @@ static int nwl_dsi_config_dpi(struct nwl_dsi *dsi)
static int nwl_dsi_init_interrupts(struct nwl_dsi *dsi)
{
- u32 irq_enable;
-
- nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, 0xffffffff);
- nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
-
- irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
- NWL_DSI_RX_PKT_HDR_RCVD_MASK |
- NWL_DSI_TX_FIFO_OVFLW_MASK |
- NWL_DSI_HS_TX_TIMEOUT_MASK);
+ u32 irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |
+ NWL_DSI_RX_PKT_HDR_RCVD_MASK |
+ NWL_DSI_TX_FIFO_OVFLW_MASK |
+ NWL_DSI_HS_TX_TIMEOUT_MASK);
nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, irq_enable);
+ nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);
return nwl_dsi_clear_error(dsi);
}
@@ -679,6 +666,12 @@ static int nwl_dsi_mode_set(struct nwl_dsi *dsi)
return ret;
}
+ ret = phy_set_mode(dsi->phy, PHY_MODE_MIPI_DPHY);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set DSI phy mode: %d\n", ret);
+ goto uninit_phy;
+ }
+
ret = phy_configure(dsi->phy, phy_cfg);
if (ret < 0) {
DRM_DEV_ERROR(dev, "Failed to configure DSI phy: %d\n", ret);
@@ -743,9 +736,8 @@ static int nwl_dsi_disable(struct nwl_dsi *dsi)
return 0;
}
-static void
-nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct nwl_dsi *dsi = bridge_to_dsi(bridge);
int ret;
@@ -866,21 +858,22 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
/* Save the new desired phy config */
memcpy(&dsi->phy_cfg, &new_cfg, sizeof(new_cfg));
- memcpy(&dsi->mode, adjusted_mode, sizeof(dsi->mode));
+ drm_mode_copy(&dsi->mode, adjusted_mode);
drm_mode_debug_printmodeline(adjusted_mode);
- pm_runtime_get_sync(dev);
+ if (pm_runtime_resume_and_get(dev) < 0)
+ return;
if (clk_prepare_enable(dsi->lcdif_clk) < 0)
- return;
+ goto runtime_put;
if (clk_prepare_enable(dsi->core_clk) < 0)
- return;
+ goto runtime_put;
/* Step 1 from DSI reset-out instructions */
ret = reset_control_deassert(dsi->rst_pclk);
if (ret < 0) {
DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);
- return;
+ goto runtime_put;
}
/* Step 2 from DSI reset-out instructions */
@@ -890,18 +883,22 @@ nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
ret = reset_control_deassert(dsi->rst_esc);
if (ret < 0) {
DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);
- return;
+ goto runtime_put;
}
ret = reset_control_deassert(dsi->rst_byte);
if (ret < 0) {
DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);
- return;
+ goto runtime_put;
}
+
+ return;
+
+runtime_put:
+ pm_runtime_put_sync(dev);
}
-static void
-nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct nwl_dsi *dsi = bridge_to_dsi(bridge);
int ret;
@@ -913,36 +910,51 @@ nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
}
static int nwl_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct nwl_dsi *dsi = bridge_to_dsi(bridge);
struct drm_bridge *panel_bridge;
- struct drm_panel *panel;
- int ret;
- ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel,
- &panel_bridge);
- if (ret)
- return ret;
+ panel_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
- if (panel) {
- panel_bridge = drm_panel_bridge_add(panel);
- if (IS_ERR(panel_bridge))
- return PTR_ERR(panel_bridge);
- }
- dsi->panel_bridge = panel_bridge;
+ return drm_bridge_attach(encoder, panel_bridge, bridge, flags);
+}
- if (!dsi->panel_bridge)
- return -EPROBE_DEFER;
+static u32 *nwl_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts, input_fmt;
- return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
- flags);
-}
+ *num_input_fmts = 0;
-static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
-{ struct nwl_dsi *dsi = bridge_to_dsi(bridge);
+ switch (output_fmt) {
+ /* If MEDIA_BUS_FMT_FIXED is tested, return default bus format */
+ case MEDIA_BUS_FMT_FIXED:
+ input_fmt = MEDIA_BUS_FMT_RGB888_1X24;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ input_fmt = output_fmt;
+ break;
+ default:
+ return NULL;
+ }
- drm_of_panel_bridge_remove(dsi->dev->of_node, 1, 0);
+ input_fmts = kcalloc(1, sizeof(*input_fmts), GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+ input_fmts[0] = input_fmt;
+ *num_input_fmts = 1;
+
+ return input_fmts;
}
static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
@@ -952,10 +964,10 @@ static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
.atomic_check = nwl_dsi_bridge_atomic_check,
.atomic_enable = nwl_dsi_bridge_atomic_enable,
.atomic_disable = nwl_dsi_bridge_atomic_disable,
+ .atomic_get_input_bus_fmts = nwl_bridge_atomic_get_input_bus_fmts,
.mode_set = nwl_dsi_bridge_mode_set,
.mode_valid = nwl_dsi_bridge_mode_valid,
.attach = nwl_dsi_bridge_attach,
- .detach = nwl_dsi_bridge_detach,
};
static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
@@ -1127,7 +1139,7 @@ MODULE_DEVICE_TABLE(of, nwl_dsi_dt_ids);
static const struct soc_device_attribute nwl_dsi_quirks_match[] = {
{ .soc_id = "i.MX8MQ", .revision = "2.0",
.data = (void *)E11418_HS_MODE_QUIRK },
- { /* sentinel. */ },
+ { /* sentinel. */ }
};
static int nwl_dsi_probe(struct platform_device *pdev)
@@ -1137,9 +1149,10 @@ static int nwl_dsi_probe(struct platform_device *pdev)
struct nwl_dsi *dsi;
int ret;
- dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
- if (!dsi)
- return -ENOMEM;
+ dsi = devm_drm_bridge_alloc(dev, struct nwl_dsi, bridge,
+ &nwl_dsi_bridge_funcs);
+ if (IS_ERR(dsi))
+ return PTR_ERR(dsi);
dsi->dev = dev;
@@ -1168,15 +1181,16 @@ static int nwl_dsi_probe(struct platform_device *pdev)
dsi->quirks = (uintptr_t)attr->data;
dsi->bridge.driver_private = dsi;
- dsi->bridge.funcs = &nwl_dsi_bridge_funcs;
dsi->bridge.of_node = dev->of_node;
dsi->bridge.timings = &nwl_dsi_timings;
+ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
dev_set_drvdata(dev, dsi);
pm_runtime_enable(dev);
ret = nwl_dsi_select_input(dsi);
if (ret < 0) {
+ pm_runtime_disable(dev);
mipi_dsi_host_unregister(&dsi->dsi_host);
return ret;
}
@@ -1185,7 +1199,7 @@ static int nwl_dsi_probe(struct platform_device *pdev)
return 0;
}
-static int nwl_dsi_remove(struct platform_device *pdev)
+static void nwl_dsi_remove(struct platform_device *pdev)
{
struct nwl_dsi *dsi = platform_get_drvdata(pdev);
@@ -1193,7 +1207,6 @@ static int nwl_dsi_remove(struct platform_device *pdev)
mipi_dsi_host_unregister(&dsi->dsi_host);
drm_bridge_remove(&dsi->bridge);
pm_runtime_disable(&pdev->dev);
- return 0;
}
static struct platform_driver nwl_dsi_driver = {