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 <linux/clk.h> 8 #include <linux/component.h> 9 #include <linux/platform_device.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/soc/mediatek/mtk-cmdq.h> 12 13 #include "mtk_disp_drv.h" 14 #include "mtk_drm_drv.h" 15 #include "mtk_mdp_rdma.h" 16 17 #define MDP_RDMA_EN 0x000 18 #define FLD_ROT_ENABLE BIT(0) 19 #define MDP_RDMA_RESET 0x008 20 #define MDP_RDMA_CON 0x020 21 #define FLD_OUTPUT_10B BIT(5) 22 #define FLD_SIMPLE_MODE BIT(4) 23 #define MDP_RDMA_GMCIF_CON 0x028 24 #define FLD_COMMAND_DIV BIT(0) 25 #define FLD_EXT_PREULTRA_EN BIT(3) 26 #define FLD_RD_REQ_TYPE GENMASK(7, 4) 27 #define VAL_RD_REQ_TYPE_BURST_8_ACCESS 7 28 #define FLD_ULTRA_EN GENMASK(13, 12) 29 #define VAL_ULTRA_EN_ENABLE 1 30 #define FLD_PRE_ULTRA_EN GENMASK(17, 16) 31 #define VAL_PRE_ULTRA_EN_ENABLE 1 32 #define FLD_EXT_ULTRA_EN BIT(18) 33 #define MDP_RDMA_SRC_CON 0x030 34 #define FLD_OUTPUT_ARGB BIT(25) 35 #define FLD_BIT_NUMBER GENMASK(19, 18) 36 #define FLD_SWAP BIT(14) 37 #define FLD_UNIFORM_CONFIG BIT(17) 38 #define RDMA_INPUT_10BIT BIT(18) 39 #define FLD_SRC_FORMAT GENMASK(3, 0) 40 #define MDP_RDMA_COMP_CON 0x038 41 #define FLD_AFBC_EN BIT(22) 42 #define FLD_AFBC_YUV_TRANSFORM BIT(21) 43 #define FLD_UFBDC_EN BIT(12) 44 #define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE 0x060 45 #define FLD_MF_BKGD_WB GENMASK(22, 0) 46 #define MDP_RDMA_MF_SRC_SIZE 0x070 47 #define FLD_MF_SRC_H GENMASK(30, 16) 48 #define FLD_MF_SRC_W GENMASK(14, 0) 49 #define MDP_RDMA_MF_CLIP_SIZE 0x078 50 #define FLD_MF_CLIP_H GENMASK(30, 16) 51 #define FLD_MF_CLIP_W GENMASK(14, 0) 52 #define MDP_RDMA_SRC_OFFSET_0 0x118 53 #define FLD_SRC_OFFSET_0 GENMASK(31, 0) 54 #define MDP_RDMA_TRANSFORM_0 0x200 55 #define FLD_INT_MATRIX_SEL GENMASK(27, 23) 56 #define FLD_TRANS_EN BIT(16) 57 #define MDP_RDMA_SRC_BASE_0 0xf00 58 #define FLD_SRC_BASE_0 GENMASK(31, 0) 59 60 #define RDMA_CSC_FULL709_TO_RGB 5 61 #define RDMA_CSC_BT601_TO_RGB 6 62 63 static const u32 formats[] = { 64 DRM_FORMAT_XRGB8888, 65 DRM_FORMAT_ARGB8888, 66 DRM_FORMAT_BGRX8888, 67 DRM_FORMAT_BGRA8888, 68 DRM_FORMAT_ABGR8888, 69 DRM_FORMAT_XBGR8888, 70 DRM_FORMAT_RGB888, 71 DRM_FORMAT_BGR888, 72 DRM_FORMAT_RGB565, 73 DRM_FORMAT_UYVY, 74 DRM_FORMAT_YUYV, 75 }; 76 77 enum rdma_format { 78 RDMA_INPUT_FORMAT_RGB565 = 0, 79 RDMA_INPUT_FORMAT_RGB888 = 1, 80 RDMA_INPUT_FORMAT_RGBA8888 = 2, 81 RDMA_INPUT_FORMAT_ARGB8888 = 3, 82 RDMA_INPUT_FORMAT_UYVY = 4, 83 RDMA_INPUT_FORMAT_YUY2 = 5, 84 RDMA_INPUT_FORMAT_Y8 = 7, 85 RDMA_INPUT_FORMAT_YV12 = 8, 86 RDMA_INPUT_FORMAT_UYVY_3PL = 9, 87 RDMA_INPUT_FORMAT_NV12 = 12, 88 RDMA_INPUT_FORMAT_UYVY_2PL = 13, 89 RDMA_INPUT_FORMAT_Y410 = 14 90 }; 91 92 struct mtk_mdp_rdma { 93 void __iomem *regs; 94 struct clk *clk; 95 struct cmdq_client_reg cmdq_reg; 96 }; 97 98 static unsigned int rdma_fmt_convert(unsigned int fmt) 99 { 100 switch (fmt) { 101 default: 102 case DRM_FORMAT_RGB565: 103 return RDMA_INPUT_FORMAT_RGB565; 104 case DRM_FORMAT_BGR565: 105 return RDMA_INPUT_FORMAT_RGB565 | FLD_SWAP; 106 case DRM_FORMAT_RGB888: 107 return RDMA_INPUT_FORMAT_RGB888; 108 case DRM_FORMAT_BGR888: 109 return RDMA_INPUT_FORMAT_RGB888 | FLD_SWAP; 110 case DRM_FORMAT_RGBX8888: 111 case DRM_FORMAT_RGBA8888: 112 return RDMA_INPUT_FORMAT_ARGB8888; 113 case DRM_FORMAT_BGRX8888: 114 case DRM_FORMAT_BGRA8888: 115 return RDMA_INPUT_FORMAT_ARGB8888 | FLD_SWAP; 116 case DRM_FORMAT_XRGB8888: 117 case DRM_FORMAT_ARGB8888: 118 return RDMA_INPUT_FORMAT_RGBA8888; 119 case DRM_FORMAT_XBGR8888: 120 case DRM_FORMAT_ABGR8888: 121 return RDMA_INPUT_FORMAT_RGBA8888 | FLD_SWAP; 122 case DRM_FORMAT_ABGR2101010: 123 return RDMA_INPUT_FORMAT_RGBA8888 | FLD_SWAP | RDMA_INPUT_10BIT; 124 case DRM_FORMAT_ARGB2101010: 125 return RDMA_INPUT_FORMAT_RGBA8888 | RDMA_INPUT_10BIT; 126 case DRM_FORMAT_RGBA1010102: 127 return RDMA_INPUT_FORMAT_ARGB8888 | FLD_SWAP | RDMA_INPUT_10BIT; 128 case DRM_FORMAT_BGRA1010102: 129 return RDMA_INPUT_FORMAT_ARGB8888 | RDMA_INPUT_10BIT; 130 case DRM_FORMAT_UYVY: 131 return RDMA_INPUT_FORMAT_UYVY; 132 case DRM_FORMAT_YUYV: 133 return RDMA_INPUT_FORMAT_YUY2; 134 } 135 } 136 137 static unsigned int rdma_color_convert(unsigned int color_encoding) 138 { 139 switch (color_encoding) { 140 default: 141 case DRM_COLOR_YCBCR_BT709: 142 return RDMA_CSC_FULL709_TO_RGB; 143 case DRM_COLOR_YCBCR_BT601: 144 return RDMA_CSC_BT601_TO_RGB; 145 } 146 } 147 148 static void mtk_mdp_rdma_fifo_config(struct device *dev, struct cmdq_pkt *cmdq_pkt) 149 { 150 struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); 151 152 mtk_ddp_write_mask(cmdq_pkt, FLD_EXT_ULTRA_EN | VAL_PRE_ULTRA_EN_ENABLE << 16 | 153 VAL_ULTRA_EN_ENABLE << 12 | VAL_RD_REQ_TYPE_BURST_8_ACCESS << 4 | 154 FLD_EXT_PREULTRA_EN | FLD_COMMAND_DIV, &priv->cmdq_reg, 155 priv->regs, MDP_RDMA_GMCIF_CON, FLD_EXT_ULTRA_EN | 156 FLD_PRE_ULTRA_EN | FLD_ULTRA_EN | FLD_RD_REQ_TYPE | 157 FLD_EXT_PREULTRA_EN | FLD_COMMAND_DIV); 158 } 159 160 void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt) 161 { 162 struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); 163 164 mtk_ddp_write_mask(cmdq_pkt, FLD_ROT_ENABLE, &priv->cmdq_reg, 165 priv->regs, MDP_RDMA_EN, FLD_ROT_ENABLE); 166 } 167 168 void mtk_mdp_rdma_stop(struct device *dev, struct cmdq_pkt *cmdq_pkt) 169 { 170 struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); 171 172 mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, 173 priv->regs, MDP_RDMA_EN, FLD_ROT_ENABLE); 174 mtk_ddp_write(cmdq_pkt, 1, &priv->cmdq_reg, priv->regs, MDP_RDMA_RESET); 175 mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, MDP_RDMA_RESET); 176 } 177 178 void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg, 179 struct cmdq_pkt *cmdq_pkt) 180 { 181 struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); 182 const struct drm_format_info *fmt_info = drm_format_info(cfg->fmt); 183 bool csc_enable = fmt_info->is_yuv ? true : false; 184 unsigned int src_pitch_y = cfg->pitch; 185 unsigned int offset_y = 0; 186 187 mtk_mdp_rdma_fifo_config(dev, cmdq_pkt); 188 189 mtk_ddp_write_mask(cmdq_pkt, FLD_UNIFORM_CONFIG, &priv->cmdq_reg, priv->regs, 190 MDP_RDMA_SRC_CON, FLD_UNIFORM_CONFIG); 191 mtk_ddp_write_mask(cmdq_pkt, rdma_fmt_convert(cfg->fmt), &priv->cmdq_reg, priv->regs, 192 MDP_RDMA_SRC_CON, FLD_SWAP | FLD_SRC_FORMAT | FLD_BIT_NUMBER); 193 194 if (!csc_enable && fmt_info->has_alpha) 195 mtk_ddp_write_mask(cmdq_pkt, FLD_OUTPUT_ARGB, &priv->cmdq_reg, 196 priv->regs, MDP_RDMA_SRC_CON, FLD_OUTPUT_ARGB); 197 else 198 mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, 199 MDP_RDMA_SRC_CON, FLD_OUTPUT_ARGB); 200 201 mtk_ddp_write_mask(cmdq_pkt, cfg->addr0, &priv->cmdq_reg, priv->regs, 202 MDP_RDMA_SRC_BASE_0, FLD_SRC_BASE_0); 203 204 mtk_ddp_write_mask(cmdq_pkt, src_pitch_y, &priv->cmdq_reg, priv->regs, 205 MDP_RDMA_MF_BKGD_SIZE_IN_BYTE, FLD_MF_BKGD_WB); 206 207 mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, MDP_RDMA_COMP_CON, 208 FLD_AFBC_YUV_TRANSFORM | FLD_UFBDC_EN | FLD_AFBC_EN); 209 mtk_ddp_write_mask(cmdq_pkt, FLD_OUTPUT_10B, &priv->cmdq_reg, priv->regs, 210 MDP_RDMA_CON, FLD_OUTPUT_10B); 211 mtk_ddp_write_mask(cmdq_pkt, FLD_SIMPLE_MODE, &priv->cmdq_reg, priv->regs, 212 MDP_RDMA_CON, FLD_SIMPLE_MODE); 213 if (csc_enable) 214 mtk_ddp_write_mask(cmdq_pkt, rdma_color_convert(cfg->color_encoding) << 23, 215 &priv->cmdq_reg, priv->regs, MDP_RDMA_TRANSFORM_0, 216 FLD_INT_MATRIX_SEL); 217 mtk_ddp_write_mask(cmdq_pkt, csc_enable << 16, &priv->cmdq_reg, priv->regs, 218 MDP_RDMA_TRANSFORM_0, FLD_TRANS_EN); 219 220 offset_y = cfg->x_left * fmt_info->cpp[0] + cfg->y_top * src_pitch_y; 221 222 mtk_ddp_write_mask(cmdq_pkt, offset_y, &priv->cmdq_reg, priv->regs, 223 MDP_RDMA_SRC_OFFSET_0, FLD_SRC_OFFSET_0); 224 mtk_ddp_write_mask(cmdq_pkt, cfg->width, &priv->cmdq_reg, priv->regs, 225 MDP_RDMA_MF_SRC_SIZE, FLD_MF_SRC_W); 226 mtk_ddp_write_mask(cmdq_pkt, cfg->height << 16, &priv->cmdq_reg, priv->regs, 227 MDP_RDMA_MF_SRC_SIZE, FLD_MF_SRC_H); 228 mtk_ddp_write_mask(cmdq_pkt, cfg->width, &priv->cmdq_reg, priv->regs, 229 MDP_RDMA_MF_CLIP_SIZE, FLD_MF_CLIP_W); 230 mtk_ddp_write_mask(cmdq_pkt, cfg->height << 16, &priv->cmdq_reg, priv->regs, 231 MDP_RDMA_MF_CLIP_SIZE, FLD_MF_CLIP_H); 232 } 233 234 const u32 *mtk_mdp_rdma_get_formats(struct device *dev) 235 { 236 return formats; 237 } 238 239 size_t mtk_mdp_rdma_get_num_formats(struct device *dev) 240 { 241 return ARRAY_SIZE(formats); 242 } 243 244 int mtk_mdp_rdma_power_on(struct device *dev) 245 { 246 int ret = pm_runtime_resume_and_get(dev); 247 248 if (ret < 0) { 249 dev_err(dev, "Failed to power on: %d\n", ret); 250 return ret; 251 } 252 return 0; 253 } 254 255 void mtk_mdp_rdma_power_off(struct device *dev) 256 { 257 pm_runtime_put(dev); 258 } 259 260 int mtk_mdp_rdma_clk_enable(struct device *dev) 261 { 262 struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev); 263 264 return clk_prepare_enable(rdma->clk); 265 } 266 267 void mtk_mdp_rdma_clk_disable(struct device *dev) 268 { 269 struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev); 270 271 clk_disable_unprepare(rdma->clk); 272 } 273 274 static int mtk_mdp_rdma_bind(struct device *dev, struct device *master, 275 void *data) 276 { 277 return 0; 278 } 279 280 static void mtk_mdp_rdma_unbind(struct device *dev, struct device *master, 281 void *data) 282 { 283 } 284 285 static const struct component_ops mtk_mdp_rdma_component_ops = { 286 .bind = mtk_mdp_rdma_bind, 287 .unbind = mtk_mdp_rdma_unbind, 288 }; 289 290 static int mtk_mdp_rdma_probe(struct platform_device *pdev) 291 { 292 struct device *dev = &pdev->dev; 293 struct mtk_mdp_rdma *priv; 294 int ret = 0; 295 296 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 297 if (!priv) 298 return -ENOMEM; 299 300 priv->regs = devm_platform_ioremap_resource(pdev, 0); 301 if (IS_ERR(priv->regs)) 302 return dev_err_probe(dev, PTR_ERR(priv->regs), 303 "failed to ioremap rdma\n"); 304 305 priv->clk = devm_clk_get(dev, NULL); 306 if (IS_ERR(priv->clk)) 307 return dev_err_probe(dev, PTR_ERR(priv->clk), 308 "failed to get rdma clk\n"); 309 310 #if IS_REACHABLE(CONFIG_MTK_CMDQ) 311 ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0); 312 if (ret) 313 dev_dbg(dev, "get mediatek,gce-client-reg fail!\n"); 314 #endif 315 platform_set_drvdata(pdev, priv); 316 317 pm_runtime_enable(dev); 318 319 ret = component_add(dev, &mtk_mdp_rdma_component_ops); 320 if (ret != 0) { 321 pm_runtime_disable(dev); 322 return dev_err_probe(dev, ret, "Failed to add component\n"); 323 } 324 return 0; 325 } 326 327 static void mtk_mdp_rdma_remove(struct platform_device *pdev) 328 { 329 component_del(&pdev->dev, &mtk_mdp_rdma_component_ops); 330 pm_runtime_disable(&pdev->dev); 331 } 332 333 static const struct of_device_id mtk_mdp_rdma_driver_dt_match[] = { 334 { .compatible = "mediatek,mt8195-vdo1-rdma", }, 335 {}, 336 }; 337 MODULE_DEVICE_TABLE(of, mtk_mdp_rdma_driver_dt_match); 338 339 struct platform_driver mtk_mdp_rdma_driver = { 340 .probe = mtk_mdp_rdma_probe, 341 .remove = mtk_mdp_rdma_remove, 342 .driver = { 343 .name = "mediatek-mdp-rdma", 344 .of_match_table = mtk_mdp_rdma_driver_dt_match, 345 }, 346 }; 347