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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.16-rc7 423 lines 12 kB view raw
1/* 2 * Copyright (c) 2015 MediaTek Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14#include <linux/clk.h> 15#include <linux/iopoll.h> 16#include <linux/module.h> 17#include <linux/of_device.h> 18#include <linux/platform_device.h> 19#include <linux/regmap.h> 20 21#include "mtk_drm_ddp.h" 22#include "mtk_drm_ddp_comp.h" 23 24#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 25#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 26#define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 27#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c 28#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 29#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 30#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 31#define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac 32#define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN 0x0c8 33#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 34 35#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 36#define DISP_REG_CONFIG_OUT_SEL 0x04c 37#define DISP_REG_CONFIG_DSI_SEL 0x050 38 39#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) 40#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) 41#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) 42#define DISP_REG_MUTEX_MOD(n) (0x2c + 0x20 * (n)) 43#define DISP_REG_MUTEX_SOF(n) (0x30 + 0x20 * (n)) 44 45#define INT_MUTEX BIT(1) 46 47#define MT8173_MUTEX_MOD_DISP_OVL0 BIT(11) 48#define MT8173_MUTEX_MOD_DISP_OVL1 BIT(12) 49#define MT8173_MUTEX_MOD_DISP_RDMA0 BIT(13) 50#define MT8173_MUTEX_MOD_DISP_RDMA1 BIT(14) 51#define MT8173_MUTEX_MOD_DISP_RDMA2 BIT(15) 52#define MT8173_MUTEX_MOD_DISP_WDMA0 BIT(16) 53#define MT8173_MUTEX_MOD_DISP_WDMA1 BIT(17) 54#define MT8173_MUTEX_MOD_DISP_COLOR0 BIT(18) 55#define MT8173_MUTEX_MOD_DISP_COLOR1 BIT(19) 56#define MT8173_MUTEX_MOD_DISP_AAL BIT(20) 57#define MT8173_MUTEX_MOD_DISP_GAMMA BIT(21) 58#define MT8173_MUTEX_MOD_DISP_UFOE BIT(22) 59#define MT8173_MUTEX_MOD_DISP_PWM0 BIT(23) 60#define MT8173_MUTEX_MOD_DISP_PWM1 BIT(24) 61#define MT8173_MUTEX_MOD_DISP_OD BIT(25) 62 63#define MT2701_MUTEX_MOD_DISP_OVL BIT(3) 64#define MT2701_MUTEX_MOD_DISP_WDMA BIT(6) 65#define MT2701_MUTEX_MOD_DISP_COLOR BIT(7) 66#define MT2701_MUTEX_MOD_DISP_BLS BIT(9) 67#define MT2701_MUTEX_MOD_DISP_RDMA0 BIT(10) 68#define MT2701_MUTEX_MOD_DISP_RDMA1 BIT(12) 69 70#define MUTEX_SOF_SINGLE_MODE 0 71#define MUTEX_SOF_DSI0 1 72#define MUTEX_SOF_DSI1 2 73#define MUTEX_SOF_DPI0 3 74 75#define OVL0_MOUT_EN_COLOR0 0x1 76#define OD_MOUT_EN_RDMA0 0x1 77#define UFOE_MOUT_EN_DSI0 0x1 78#define COLOR0_SEL_IN_OVL0 0x1 79#define OVL1_MOUT_EN_COLOR1 0x1 80#define GAMMA_MOUT_EN_RDMA1 0x1 81#define RDMA1_MOUT_DPI0 0x2 82#define DPI0_SEL_IN_RDMA1 0x1 83#define COLOR1_SEL_IN_OVL1 0x1 84 85#define OVL_MOUT_EN_RDMA 0x1 86#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8 87#define DSI_SEL_IN_BLS 0x0 88 89struct mtk_disp_mutex { 90 int id; 91 bool claimed; 92}; 93 94struct mtk_ddp { 95 struct device *dev; 96 struct clk *clk; 97 void __iomem *regs; 98 struct mtk_disp_mutex mutex[10]; 99 const unsigned int *mutex_mod; 100}; 101 102static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { 103 [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS, 104 [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR, 105 [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL, 106 [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0, 107 [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1, 108 [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA, 109}; 110 111static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { 112 [DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL, 113 [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, 114 [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, 115 [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA, 116 [DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD, 117 [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0, 118 [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1, 119 [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0, 120 [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1, 121 [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0, 122 [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1, 123 [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2, 124 [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE, 125 [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0, 126 [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, 127}; 128 129static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, 130 enum mtk_ddp_comp_id next, 131 unsigned int *addr) 132{ 133 unsigned int value; 134 135 if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { 136 *addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN; 137 value = OVL0_MOUT_EN_COLOR0; 138 } else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) { 139 *addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN; 140 value = OVL_MOUT_EN_RDMA; 141 } else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) { 142 *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; 143 value = OD_MOUT_EN_RDMA0; 144 } else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) { 145 *addr = DISP_REG_CONFIG_DISP_UFOE_MOUT_EN; 146 value = UFOE_MOUT_EN_DSI0; 147 } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { 148 *addr = DISP_REG_CONFIG_DISP_OVL1_MOUT_EN; 149 value = OVL1_MOUT_EN_COLOR1; 150 } else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) { 151 *addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN; 152 value = GAMMA_MOUT_EN_RDMA1; 153 } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { 154 *addr = DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN; 155 value = RDMA1_MOUT_DPI0; 156 } else { 157 value = 0; 158 } 159 160 return value; 161} 162 163static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, 164 enum mtk_ddp_comp_id next, 165 unsigned int *addr) 166{ 167 unsigned int value; 168 169 if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { 170 *addr = DISP_REG_CONFIG_DISP_COLOR0_SEL_IN; 171 value = COLOR0_SEL_IN_OVL0; 172 } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { 173 *addr = DISP_REG_CONFIG_DPI_SEL_IN; 174 value = DPI0_SEL_IN_RDMA1; 175 } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { 176 *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; 177 value = COLOR1_SEL_IN_OVL1; 178 } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) { 179 *addr = DISP_REG_CONFIG_DSI_SEL; 180 value = DSI_SEL_IN_BLS; 181 } else { 182 value = 0; 183 } 184 185 return value; 186} 187 188static void mtk_ddp_sout_sel(void __iomem *config_regs, 189 enum mtk_ddp_comp_id cur, 190 enum mtk_ddp_comp_id next) 191{ 192 if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) 193 writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1, 194 config_regs + DISP_REG_CONFIG_OUT_SEL); 195} 196 197void mtk_ddp_add_comp_to_path(void __iomem *config_regs, 198 enum mtk_ddp_comp_id cur, 199 enum mtk_ddp_comp_id next) 200{ 201 unsigned int addr, value, reg; 202 203 value = mtk_ddp_mout_en(cur, next, &addr); 204 if (value) { 205 reg = readl_relaxed(config_regs + addr) | value; 206 writel_relaxed(reg, config_regs + addr); 207 } 208 209 mtk_ddp_sout_sel(config_regs, cur, next); 210 211 value = mtk_ddp_sel_in(cur, next, &addr); 212 if (value) { 213 reg = readl_relaxed(config_regs + addr) | value; 214 writel_relaxed(reg, config_regs + addr); 215 } 216} 217 218void mtk_ddp_remove_comp_from_path(void __iomem *config_regs, 219 enum mtk_ddp_comp_id cur, 220 enum mtk_ddp_comp_id next) 221{ 222 unsigned int addr, value, reg; 223 224 value = mtk_ddp_mout_en(cur, next, &addr); 225 if (value) { 226 reg = readl_relaxed(config_regs + addr) & ~value; 227 writel_relaxed(reg, config_regs + addr); 228 } 229 230 value = mtk_ddp_sel_in(cur, next, &addr); 231 if (value) { 232 reg = readl_relaxed(config_regs + addr) & ~value; 233 writel_relaxed(reg, config_regs + addr); 234 } 235} 236 237struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id) 238{ 239 struct mtk_ddp *ddp = dev_get_drvdata(dev); 240 241 if (id >= 10) 242 return ERR_PTR(-EINVAL); 243 if (ddp->mutex[id].claimed) 244 return ERR_PTR(-EBUSY); 245 246 ddp->mutex[id].claimed = true; 247 248 return &ddp->mutex[id]; 249} 250 251void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex) 252{ 253 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 254 mutex[mutex->id]); 255 256 WARN_ON(&ddp->mutex[mutex->id] != mutex); 257 258 mutex->claimed = false; 259} 260 261int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex) 262{ 263 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 264 mutex[mutex->id]); 265 return clk_prepare_enable(ddp->clk); 266} 267 268void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex) 269{ 270 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 271 mutex[mutex->id]); 272 clk_disable_unprepare(ddp->clk); 273} 274 275void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, 276 enum mtk_ddp_comp_id id) 277{ 278 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 279 mutex[mutex->id]); 280 unsigned int reg; 281 282 WARN_ON(&ddp->mutex[mutex->id] != mutex); 283 284 switch (id) { 285 case DDP_COMPONENT_DSI0: 286 reg = MUTEX_SOF_DSI0; 287 break; 288 case DDP_COMPONENT_DSI1: 289 reg = MUTEX_SOF_DSI0; 290 break; 291 case DDP_COMPONENT_DPI0: 292 reg = MUTEX_SOF_DPI0; 293 break; 294 default: 295 reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 296 reg |= ddp->mutex_mod[id]; 297 writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 298 return; 299 } 300 301 writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_SOF(mutex->id)); 302} 303 304void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, 305 enum mtk_ddp_comp_id id) 306{ 307 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 308 mutex[mutex->id]); 309 unsigned int reg; 310 311 WARN_ON(&ddp->mutex[mutex->id] != mutex); 312 313 switch (id) { 314 case DDP_COMPONENT_DSI0: 315 case DDP_COMPONENT_DSI1: 316 case DDP_COMPONENT_DPI0: 317 writel_relaxed(MUTEX_SOF_SINGLE_MODE, 318 ddp->regs + DISP_REG_MUTEX_SOF(mutex->id)); 319 break; 320 default: 321 reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 322 reg &= ~(ddp->mutex_mod[id]); 323 writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 324 break; 325 } 326} 327 328void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex) 329{ 330 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 331 mutex[mutex->id]); 332 333 WARN_ON(&ddp->mutex[mutex->id] != mutex); 334 335 writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); 336} 337 338void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex) 339{ 340 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 341 mutex[mutex->id]); 342 343 WARN_ON(&ddp->mutex[mutex->id] != mutex); 344 345 writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); 346} 347 348void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex) 349{ 350 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 351 mutex[mutex->id]); 352 u32 tmp; 353 354 writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); 355 writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id)); 356 if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id), 357 tmp, tmp & INT_MUTEX, 1, 10000)) 358 pr_err("could not acquire mutex %d\n", mutex->id); 359} 360 361void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex) 362{ 363 struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 364 mutex[mutex->id]); 365 366 writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id)); 367} 368 369static int mtk_ddp_probe(struct platform_device *pdev) 370{ 371 struct device *dev = &pdev->dev; 372 struct mtk_ddp *ddp; 373 struct resource *regs; 374 int i; 375 376 ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL); 377 if (!ddp) 378 return -ENOMEM; 379 380 for (i = 0; i < 10; i++) 381 ddp->mutex[i].id = i; 382 383 ddp->clk = devm_clk_get(dev, NULL); 384 if (IS_ERR(ddp->clk)) { 385 dev_err(dev, "Failed to get clock\n"); 386 return PTR_ERR(ddp->clk); 387 } 388 389 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 390 ddp->regs = devm_ioremap_resource(dev, regs); 391 if (IS_ERR(ddp->regs)) { 392 dev_err(dev, "Failed to map mutex registers\n"); 393 return PTR_ERR(ddp->regs); 394 } 395 396 ddp->mutex_mod = of_device_get_match_data(dev); 397 398 platform_set_drvdata(pdev, ddp); 399 400 return 0; 401} 402 403static int mtk_ddp_remove(struct platform_device *pdev) 404{ 405 return 0; 406} 407 408static const struct of_device_id ddp_driver_dt_match[] = { 409 { .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod}, 410 { .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod}, 411 {}, 412}; 413MODULE_DEVICE_TABLE(of, ddp_driver_dt_match); 414 415struct platform_driver mtk_ddp_driver = { 416 .probe = mtk_ddp_probe, 417 .remove = mtk_ddp_remove, 418 .driver = { 419 .name = "mediatek-ddp", 420 .owner = THIS_MODULE, 421 .of_match_table = ddp_driver_dt_match, 422 }, 423};