Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/mediatek: Add ETHDR support for MT8195

ETHDR is a part of ovl_adaptor.
ETHDR is designed for HDR video and graphics conversion in the external
display path. It handles multiple HDR input types and performs tone
mapping, color space/color format conversion, and then combine
different layers, output the required HDR or SDR signal to the
subsequent display path.

Signed-off-by: Nancy.Lin <nancy.lin@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Bo-Chen Chen <rex-bc.chen@mediatek.com>
Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20230321121859.2355-3-nancy.lin@mediatek.com/
Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>

authored by

Nancy.Lin and committed by
Chun-Kuang Hu
d886c000 64e352c9

+398
+1
drivers/gpu/drm/mediatek/Makefile
··· 14 14 mtk_drm_plane.o \ 15 15 mtk_dsi.o \ 16 16 mtk_dpi.o \ 17 + mtk_ethdr.o \ 17 18 mtk_mdp_rdma.o 18 19 19 20 obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
+1
drivers/gpu/drm/mediatek/mtk_drm_drv.c
··· 782 782 &mtk_dpi_driver, 783 783 &mtk_drm_platform_driver, 784 784 &mtk_dsi_driver, 785 + &mtk_ethdr_driver, 785 786 &mtk_mdp_rdma_driver, 786 787 }; 787 788
+1
drivers/gpu/drm/mediatek/mtk_drm_drv.h
··· 55 55 extern struct platform_driver mtk_disp_rdma_driver; 56 56 extern struct platform_driver mtk_dpi_driver; 57 57 extern struct platform_driver mtk_dsi_driver; 58 + extern struct platform_driver mtk_ethdr_driver; 58 59 extern struct platform_driver mtk_mdp_rdma_driver; 59 60 60 61 #endif /* MTK_DRM_DRV_H */
+370
drivers/gpu/drm/mediatek/mtk_ethdr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2021 MediaTek Inc. 4 + */ 5 + 6 + #include <drm/drm_fourcc.h> 7 + #include <drm/drm_framebuffer.h> 8 + #include <linux/clk.h> 9 + #include <linux/component.h> 10 + #include <linux/of_device.h> 11 + #include <linux/of_address.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/reset.h> 14 + #include <linux/soc/mediatek/mtk-cmdq.h> 15 + #include <linux/soc/mediatek/mtk-mmsys.h> 16 + 17 + #include "mtk_drm_crtc.h" 18 + #include "mtk_drm_ddp_comp.h" 19 + #include "mtk_drm_drv.h" 20 + #include "mtk_ethdr.h" 21 + 22 + #define MIX_INTEN 0x4 23 + #define MIX_FME_CPL_INTEN BIT(1) 24 + #define MIX_INTSTA 0x8 25 + #define MIX_EN 0xc 26 + #define MIX_RST 0x14 27 + #define MIX_ROI_SIZE 0x18 28 + #define MIX_DATAPATH_CON 0x1c 29 + #define OUTPUT_NO_RND BIT(3) 30 + #define SOURCE_RGB_SEL BIT(7) 31 + #define BACKGROUND_RELAY (4 << 9) 32 + #define MIX_ROI_BGCLR 0x20 33 + #define BGCLR_BLACK 0xff000000 34 + #define MIX_SRC_CON 0x24 35 + #define MIX_SRC_L0_EN BIT(0) 36 + #define MIX_L_SRC_CON(n) (0x28 + 0x18 * (n)) 37 + #define NON_PREMULTI_SOURCE (2 << 12) 38 + #define MIX_L_SRC_SIZE(n) (0x30 + 0x18 * (n)) 39 + #define MIX_L_SRC_OFFSET(n) (0x34 + 0x18 * (n)) 40 + #define MIX_FUNC_DCM0 0x120 41 + #define MIX_FUNC_DCM1 0x124 42 + #define MIX_FUNC_DCM_ENABLE 0xffffffff 43 + 44 + #define HDR_VDO_FE_0804_HDR_DM_FE 0x804 45 + #define HDR_VDO_FE_0804_BYPASS_ALL 0xfd 46 + #define HDR_GFX_FE_0204_GFX_HDR_FE 0x204 47 + #define HDR_GFX_FE_0204_BYPASS_ALL 0xfd 48 + #define HDR_VDO_BE_0204_VDO_DM_BE 0x204 49 + #define HDR_VDO_BE_0204_BYPASS_ALL 0x7e 50 + 51 + #define MIXER_INX_MODE_BYPASS 0 52 + #define MIXER_INX_MODE_EVEN_EXTEND 1 53 + #define DEFAULT_9BIT_ALPHA 0x100 54 + #define MIXER_ALPHA_AEN BIT(8) 55 + #define MIXER_ALPHA 0xff 56 + #define ETHDR_CLK_NUM 13 57 + 58 + enum mtk_ethdr_comp_id { 59 + ETHDR_MIXER, 60 + ETHDR_VDO_FE0, 61 + ETHDR_VDO_FE1, 62 + ETHDR_GFX_FE0, 63 + ETHDR_GFX_FE1, 64 + ETHDR_VDO_BE, 65 + ETHDR_ADL_DS, 66 + ETHDR_ID_MAX 67 + }; 68 + 69 + struct mtk_ethdr_comp { 70 + struct device *dev; 71 + void __iomem *regs; 72 + struct cmdq_client_reg cmdq_base; 73 + }; 74 + 75 + struct mtk_ethdr { 76 + struct mtk_ethdr_comp ethdr_comp[ETHDR_ID_MAX]; 77 + struct clk_bulk_data ethdr_clk[ETHDR_CLK_NUM]; 78 + struct device *mmsys_dev; 79 + void (*vblank_cb)(void *data); 80 + void *vblank_cb_data; 81 + int irq; 82 + struct reset_control *reset_ctl; 83 + }; 84 + 85 + static const char * const ethdr_clk_str[] = { 86 + "ethdr_top", 87 + "mixer", 88 + "vdo_fe0", 89 + "vdo_fe1", 90 + "gfx_fe0", 91 + "gfx_fe1", 92 + "vdo_be", 93 + "adl_ds", 94 + "vdo_fe0_async", 95 + "vdo_fe1_async", 96 + "gfx_fe0_async", 97 + "gfx_fe1_async", 98 + "vdo_be_async", 99 + }; 100 + 101 + void mtk_ethdr_register_vblank_cb(struct device *dev, 102 + void (*vblank_cb)(void *), 103 + void *vblank_cb_data) 104 + { 105 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 106 + 107 + priv->vblank_cb = vblank_cb; 108 + priv->vblank_cb_data = vblank_cb_data; 109 + } 110 + 111 + void mtk_ethdr_unregister_vblank_cb(struct device *dev) 112 + { 113 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 114 + 115 + priv->vblank_cb = NULL; 116 + priv->vblank_cb_data = NULL; 117 + } 118 + 119 + void mtk_ethdr_enable_vblank(struct device *dev) 120 + { 121 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 122 + 123 + writel(MIX_FME_CPL_INTEN, priv->ethdr_comp[ETHDR_MIXER].regs + MIX_INTEN); 124 + } 125 + 126 + void mtk_ethdr_disable_vblank(struct device *dev) 127 + { 128 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 129 + 130 + writel(0x0, priv->ethdr_comp[ETHDR_MIXER].regs + MIX_INTEN); 131 + } 132 + 133 + static irqreturn_t mtk_ethdr_irq_handler(int irq, void *dev_id) 134 + { 135 + struct mtk_ethdr *priv = dev_id; 136 + 137 + writel(0x0, priv->ethdr_comp[ETHDR_MIXER].regs + MIX_INTSTA); 138 + 139 + if (!priv->vblank_cb) 140 + return IRQ_NONE; 141 + 142 + priv->vblank_cb(priv->vblank_cb_data); 143 + 144 + return IRQ_HANDLED; 145 + } 146 + 147 + void mtk_ethdr_layer_config(struct device *dev, unsigned int idx, 148 + struct mtk_plane_state *state, 149 + struct cmdq_pkt *cmdq_pkt) 150 + { 151 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 152 + struct mtk_ethdr_comp *mixer = &priv->ethdr_comp[ETHDR_MIXER]; 153 + struct mtk_plane_pending_state *pending = &state->pending; 154 + unsigned int offset = (pending->x & 1) << 31 | pending->y << 16 | pending->x; 155 + unsigned int align_width = ALIGN_DOWN(pending->width, 2); 156 + unsigned int alpha_con = 0; 157 + 158 + dev_dbg(dev, "%s+ idx:%d", __func__, idx); 159 + 160 + if (idx >= 4) 161 + return; 162 + 163 + if (!pending->enable) { 164 + mtk_ddp_write(cmdq_pkt, 0, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_SIZE(idx)); 165 + return; 166 + } 167 + 168 + if (state->base.fb && state->base.fb->format->has_alpha) 169 + alpha_con = MIXER_ALPHA_AEN | MIXER_ALPHA; 170 + 171 + mtk_mmsys_mixer_in_config(priv->mmsys_dev, idx + 1, alpha_con ? false : true, 172 + DEFAULT_9BIT_ALPHA, 173 + pending->x & 1 ? MIXER_INX_MODE_EVEN_EXTEND : 174 + MIXER_INX_MODE_BYPASS, align_width / 2 - 1, cmdq_pkt); 175 + 176 + mtk_ddp_write(cmdq_pkt, pending->height << 16 | align_width, &mixer->cmdq_base, 177 + mixer->regs, MIX_L_SRC_SIZE(idx)); 178 + mtk_ddp_write(cmdq_pkt, offset, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_OFFSET(idx)); 179 + mtk_ddp_write_mask(cmdq_pkt, alpha_con, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_CON(idx), 180 + 0x1ff); 181 + mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &mixer->cmdq_base, mixer->regs, MIX_SRC_CON, 182 + BIT(idx)); 183 + } 184 + 185 + void mtk_ethdr_config(struct device *dev, unsigned int w, 186 + unsigned int h, unsigned int vrefresh, 187 + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) 188 + { 189 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 190 + struct mtk_ethdr_comp *vdo_fe0 = &priv->ethdr_comp[ETHDR_VDO_FE0]; 191 + struct mtk_ethdr_comp *vdo_fe1 = &priv->ethdr_comp[ETHDR_VDO_FE1]; 192 + struct mtk_ethdr_comp *gfx_fe0 = &priv->ethdr_comp[ETHDR_GFX_FE0]; 193 + struct mtk_ethdr_comp *gfx_fe1 = &priv->ethdr_comp[ETHDR_GFX_FE1]; 194 + struct mtk_ethdr_comp *vdo_be = &priv->ethdr_comp[ETHDR_VDO_BE]; 195 + struct mtk_ethdr_comp *mixer = &priv->ethdr_comp[ETHDR_MIXER]; 196 + 197 + dev_dbg(dev, "%s-w:%d, h:%d\n", __func__, w, h); 198 + 199 + mtk_ddp_write(cmdq_pkt, HDR_VDO_FE_0804_BYPASS_ALL, &vdo_fe0->cmdq_base, 200 + vdo_fe0->regs, HDR_VDO_FE_0804_HDR_DM_FE); 201 + 202 + mtk_ddp_write(cmdq_pkt, HDR_VDO_FE_0804_BYPASS_ALL, &vdo_fe1->cmdq_base, 203 + vdo_fe1->regs, HDR_VDO_FE_0804_HDR_DM_FE); 204 + 205 + mtk_ddp_write(cmdq_pkt, HDR_GFX_FE_0204_BYPASS_ALL, &gfx_fe0->cmdq_base, 206 + gfx_fe0->regs, HDR_GFX_FE_0204_GFX_HDR_FE); 207 + 208 + mtk_ddp_write(cmdq_pkt, HDR_GFX_FE_0204_BYPASS_ALL, &gfx_fe1->cmdq_base, 209 + gfx_fe1->regs, HDR_GFX_FE_0204_GFX_HDR_FE); 210 + 211 + mtk_ddp_write(cmdq_pkt, HDR_VDO_BE_0204_BYPASS_ALL, &vdo_be->cmdq_base, 212 + vdo_be->regs, HDR_VDO_BE_0204_VDO_DM_BE); 213 + 214 + mtk_ddp_write(cmdq_pkt, MIX_FUNC_DCM_ENABLE, &mixer->cmdq_base, mixer->regs, MIX_FUNC_DCM0); 215 + mtk_ddp_write(cmdq_pkt, MIX_FUNC_DCM_ENABLE, &mixer->cmdq_base, mixer->regs, MIX_FUNC_DCM1); 216 + mtk_ddp_write(cmdq_pkt, h << 16 | w, &mixer->cmdq_base, mixer->regs, MIX_ROI_SIZE); 217 + mtk_ddp_write(cmdq_pkt, BGCLR_BLACK, &mixer->cmdq_base, mixer->regs, MIX_ROI_BGCLR); 218 + mtk_ddp_write(cmdq_pkt, NON_PREMULTI_SOURCE, &mixer->cmdq_base, mixer->regs, 219 + MIX_L_SRC_CON(0)); 220 + mtk_ddp_write(cmdq_pkt, NON_PREMULTI_SOURCE, &mixer->cmdq_base, mixer->regs, 221 + MIX_L_SRC_CON(1)); 222 + mtk_ddp_write(cmdq_pkt, NON_PREMULTI_SOURCE, &mixer->cmdq_base, mixer->regs, 223 + MIX_L_SRC_CON(2)); 224 + mtk_ddp_write(cmdq_pkt, NON_PREMULTI_SOURCE, &mixer->cmdq_base, mixer->regs, 225 + MIX_L_SRC_CON(3)); 226 + mtk_ddp_write(cmdq_pkt, 0x0, &mixer->cmdq_base, mixer->regs, MIX_L_SRC_SIZE(0)); 227 + mtk_ddp_write(cmdq_pkt, OUTPUT_NO_RND | SOURCE_RGB_SEL | BACKGROUND_RELAY, 228 + &mixer->cmdq_base, mixer->regs, MIX_DATAPATH_CON); 229 + mtk_ddp_write_mask(cmdq_pkt, MIX_SRC_L0_EN, &mixer->cmdq_base, mixer->regs, 230 + MIX_SRC_CON, MIX_SRC_L0_EN); 231 + 232 + mtk_mmsys_hdr_config(priv->mmsys_dev, w / 2, h, cmdq_pkt); 233 + mtk_mmsys_mixer_in_channel_swap(priv->mmsys_dev, 4, 0, cmdq_pkt); 234 + } 235 + 236 + void mtk_ethdr_start(struct device *dev) 237 + { 238 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 239 + struct mtk_ethdr_comp *mixer = &priv->ethdr_comp[ETHDR_MIXER]; 240 + 241 + writel(1, mixer->regs + MIX_EN); 242 + } 243 + 244 + void mtk_ethdr_stop(struct device *dev) 245 + { 246 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 247 + struct mtk_ethdr_comp *mixer = &priv->ethdr_comp[ETHDR_MIXER]; 248 + 249 + writel(0, mixer->regs + MIX_EN); 250 + writel(1, mixer->regs + MIX_RST); 251 + reset_control_reset(priv->reset_ctl); 252 + writel(0, mixer->regs + MIX_RST); 253 + } 254 + 255 + int mtk_ethdr_clk_enable(struct device *dev) 256 + { 257 + int ret; 258 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 259 + 260 + ret = clk_bulk_prepare_enable(ETHDR_CLK_NUM, priv->ethdr_clk); 261 + if (ret) 262 + dev_err(dev, 263 + "ethdr_clk prepare enable failed\n"); 264 + return ret; 265 + } 266 + 267 + void mtk_ethdr_clk_disable(struct device *dev) 268 + { 269 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 270 + 271 + clk_bulk_disable_unprepare(ETHDR_CLK_NUM, priv->ethdr_clk); 272 + } 273 + 274 + static int mtk_ethdr_bind(struct device *dev, struct device *master, 275 + void *data) 276 + { 277 + struct mtk_ethdr *priv = dev_get_drvdata(dev); 278 + 279 + priv->mmsys_dev = data; 280 + return 0; 281 + } 282 + 283 + static void mtk_ethdr_unbind(struct device *dev, struct device *master, void *data) 284 + { 285 + } 286 + 287 + static const struct component_ops mtk_ethdr_component_ops = { 288 + .bind = mtk_ethdr_bind, 289 + .unbind = mtk_ethdr_unbind, 290 + }; 291 + 292 + static int mtk_ethdr_probe(struct platform_device *pdev) 293 + { 294 + struct device *dev = &pdev->dev; 295 + struct mtk_ethdr *priv; 296 + int ret; 297 + int i; 298 + 299 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 300 + if (!priv) 301 + return -ENOMEM; 302 + 303 + for (i = 0; i < ETHDR_ID_MAX; i++) { 304 + priv->ethdr_comp[i].dev = dev; 305 + priv->ethdr_comp[i].regs = of_iomap(dev->of_node, i); 306 + #if IS_REACHABLE(CONFIG_MTK_CMDQ) 307 + ret = cmdq_dev_get_client_reg(dev, 308 + &priv->ethdr_comp[i].cmdq_base, i); 309 + if (ret) 310 + dev_dbg(dev, "get mediatek,gce-client-reg fail!\n"); 311 + #endif 312 + dev_dbg(dev, "[DRM]regs:0x%p, node:%d\n", priv->ethdr_comp[i].regs, i); 313 + } 314 + 315 + for (i = 0; i < ETHDR_CLK_NUM; i++) 316 + priv->ethdr_clk[i].id = ethdr_clk_str[i]; 317 + ret = devm_clk_bulk_get_optional(dev, ETHDR_CLK_NUM, priv->ethdr_clk); 318 + if (ret) 319 + return ret; 320 + 321 + priv->irq = platform_get_irq(pdev, 0); 322 + if (priv->irq < 0) 323 + priv->irq = 0; 324 + 325 + if (priv->irq) { 326 + ret = devm_request_irq(dev, priv->irq, mtk_ethdr_irq_handler, 327 + IRQF_TRIGGER_NONE, dev_name(dev), priv); 328 + if (ret < 0) { 329 + dev_err(dev, "Failed to request irq %d: %d\n", priv->irq, ret); 330 + return ret; 331 + } 332 + } 333 + 334 + priv->reset_ctl = devm_reset_control_array_get_optional_exclusive(dev); 335 + if (IS_ERR(priv->reset_ctl)) { 336 + dev_err_probe(dev, PTR_ERR(priv->reset_ctl), "cannot get ethdr reset control\n"); 337 + return PTR_ERR(priv->reset_ctl); 338 + } 339 + 340 + platform_set_drvdata(pdev, priv); 341 + 342 + ret = component_add(dev, &mtk_ethdr_component_ops); 343 + if (ret) 344 + dev_notice(dev, "Failed to add component: %d\n", ret); 345 + 346 + return ret; 347 + } 348 + 349 + static int mtk_ethdr_remove(struct platform_device *pdev) 350 + { 351 + component_del(&pdev->dev, &mtk_ethdr_component_ops); 352 + return 0; 353 + } 354 + 355 + static const struct of_device_id mtk_ethdr_driver_dt_match[] = { 356 + { .compatible = "mediatek,mt8195-disp-ethdr"}, 357 + {}, 358 + }; 359 + 360 + MODULE_DEVICE_TABLE(of, mtk_ethdr_driver_dt_match); 361 + 362 + struct platform_driver mtk_ethdr_driver = { 363 + .probe = mtk_ethdr_probe, 364 + .remove = mtk_ethdr_remove, 365 + .driver = { 366 + .name = "mediatek-disp-ethdr", 367 + .owner = THIS_MODULE, 368 + .of_match_table = mtk_ethdr_driver_dt_match, 369 + }, 370 + };
+25
drivers/gpu/drm/mediatek/mtk_ethdr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (c) 2021 MediaTek Inc. 4 + */ 5 + 6 + #ifndef __MTK_ETHDR_H__ 7 + #define __MTK_ETHDR_H__ 8 + 9 + void mtk_ethdr_start(struct device *dev); 10 + void mtk_ethdr_stop(struct device *dev); 11 + int mtk_ethdr_clk_enable(struct device *dev); 12 + void mtk_ethdr_clk_disable(struct device *dev); 13 + void mtk_ethdr_config(struct device *dev, unsigned int w, 14 + unsigned int h, unsigned int vrefresh, 15 + unsigned int bpc, struct cmdq_pkt *cmdq_pkt); 16 + void mtk_ethdr_layer_config(struct device *dev, unsigned int idx, 17 + struct mtk_plane_state *state, 18 + struct cmdq_pkt *cmdq_pkt); 19 + void mtk_ethdr_register_vblank_cb(struct device *dev, 20 + void (*vblank_cb)(void *), 21 + void *vblank_cb_data); 22 + void mtk_ethdr_unregister_vblank_cb(struct device *dev); 23 + void mtk_ethdr_enable_vblank(struct device *dev); 24 + void mtk_ethdr_disable_vblank(struct device *dev); 25 + #endif