aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mediatek
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2021-06-18 10:21:44 +1000
committerDave Airlie <airlied@redhat.com>2021-06-18 10:21:53 +1000
commit43ccc7831fc4864b99954914537ec3c819997f41 (patch)
tree451a95ef2c046e8e056c892e4d4fccf1f3f91080 /drivers/gpu/drm/mediatek
parentMerge tag 'exynos-drm-next-for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next (diff)
parentdrm/mediatek: dpi: Add bus format negotiation (diff)
downloadlinux-dev-43ccc7831fc4864b99954914537ec3c819997f41.tar.xz
linux-dev-43ccc7831fc4864b99954914537ec3c819997f41.zip
Merge tag 'mediatek-drm-next-5.14' of https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux into drm-next
Mediatek DRM Next for Linux 5.14 1. Add MT8167 HDMI support 2. Fix PM reference leak 3. Add MT8183 DPI dual edge support Signed-off-by: Dave Airlie <airlied@redhat.com> From: Chun-Kuang Hu <chunkuang.hu@kernel.org> Link: https://patchwork.freedesktop.org/patch/msgid/20210616150301.292-1-chunkuang.hu@kernel.org
Diffstat (limited to 'drivers/gpu/drm/mediatek')
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c129
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c17
3 files changed, 141 insertions, 7 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index bea91c81626e..bced555648b0 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -83,6 +83,7 @@ struct mtk_dpi {
struct pinctrl *pinctrl;
struct pinctrl_state *pins_gpio;
struct pinctrl_state *pins_dpi;
+ u32 output_fmt;
int refcount;
};
@@ -122,6 +123,8 @@ struct mtk_dpi_conf {
u32 reg_h_fre_con;
u32 max_clock_khz;
bool edge_sel_en;
+ const u32 *output_fmts;
+ u32 num_output_fmts;
};
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -381,6 +384,20 @@ static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
}
}
+static void mtk_dpi_dual_edge(struct mtk_dpi *dpi)
+{
+ if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
+ (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE)) {
+ mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE,
+ DDR_EN | DDR_4PHASE);
+ mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING,
+ dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE ?
+ EDGE_SEL : 0, EDGE_SEL);
+ } else {
+ mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE, 0);
+ }
+}
+
static void mtk_dpi_power_off(struct mtk_dpi *dpi)
{
if (WARN_ON(dpi->refcount == 0))
@@ -455,7 +472,13 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
pll_rate = clk_get_rate(dpi->tvd_clk);
vm.pixelclock = pll_rate / factor;
- clk_set_rate(dpi->pixel_clk, vm.pixelclock);
+ if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
+ (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
+ clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
+ else
+ clk_set_rate(dpi->pixel_clk, vm.pixelclock);
+
+
vm.pixelclock = clk_get_rate(dpi->pixel_clk);
dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
@@ -519,12 +542,87 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_color_format(dpi, dpi->color_format);
mtk_dpi_config_2n_h_fre(dpi);
+ mtk_dpi_dual_edge(dpi);
mtk_dpi_config_disable_edge(dpi);
mtk_dpi_sw_reset(dpi, false);
return 0;
}
+static u32 *mtk_dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts)
+{
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ u32 *output_fmts;
+
+ *num_output_fmts = 0;
+
+ if (!dpi->conf->output_fmts) {
+ dev_err(dpi->dev, "output_fmts should not be null\n");
+ return NULL;
+ }
+
+ output_fmts = kcalloc(dpi->conf->num_output_fmts, sizeof(*output_fmts),
+ GFP_KERNEL);
+ if (!output_fmts)
+ return NULL;
+
+ *num_output_fmts = dpi->conf->num_output_fmts;
+
+ memcpy(output_fmts, dpi->conf->output_fmts,
+ sizeof(*output_fmts) * dpi->conf->num_output_fmts);
+
+ return output_fmts;
+}
+
+static u32 *mtk_dpi_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;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kcalloc(1, sizeof(*input_fmts),
+ GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ *num_input_fmts = 1;
+ input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+
+ return input_fmts;
+}
+
+static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct mtk_dpi *dpi = bridge->driver_private;
+ unsigned int out_bus_format;
+
+ out_bus_format = bridge_state->output_bus_cfg.format;
+
+ dev_dbg(dpi->dev, "input format 0x%04x, output format 0x%04x\n",
+ bridge_state->input_bus_cfg.format,
+ bridge_state->output_bus_cfg.format);
+
+ dpi->output_fmt = out_bus_format;
+ dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
+ dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
+ dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
+ dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
+
+ return 0;
+}
+
static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
@@ -577,6 +675,12 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
.mode_valid = mtk_dpi_bridge_mode_valid,
.disable = mtk_dpi_bridge_disable,
.enable = mtk_dpi_bridge_enable,
+ .atomic_check = mtk_dpi_bridge_atomic_check,
+ .atomic_get_output_bus_fmts = mtk_dpi_bridge_atomic_get_output_bus_fmts,
+ .atomic_get_input_bus_fmts = mtk_dpi_bridge_atomic_get_input_bus_fmts,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
};
void mtk_dpi_start(struct device *dev)
@@ -623,11 +727,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
}
drm_connector_attach_encoder(dpi->connector, &dpi->encoder);
- dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
- dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
- dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
- dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
-
return 0;
err_cleanup:
@@ -680,10 +779,21 @@ static unsigned int mt8183_calculate_factor(int clock)
return 2;
}
+static const u32 mt8173_output_fmts[] = {
+ MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+static const u32 mt8183_output_fmts[] = {
+ MEDIA_BUS_FMT_RGB888_2X12_LE,
+ MEDIA_BUS_FMT_RGB888_2X12_BE,
+};
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
.max_clock_khz = 300000,
+ .output_fmts = mt8173_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
};
static const struct mtk_dpi_conf mt2701_conf = {
@@ -691,18 +801,24 @@ static const struct mtk_dpi_conf mt2701_conf = {
.reg_h_fre_con = 0xb0,
.edge_sel_en = true,
.max_clock_khz = 150000,
+ .output_fmts = mt8173_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
};
static const struct mtk_dpi_conf mt8183_conf = {
.cal_factor = mt8183_calculate_factor,
.reg_h_fre_con = 0xe0,
.max_clock_khz = 100000,
+ .output_fmts = mt8183_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
};
static const struct mtk_dpi_conf mt8192_conf = {
.cal_factor = mt8183_calculate_factor,
.reg_h_fre_con = 0xe0,
.max_clock_khz = 150000,
+ .output_fmts = mt8173_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
};
static int mtk_dpi_probe(struct platform_device *pdev)
@@ -718,6 +834,7 @@ static int mtk_dpi_probe(struct platform_device *pdev)
dpi->dev = dev;
dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev);
+ dpi->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
dpi->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(dpi->pinctrl)) {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 40df2c823187..474efb844249 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -260,7 +260,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
drm_connector_list_iter_end(&conn_iter);
}
- ret = pm_runtime_get_sync(crtc->dev->dev);
+ ret = pm_runtime_resume_and_get(crtc->dev->dev);
if (ret < 0) {
DRM_ERROR("Failed to enable power domain: %d\n", ret);
return ret;
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index dea46d66e712..c1651a83700d 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -148,6 +148,8 @@ struct hdmi_audio_param {
struct mtk_hdmi_conf {
bool tz_disabled;
+ bool cea_modes_only;
+ unsigned long max_mode_clock;
};
struct mtk_hdmi {
@@ -1222,6 +1224,13 @@ static int mtk_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_BAD;
}
+ if (hdmi->conf->cea_modes_only && !drm_match_cea_mode(mode))
+ return MODE_BAD;
+
+ if (hdmi->conf->max_mode_clock &&
+ mode->clock > hdmi->conf->max_mode_clock)
+ return MODE_CLOCK_HIGH;
+
if (mode->clock < 27000)
return MODE_CLOCK_LOW;
if (mode->clock > 297000)
@@ -1778,10 +1787,18 @@ static const struct mtk_hdmi_conf mtk_hdmi_conf_mt2701 = {
.tz_disabled = true,
};
+static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8167 = {
+ .max_mode_clock = 148500,
+ .cea_modes_only = true,
+};
+
static const struct of_device_id mtk_drm_hdmi_of_ids[] = {
{ .compatible = "mediatek,mt2701-hdmi",
.data = &mtk_hdmi_conf_mt2701,
},
+ { .compatible = "mediatek,mt8167-hdmi",
+ .data = &mtk_hdmi_conf_mt8167,
+ },
{ .compatible = "mediatek,mt8173-hdmi",
},
{}