1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/ 4 * Author: Jyri Sarha <jsarha@ti.com> 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/delay.h> 9 #include <linux/dma-mapping.h> 10 #include <linux/err.h> 11 #include <linux/interrupt.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/media-bus-format.h> 15 #include <linux/module.h> 16 #include <linux/mfd/syscon.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/pm_runtime.h> 20 #include <linux/regmap.h> 21 #include <linux/sys_soc.h> 22 23 #include <drm/drm_blend.h> 24 #include <drm/drm_fourcc.h> 25 #include <drm/drm_fb_dma_helper.h> 26 #include <drm/drm_framebuffer.h> 27 #include <drm/drm_gem_dma_helper.h> 28 #include <drm/drm_panel.h> 29 30 #include "tidss_crtc.h" 31 #include "tidss_dispc.h" 32 #include "tidss_drv.h" 33 #include "tidss_irq.h" 34 #include "tidss_plane.h" 35 36 #include "tidss_dispc_regs.h" 37 #include "tidss_scale_coefs.h" 38 39 static const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { 40 [DSS_REVISION_OFF] = 0x00, 41 [DSS_SYSCONFIG_OFF] = 0x04, 42 [DSS_SYSSTATUS_OFF] = 0x08, 43 [DISPC_IRQ_EOI_OFF] = 0x20, 44 [DISPC_IRQSTATUS_RAW_OFF] = 0x24, 45 [DISPC_IRQSTATUS_OFF] = 0x28, 46 [DISPC_IRQENABLE_SET_OFF] = 0x2c, 47 [DISPC_IRQENABLE_CLR_OFF] = 0x30, 48 49 [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x40, 50 [DISPC_GLOBAL_BUFFER_OFF] = 0x44, 51 52 [DISPC_DBG_CONTROL_OFF] = 0x4c, 53 [DISPC_DBG_STATUS_OFF] = 0x50, 54 55 [DISPC_CLKGATING_DISABLE_OFF] = 0x54, 56 }; 57 58 const struct dispc_features dispc_k2g_feats = { 59 .min_pclk_khz = 4375, 60 61 .max_pclk_khz = { 62 [DISPC_VP_DPI] = 150000, 63 }, 64 65 /* 66 * XXX According TRM the RGB input buffer width up to 2560 should 67 * work on 3 taps, but in practice it only works up to 1280. 68 */ 69 .scaling = { 70 .in_width_max_5tap_rgb = 1280, 71 .in_width_max_3tap_rgb = 1280, 72 .in_width_max_5tap_yuv = 2560, 73 .in_width_max_3tap_yuv = 2560, 74 .upscale_limit = 16, 75 .downscale_limit_5tap = 4, 76 .downscale_limit_3tap = 2, 77 /* 78 * The max supported pixel inc value is 255. The value 79 * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 80 * The maximum bpp of all formats supported by the HW 81 * is 8. So the maximum supported xinc value is 32, 82 * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 83 */ 84 .xinc_max = 32, 85 }, 86 87 .subrev = DISPC_K2G, 88 89 .common = "common", 90 91 .common_regs = tidss_k2g_common_regs, 92 93 .num_vps = 1, 94 .vp_name = { "vp1" }, 95 .ovr_name = { "ovr1" }, 96 .vpclk_name = { "vp1" }, 97 .vp_bus_type = { DISPC_VP_DPI }, 98 99 .vp_feat = { .color = { 100 .has_ctm = true, 101 .gamma_size = 256, 102 .gamma_type = TIDSS_GAMMA_8BIT, 103 }, 104 }, 105 106 .num_planes = 1, 107 .vid_name = { "vid1" }, 108 .vid_lite = { false }, 109 .vid_order = { 0 }, 110 }; 111 112 static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { 113 [DSS_REVISION_OFF] = 0x4, 114 [DSS_SYSCONFIG_OFF] = 0x8, 115 [DSS_SYSSTATUS_OFF] = 0x20, 116 [DISPC_IRQ_EOI_OFF] = 0x24, 117 [DISPC_IRQSTATUS_RAW_OFF] = 0x28, 118 [DISPC_IRQSTATUS_OFF] = 0x2c, 119 [DISPC_IRQENABLE_SET_OFF] = 0x30, 120 [DISPC_IRQENABLE_CLR_OFF] = 0x40, 121 [DISPC_VID_IRQENABLE_OFF] = 0x44, 122 [DISPC_VID_IRQSTATUS_OFF] = 0x58, 123 [DISPC_VP_IRQENABLE_OFF] = 0x70, 124 [DISPC_VP_IRQSTATUS_OFF] = 0x7c, 125 126 [WB_IRQENABLE_OFF] = 0x88, 127 [WB_IRQSTATUS_OFF] = 0x8c, 128 129 [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x90, 130 [DISPC_GLOBAL_OUTPUT_ENABLE_OFF] = 0x94, 131 [DISPC_GLOBAL_BUFFER_OFF] = 0x98, 132 [DSS_CBA_CFG_OFF] = 0x9c, 133 [DISPC_DBG_CONTROL_OFF] = 0xa0, 134 [DISPC_DBG_STATUS_OFF] = 0xa4, 135 [DISPC_CLKGATING_DISABLE_OFF] = 0xa8, 136 [DISPC_SECURE_DISABLE_OFF] = 0xac, 137 }; 138 139 const struct dispc_features dispc_am65x_feats = { 140 .max_pclk_khz = { 141 [DISPC_VP_DPI] = 165000, 142 [DISPC_VP_OLDI] = 165000, 143 }, 144 145 .scaling = { 146 .in_width_max_5tap_rgb = 1280, 147 .in_width_max_3tap_rgb = 2560, 148 .in_width_max_5tap_yuv = 2560, 149 .in_width_max_3tap_yuv = 4096, 150 .upscale_limit = 16, 151 .downscale_limit_5tap = 4, 152 .downscale_limit_3tap = 2, 153 /* 154 * The max supported pixel inc value is 255. The value 155 * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 156 * The maximum bpp of all formats supported by the HW 157 * is 8. So the maximum supported xinc value is 32, 158 * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 159 */ 160 .xinc_max = 32, 161 }, 162 163 .subrev = DISPC_AM65X, 164 165 .common = "common", 166 .common_regs = tidss_am65x_common_regs, 167 168 .num_vps = 2, 169 .vp_name = { "vp1", "vp2" }, 170 .ovr_name = { "ovr1", "ovr2" }, 171 .vpclk_name = { "vp1", "vp2" }, 172 .vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI }, 173 174 .vp_feat = { .color = { 175 .has_ctm = true, 176 .gamma_size = 256, 177 .gamma_type = TIDSS_GAMMA_8BIT, 178 }, 179 }, 180 181 .num_planes = 2, 182 /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ 183 .vid_name = { "vid", "vidl1" }, 184 .vid_lite = { false, true, }, 185 .vid_order = { 1, 0 }, 186 }; 187 188 static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = { 189 [DSS_REVISION_OFF] = 0x4, 190 [DSS_SYSCONFIG_OFF] = 0x8, 191 [DSS_SYSSTATUS_OFF] = 0x20, 192 [DISPC_IRQ_EOI_OFF] = 0x80, 193 [DISPC_IRQSTATUS_RAW_OFF] = 0x28, 194 [DISPC_IRQSTATUS_OFF] = 0x2c, 195 [DISPC_IRQENABLE_SET_OFF] = 0x30, 196 [DISPC_IRQENABLE_CLR_OFF] = 0x34, 197 [DISPC_VID_IRQENABLE_OFF] = 0x38, 198 [DISPC_VID_IRQSTATUS_OFF] = 0x48, 199 [DISPC_VP_IRQENABLE_OFF] = 0x58, 200 [DISPC_VP_IRQSTATUS_OFF] = 0x68, 201 202 [WB_IRQENABLE_OFF] = 0x78, 203 [WB_IRQSTATUS_OFF] = 0x7c, 204 205 [DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x98, 206 [DISPC_GLOBAL_OUTPUT_ENABLE_OFF] = 0x9c, 207 [DISPC_GLOBAL_BUFFER_OFF] = 0xa0, 208 [DSS_CBA_CFG_OFF] = 0xa4, 209 [DISPC_DBG_CONTROL_OFF] = 0xa8, 210 [DISPC_DBG_STATUS_OFF] = 0xac, 211 [DISPC_CLKGATING_DISABLE_OFF] = 0xb0, 212 [DISPC_SECURE_DISABLE_OFF] = 0x90, 213 214 [FBDC_REVISION_1_OFF] = 0xb8, 215 [FBDC_REVISION_2_OFF] = 0xbc, 216 [FBDC_REVISION_3_OFF] = 0xc0, 217 [FBDC_REVISION_4_OFF] = 0xc4, 218 [FBDC_REVISION_5_OFF] = 0xc8, 219 [FBDC_REVISION_6_OFF] = 0xcc, 220 [FBDC_COMMON_CONTROL_OFF] = 0xd0, 221 [FBDC_CONSTANT_COLOR_0_OFF] = 0xd4, 222 [FBDC_CONSTANT_COLOR_1_OFF] = 0xd8, 223 [DISPC_CONNECTIONS_OFF] = 0xe4, 224 [DISPC_MSS_VP1_OFF] = 0xe8, 225 [DISPC_MSS_VP3_OFF] = 0xec, 226 }; 227 228 const struct dispc_features dispc_j721e_feats = { 229 .max_pclk_khz = { 230 [DISPC_VP_DPI] = 170000, 231 [DISPC_VP_INTERNAL] = 600000, 232 }, 233 234 .scaling = { 235 .in_width_max_5tap_rgb = 2048, 236 .in_width_max_3tap_rgb = 4096, 237 .in_width_max_5tap_yuv = 4096, 238 .in_width_max_3tap_yuv = 4096, 239 .upscale_limit = 16, 240 .downscale_limit_5tap = 4, 241 .downscale_limit_3tap = 2, 242 /* 243 * The max supported pixel inc value is 255. The value 244 * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 245 * The maximum bpp of all formats supported by the HW 246 * is 8. So the maximum supported xinc value is 32, 247 * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 248 */ 249 .xinc_max = 32, 250 }, 251 252 .subrev = DISPC_J721E, 253 254 .common = "common_m", 255 .common_regs = tidss_j721e_common_regs, 256 257 .num_vps = 4, 258 .vp_name = { "vp1", "vp2", "vp3", "vp4" }, 259 .ovr_name = { "ovr1", "ovr2", "ovr3", "ovr4" }, 260 .vpclk_name = { "vp1", "vp2", "vp3", "vp4" }, 261 /* Currently hard coded VP routing (see dispc_initial_config()) */ 262 .vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_DPI, 263 DISPC_VP_INTERNAL, DISPC_VP_DPI, }, 264 .vp_feat = { .color = { 265 .has_ctm = true, 266 .gamma_size = 1024, 267 .gamma_type = TIDSS_GAMMA_10BIT, 268 }, 269 }, 270 .num_planes = 4, 271 .vid_name = { "vid1", "vidl1", "vid2", "vidl2" }, 272 .vid_lite = { 0, 1, 0, 1, }, 273 .vid_order = { 1, 3, 0, 2 }, 274 }; 275 276 const struct dispc_features dispc_am625_feats = { 277 .max_pclk_khz = { 278 [DISPC_VP_DPI] = 165000, 279 [DISPC_VP_INTERNAL] = 170000, 280 }, 281 282 .scaling = { 283 .in_width_max_5tap_rgb = 1280, 284 .in_width_max_3tap_rgb = 2560, 285 .in_width_max_5tap_yuv = 2560, 286 .in_width_max_3tap_yuv = 4096, 287 .upscale_limit = 16, 288 .downscale_limit_5tap = 4, 289 .downscale_limit_3tap = 2, 290 /* 291 * The max supported pixel inc value is 255. The value 292 * of pixel inc is calculated like this: 1+(xinc-1)*bpp. 293 * The maximum bpp of all formats supported by the HW 294 * is 8. So the maximum supported xinc value is 32, 295 * because 1+(32-1)*8 < 255 < 1+(33-1)*4. 296 */ 297 .xinc_max = 32, 298 }, 299 300 .subrev = DISPC_AM625, 301 302 .common = "common", 303 .common_regs = tidss_am65x_common_regs, 304 305 .num_vps = 2, 306 .vp_name = { "vp1", "vp2" }, 307 .ovr_name = { "ovr1", "ovr2" }, 308 .vpclk_name = { "vp1", "vp2" }, 309 .vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_DPI }, 310 311 .vp_feat = { .color = { 312 .has_ctm = true, 313 .gamma_size = 256, 314 .gamma_type = TIDSS_GAMMA_8BIT, 315 }, 316 }, 317 318 .num_planes = 2, 319 /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ 320 .vid_name = { "vid", "vidl1" }, 321 .vid_lite = { false, true, }, 322 .vid_order = { 1, 0 }, 323 }; 324 325 static const u16 *dispc_common_regmap; 326 327 struct dss_vp_data { 328 u32 *gamma_table; 329 }; 330 331 struct dispc_device { 332 struct tidss_device *tidss; 333 struct device *dev; 334 335 void __iomem *base_common; 336 void __iomem *base_vid[TIDSS_MAX_PLANES]; 337 void __iomem *base_ovr[TIDSS_MAX_PORTS]; 338 void __iomem *base_vp[TIDSS_MAX_PORTS]; 339 340 struct regmap *oldi_io_ctrl; 341 342 struct clk *vp_clk[TIDSS_MAX_PORTS]; 343 344 const struct dispc_features *feat; 345 346 struct clk *fclk; 347 348 bool is_enabled; 349 350 struct dss_vp_data vp_data[TIDSS_MAX_PORTS]; 351 352 u32 *fourccs; 353 u32 num_fourccs; 354 355 u32 memory_bandwidth_limit; 356 357 struct dispc_errata errata; 358 }; 359 360 static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val) 361 { 362 iowrite32(val, dispc->base_common + reg); 363 } 364 365 static u32 dispc_read(struct dispc_device *dispc, u16 reg) 366 { 367 return ioread32(dispc->base_common + reg); 368 } 369 370 static 371 void dispc_vid_write(struct dispc_device *dispc, u32 hw_plane, u16 reg, u32 val) 372 { 373 void __iomem *base = dispc->base_vid[hw_plane]; 374 375 iowrite32(val, base + reg); 376 } 377 378 static u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg) 379 { 380 void __iomem *base = dispc->base_vid[hw_plane]; 381 382 return ioread32(base + reg); 383 } 384 385 static void dispc_ovr_write(struct dispc_device *dispc, u32 hw_videoport, 386 u16 reg, u32 val) 387 { 388 void __iomem *base = dispc->base_ovr[hw_videoport]; 389 390 iowrite32(val, base + reg); 391 } 392 393 static u32 dispc_ovr_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg) 394 { 395 void __iomem *base = dispc->base_ovr[hw_videoport]; 396 397 return ioread32(base + reg); 398 } 399 400 static void dispc_vp_write(struct dispc_device *dispc, u32 hw_videoport, 401 u16 reg, u32 val) 402 { 403 void __iomem *base = dispc->base_vp[hw_videoport]; 404 405 iowrite32(val, base + reg); 406 } 407 408 static u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg) 409 { 410 void __iomem *base = dispc->base_vp[hw_videoport]; 411 412 return ioread32(base + reg); 413 } 414 415 /* 416 * TRM gives bitfields as start:end, where start is the higher bit 417 * number. For example 7:0 418 */ 419 420 static u32 FLD_MASK(u32 start, u32 end) 421 { 422 return ((1 << (start - end + 1)) - 1) << end; 423 } 424 425 static u32 FLD_VAL(u32 val, u32 start, u32 end) 426 { 427 return (val << end) & FLD_MASK(start, end); 428 } 429 430 static u32 FLD_GET(u32 val, u32 start, u32 end) 431 { 432 return (val & FLD_MASK(start, end)) >> end; 433 } 434 435 static u32 FLD_MOD(u32 orig, u32 val, u32 start, u32 end) 436 { 437 return (orig & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end); 438 } 439 440 static u32 REG_GET(struct dispc_device *dispc, u32 idx, u32 start, u32 end) 441 { 442 return FLD_GET(dispc_read(dispc, idx), start, end); 443 } 444 445 static void REG_FLD_MOD(struct dispc_device *dispc, u32 idx, u32 val, 446 u32 start, u32 end) 447 { 448 dispc_write(dispc, idx, FLD_MOD(dispc_read(dispc, idx), val, 449 start, end)); 450 } 451 452 static u32 VID_REG_GET(struct dispc_device *dispc, u32 hw_plane, u32 idx, 453 u32 start, u32 end) 454 { 455 return FLD_GET(dispc_vid_read(dispc, hw_plane, idx), start, end); 456 } 457 458 static void VID_REG_FLD_MOD(struct dispc_device *dispc, u32 hw_plane, u32 idx, 459 u32 val, u32 start, u32 end) 460 { 461 dispc_vid_write(dispc, hw_plane, idx, 462 FLD_MOD(dispc_vid_read(dispc, hw_plane, idx), 463 val, start, end)); 464 } 465 466 static u32 VP_REG_GET(struct dispc_device *dispc, u32 vp, u32 idx, 467 u32 start, u32 end) 468 { 469 return FLD_GET(dispc_vp_read(dispc, vp, idx), start, end); 470 } 471 472 static void VP_REG_FLD_MOD(struct dispc_device *dispc, u32 vp, u32 idx, u32 val, 473 u32 start, u32 end) 474 { 475 dispc_vp_write(dispc, vp, idx, FLD_MOD(dispc_vp_read(dispc, vp, idx), 476 val, start, end)); 477 } 478 479 __maybe_unused 480 static u32 OVR_REG_GET(struct dispc_device *dispc, u32 ovr, u32 idx, 481 u32 start, u32 end) 482 { 483 return FLD_GET(dispc_ovr_read(dispc, ovr, idx), start, end); 484 } 485 486 static void OVR_REG_FLD_MOD(struct dispc_device *dispc, u32 ovr, u32 idx, 487 u32 val, u32 start, u32 end) 488 { 489 dispc_ovr_write(dispc, ovr, idx, 490 FLD_MOD(dispc_ovr_read(dispc, ovr, idx), 491 val, start, end)); 492 } 493 494 static dispc_irq_t dispc_vp_irq_from_raw(u32 stat, u32 hw_videoport) 495 { 496 dispc_irq_t vp_stat = 0; 497 498 if (stat & BIT(0)) 499 vp_stat |= DSS_IRQ_VP_FRAME_DONE(hw_videoport); 500 if (stat & BIT(1)) 501 vp_stat |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport); 502 if (stat & BIT(2)) 503 vp_stat |= DSS_IRQ_VP_VSYNC_ODD(hw_videoport); 504 if (stat & BIT(4)) 505 vp_stat |= DSS_IRQ_VP_SYNC_LOST(hw_videoport); 506 507 return vp_stat; 508 } 509 510 static u32 dispc_vp_irq_to_raw(dispc_irq_t vpstat, u32 hw_videoport) 511 { 512 u32 stat = 0; 513 514 if (vpstat & DSS_IRQ_VP_FRAME_DONE(hw_videoport)) 515 stat |= BIT(0); 516 if (vpstat & DSS_IRQ_VP_VSYNC_EVEN(hw_videoport)) 517 stat |= BIT(1); 518 if (vpstat & DSS_IRQ_VP_VSYNC_ODD(hw_videoport)) 519 stat |= BIT(2); 520 if (vpstat & DSS_IRQ_VP_SYNC_LOST(hw_videoport)) 521 stat |= BIT(4); 522 523 return stat; 524 } 525 526 static dispc_irq_t dispc_vid_irq_from_raw(u32 stat, u32 hw_plane) 527 { 528 dispc_irq_t vid_stat = 0; 529 530 if (stat & BIT(0)) 531 vid_stat |= DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane); 532 533 return vid_stat; 534 } 535 536 static u32 dispc_vid_irq_to_raw(dispc_irq_t vidstat, u32 hw_plane) 537 { 538 u32 stat = 0; 539 540 if (vidstat & DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane)) 541 stat |= BIT(0); 542 543 return stat; 544 } 545 546 static dispc_irq_t dispc_k2g_vp_read_irqstatus(struct dispc_device *dispc, 547 u32 hw_videoport) 548 { 549 u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS); 550 551 return dispc_vp_irq_from_raw(stat, hw_videoport); 552 } 553 554 static void dispc_k2g_vp_write_irqstatus(struct dispc_device *dispc, 555 u32 hw_videoport, dispc_irq_t vpstat) 556 { 557 u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 558 559 dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS, stat); 560 } 561 562 static dispc_irq_t dispc_k2g_vid_read_irqstatus(struct dispc_device *dispc, 563 u32 hw_plane) 564 { 565 u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS); 566 567 return dispc_vid_irq_from_raw(stat, hw_plane); 568 } 569 570 static void dispc_k2g_vid_write_irqstatus(struct dispc_device *dispc, 571 u32 hw_plane, dispc_irq_t vidstat) 572 { 573 u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 574 575 dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS, stat); 576 } 577 578 static dispc_irq_t dispc_k2g_vp_read_irqenable(struct dispc_device *dispc, 579 u32 hw_videoport) 580 { 581 u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE); 582 583 return dispc_vp_irq_from_raw(stat, hw_videoport); 584 } 585 586 static void dispc_k2g_vp_set_irqenable(struct dispc_device *dispc, 587 u32 hw_videoport, dispc_irq_t vpstat) 588 { 589 u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 590 591 dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE, stat); 592 } 593 594 static dispc_irq_t dispc_k2g_vid_read_irqenable(struct dispc_device *dispc, 595 u32 hw_plane) 596 { 597 u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE); 598 599 return dispc_vid_irq_from_raw(stat, hw_plane); 600 } 601 602 static void dispc_k2g_vid_set_irqenable(struct dispc_device *dispc, 603 u32 hw_plane, dispc_irq_t vidstat) 604 { 605 u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 606 607 dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE, stat); 608 } 609 610 static void dispc_k2g_clear_irqstatus(struct dispc_device *dispc, 611 dispc_irq_t mask) 612 { 613 dispc_k2g_vp_write_irqstatus(dispc, 0, mask); 614 dispc_k2g_vid_write_irqstatus(dispc, 0, mask); 615 } 616 617 static 618 dispc_irq_t dispc_k2g_read_and_clear_irqstatus(struct dispc_device *dispc) 619 { 620 dispc_irq_t stat = 0; 621 622 /* always clear the top level irqstatus */ 623 dispc_write(dispc, DISPC_IRQSTATUS, 624 dispc_read(dispc, DISPC_IRQSTATUS)); 625 626 stat |= dispc_k2g_vp_read_irqstatus(dispc, 0); 627 stat |= dispc_k2g_vid_read_irqstatus(dispc, 0); 628 629 dispc_k2g_clear_irqstatus(dispc, stat); 630 631 return stat; 632 } 633 634 static dispc_irq_t dispc_k2g_read_irqenable(struct dispc_device *dispc) 635 { 636 dispc_irq_t stat = 0; 637 638 stat |= dispc_k2g_vp_read_irqenable(dispc, 0); 639 stat |= dispc_k2g_vid_read_irqenable(dispc, 0); 640 641 return stat; 642 } 643 644 static 645 void dispc_k2g_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask) 646 { 647 dispc_irq_t old_mask = dispc_k2g_read_irqenable(dispc); 648 649 /* clear the irqstatus for newly enabled irqs */ 650 dispc_k2g_clear_irqstatus(dispc, (mask ^ old_mask) & mask); 651 652 dispc_k2g_vp_set_irqenable(dispc, 0, mask); 653 dispc_k2g_vid_set_irqenable(dispc, 0, mask); 654 655 dispc_write(dispc, DISPC_IRQENABLE_SET, (1 << 0) | (1 << 7)); 656 657 /* flush posted write */ 658 dispc_k2g_read_irqenable(dispc); 659 } 660 661 static dispc_irq_t dispc_k3_vp_read_irqstatus(struct dispc_device *dispc, 662 u32 hw_videoport) 663 { 664 u32 stat = dispc_read(dispc, DISPC_VP_IRQSTATUS(hw_videoport)); 665 666 return dispc_vp_irq_from_raw(stat, hw_videoport); 667 } 668 669 static void dispc_k3_vp_write_irqstatus(struct dispc_device *dispc, 670 u32 hw_videoport, dispc_irq_t vpstat) 671 { 672 u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 673 674 dispc_write(dispc, DISPC_VP_IRQSTATUS(hw_videoport), stat); 675 } 676 677 static dispc_irq_t dispc_k3_vid_read_irqstatus(struct dispc_device *dispc, 678 u32 hw_plane) 679 { 680 u32 stat = dispc_read(dispc, DISPC_VID_IRQSTATUS(hw_plane)); 681 682 return dispc_vid_irq_from_raw(stat, hw_plane); 683 } 684 685 static void dispc_k3_vid_write_irqstatus(struct dispc_device *dispc, 686 u32 hw_plane, dispc_irq_t vidstat) 687 { 688 u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 689 690 dispc_write(dispc, DISPC_VID_IRQSTATUS(hw_plane), stat); 691 } 692 693 static dispc_irq_t dispc_k3_vp_read_irqenable(struct dispc_device *dispc, 694 u32 hw_videoport) 695 { 696 u32 stat = dispc_read(dispc, DISPC_VP_IRQENABLE(hw_videoport)); 697 698 return dispc_vp_irq_from_raw(stat, hw_videoport); 699 } 700 701 static void dispc_k3_vp_set_irqenable(struct dispc_device *dispc, 702 u32 hw_videoport, dispc_irq_t vpstat) 703 { 704 u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport); 705 706 dispc_write(dispc, DISPC_VP_IRQENABLE(hw_videoport), stat); 707 } 708 709 static dispc_irq_t dispc_k3_vid_read_irqenable(struct dispc_device *dispc, 710 u32 hw_plane) 711 { 712 u32 stat = dispc_read(dispc, DISPC_VID_IRQENABLE(hw_plane)); 713 714 return dispc_vid_irq_from_raw(stat, hw_plane); 715 } 716 717 static void dispc_k3_vid_set_irqenable(struct dispc_device *dispc, 718 u32 hw_plane, dispc_irq_t vidstat) 719 { 720 u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane); 721 722 dispc_write(dispc, DISPC_VID_IRQENABLE(hw_plane), stat); 723 } 724 725 static 726 void dispc_k3_clear_irqstatus(struct dispc_device *dispc, dispc_irq_t clearmask) 727 { 728 unsigned int i; 729 u32 top_clear = 0; 730 731 for (i = 0; i < dispc->feat->num_vps; ++i) { 732 if (clearmask & DSS_IRQ_VP_MASK(i)) { 733 dispc_k3_vp_write_irqstatus(dispc, i, clearmask); 734 top_clear |= BIT(i); 735 } 736 } 737 for (i = 0; i < dispc->feat->num_planes; ++i) { 738 if (clearmask & DSS_IRQ_PLANE_MASK(i)) { 739 dispc_k3_vid_write_irqstatus(dispc, i, clearmask); 740 top_clear |= BIT(4 + i); 741 } 742 } 743 if (dispc->feat->subrev == DISPC_K2G) 744 return; 745 746 dispc_write(dispc, DISPC_IRQSTATUS, top_clear); 747 748 /* Flush posted writes */ 749 dispc_read(dispc, DISPC_IRQSTATUS); 750 } 751 752 static 753 dispc_irq_t dispc_k3_read_and_clear_irqstatus(struct dispc_device *dispc) 754 { 755 dispc_irq_t status = 0; 756 unsigned int i; 757 758 for (i = 0; i < dispc->feat->num_vps; ++i) 759 status |= dispc_k3_vp_read_irqstatus(dispc, i); 760 761 for (i = 0; i < dispc->feat->num_planes; ++i) 762 status |= dispc_k3_vid_read_irqstatus(dispc, i); 763 764 dispc_k3_clear_irqstatus(dispc, status); 765 766 return status; 767 } 768 769 static dispc_irq_t dispc_k3_read_irqenable(struct dispc_device *dispc) 770 { 771 dispc_irq_t enable = 0; 772 unsigned int i; 773 774 for (i = 0; i < dispc->feat->num_vps; ++i) 775 enable |= dispc_k3_vp_read_irqenable(dispc, i); 776 777 for (i = 0; i < dispc->feat->num_planes; ++i) 778 enable |= dispc_k3_vid_read_irqenable(dispc, i); 779 780 return enable; 781 } 782 783 static void dispc_k3_set_irqenable(struct dispc_device *dispc, 784 dispc_irq_t mask) 785 { 786 unsigned int i; 787 u32 main_enable = 0, main_disable = 0; 788 dispc_irq_t old_mask; 789 790 old_mask = dispc_k3_read_irqenable(dispc); 791 792 /* clear the irqstatus for newly enabled irqs */ 793 dispc_k3_clear_irqstatus(dispc, (old_mask ^ mask) & mask); 794 795 for (i = 0; i < dispc->feat->num_vps; ++i) { 796 dispc_k3_vp_set_irqenable(dispc, i, mask); 797 if (mask & DSS_IRQ_VP_MASK(i)) 798 main_enable |= BIT(i); /* VP IRQ */ 799 else 800 main_disable |= BIT(i); /* VP IRQ */ 801 } 802 803 for (i = 0; i < dispc->feat->num_planes; ++i) { 804 dispc_k3_vid_set_irqenable(dispc, i, mask); 805 if (mask & DSS_IRQ_PLANE_MASK(i)) 806 main_enable |= BIT(i + 4); /* VID IRQ */ 807 else 808 main_disable |= BIT(i + 4); /* VID IRQ */ 809 } 810 811 if (main_enable) 812 dispc_write(dispc, DISPC_IRQENABLE_SET, main_enable); 813 814 if (main_disable) 815 dispc_write(dispc, DISPC_IRQENABLE_CLR, main_disable); 816 817 /* Flush posted writes */ 818 dispc_read(dispc, DISPC_IRQENABLE_SET); 819 } 820 821 dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc) 822 { 823 switch (dispc->feat->subrev) { 824 case DISPC_K2G: 825 return dispc_k2g_read_and_clear_irqstatus(dispc); 826 case DISPC_AM625: 827 case DISPC_AM65X: 828 case DISPC_J721E: 829 return dispc_k3_read_and_clear_irqstatus(dispc); 830 default: 831 WARN_ON(1); 832 return 0; 833 } 834 } 835 836 void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask) 837 { 838 switch (dispc->feat->subrev) { 839 case DISPC_K2G: 840 dispc_k2g_set_irqenable(dispc, mask); 841 break; 842 case DISPC_AM625: 843 case DISPC_AM65X: 844 case DISPC_J721E: 845 dispc_k3_set_irqenable(dispc, mask); 846 break; 847 default: 848 WARN_ON(1); 849 break; 850 } 851 } 852 853 enum dispc_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 }; 854 855 struct dispc_bus_format { 856 u32 bus_fmt; 857 u32 data_width; 858 bool is_oldi_fmt; 859 enum dispc_oldi_mode_reg_val oldi_mode_reg_val; 860 }; 861 862 static const struct dispc_bus_format dispc_bus_formats[] = { 863 { MEDIA_BUS_FMT_RGB444_1X12, 12, false, 0 }, 864 { MEDIA_BUS_FMT_RGB565_1X16, 16, false, 0 }, 865 { MEDIA_BUS_FMT_RGB666_1X18, 18, false, 0 }, 866 { MEDIA_BUS_FMT_RGB888_1X24, 24, false, 0 }, 867 { MEDIA_BUS_FMT_RGB101010_1X30, 30, false, 0 }, 868 { MEDIA_BUS_FMT_RGB121212_1X36, 36, false, 0 }, 869 { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, true, SPWG_18 }, 870 { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, true, SPWG_24 }, 871 { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, true, JEIDA_24 }, 872 }; 873 874 static const 875 struct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc, 876 u32 hw_videoport, 877 u32 bus_fmt, u32 bus_flags) 878 { 879 unsigned int i; 880 881 for (i = 0; i < ARRAY_SIZE(dispc_bus_formats); ++i) { 882 if (dispc_bus_formats[i].bus_fmt == bus_fmt) 883 return &dispc_bus_formats[i]; 884 } 885 886 return NULL; 887 } 888 889 int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport, 890 const struct drm_crtc_state *state) 891 { 892 const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state); 893 const struct dispc_bus_format *fmt; 894 895 fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format, 896 tstate->bus_flags); 897 if (!fmt) { 898 dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n", 899 __func__, tstate->bus_format); 900 return -EINVAL; 901 } 902 903 if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI && 904 fmt->is_oldi_fmt) { 905 dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n", 906 __func__, dispc->feat->vp_name[hw_videoport]); 907 return -EINVAL; 908 } 909 910 return 0; 911 } 912 913 static void dispc_oldi_tx_power(struct dispc_device *dispc, bool power) 914 { 915 u32 val = power ? 0 : OLDI_PWRDN_TX; 916 917 if (WARN_ON(!dispc->oldi_io_ctrl)) 918 return; 919 920 regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL, 921 OLDI_PWRDN_TX, val); 922 regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL, 923 OLDI_PWRDN_TX, val); 924 regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL, 925 OLDI_PWRDN_TX, val); 926 regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL, 927 OLDI_PWRDN_TX, val); 928 regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL, 929 OLDI_PWRDN_TX, val); 930 } 931 932 static void dispc_set_num_datalines(struct dispc_device *dispc, 933 u32 hw_videoport, int num_lines) 934 { 935 int v; 936 937 switch (num_lines) { 938 case 12: 939 v = 0; break; 940 case 16: 941 v = 1; break; 942 case 18: 943 v = 2; break; 944 case 24: 945 v = 3; break; 946 case 30: 947 v = 4; break; 948 case 36: 949 v = 5; break; 950 default: 951 WARN_ON(1); 952 v = 3; 953 } 954 955 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8); 956 } 957 958 static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport, 959 const struct dispc_bus_format *fmt) 960 { 961 u32 oldi_cfg = 0; 962 u32 oldi_reset_bit = BIT(5 + hw_videoport); 963 int count = 0; 964 965 /* 966 * For the moment DUALMODESYNC, MASTERSLAVE, MODE, and SRC 967 * bits of DISPC_VP_DSS_OLDI_CFG are set statically to 0. 968 */ 969 970 if (fmt->data_width == 24) 971 oldi_cfg |= BIT(8); /* MSB */ 972 else if (fmt->data_width != 18) 973 dev_warn(dispc->dev, "%s: %d port width not supported\n", 974 __func__, fmt->data_width); 975 976 oldi_cfg |= BIT(7); /* DEPOL */ 977 978 oldi_cfg = FLD_MOD(oldi_cfg, fmt->oldi_mode_reg_val, 3, 1); 979 980 oldi_cfg |= BIT(12); /* SOFTRST */ 981 982 oldi_cfg |= BIT(0); /* ENABLE */ 983 984 dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, oldi_cfg); 985 986 while (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS)) && 987 count < 10000) 988 count++; 989 990 if (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS))) 991 dev_warn(dispc->dev, "%s: timeout waiting OLDI reset done\n", 992 __func__); 993 } 994 995 void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport, 996 const struct drm_crtc_state *state) 997 { 998 const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state); 999 const struct dispc_bus_format *fmt; 1000 1001 fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format, 1002 tstate->bus_flags); 1003 1004 if (WARN_ON(!fmt)) 1005 return; 1006 1007 if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) { 1008 dispc_oldi_tx_power(dispc, true); 1009 1010 dispc_enable_oldi(dispc, hw_videoport, fmt); 1011 } 1012 } 1013 1014 void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport, 1015 const struct drm_crtc_state *state) 1016 { 1017 const struct drm_display_mode *mode = &state->adjusted_mode; 1018 const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state); 1019 bool align, onoff, rf, ieo, ipc, ihs, ivs; 1020 const struct dispc_bus_format *fmt; 1021 u32 hsw, hfp, hbp, vsw, vfp, vbp; 1022 1023 fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format, 1024 tstate->bus_flags); 1025 1026 if (WARN_ON(!fmt)) 1027 return; 1028 1029 dispc_set_num_datalines(dispc, hw_videoport, fmt->data_width); 1030 1031 hfp = mode->hsync_start - mode->hdisplay; 1032 hsw = mode->hsync_end - mode->hsync_start; 1033 hbp = mode->htotal - mode->hsync_end; 1034 1035 vfp = mode->vsync_start - mode->vdisplay; 1036 vsw = mode->vsync_end - mode->vsync_start; 1037 vbp = mode->vtotal - mode->vsync_end; 1038 1039 dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_H, 1040 FLD_VAL(hsw - 1, 7, 0) | 1041 FLD_VAL(hfp - 1, 19, 8) | 1042 FLD_VAL(hbp - 1, 31, 20)); 1043 1044 dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_V, 1045 FLD_VAL(vsw - 1, 7, 0) | 1046 FLD_VAL(vfp, 19, 8) | 1047 FLD_VAL(vbp, 31, 20)); 1048 1049 ivs = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); 1050 1051 ihs = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); 1052 1053 ieo = !!(tstate->bus_flags & DRM_BUS_FLAG_DE_LOW); 1054 1055 ipc = !!(tstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE); 1056 1057 /* always use the 'rf' setting */ 1058 onoff = true; 1059 1060 rf = !!(tstate->bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE); 1061 1062 /* always use aligned syncs */ 1063 align = true; 1064 1065 /* always use DE_HIGH for OLDI */ 1066 if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) 1067 ieo = false; 1068 1069 dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ, 1070 FLD_VAL(align, 18, 18) | 1071 FLD_VAL(onoff, 17, 17) | 1072 FLD_VAL(rf, 16, 16) | 1073 FLD_VAL(ieo, 15, 15) | 1074 FLD_VAL(ipc, 14, 14) | 1075 FLD_VAL(ihs, 13, 13) | 1076 FLD_VAL(ivs, 12, 12)); 1077 1078 dispc_vp_write(dispc, hw_videoport, DISPC_VP_SIZE_SCREEN, 1079 FLD_VAL(mode->hdisplay - 1, 11, 0) | 1080 FLD_VAL(mode->vdisplay - 1, 27, 16)); 1081 1082 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 0, 0); 1083 } 1084 1085 void dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport) 1086 { 1087 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 0, 0, 0); 1088 } 1089 1090 void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport) 1091 { 1092 if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) { 1093 dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0); 1094 1095 dispc_oldi_tx_power(dispc, false); 1096 } 1097 } 1098 1099 bool dispc_vp_go_busy(struct dispc_device *dispc, u32 hw_videoport) 1100 { 1101 return VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5); 1102 } 1103 1104 void dispc_vp_go(struct dispc_device *dispc, u32 hw_videoport) 1105 { 1106 WARN_ON(VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5)); 1107 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 5, 5); 1108 } 1109 1110 enum c8_to_c12_mode { C8_TO_C12_REPLICATE, C8_TO_C12_MAX, C8_TO_C12_MIN }; 1111 1112 static u16 c8_to_c12(u8 c8, enum c8_to_c12_mode mode) 1113 { 1114 u16 c12; 1115 1116 c12 = c8 << 4; 1117 1118 switch (mode) { 1119 case C8_TO_C12_REPLICATE: 1120 /* Copy c8 4 MSB to 4 LSB for full scale c12 */ 1121 c12 |= c8 >> 4; 1122 break; 1123 case C8_TO_C12_MAX: 1124 c12 |= 0xF; 1125 break; 1126 default: 1127 case C8_TO_C12_MIN: 1128 break; 1129 } 1130 1131 return c12; 1132 } 1133 1134 static u64 argb8888_to_argb12121212(u32 argb8888, enum c8_to_c12_mode m) 1135 { 1136 u8 a, r, g, b; 1137 u64 v; 1138 1139 a = (argb8888 >> 24) & 0xff; 1140 r = (argb8888 >> 16) & 0xff; 1141 g = (argb8888 >> 8) & 0xff; 1142 b = (argb8888 >> 0) & 0xff; 1143 1144 v = ((u64)c8_to_c12(a, m) << 36) | ((u64)c8_to_c12(r, m) << 24) | 1145 ((u64)c8_to_c12(g, m) << 12) | (u64)c8_to_c12(b, m); 1146 1147 return v; 1148 } 1149 1150 static void dispc_vp_set_default_color(struct dispc_device *dispc, 1151 u32 hw_videoport, u32 default_color) 1152 { 1153 u64 v; 1154 1155 v = argb8888_to_argb12121212(default_color, C8_TO_C12_REPLICATE); 1156 1157 dispc_ovr_write(dispc, hw_videoport, 1158 DISPC_OVR_DEFAULT_COLOR, v & 0xffffffff); 1159 dispc_ovr_write(dispc, hw_videoport, 1160 DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff); 1161 } 1162 1163 enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc, 1164 u32 hw_videoport, 1165 const struct drm_display_mode *mode) 1166 { 1167 u32 hsw, hfp, hbp, vsw, vfp, vbp; 1168 enum dispc_vp_bus_type bus_type; 1169 int max_pclk; 1170 1171 bus_type = dispc->feat->vp_bus_type[hw_videoport]; 1172 1173 max_pclk = dispc->feat->max_pclk_khz[bus_type]; 1174 1175 if (WARN_ON(max_pclk == 0)) 1176 return MODE_BAD; 1177 1178 if (mode->clock < dispc->feat->min_pclk_khz) 1179 return MODE_CLOCK_LOW; 1180 1181 if (mode->clock > max_pclk) 1182 return MODE_CLOCK_HIGH; 1183 1184 if (mode->hdisplay > 4096) 1185 return MODE_BAD; 1186 1187 if (mode->vdisplay > 4096) 1188 return MODE_BAD; 1189 1190 /* TODO: add interlace support */ 1191 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1192 return MODE_NO_INTERLACE; 1193 1194 /* 1195 * Enforce the output width is divisible by 2. Actually this 1196 * is only needed in following cases: 1197 * - YUV output selected (BT656, BT1120) 1198 * - Dithering enabled 1199 * - TDM with TDMCycleFormat == 3 1200 * But for simplicity we enforce that always. 1201 */ 1202 if ((mode->hdisplay % 2) != 0) 1203 return MODE_BAD_HVALUE; 1204 1205 hfp = mode->hsync_start - mode->hdisplay; 1206 hsw = mode->hsync_end - mode->hsync_start; 1207 hbp = mode->htotal - mode->hsync_end; 1208 1209 vfp = mode->vsync_start - mode->vdisplay; 1210 vsw = mode->vsync_end - mode->vsync_start; 1211 vbp = mode->vtotal - mode->vsync_end; 1212 1213 if (hsw < 1 || hsw > 256 || 1214 hfp < 1 || hfp > 4096 || 1215 hbp < 1 || hbp > 4096) 1216 return MODE_BAD_HVALUE; 1217 1218 if (vsw < 1 || vsw > 256 || 1219 vfp > 4095 || vbp > 4095) 1220 return MODE_BAD_VVALUE; 1221 1222 if (dispc->memory_bandwidth_limit) { 1223 const unsigned int bpp = 4; 1224 u64 bandwidth; 1225 1226 bandwidth = 1000 * mode->clock; 1227 bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp; 1228 bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal); 1229 1230 if (dispc->memory_bandwidth_limit < bandwidth) 1231 return MODE_BAD; 1232 } 1233 1234 return MODE_OK; 1235 } 1236 1237 int dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport) 1238 { 1239 int ret = clk_prepare_enable(dispc->vp_clk[hw_videoport]); 1240 1241 if (ret) 1242 dev_err(dispc->dev, "%s: enabling clk failed: %d\n", __func__, 1243 ret); 1244 1245 return ret; 1246 } 1247 1248 void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport) 1249 { 1250 clk_disable_unprepare(dispc->vp_clk[hw_videoport]); 1251 } 1252 1253 /* 1254 * Calculate the percentage difference between the requested pixel clock rate 1255 * and the effective rate resulting from calculating the clock divider value. 1256 */ 1257 static 1258 unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate) 1259 { 1260 int r = rate / 100, rr = real_rate / 100; 1261 1262 return (unsigned int)(abs(((rr - r) * 100) / r)); 1263 } 1264 1265 int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport, 1266 unsigned long rate) 1267 { 1268 int r; 1269 unsigned long new_rate; 1270 1271 r = clk_set_rate(dispc->vp_clk[hw_videoport], rate); 1272 if (r) { 1273 dev_err(dispc->dev, "vp%d: failed to set clk rate to %lu\n", 1274 hw_videoport, rate); 1275 return r; 1276 } 1277 1278 new_rate = clk_get_rate(dispc->vp_clk[hw_videoport]); 1279 1280 if (dispc_pclk_diff(rate, new_rate) > 5) 1281 dev_warn(dispc->dev, 1282 "vp%d: Clock rate %lu differs over 5%% from requested %lu\n", 1283 hw_videoport, new_rate, rate); 1284 1285 dev_dbg(dispc->dev, "vp%d: new rate %lu Hz (requested %lu Hz)\n", 1286 hw_videoport, clk_get_rate(dispc->vp_clk[hw_videoport]), rate); 1287 1288 return 0; 1289 } 1290 1291 /* OVR */ 1292 static void dispc_k2g_ovr_set_plane(struct dispc_device *dispc, 1293 u32 hw_plane, u32 hw_videoport, 1294 u32 x, u32 y, u32 layer) 1295 { 1296 /* On k2g there is only one plane and no need for ovr */ 1297 dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_POSITION, 1298 x | (y << 16)); 1299 } 1300 1301 static void dispc_am65x_ovr_set_plane(struct dispc_device *dispc, 1302 u32 hw_plane, u32 hw_videoport, 1303 u32 x, u32 y, u32 layer) 1304 { 1305 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 1306 hw_plane, 4, 1); 1307 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 1308 x, 17, 6); 1309 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 1310 y, 30, 19); 1311 } 1312 1313 static void dispc_j721e_ovr_set_plane(struct dispc_device *dispc, 1314 u32 hw_plane, u32 hw_videoport, 1315 u32 x, u32 y, u32 layer) 1316 { 1317 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 1318 hw_plane, 4, 1); 1319 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer), 1320 x, 13, 0); 1321 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer), 1322 y, 29, 16); 1323 } 1324 1325 void dispc_ovr_set_plane(struct dispc_device *dispc, u32 hw_plane, 1326 u32 hw_videoport, u32 x, u32 y, u32 layer) 1327 { 1328 switch (dispc->feat->subrev) { 1329 case DISPC_K2G: 1330 dispc_k2g_ovr_set_plane(dispc, hw_plane, hw_videoport, 1331 x, y, layer); 1332 break; 1333 case DISPC_AM625: 1334 case DISPC_AM65X: 1335 dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport, 1336 x, y, layer); 1337 break; 1338 case DISPC_J721E: 1339 dispc_j721e_ovr_set_plane(dispc, hw_plane, hw_videoport, 1340 x, y, layer); 1341 break; 1342 default: 1343 WARN_ON(1); 1344 break; 1345 } 1346 } 1347 1348 void dispc_ovr_enable_layer(struct dispc_device *dispc, 1349 u32 hw_videoport, u32 layer, bool enable) 1350 { 1351 if (dispc->feat->subrev == DISPC_K2G) 1352 return; 1353 1354 OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer), 1355 !!enable, 0, 0); 1356 } 1357 1358 /* CSC */ 1359 enum csc_ctm { 1360 CSC_RR, CSC_RG, CSC_RB, 1361 CSC_GR, CSC_GG, CSC_GB, 1362 CSC_BR, CSC_BG, CSC_BB, 1363 }; 1364 1365 enum csc_yuv2rgb { 1366 CSC_RY, CSC_RCB, CSC_RCR, 1367 CSC_GY, CSC_GCB, CSC_GCR, 1368 CSC_BY, CSC_BCB, CSC_BCR, 1369 }; 1370 1371 enum csc_rgb2yuv { 1372 CSC_YR, CSC_YG, CSC_YB, 1373 CSC_CBR, CSC_CBG, CSC_CBB, 1374 CSC_CRR, CSC_CRG, CSC_CRB, 1375 }; 1376 1377 struct dispc_csc_coef { 1378 void (*to_regval)(const struct dispc_csc_coef *csc, u32 *regval); 1379 int m[9]; 1380 int preoffset[3]; 1381 int postoffset[3]; 1382 enum { CLIP_LIMITED_RANGE = 0, CLIP_FULL_RANGE = 1, } cliping; 1383 const char *name; 1384 }; 1385 1386 #define DISPC_CSC_REGVAL_LEN 8 1387 1388 static 1389 void dispc_csc_offset_regval(const struct dispc_csc_coef *csc, u32 *regval) 1390 { 1391 #define OVAL(x, y) (FLD_VAL(x, 15, 3) | FLD_VAL(y, 31, 19)) 1392 regval[5] = OVAL(csc->preoffset[0], csc->preoffset[1]); 1393 regval[6] = OVAL(csc->preoffset[2], csc->postoffset[0]); 1394 regval[7] = OVAL(csc->postoffset[1], csc->postoffset[2]); 1395 #undef OVAL 1396 } 1397 1398 #define CVAL(x, y) (FLD_VAL(x, 10, 0) | FLD_VAL(y, 26, 16)) 1399 static 1400 void dispc_csc_yuv2rgb_regval(const struct dispc_csc_coef *csc, u32 *regval) 1401 { 1402 regval[0] = CVAL(csc->m[CSC_RY], csc->m[CSC_RCR]); 1403 regval[1] = CVAL(csc->m[CSC_RCB], csc->m[CSC_GY]); 1404 regval[2] = CVAL(csc->m[CSC_GCR], csc->m[CSC_GCB]); 1405 regval[3] = CVAL(csc->m[CSC_BY], csc->m[CSC_BCR]); 1406 regval[4] = CVAL(csc->m[CSC_BCB], 0); 1407 1408 dispc_csc_offset_regval(csc, regval); 1409 } 1410 1411 __maybe_unused static 1412 void dispc_csc_rgb2yuv_regval(const struct dispc_csc_coef *csc, u32 *regval) 1413 { 1414 regval[0] = CVAL(csc->m[CSC_YR], csc->m[CSC_YG]); 1415 regval[1] = CVAL(csc->m[CSC_YB], csc->m[CSC_CRR]); 1416 regval[2] = CVAL(csc->m[CSC_CRG], csc->m[CSC_CRB]); 1417 regval[3] = CVAL(csc->m[CSC_CBR], csc->m[CSC_CBG]); 1418 regval[4] = CVAL(csc->m[CSC_CBB], 0); 1419 1420 dispc_csc_offset_regval(csc, regval); 1421 } 1422 1423 static void dispc_csc_cpr_regval(const struct dispc_csc_coef *csc, 1424 u32 *regval) 1425 { 1426 regval[0] = CVAL(csc->m[CSC_RR], csc->m[CSC_RG]); 1427 regval[1] = CVAL(csc->m[CSC_RB], csc->m[CSC_GR]); 1428 regval[2] = CVAL(csc->m[CSC_GG], csc->m[CSC_GB]); 1429 regval[3] = CVAL(csc->m[CSC_BR], csc->m[CSC_BG]); 1430 regval[4] = CVAL(csc->m[CSC_BB], 0); 1431 1432 dispc_csc_offset_regval(csc, regval); 1433 } 1434 1435 #undef CVAL 1436 1437 static void dispc_k2g_vid_write_csc(struct dispc_device *dispc, u32 hw_plane, 1438 const struct dispc_csc_coef *csc) 1439 { 1440 static const u16 dispc_vid_csc_coef_reg[] = { 1441 DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1), 1442 DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3), 1443 DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5), 1444 DISPC_VID_CSC_COEF(6), /* K2G has no post offset support */ 1445 }; 1446 u32 regval[DISPC_CSC_REGVAL_LEN]; 1447 unsigned int i; 1448 1449 csc->to_regval(csc, regval); 1450 1451 if (regval[7] != 0) 1452 dev_warn(dispc->dev, "%s: No post offset support for %s\n", 1453 __func__, csc->name); 1454 1455 for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++) 1456 dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i], 1457 regval[i]); 1458 } 1459 1460 static void dispc_k3_vid_write_csc(struct dispc_device *dispc, u32 hw_plane, 1461 const struct dispc_csc_coef *csc) 1462 { 1463 static const u16 dispc_vid_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = { 1464 DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1), 1465 DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3), 1466 DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5), 1467 DISPC_VID_CSC_COEF(6), DISPC_VID_CSC_COEF7, 1468 }; 1469 u32 regval[DISPC_CSC_REGVAL_LEN]; 1470 unsigned int i; 1471 1472 csc->to_regval(csc, regval); 1473 1474 for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++) 1475 dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i], 1476 regval[i]); 1477 } 1478 1479 /* YUV -> RGB, ITU-R BT.601, full range */ 1480 static const struct dispc_csc_coef csc_yuv2rgb_bt601_full = { 1481 dispc_csc_yuv2rgb_regval, 1482 { 256, 0, 358, /* ry, rcb, rcr |1.000 0.000 1.402|*/ 1483 256, -88, -182, /* gy, gcb, gcr |1.000 -0.344 -0.714|*/ 1484 256, 452, 0, }, /* by, bcb, bcr |1.000 1.772 0.000|*/ 1485 { 0, -2048, -2048, }, /* full range */ 1486 { 0, 0, 0, }, 1487 CLIP_FULL_RANGE, 1488 "BT.601 Full", 1489 }; 1490 1491 /* YUV -> RGB, ITU-R BT.601, limited range */ 1492 static const struct dispc_csc_coef csc_yuv2rgb_bt601_lim = { 1493 dispc_csc_yuv2rgb_regval, 1494 { 298, 0, 409, /* ry, rcb, rcr |1.164 0.000 1.596|*/ 1495 298, -100, -208, /* gy, gcb, gcr |1.164 -0.392 -0.813|*/ 1496 298, 516, 0, }, /* by, bcb, bcr |1.164 2.017 0.000|*/ 1497 { -256, -2048, -2048, }, /* limited range */ 1498 { 0, 0, 0, }, 1499 CLIP_FULL_RANGE, 1500 "BT.601 Limited", 1501 }; 1502 1503 /* YUV -> RGB, ITU-R BT.709, full range */ 1504 static const struct dispc_csc_coef csc_yuv2rgb_bt709_full = { 1505 dispc_csc_yuv2rgb_regval, 1506 { 256, 0, 402, /* ry, rcb, rcr |1.000 0.000 1.570|*/ 1507 256, -48, -120, /* gy, gcb, gcr |1.000 -0.187 -0.467|*/ 1508 256, 475, 0, }, /* by, bcb, bcr |1.000 1.856 0.000|*/ 1509 { 0, -2048, -2048, }, /* full range */ 1510 { 0, 0, 0, }, 1511 CLIP_FULL_RANGE, 1512 "BT.709 Full", 1513 }; 1514 1515 /* YUV -> RGB, ITU-R BT.709, limited range */ 1516 static const struct dispc_csc_coef csc_yuv2rgb_bt709_lim = { 1517 dispc_csc_yuv2rgb_regval, 1518 { 298, 0, 459, /* ry, rcb, rcr |1.164 0.000 1.793|*/ 1519 298, -55, -136, /* gy, gcb, gcr |1.164 -0.213 -0.533|*/ 1520 298, 541, 0, }, /* by, bcb, bcr |1.164 2.112 0.000|*/ 1521 { -256, -2048, -2048, }, /* limited range */ 1522 { 0, 0, 0, }, 1523 CLIP_FULL_RANGE, 1524 "BT.709 Limited", 1525 }; 1526 1527 static const struct { 1528 enum drm_color_encoding encoding; 1529 enum drm_color_range range; 1530 const struct dispc_csc_coef *csc; 1531 } dispc_csc_table[] = { 1532 { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_FULL_RANGE, 1533 &csc_yuv2rgb_bt601_full, }, 1534 { DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_LIMITED_RANGE, 1535 &csc_yuv2rgb_bt601_lim, }, 1536 { DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_FULL_RANGE, 1537 &csc_yuv2rgb_bt709_full, }, 1538 { DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE, 1539 &csc_yuv2rgb_bt709_lim, }, 1540 }; 1541 1542 static const 1543 struct dispc_csc_coef *dispc_find_csc(enum drm_color_encoding encoding, 1544 enum drm_color_range range) 1545 { 1546 unsigned int i; 1547 1548 for (i = 0; i < ARRAY_SIZE(dispc_csc_table); i++) { 1549 if (dispc_csc_table[i].encoding == encoding && 1550 dispc_csc_table[i].range == range) { 1551 return dispc_csc_table[i].csc; 1552 } 1553 } 1554 return NULL; 1555 } 1556 1557 static void dispc_vid_csc_setup(struct dispc_device *dispc, u32 hw_plane, 1558 const struct drm_plane_state *state) 1559 { 1560 const struct dispc_csc_coef *coef; 1561 1562 coef = dispc_find_csc(state->color_encoding, state->color_range); 1563 if (!coef) { 1564 dev_err(dispc->dev, "%s: CSC (%u,%u) not found\n", 1565 __func__, state->color_encoding, state->color_range); 1566 return; 1567 } 1568 1569 if (dispc->feat->subrev == DISPC_K2G) 1570 dispc_k2g_vid_write_csc(dispc, hw_plane, coef); 1571 else 1572 dispc_k3_vid_write_csc(dispc, hw_plane, coef); 1573 } 1574 1575 static void dispc_vid_csc_enable(struct dispc_device *dispc, u32 hw_plane, 1576 bool enable) 1577 { 1578 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 9, 9); 1579 } 1580 1581 /* SCALER */ 1582 1583 static u32 dispc_calc_fir_inc(u32 in, u32 out) 1584 { 1585 return (u32)div_u64(0x200000ull * in, out); 1586 } 1587 1588 enum dispc_vid_fir_coef_set { 1589 DISPC_VID_FIR_COEF_HORIZ, 1590 DISPC_VID_FIR_COEF_HORIZ_UV, 1591 DISPC_VID_FIR_COEF_VERT, 1592 DISPC_VID_FIR_COEF_VERT_UV, 1593 }; 1594 1595 static void dispc_vid_write_fir_coefs(struct dispc_device *dispc, 1596 u32 hw_plane, 1597 enum dispc_vid_fir_coef_set coef_set, 1598 const struct tidss_scale_coefs *coefs) 1599 { 1600 static const u16 c0_regs[] = { 1601 [DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H0, 1602 [DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H0_C, 1603 [DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V0, 1604 [DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V0_C, 1605 }; 1606 1607 static const u16 c12_regs[] = { 1608 [DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H12, 1609 [DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H12_C, 1610 [DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V12, 1611 [DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V12_C, 1612 }; 1613 1614 const u16 c0_base = c0_regs[coef_set]; 1615 const u16 c12_base = c12_regs[coef_set]; 1616 int phase; 1617 1618 if (!coefs) { 1619 dev_err(dispc->dev, "%s: No coefficients given.\n", __func__); 1620 return; 1621 } 1622 1623 for (phase = 0; phase <= 8; ++phase) { 1624 u16 reg = c0_base + phase * 4; 1625 u16 c0 = coefs->c0[phase]; 1626 1627 dispc_vid_write(dispc, hw_plane, reg, c0); 1628 } 1629 1630 for (phase = 0; phase <= 15; ++phase) { 1631 u16 reg = c12_base + phase * 4; 1632 s16 c1, c2; 1633 u32 c12; 1634 1635 c1 = coefs->c1[phase]; 1636 c2 = coefs->c2[phase]; 1637 c12 = FLD_VAL(c1, 19, 10) | FLD_VAL(c2, 29, 20); 1638 1639 dispc_vid_write(dispc, hw_plane, reg, c12); 1640 } 1641 } 1642 1643 static bool dispc_fourcc_is_yuv(u32 fourcc) 1644 { 1645 switch (fourcc) { 1646 case DRM_FORMAT_YUYV: 1647 case DRM_FORMAT_UYVY: 1648 case DRM_FORMAT_NV12: 1649 return true; 1650 default: 1651 return false; 1652 } 1653 } 1654 1655 struct dispc_scaling_params { 1656 int xinc, yinc; 1657 u32 in_w, in_h, in_w_uv, in_h_uv; 1658 u32 fir_xinc, fir_yinc, fir_xinc_uv, fir_yinc_uv; 1659 bool scale_x, scale_y; 1660 const struct tidss_scale_coefs *xcoef, *ycoef, *xcoef_uv, *ycoef_uv; 1661 bool five_taps; 1662 }; 1663 1664 static int dispc_vid_calc_scaling(struct dispc_device *dispc, 1665 const struct drm_plane_state *state, 1666 struct dispc_scaling_params *sp, 1667 bool lite_plane) 1668 { 1669 const struct dispc_features_scaling *f = &dispc->feat->scaling; 1670 u32 fourcc = state->fb->format->format; 1671 u32 in_width_max_5tap = f->in_width_max_5tap_rgb; 1672 u32 in_width_max_3tap = f->in_width_max_3tap_rgb; 1673 u32 downscale_limit; 1674 u32 in_width_max; 1675 1676 memset(sp, 0, sizeof(*sp)); 1677 sp->xinc = 1; 1678 sp->yinc = 1; 1679 sp->in_w = state->src_w >> 16; 1680 sp->in_w_uv = sp->in_w; 1681 sp->in_h = state->src_h >> 16; 1682 sp->in_h_uv = sp->in_h; 1683 1684 sp->scale_x = sp->in_w != state->crtc_w; 1685 sp->scale_y = sp->in_h != state->crtc_h; 1686 1687 if (dispc_fourcc_is_yuv(fourcc)) { 1688 in_width_max_5tap = f->in_width_max_5tap_yuv; 1689 in_width_max_3tap = f->in_width_max_3tap_yuv; 1690 1691 sp->in_w_uv >>= 1; 1692 sp->scale_x = true; 1693 1694 if (fourcc == DRM_FORMAT_NV12) { 1695 sp->in_h_uv >>= 1; 1696 sp->scale_y = true; 1697 } 1698 } 1699 1700 /* Skip the rest if no scaling is used */ 1701 if ((!sp->scale_x && !sp->scale_y) || lite_plane) 1702 return 0; 1703 1704 if (sp->in_w > in_width_max_5tap) { 1705 sp->five_taps = false; 1706 in_width_max = in_width_max_3tap; 1707 downscale_limit = f->downscale_limit_3tap; 1708 } else { 1709 sp->five_taps = true; 1710 in_width_max = in_width_max_5tap; 1711 downscale_limit = f->downscale_limit_5tap; 1712 } 1713 1714 if (sp->scale_x) { 1715 sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w); 1716 1717 if (sp->fir_xinc < dispc_calc_fir_inc(1, f->upscale_limit)) { 1718 dev_dbg(dispc->dev, 1719 "%s: X-scaling factor %u/%u > %u\n", 1720 __func__, state->crtc_w, state->src_w >> 16, 1721 f->upscale_limit); 1722 return -EINVAL; 1723 } 1724 1725 if (sp->fir_xinc >= dispc_calc_fir_inc(downscale_limit, 1)) { 1726 sp->xinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_w, 1727 state->crtc_w), 1728 downscale_limit); 1729 1730 if (sp->xinc > f->xinc_max) { 1731 dev_dbg(dispc->dev, 1732 "%s: X-scaling factor %u/%u < 1/%u\n", 1733 __func__, state->crtc_w, 1734 state->src_w >> 16, 1735 downscale_limit * f->xinc_max); 1736 return -EINVAL; 1737 } 1738 1739 sp->in_w = (state->src_w >> 16) / sp->xinc; 1740 } 1741 1742 while (sp->in_w > in_width_max) { 1743 sp->xinc++; 1744 sp->in_w = (state->src_w >> 16) / sp->xinc; 1745 } 1746 1747 if (sp->xinc > f->xinc_max) { 1748 dev_dbg(dispc->dev, 1749 "%s: Too wide input buffer %u > %u\n", __func__, 1750 state->src_w >> 16, in_width_max * f->xinc_max); 1751 return -EINVAL; 1752 } 1753 1754 /* 1755 * We need even line length for YUV formats. Decimation 1756 * can lead to odd length, so we need to make it even 1757 * again. 1758 */ 1759 if (dispc_fourcc_is_yuv(fourcc)) 1760 sp->in_w &= ~1; 1761 1762 sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w); 1763 } 1764 1765 if (sp->scale_y) { 1766 sp->fir_yinc = dispc_calc_fir_inc(sp->in_h, state->crtc_h); 1767 1768 if (sp->fir_yinc < dispc_calc_fir_inc(1, f->upscale_limit)) { 1769 dev_dbg(dispc->dev, 1770 "%s: Y-scaling factor %u/%u > %u\n", 1771 __func__, state->crtc_h, state->src_h >> 16, 1772 f->upscale_limit); 1773 return -EINVAL; 1774 } 1775 1776 if (sp->fir_yinc >= dispc_calc_fir_inc(downscale_limit, 1)) { 1777 sp->yinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_h, 1778 state->crtc_h), 1779 downscale_limit); 1780 1781 sp->in_h /= sp->yinc; 1782 sp->fir_yinc = dispc_calc_fir_inc(sp->in_h, 1783 state->crtc_h); 1784 } 1785 } 1786 1787 dev_dbg(dispc->dev, 1788 "%s: %ux%u decim %ux%u -> %ux%u firinc %u.%03ux%u.%03u taps %u -> %ux%u\n", 1789 __func__, state->src_w >> 16, state->src_h >> 16, 1790 sp->xinc, sp->yinc, sp->in_w, sp->in_h, 1791 sp->fir_xinc / 0x200000u, 1792 ((sp->fir_xinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu, 1793 sp->fir_yinc / 0x200000u, 1794 ((sp->fir_yinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu, 1795 sp->five_taps ? 5 : 3, 1796 state->crtc_w, state->crtc_h); 1797 1798 if (dispc_fourcc_is_yuv(fourcc)) { 1799 if (sp->scale_x) { 1800 sp->in_w_uv /= sp->xinc; 1801 sp->fir_xinc_uv = dispc_calc_fir_inc(sp->in_w_uv, 1802 state->crtc_w); 1803 sp->xcoef_uv = tidss_get_scale_coefs(dispc->dev, 1804 sp->fir_xinc_uv, 1805 true); 1806 } 1807 if (sp->scale_y) { 1808 sp->in_h_uv /= sp->yinc; 1809 sp->fir_yinc_uv = dispc_calc_fir_inc(sp->in_h_uv, 1810 state->crtc_h); 1811 sp->ycoef_uv = tidss_get_scale_coefs(dispc->dev, 1812 sp->fir_yinc_uv, 1813 sp->five_taps); 1814 } 1815 } 1816 1817 if (sp->scale_x) 1818 sp->xcoef = tidss_get_scale_coefs(dispc->dev, sp->fir_xinc, 1819 true); 1820 1821 if (sp->scale_y) 1822 sp->ycoef = tidss_get_scale_coefs(dispc->dev, sp->fir_yinc, 1823 sp->five_taps); 1824 1825 return 0; 1826 } 1827 1828 static void dispc_vid_set_scaling(struct dispc_device *dispc, 1829 u32 hw_plane, 1830 struct dispc_scaling_params *sp, 1831 u32 fourcc) 1832 { 1833 /* HORIZONTAL RESIZE ENABLE */ 1834 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1835 sp->scale_x, 7, 7); 1836 1837 /* VERTICAL RESIZE ENABLE */ 1838 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1839 sp->scale_y, 8, 8); 1840 1841 /* Skip the rest if no scaling is used */ 1842 if (!sp->scale_x && !sp->scale_y) 1843 return; 1844 1845 /* VERTICAL 5-TAPS */ 1846 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1847 sp->five_taps, 21, 21); 1848 1849 if (dispc_fourcc_is_yuv(fourcc)) { 1850 if (sp->scale_x) { 1851 dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH2, 1852 sp->fir_xinc_uv); 1853 dispc_vid_write_fir_coefs(dispc, hw_plane, 1854 DISPC_VID_FIR_COEF_HORIZ_UV, 1855 sp->xcoef_uv); 1856 } 1857 if (sp->scale_y) { 1858 dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV2, 1859 sp->fir_yinc_uv); 1860 dispc_vid_write_fir_coefs(dispc, hw_plane, 1861 DISPC_VID_FIR_COEF_VERT_UV, 1862 sp->ycoef_uv); 1863 } 1864 } 1865 1866 if (sp->scale_x) { 1867 dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH, sp->fir_xinc); 1868 dispc_vid_write_fir_coefs(dispc, hw_plane, 1869 DISPC_VID_FIR_COEF_HORIZ, 1870 sp->xcoef); 1871 } 1872 1873 if (sp->scale_y) { 1874 dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV, sp->fir_yinc); 1875 dispc_vid_write_fir_coefs(dispc, hw_plane, 1876 DISPC_VID_FIR_COEF_VERT, sp->ycoef); 1877 } 1878 } 1879 1880 /* OTHER */ 1881 1882 static const struct { 1883 u32 fourcc; 1884 u8 dss_code; 1885 } dispc_color_formats[] = { 1886 { DRM_FORMAT_ARGB4444, 0x0, }, 1887 { DRM_FORMAT_ABGR4444, 0x1, }, 1888 { DRM_FORMAT_RGBA4444, 0x2, }, 1889 1890 { DRM_FORMAT_RGB565, 0x3, }, 1891 { DRM_FORMAT_BGR565, 0x4, }, 1892 1893 { DRM_FORMAT_ARGB1555, 0x5, }, 1894 { DRM_FORMAT_ABGR1555, 0x6, }, 1895 1896 { DRM_FORMAT_ARGB8888, 0x7, }, 1897 { DRM_FORMAT_ABGR8888, 0x8, }, 1898 { DRM_FORMAT_RGBA8888, 0x9, }, 1899 { DRM_FORMAT_BGRA8888, 0xa, }, 1900 1901 { DRM_FORMAT_RGB888, 0xb, }, 1902 { DRM_FORMAT_BGR888, 0xc, }, 1903 1904 { DRM_FORMAT_ARGB2101010, 0xe, }, 1905 { DRM_FORMAT_ABGR2101010, 0xf, }, 1906 1907 { DRM_FORMAT_XRGB4444, 0x20, }, 1908 { DRM_FORMAT_XBGR4444, 0x21, }, 1909 { DRM_FORMAT_RGBX4444, 0x22, }, 1910 1911 { DRM_FORMAT_XRGB1555, 0x25, }, 1912 { DRM_FORMAT_XBGR1555, 0x26, }, 1913 1914 { DRM_FORMAT_XRGB8888, 0x27, }, 1915 { DRM_FORMAT_XBGR8888, 0x28, }, 1916 { DRM_FORMAT_RGBX8888, 0x29, }, 1917 { DRM_FORMAT_BGRX8888, 0x2a, }, 1918 1919 { DRM_FORMAT_XRGB2101010, 0x2e, }, 1920 { DRM_FORMAT_XBGR2101010, 0x2f, }, 1921 1922 { DRM_FORMAT_YUYV, 0x3e, }, 1923 { DRM_FORMAT_UYVY, 0x3f, }, 1924 1925 { DRM_FORMAT_NV12, 0x3d, }, 1926 }; 1927 1928 static void dispc_plane_set_pixel_format(struct dispc_device *dispc, 1929 u32 hw_plane, u32 fourcc) 1930 { 1931 unsigned int i; 1932 1933 for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) { 1934 if (dispc_color_formats[i].fourcc == fourcc) { 1935 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1936 dispc_color_formats[i].dss_code, 1937 6, 1); 1938 return; 1939 } 1940 } 1941 1942 WARN_ON(1); 1943 } 1944 1945 const u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len) 1946 { 1947 WARN_ON(!dispc->fourccs); 1948 1949 *len = dispc->num_fourccs; 1950 1951 return dispc->fourccs; 1952 } 1953 1954 static s32 pixinc(int pixels, u8 ps) 1955 { 1956 if (pixels == 1) 1957 return 1; 1958 else if (pixels > 1) 1959 return 1 + (pixels - 1) * ps; 1960 else if (pixels < 0) 1961 return 1 - (-pixels + 1) * ps; 1962 1963 WARN_ON(1); 1964 return 0; 1965 } 1966 1967 int dispc_plane_check(struct dispc_device *dispc, u32 hw_plane, 1968 const struct drm_plane_state *state, 1969 u32 hw_videoport) 1970 { 1971 bool lite = dispc->feat->vid_lite[hw_plane]; 1972 u32 fourcc = state->fb->format->format; 1973 bool need_scaling = state->src_w >> 16 != state->crtc_w || 1974 state->src_h >> 16 != state->crtc_h; 1975 struct dispc_scaling_params scaling; 1976 int ret; 1977 1978 if (dispc_fourcc_is_yuv(fourcc)) { 1979 if (!dispc_find_csc(state->color_encoding, 1980 state->color_range)) { 1981 dev_dbg(dispc->dev, 1982 "%s: Unsupported CSC (%u,%u) for HW plane %u\n", 1983 __func__, state->color_encoding, 1984 state->color_range, hw_plane); 1985 return -EINVAL; 1986 } 1987 } 1988 1989 if (need_scaling) { 1990 if (lite) { 1991 dev_dbg(dispc->dev, 1992 "%s: Lite plane %u can't scale %ux%u!=%ux%u\n", 1993 __func__, hw_plane, 1994 state->src_w >> 16, state->src_h >> 16, 1995 state->crtc_w, state->crtc_h); 1996 return -EINVAL; 1997 } 1998 ret = dispc_vid_calc_scaling(dispc, state, &scaling, false); 1999 if (ret) 2000 return ret; 2001 } 2002 2003 return 0; 2004 } 2005 2006 static 2007 dma_addr_t dispc_plane_state_dma_addr(const struct drm_plane_state *state) 2008 { 2009 struct drm_framebuffer *fb = state->fb; 2010 struct drm_gem_dma_object *gem; 2011 u32 x = state->src_x >> 16; 2012 u32 y = state->src_y >> 16; 2013 2014 gem = drm_fb_dma_get_gem_obj(state->fb, 0); 2015 2016 return gem->dma_addr + fb->offsets[0] + x * fb->format->cpp[0] + 2017 y * fb->pitches[0]; 2018 } 2019 2020 static 2021 dma_addr_t dispc_plane_state_p_uv_addr(const struct drm_plane_state *state) 2022 { 2023 struct drm_framebuffer *fb = state->fb; 2024 struct drm_gem_dma_object *gem; 2025 u32 x = state->src_x >> 16; 2026 u32 y = state->src_y >> 16; 2027 2028 if (WARN_ON(state->fb->format->num_planes != 2)) 2029 return 0; 2030 2031 gem = drm_fb_dma_get_gem_obj(fb, 1); 2032 2033 return gem->dma_addr + fb->offsets[1] + 2034 (x * fb->format->cpp[1] / fb->format->hsub) + 2035 (y * fb->pitches[1] / fb->format->vsub); 2036 } 2037 2038 void dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane, 2039 const struct drm_plane_state *state, 2040 u32 hw_videoport) 2041 { 2042 bool lite = dispc->feat->vid_lite[hw_plane]; 2043 u32 fourcc = state->fb->format->format; 2044 u16 cpp = state->fb->format->cpp[0]; 2045 u32 fb_width = state->fb->pitches[0] / cpp; 2046 dma_addr_t dma_addr = dispc_plane_state_dma_addr(state); 2047 struct dispc_scaling_params scale; 2048 2049 dispc_vid_calc_scaling(dispc, state, &scale, lite); 2050 2051 dispc_plane_set_pixel_format(dispc, hw_plane, fourcc); 2052 2053 dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_0, dma_addr & 0xffffffff); 2054 dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_0, (u64)dma_addr >> 32); 2055 dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_1, dma_addr & 0xffffffff); 2056 dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_1, (u64)dma_addr >> 32); 2057 2058 dispc_vid_write(dispc, hw_plane, DISPC_VID_PICTURE_SIZE, 2059 (scale.in_w - 1) | ((scale.in_h - 1) << 16)); 2060 2061 /* For YUV422 format we use the macropixel size for pixel inc */ 2062 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) 2063 dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC, 2064 pixinc(scale.xinc, cpp * 2)); 2065 else 2066 dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC, 2067 pixinc(scale.xinc, cpp)); 2068 2069 dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC, 2070 pixinc(1 + (scale.yinc * fb_width - 2071 scale.xinc * scale.in_w), 2072 cpp)); 2073 2074 if (state->fb->format->num_planes == 2) { 2075 u16 cpp_uv = state->fb->format->cpp[1]; 2076 u32 fb_width_uv = state->fb->pitches[1] / cpp_uv; 2077 dma_addr_t p_uv_addr = dispc_plane_state_p_uv_addr(state); 2078 2079 dispc_vid_write(dispc, hw_plane, 2080 DISPC_VID_BA_UV_0, p_uv_addr & 0xffffffff); 2081 dispc_vid_write(dispc, hw_plane, 2082 DISPC_VID_BA_UV_EXT_0, (u64)p_uv_addr >> 32); 2083 dispc_vid_write(dispc, hw_plane, 2084 DISPC_VID_BA_UV_1, p_uv_addr & 0xffffffff); 2085 dispc_vid_write(dispc, hw_plane, 2086 DISPC_VID_BA_UV_EXT_1, (u64)p_uv_addr >> 32); 2087 2088 dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC_UV, 2089 pixinc(1 + (scale.yinc * fb_width_uv - 2090 scale.xinc * scale.in_w_uv), 2091 cpp_uv)); 2092 } 2093 2094 if (!lite) { 2095 dispc_vid_write(dispc, hw_plane, DISPC_VID_SIZE, 2096 (state->crtc_w - 1) | 2097 ((state->crtc_h - 1) << 16)); 2098 2099 dispc_vid_set_scaling(dispc, hw_plane, &scale, fourcc); 2100 } 2101 2102 /* enable YUV->RGB color conversion */ 2103 if (dispc_fourcc_is_yuv(fourcc)) { 2104 dispc_vid_csc_setup(dispc, hw_plane, state); 2105 dispc_vid_csc_enable(dispc, hw_plane, true); 2106 } else { 2107 dispc_vid_csc_enable(dispc, hw_plane, false); 2108 } 2109 2110 dispc_vid_write(dispc, hw_plane, DISPC_VID_GLOBAL_ALPHA, 2111 0xFF & (state->alpha >> 8)); 2112 2113 if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) 2114 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1, 2115 28, 28); 2116 else 2117 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0, 2118 28, 28); 2119 } 2120 2121 void dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable) 2122 { 2123 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 0, 0); 2124 } 2125 2126 static u32 dispc_vid_get_fifo_size(struct dispc_device *dispc, u32 hw_plane) 2127 { 2128 return VID_REG_GET(dispc, hw_plane, DISPC_VID_BUF_SIZE_STATUS, 15, 0); 2129 } 2130 2131 static void dispc_vid_set_mflag_threshold(struct dispc_device *dispc, 2132 u32 hw_plane, u32 low, u32 high) 2133 { 2134 dispc_vid_write(dispc, hw_plane, DISPC_VID_MFLAG_THRESHOLD, 2135 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 2136 } 2137 2138 static void dispc_vid_set_buf_threshold(struct dispc_device *dispc, 2139 u32 hw_plane, u32 low, u32 high) 2140 { 2141 dispc_vid_write(dispc, hw_plane, DISPC_VID_BUF_THRESHOLD, 2142 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 2143 } 2144 2145 static void dispc_k2g_plane_init(struct dispc_device *dispc) 2146 { 2147 unsigned int hw_plane; 2148 2149 dev_dbg(dispc->dev, "%s()\n", __func__); 2150 2151 /* MFLAG_CTRL = ENABLED */ 2152 REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0); 2153 /* MFLAG_START = MFLAGNORMALSTARTMODE */ 2154 REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6); 2155 2156 for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) { 2157 u32 size = dispc_vid_get_fifo_size(dispc, hw_plane); 2158 u32 thr_low, thr_high; 2159 u32 mflag_low, mflag_high; 2160 u32 preload; 2161 2162 thr_high = size - 1; 2163 thr_low = size / 2; 2164 2165 mflag_high = size * 2 / 3; 2166 mflag_low = size / 3; 2167 2168 preload = thr_low; 2169 2170 dev_dbg(dispc->dev, 2171 "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n", 2172 dispc->feat->vid_name[hw_plane], 2173 size, 2174 thr_high, thr_low, 2175 mflag_high, mflag_low, 2176 preload); 2177 2178 dispc_vid_set_buf_threshold(dispc, hw_plane, 2179 thr_low, thr_high); 2180 dispc_vid_set_mflag_threshold(dispc, hw_plane, 2181 mflag_low, mflag_high); 2182 2183 dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload); 2184 2185 /* 2186 * Prefetch up to fifo high-threshold value to minimize the 2187 * possibility of underflows. Note that this means the PRELOAD 2188 * register is ignored. 2189 */ 2190 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1, 2191 19, 19); 2192 } 2193 } 2194 2195 static void dispc_k3_plane_init(struct dispc_device *dispc) 2196 { 2197 unsigned int hw_plane; 2198 u32 cba_lo_pri = 1; 2199 u32 cba_hi_pri = 0; 2200 2201 dev_dbg(dispc->dev, "%s()\n", __func__); 2202 2203 REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_lo_pri, 2, 0); 2204 REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_hi_pri, 5, 3); 2205 2206 /* MFLAG_CTRL = ENABLED */ 2207 REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0); 2208 /* MFLAG_START = MFLAGNORMALSTARTMODE */ 2209 REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6); 2210 2211 for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) { 2212 u32 size = dispc_vid_get_fifo_size(dispc, hw_plane); 2213 u32 thr_low, thr_high; 2214 u32 mflag_low, mflag_high; 2215 u32 preload; 2216 2217 thr_high = size - 1; 2218 thr_low = size / 2; 2219 2220 mflag_high = size * 2 / 3; 2221 mflag_low = size / 3; 2222 2223 preload = thr_low; 2224 2225 dev_dbg(dispc->dev, 2226 "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n", 2227 dispc->feat->vid_name[hw_plane], 2228 size, 2229 thr_high, thr_low, 2230 mflag_high, mflag_low, 2231 preload); 2232 2233 dispc_vid_set_buf_threshold(dispc, hw_plane, 2234 thr_low, thr_high); 2235 dispc_vid_set_mflag_threshold(dispc, hw_plane, 2236 mflag_low, mflag_high); 2237 2238 dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload); 2239 2240 /* Prefech up to PRELOAD value */ 2241 VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0, 2242 19, 19); 2243 } 2244 } 2245 2246 static void dispc_plane_init(struct dispc_device *dispc) 2247 { 2248 switch (dispc->feat->subrev) { 2249 case DISPC_K2G: 2250 dispc_k2g_plane_init(dispc); 2251 break; 2252 case DISPC_AM625: 2253 case DISPC_AM65X: 2254 case DISPC_J721E: 2255 dispc_k3_plane_init(dispc); 2256 break; 2257 default: 2258 WARN_ON(1); 2259 } 2260 } 2261 2262 static void dispc_vp_init(struct dispc_device *dispc) 2263 { 2264 unsigned int i; 2265 2266 dev_dbg(dispc->dev, "%s()\n", __func__); 2267 2268 /* Enable the gamma Shadow bit-field for all VPs*/ 2269 for (i = 0; i < dispc->feat->num_vps; i++) 2270 VP_REG_FLD_MOD(dispc, i, DISPC_VP_CONFIG, 1, 2, 2); 2271 } 2272 2273 static void dispc_initial_config(struct dispc_device *dispc) 2274 { 2275 dispc_plane_init(dispc); 2276 dispc_vp_init(dispc); 2277 2278 /* Note: Hardcoded DPI routing on J721E for now */ 2279 if (dispc->feat->subrev == DISPC_J721E) { 2280 dispc_write(dispc, DISPC_CONNECTIONS, 2281 FLD_VAL(2, 3, 0) | /* VP1 to DPI0 */ 2282 FLD_VAL(8, 7, 4) /* VP3 to DPI1 */ 2283 ); 2284 } 2285 } 2286 2287 static void dispc_k2g_vp_write_gamma_table(struct dispc_device *dispc, 2288 u32 hw_videoport) 2289 { 2290 u32 *table = dispc->vp_data[hw_videoport].gamma_table; 2291 u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 2292 unsigned int i; 2293 2294 dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 2295 2296 if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT)) 2297 return; 2298 2299 for (i = 0; i < hwlen; ++i) { 2300 u32 v = table[i]; 2301 2302 v |= i << 24; 2303 2304 dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_GAMMA_TABLE, 2305 v); 2306 } 2307 } 2308 2309 static void dispc_am65x_vp_write_gamma_table(struct dispc_device *dispc, 2310 u32 hw_videoport) 2311 { 2312 u32 *table = dispc->vp_data[hw_videoport].gamma_table; 2313 u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 2314 unsigned int i; 2315 2316 dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 2317 2318 if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT)) 2319 return; 2320 2321 for (i = 0; i < hwlen; ++i) { 2322 u32 v = table[i]; 2323 2324 v |= i << 24; 2325 2326 dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v); 2327 } 2328 } 2329 2330 static void dispc_j721e_vp_write_gamma_table(struct dispc_device *dispc, 2331 u32 hw_videoport) 2332 { 2333 u32 *table = dispc->vp_data[hw_videoport].gamma_table; 2334 u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 2335 unsigned int i; 2336 2337 dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 2338 2339 if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_10BIT)) 2340 return; 2341 2342 for (i = 0; i < hwlen; ++i) { 2343 u32 v = table[i]; 2344 2345 if (i == 0) 2346 v |= 1 << 31; 2347 2348 dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v); 2349 } 2350 } 2351 2352 static void dispc_vp_write_gamma_table(struct dispc_device *dispc, 2353 u32 hw_videoport) 2354 { 2355 switch (dispc->feat->subrev) { 2356 case DISPC_K2G: 2357 dispc_k2g_vp_write_gamma_table(dispc, hw_videoport); 2358 break; 2359 case DISPC_AM625: 2360 case DISPC_AM65X: 2361 dispc_am65x_vp_write_gamma_table(dispc, hw_videoport); 2362 break; 2363 case DISPC_J721E: 2364 dispc_j721e_vp_write_gamma_table(dispc, hw_videoport); 2365 break; 2366 default: 2367 WARN_ON(1); 2368 break; 2369 } 2370 } 2371 2372 static const struct drm_color_lut dispc_vp_gamma_default_lut[] = { 2373 { .red = 0, .green = 0, .blue = 0, }, 2374 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, 2375 }; 2376 2377 static void dispc_vp_set_gamma(struct dispc_device *dispc, 2378 u32 hw_videoport, 2379 const struct drm_color_lut *lut, 2380 unsigned int length) 2381 { 2382 u32 *table = dispc->vp_data[hw_videoport].gamma_table; 2383 u32 hwlen = dispc->feat->vp_feat.color.gamma_size; 2384 u32 hwbits; 2385 unsigned int i; 2386 2387 dev_dbg(dispc->dev, "%s: hw_videoport %d, lut len %u, hw len %u\n", 2388 __func__, hw_videoport, length, hwlen); 2389 2390 if (dispc->feat->vp_feat.color.gamma_type == TIDSS_GAMMA_10BIT) 2391 hwbits = 10; 2392 else 2393 hwbits = 8; 2394 2395 if (!lut || length < 2) { 2396 lut = dispc_vp_gamma_default_lut; 2397 length = ARRAY_SIZE(dispc_vp_gamma_default_lut); 2398 } 2399 2400 for (i = 0; i < length - 1; ++i) { 2401 unsigned int first = i * (hwlen - 1) / (length - 1); 2402 unsigned int last = (i + 1) * (hwlen - 1) / (length - 1); 2403 unsigned int w = last - first; 2404 u16 r, g, b; 2405 unsigned int j; 2406 2407 if (w == 0) 2408 continue; 2409 2410 for (j = 0; j <= w; j++) { 2411 r = (lut[i].red * (w - j) + lut[i + 1].red * j) / w; 2412 g = (lut[i].green * (w - j) + lut[i + 1].green * j) / w; 2413 b = (lut[i].blue * (w - j) + lut[i + 1].blue * j) / w; 2414 2415 r >>= 16 - hwbits; 2416 g >>= 16 - hwbits; 2417 b >>= 16 - hwbits; 2418 2419 table[first + j] = (r << (hwbits * 2)) | 2420 (g << hwbits) | b; 2421 } 2422 } 2423 2424 dispc_vp_write_gamma_table(dispc, hw_videoport); 2425 } 2426 2427 static s16 dispc_S31_32_to_s2_8(s64 coef) 2428 { 2429 u64 sign_bit = 1ULL << 63; 2430 u64 cbits = (u64)coef; 2431 s16 ret; 2432 2433 if (cbits & sign_bit) 2434 ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x200); 2435 else 2436 ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x1FF); 2437 2438 return ret; 2439 } 2440 2441 static void dispc_k2g_cpr_from_ctm(const struct drm_color_ctm *ctm, 2442 struct dispc_csc_coef *cpr) 2443 { 2444 memset(cpr, 0, sizeof(*cpr)); 2445 2446 cpr->to_regval = dispc_csc_cpr_regval; 2447 cpr->m[CSC_RR] = dispc_S31_32_to_s2_8(ctm->matrix[0]); 2448 cpr->m[CSC_RG] = dispc_S31_32_to_s2_8(ctm->matrix[1]); 2449 cpr->m[CSC_RB] = dispc_S31_32_to_s2_8(ctm->matrix[2]); 2450 cpr->m[CSC_GR] = dispc_S31_32_to_s2_8(ctm->matrix[3]); 2451 cpr->m[CSC_GG] = dispc_S31_32_to_s2_8(ctm->matrix[4]); 2452 cpr->m[CSC_GB] = dispc_S31_32_to_s2_8(ctm->matrix[5]); 2453 cpr->m[CSC_BR] = dispc_S31_32_to_s2_8(ctm->matrix[6]); 2454 cpr->m[CSC_BG] = dispc_S31_32_to_s2_8(ctm->matrix[7]); 2455 cpr->m[CSC_BB] = dispc_S31_32_to_s2_8(ctm->matrix[8]); 2456 } 2457 2458 #define CVAL(xR, xG, xB) (FLD_VAL(xR, 9, 0) | FLD_VAL(xG, 20, 11) | \ 2459 FLD_VAL(xB, 31, 22)) 2460 2461 static void dispc_k2g_vp_csc_cpr_regval(const struct dispc_csc_coef *csc, 2462 u32 *regval) 2463 { 2464 regval[0] = CVAL(csc->m[CSC_BB], csc->m[CSC_BG], csc->m[CSC_BR]); 2465 regval[1] = CVAL(csc->m[CSC_GB], csc->m[CSC_GG], csc->m[CSC_GR]); 2466 regval[2] = CVAL(csc->m[CSC_RB], csc->m[CSC_RG], csc->m[CSC_RR]); 2467 } 2468 2469 #undef CVAL 2470 2471 static void dispc_k2g_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport, 2472 const struct dispc_csc_coef *csc) 2473 { 2474 static const u16 dispc_vp_cpr_coef_reg[] = { 2475 DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2, 2476 /* K2G CPR is packed to three registers. */ 2477 }; 2478 u32 regval[DISPC_CSC_REGVAL_LEN]; 2479 unsigned int i; 2480 2481 dispc_k2g_vp_csc_cpr_regval(csc, regval); 2482 2483 for (i = 0; i < ARRAY_SIZE(dispc_vp_cpr_coef_reg); i++) 2484 dispc_vp_write(dispc, hw_videoport, dispc_vp_cpr_coef_reg[i], 2485 regval[i]); 2486 } 2487 2488 static void dispc_k2g_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport, 2489 struct drm_color_ctm *ctm) 2490 { 2491 u32 cprenable = 0; 2492 2493 if (ctm) { 2494 struct dispc_csc_coef cpr; 2495 2496 dispc_k2g_cpr_from_ctm(ctm, &cpr); 2497 dispc_k2g_vp_write_csc(dispc, hw_videoport, &cpr); 2498 cprenable = 1; 2499 } 2500 2501 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG, 2502 cprenable, 15, 15); 2503 } 2504 2505 static s16 dispc_S31_32_to_s3_8(s64 coef) 2506 { 2507 u64 sign_bit = 1ULL << 63; 2508 u64 cbits = (u64)coef; 2509 s16 ret; 2510 2511 if (cbits & sign_bit) 2512 ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x400); 2513 else 2514 ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x3FF); 2515 2516 return ret; 2517 } 2518 2519 static void dispc_csc_from_ctm(const struct drm_color_ctm *ctm, 2520 struct dispc_csc_coef *cpr) 2521 { 2522 memset(cpr, 0, sizeof(*cpr)); 2523 2524 cpr->to_regval = dispc_csc_cpr_regval; 2525 cpr->m[CSC_RR] = dispc_S31_32_to_s3_8(ctm->matrix[0]); 2526 cpr->m[CSC_RG] = dispc_S31_32_to_s3_8(ctm->matrix[1]); 2527 cpr->m[CSC_RB] = dispc_S31_32_to_s3_8(ctm->matrix[2]); 2528 cpr->m[CSC_GR] = dispc_S31_32_to_s3_8(ctm->matrix[3]); 2529 cpr->m[CSC_GG] = dispc_S31_32_to_s3_8(ctm->matrix[4]); 2530 cpr->m[CSC_GB] = dispc_S31_32_to_s3_8(ctm->matrix[5]); 2531 cpr->m[CSC_BR] = dispc_S31_32_to_s3_8(ctm->matrix[6]); 2532 cpr->m[CSC_BG] = dispc_S31_32_to_s3_8(ctm->matrix[7]); 2533 cpr->m[CSC_BB] = dispc_S31_32_to_s3_8(ctm->matrix[8]); 2534 } 2535 2536 static void dispc_k3_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport, 2537 const struct dispc_csc_coef *csc) 2538 { 2539 static const u16 dispc_vp_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = { 2540 DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2, 2541 DISPC_VP_CSC_COEF3, DISPC_VP_CSC_COEF4, DISPC_VP_CSC_COEF5, 2542 DISPC_VP_CSC_COEF6, DISPC_VP_CSC_COEF7, 2543 }; 2544 u32 regval[DISPC_CSC_REGVAL_LEN]; 2545 unsigned int i; 2546 2547 csc->to_regval(csc, regval); 2548 2549 for (i = 0; i < ARRAY_SIZE(regval); i++) 2550 dispc_vp_write(dispc, hw_videoport, dispc_vp_csc_coef_reg[i], 2551 regval[i]); 2552 } 2553 2554 static void dispc_k3_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport, 2555 struct drm_color_ctm *ctm) 2556 { 2557 u32 colorconvenable = 0; 2558 2559 if (ctm) { 2560 struct dispc_csc_coef csc; 2561 2562 dispc_csc_from_ctm(ctm, &csc); 2563 dispc_k3_vp_write_csc(dispc, hw_videoport, &csc); 2564 colorconvenable = 1; 2565 } 2566 2567 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG, 2568 colorconvenable, 24, 24); 2569 } 2570 2571 static void dispc_vp_set_color_mgmt(struct dispc_device *dispc, 2572 u32 hw_videoport, 2573 const struct drm_crtc_state *state, 2574 bool newmodeset) 2575 { 2576 struct drm_color_lut *lut = NULL; 2577 struct drm_color_ctm *ctm = NULL; 2578 unsigned int length = 0; 2579 2580 if (!(state->color_mgmt_changed || newmodeset)) 2581 return; 2582 2583 if (state->gamma_lut) { 2584 lut = (struct drm_color_lut *)state->gamma_lut->data; 2585 length = state->gamma_lut->length / sizeof(*lut); 2586 } 2587 2588 dispc_vp_set_gamma(dispc, hw_videoport, lut, length); 2589 2590 if (state->ctm) 2591 ctm = (struct drm_color_ctm *)state->ctm->data; 2592 2593 if (dispc->feat->subrev == DISPC_K2G) 2594 dispc_k2g_vp_set_ctm(dispc, hw_videoport, ctm); 2595 else 2596 dispc_k3_vp_set_ctm(dispc, hw_videoport, ctm); 2597 } 2598 2599 void dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport, 2600 const struct drm_crtc_state *state, bool newmodeset) 2601 { 2602 dispc_vp_set_default_color(dispc, hw_videoport, 0); 2603 dispc_vp_set_color_mgmt(dispc, hw_videoport, state, newmodeset); 2604 } 2605 2606 int dispc_runtime_suspend(struct dispc_device *dispc) 2607 { 2608 dev_dbg(dispc->dev, "suspend\n"); 2609 2610 dispc->is_enabled = false; 2611 2612 clk_disable_unprepare(dispc->fclk); 2613 2614 return 0; 2615 } 2616 2617 int dispc_runtime_resume(struct dispc_device *dispc) 2618 { 2619 dev_dbg(dispc->dev, "resume\n"); 2620 2621 clk_prepare_enable(dispc->fclk); 2622 2623 if (REG_GET(dispc, DSS_SYSSTATUS, 0, 0) == 0) 2624 dev_warn(dispc->dev, "DSS FUNC RESET not done!\n"); 2625 2626 dev_dbg(dispc->dev, "OMAP DSS7 rev 0x%x\n", 2627 dispc_read(dispc, DSS_REVISION)); 2628 2629 dev_dbg(dispc->dev, "VP RESETDONE %d,%d,%d\n", 2630 REG_GET(dispc, DSS_SYSSTATUS, 1, 1), 2631 REG_GET(dispc, DSS_SYSSTATUS, 2, 2), 2632 REG_GET(dispc, DSS_SYSSTATUS, 3, 3)); 2633 2634 if (dispc->feat->subrev == DISPC_AM625 || 2635 dispc->feat->subrev == DISPC_AM65X) 2636 dev_dbg(dispc->dev, "OLDI RESETDONE %d,%d,%d\n", 2637 REG_GET(dispc, DSS_SYSSTATUS, 5, 5), 2638 REG_GET(dispc, DSS_SYSSTATUS, 6, 6), 2639 REG_GET(dispc, DSS_SYSSTATUS, 7, 7)); 2640 2641 dev_dbg(dispc->dev, "DISPC IDLE %d\n", 2642 REG_GET(dispc, DSS_SYSSTATUS, 9, 9)); 2643 2644 dispc_initial_config(dispc); 2645 2646 dispc->is_enabled = true; 2647 2648 tidss_irq_resume(dispc->tidss); 2649 2650 return 0; 2651 } 2652 2653 void dispc_remove(struct tidss_device *tidss) 2654 { 2655 dev_dbg(tidss->dev, "%s\n", __func__); 2656 2657 tidss->dispc = NULL; 2658 } 2659 2660 static int dispc_iomap_resource(struct platform_device *pdev, const char *name, 2661 void __iomem **base) 2662 { 2663 void __iomem *b; 2664 2665 b = devm_platform_ioremap_resource_byname(pdev, name); 2666 if (IS_ERR(b)) { 2667 dev_err(&pdev->dev, "cannot ioremap resource '%s'\n", name); 2668 return PTR_ERR(b); 2669 } 2670 2671 *base = b; 2672 2673 return 0; 2674 } 2675 2676 static int dispc_init_am65x_oldi_io_ctrl(struct device *dev, 2677 struct dispc_device *dispc) 2678 { 2679 dispc->oldi_io_ctrl = 2680 syscon_regmap_lookup_by_phandle(dev->of_node, 2681 "ti,am65x-oldi-io-ctrl"); 2682 if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) { 2683 dispc->oldi_io_ctrl = NULL; 2684 } else if (IS_ERR(dispc->oldi_io_ctrl)) { 2685 dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n", 2686 __func__, PTR_ERR(dispc->oldi_io_ctrl)); 2687 return PTR_ERR(dispc->oldi_io_ctrl); 2688 } 2689 return 0; 2690 } 2691 2692 static void dispc_init_errata(struct dispc_device *dispc) 2693 { 2694 static const struct soc_device_attribute am65x_sr10_soc_devices[] = { 2695 { .family = "AM65X", .revision = "SR1.0" }, 2696 { /* sentinel */ } 2697 }; 2698 2699 if (soc_device_match(am65x_sr10_soc_devices)) { 2700 dispc->errata.i2000 = true; 2701 dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n"); 2702 } 2703 } 2704 2705 static int dispc_softreset(struct dispc_device *dispc) 2706 { 2707 u32 val; 2708 int ret = 0; 2709 2710 /* K2G display controller does not support soft reset */ 2711 if (dispc->feat->subrev == DISPC_K2G) 2712 return 0; 2713 2714 /* Soft reset */ 2715 REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1); 2716 /* Wait for reset to complete */ 2717 ret = readl_poll_timeout(dispc->base_common + DSS_SYSSTATUS, 2718 val, val & 1, 100, 5000); 2719 if (ret) { 2720 dev_err(dispc->dev, "failed to reset dispc\n"); 2721 return ret; 2722 } 2723 2724 return 0; 2725 } 2726 2727 static int dispc_init_hw(struct dispc_device *dispc) 2728 { 2729 struct device *dev = dispc->dev; 2730 int ret; 2731 2732 ret = pm_runtime_set_active(dev); 2733 if (ret) { 2734 dev_err(dev, "Failed to set DSS PM to active\n"); 2735 return ret; 2736 } 2737 2738 ret = clk_prepare_enable(dispc->fclk); 2739 if (ret) { 2740 dev_err(dev, "Failed to enable DSS fclk\n"); 2741 goto err_runtime_suspend; 2742 } 2743 2744 ret = dispc_softreset(dispc); 2745 if (ret) 2746 goto err_clk_disable; 2747 2748 clk_disable_unprepare(dispc->fclk); 2749 ret = pm_runtime_set_suspended(dev); 2750 if (ret) { 2751 dev_err(dev, "Failed to set DSS PM to suspended\n"); 2752 return ret; 2753 } 2754 2755 return 0; 2756 2757 err_clk_disable: 2758 clk_disable_unprepare(dispc->fclk); 2759 2760 err_runtime_suspend: 2761 ret = pm_runtime_set_suspended(dev); 2762 if (ret) { 2763 dev_err(dev, "Failed to set DSS PM to suspended\n"); 2764 return ret; 2765 } 2766 2767 return ret; 2768 } 2769 2770 int dispc_init(struct tidss_device *tidss) 2771 { 2772 struct device *dev = tidss->dev; 2773 struct platform_device *pdev = to_platform_device(dev); 2774 struct dispc_device *dispc; 2775 const struct dispc_features *feat; 2776 unsigned int i, num_fourccs; 2777 int r = 0; 2778 2779 dev_dbg(dev, "%s\n", __func__); 2780 2781 feat = tidss->feat; 2782 2783 if (feat->subrev != DISPC_K2G) { 2784 r = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); 2785 if (r) 2786 dev_warn(dev, "cannot set DMA masks to 48-bit\n"); 2787 } 2788 2789 dma_set_max_seg_size(dev, UINT_MAX); 2790 2791 dispc = devm_kzalloc(dev, sizeof(*dispc), GFP_KERNEL); 2792 if (!dispc) 2793 return -ENOMEM; 2794 2795 dispc->tidss = tidss; 2796 dispc->dev = dev; 2797 dispc->feat = feat; 2798 2799 dispc_init_errata(dispc); 2800 2801 dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats), 2802 sizeof(*dispc->fourccs), GFP_KERNEL); 2803 if (!dispc->fourccs) 2804 return -ENOMEM; 2805 2806 num_fourccs = 0; 2807 for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) { 2808 if (dispc->errata.i2000 && 2809 dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc)) { 2810 continue; 2811 } 2812 dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc; 2813 } 2814 2815 dispc->num_fourccs = num_fourccs; 2816 2817 dispc_common_regmap = dispc->feat->common_regs; 2818 2819 r = dispc_iomap_resource(pdev, dispc->feat->common, 2820 &dispc->base_common); 2821 if (r) 2822 return r; 2823 2824 for (i = 0; i < dispc->feat->num_planes; i++) { 2825 r = dispc_iomap_resource(pdev, dispc->feat->vid_name[i], 2826 &dispc->base_vid[i]); 2827 if (r) 2828 return r; 2829 } 2830 2831 for (i = 0; i < dispc->feat->num_vps; i++) { 2832 u32 gamma_size = dispc->feat->vp_feat.color.gamma_size; 2833 u32 *gamma_table; 2834 struct clk *clk; 2835 2836 r = dispc_iomap_resource(pdev, dispc->feat->ovr_name[i], 2837 &dispc->base_ovr[i]); 2838 if (r) 2839 return r; 2840 2841 r = dispc_iomap_resource(pdev, dispc->feat->vp_name[i], 2842 &dispc->base_vp[i]); 2843 if (r) 2844 return r; 2845 2846 clk = devm_clk_get(dev, dispc->feat->vpclk_name[i]); 2847 if (IS_ERR(clk)) { 2848 dev_err(dev, "%s: Failed to get clk %s:%ld\n", __func__, 2849 dispc->feat->vpclk_name[i], PTR_ERR(clk)); 2850 return PTR_ERR(clk); 2851 } 2852 dispc->vp_clk[i] = clk; 2853 2854 gamma_table = devm_kmalloc_array(dev, gamma_size, 2855 sizeof(*gamma_table), 2856 GFP_KERNEL); 2857 if (!gamma_table) 2858 return -ENOMEM; 2859 dispc->vp_data[i].gamma_table = gamma_table; 2860 } 2861 2862 if (feat->subrev == DISPC_AM65X) { 2863 r = dispc_init_am65x_oldi_io_ctrl(dev, dispc); 2864 if (r) 2865 return r; 2866 } 2867 2868 dispc->fclk = devm_clk_get(dev, "fck"); 2869 if (IS_ERR(dispc->fclk)) { 2870 dev_err(dev, "%s: Failed to get fclk: %ld\n", 2871 __func__, PTR_ERR(dispc->fclk)); 2872 return PTR_ERR(dispc->fclk); 2873 } 2874 dev_dbg(dev, "DSS fclk %lu Hz\n", clk_get_rate(dispc->fclk)); 2875 2876 of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth", 2877 &dispc->memory_bandwidth_limit); 2878 2879 r = dispc_init_hw(dispc); 2880 if (r) 2881 return r; 2882 2883 tidss->dispc = dispc; 2884 2885 return 0; 2886 } 2887