1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2023 Texas Instruments Incorporated - https://www.ti.com/ 4 * Nikhil M Jain, n-jain1@ti.com 5 * 6 * based on the linux tidss driver, which is 7 * 8 * (C) Copyright 2018 Texas Instruments Incorporated - https://www.ti.com/ 9 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 10 */ 11 12#include <common.h> 13#include <dm.h> 14#include <clk.h> 15#include <log.h> 16#include <video.h> 17#include <errno.h> 18#include <panel.h> 19#include <reset.h> 20#include <malloc.h> 21#include <fdtdec.h> 22#include <syscon.h> 23#include <regmap.h> 24#include <cpu_func.h> 25#include <media_bus_format.h> 26 27#include <asm/io.h> 28#include <asm/cache.h> 29#include <asm/utils.h> 30#include <asm/bitops.h> 31 32#include <dm/devres.h> 33#include <dm/of_access.h> 34#include <dm/device_compat.h> 35#include <dm/device-internal.h> 36 37#include <linux/bug.h> 38#include <linux/err.h> 39#include <linux/delay.h> 40#include <linux/iopoll.h> 41 42#include "tidss_drv.h" 43#include "tidss_regs.h" 44 45DECLARE_GLOBAL_DATA_PTR; 46 47/* Panel parameters */ 48enum { 49 LCD_MAX_WIDTH = 1920, 50 LCD_MAX_HEIGHT = 1200, 51 LCD_MAX_LOG2_BPP = VIDEO_BPP32, 52}; 53 54static const u16 *dss_common_regmap; 55 56static const u16 tidss_am62x_common_regs[DSS_COMMON_REG_TABLE_LEN] = { 57 [DSS_REVISION_OFF] = 0x4, 58 [DSS_SYSCONFIG_OFF] = 0x8, 59 [DSS_SYSSTATUS_OFF] = 0x20, 60 [DSS_IRQ_EOI_OFF] = 0x24, 61 [DSS_IRQSTATUS_RAW_OFF] = 0x28, 62 [DSS_IRQSTATUS_OFF] = 0x2c, 63 [DSS_IRQENABLE_SET_OFF] = 0x30, 64 [DSS_IRQENABLE_CLR_OFF] = 0x40, 65 [DSS_VID_IRQENABLE_OFF] = 0x44, 66 [DSS_VID_IRQSTATUS_OFF] = 0x58, 67 [DSS_VP_IRQENABLE_OFF] = 0x70, 68 [DSS_VP_IRQSTATUS_OFF] = 0x7c, 69 70 [WB_IRQENABLE_OFF] = 0x88, 71 [WB_IRQSTATUS_OFF] = 0x8c, 72 73 [DSS_GLOBAL_MFLAG_ATTRIBUTE_OFF] = 0x90, 74 [DSS_GLOBAL_OUTPUT_ENABLE_OFF] = 0x94, 75 [DSS_GLOBAL_BUFFER_OFF] = 0x98, 76 [DSS_CBA_CFG_OFF] = 0x9c, 77 [DSS_DBG_CONTROL_OFF] = 0xa0, 78 [DSS_DBG_STATUS_OFF] = 0xa4, 79 [DSS_CLKGATING_DISABLE_OFF] = 0xa8, 80 [DSS_SECURE_DISABLE_OFF] = 0xac, 81}; 82 83/* TIDSS AM62x Features */ 84const struct dss_features dss_am625_feats = { 85 .max_pclk_khz = { 86 [DSS_VP_DPI] = 165000, 87 [DSS_VP_OLDI] = 165000, 88 }, 89 90 .subrev = DSS_AM625, 91 92 .common = "common", 93 .common_regs = tidss_am62x_common_regs, 94 95 .num_vps = 2, 96 .vp_name = { "vp1", "vp2" }, 97 .ovr_name = { "ovr1", "ovr2" }, 98 .vpclk_name = { "vp1", "vp2" }, 99 .vp_bus_type = { DSS_VP_OLDI, DSS_VP_DPI }, 100 101 .vp_feat = { .color = { 102 .has_ctm = true, 103 .gamma_size = 256, 104 .gamma_type = TIDSS_GAMMA_8BIT, 105 }, 106 }, 107 108 .num_planes = 2, 109 /* note: vid is plane_id 0 and vidl1 is plane_id 1 */ 110 .vid_name = { "vidl1", "vid" }, 111 .vid_lite = { true, false }, 112 .vid_order = { 1, 0 }, 113}; 114 115/* Wrapper functions to write and read TI_DSS registers */ 116static void dss_write(struct tidss_drv_priv *priv, u16 reg, u32 val) 117{ 118 writel(val, priv->base_common + reg); 119} 120 121static u32 dss_read(struct tidss_drv_priv *priv, u16 reg) 122{ 123 return readl(priv->base_common + reg); 124} 125 126static void dss_vid_write(struct tidss_drv_priv *priv, u32 hw_plane, u16 reg, u32 val) 127{ 128 void __iomem *base = priv->base_vid[hw_plane]; 129 130 writel(val, base + reg); 131} 132 133static u32 dss_vid_read(struct tidss_drv_priv *priv, u32 hw_plane, u16 reg) 134{ 135 void __iomem *base = priv->base_vid[hw_plane]; 136 137 return readl(base + reg); 138} 139 140static void dss_ovr_write(struct tidss_drv_priv *priv, u32 hw_videoport, 141 u16 reg, u32 val) 142{ 143 void __iomem *base = priv->base_ovr[hw_videoport]; 144 145 writel(val, base + reg); 146} 147 148static u32 dss_ovr_read(struct tidss_drv_priv *priv, u32 hw_videoport, u16 reg) 149{ 150 void __iomem *base = priv->base_ovr[hw_videoport]; 151 152 return readl(base + reg); 153} 154 155static void dss_vp_write(struct tidss_drv_priv *priv, u32 hw_videoport, 156 u16 reg, u32 val) 157{ 158 void __iomem *base = priv->base_vp[hw_videoport]; 159 160 writel(val, base + reg); 161} 162 163static u32 dss_vp_read(struct tidss_drv_priv *priv, u32 hw_videoport, u16 reg) 164{ 165 void __iomem *base = priv->base_vp[hw_videoport]; 166 167 return readl(base + reg); 168} 169 170/* generate mask on a register */ 171static u32 FLD_MASK(u32 start, u32 end) 172{ 173 return ((1 << (start - end + 1)) - 1) << end; 174} 175 176/* set the given val in specified range */ 177static u32 FLD_VAL(u32 val, u32 start, u32 end) 178{ 179 return (val << end) & FLD_MASK(start, end); 180} 181 182/* return the value in the specified range */ 183static u32 FLD_GET(u32 val, u32 start, u32 end) 184{ 185 return (val & FLD_MASK(start, end)) >> end; 186} 187 188/* modify the value of the specified range */ 189static u32 FLD_MOD(u32 orig, u32 val, u32 start, u32 end) 190{ 191 return (orig & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end); 192} 193 194/* read and modify common register region of DSS*/ 195__maybe_unused 196static u32 REG_GET(struct tidss_drv_priv *priv, u32 idx, u32 start, u32 end) 197{ 198 return FLD_GET(dss_read(priv, idx), start, end); 199} 200 201static void REG_FLD_MOD(struct tidss_drv_priv *priv, u32 idx, u32 val, 202 u32 start, u32 end) 203{ 204 dss_write(priv, idx, FLD_MOD(dss_read(priv, idx), val, 205 start, end)); 206} 207 208/* read and modify planes vid1 and vid2 register of DSS*/ 209static u32 VID_REG_GET(struct tidss_drv_priv *priv, u32 hw_plane, u32 idx, 210 u32 start, u32 end) 211{ 212 return FLD_GET(dss_vid_read(priv, hw_plane, idx), start, end); 213} 214 215static void VID_REG_FLD_MOD(struct tidss_drv_priv *priv, u32 hw_plane, u32 idx, 216 u32 val, u32 start, u32 end) 217{ 218 dss_vid_write(priv, hw_plane, idx, 219 FLD_MOD(dss_vid_read(priv, hw_plane, idx), 220 val, start, end)); 221} 222 223/* read and modify port vid1 and vid2 registers of DSS*/ 224__maybe_unused 225static u32 VP_REG_GET(struct tidss_drv_priv *priv, u32 vp, u32 idx, 226 u32 start, u32 end) 227{ 228 return FLD_GET(dss_vp_read(priv, vp, idx), start, end); 229} 230 231static void VP_REG_FLD_MOD(struct tidss_drv_priv *priv, u32 vp, u32 idx, u32 val, 232 u32 start, u32 end) 233{ 234 dss_vp_write(priv, vp, idx, FLD_MOD(dss_vp_read(priv, vp, idx), 235 val, start, end)); 236} 237 238/* read and modify overlay ovr1 and ovr2 registers of DSS*/ 239__maybe_unused 240static u32 OVR_REG_GET(struct tidss_drv_priv *priv, u32 ovr, u32 idx, 241 u32 start, u32 end) 242{ 243 return FLD_GET(dss_ovr_read(priv, ovr, idx), start, end); 244} 245 246static void OVR_REG_FLD_MOD(struct tidss_drv_priv *priv, u32 ovr, u32 idx, 247 u32 val, u32 start, u32 end) 248{ 249 dss_ovr_write(priv, ovr, idx, FLD_MOD(dss_ovr_read(priv, ovr, idx), 250 val, start, end)); 251} 252 253static void dss_oldi_tx_power(struct tidss_drv_priv *priv, bool power) 254{ 255 u32 val; 256 257 if (WARN_ON(!priv->oldi_io_ctrl)) 258 return; 259 260 if (priv->feat->subrev == DSS_AM625) { 261 if (power) { 262 switch (priv->oldi_mode) { 263 case OLDI_SINGLE_LINK_SINGLE_MODE: 264 /* Power down OLDI TX 1 */ 265 val = OLDI1_PWRDN_TX; 266 break; 267 case OLDI_DUAL_LINK: 268 /* No Power down */ 269 val = 0; 270 break; 271 default: 272 /* Power down both the OLDI TXes */ 273 val = OLDI_BANDGAP_PWR | OLDI0_PWRDN_TX | OLDI1_PWRDN_TX; 274 break; 275 } 276 } else { 277 val = OLDI_BANDGAP_PWR | OLDI0_PWRDN_TX | OLDI1_PWRDN_TX; 278 } 279 regmap_update_bits(priv->oldi_io_ctrl, OLDI_PD_CTRL, 280 OLDI_BANDGAP_PWR | OLDI0_PWRDN_TX | OLDI1_PWRDN_TX, val); 281 } 282} 283 284static void dss_set_num_datalines(struct tidss_drv_priv *priv, 285 u32 hw_videoport) 286{ 287 int v; 288 u32 num_lines = priv->bus_format->data_width; 289 290 switch (num_lines) { 291 case 12: 292 v = 0; break; 293 case 16: 294 v = 1; break; 295 case 18: 296 v = 2; break; 297 case 24: 298 v = 3; break; 299 case 30: 300 v = 4; break; 301 case 36: 302 v = 5; break; 303 default: 304 WARN_ON(1); 305 v = 3; 306 } 307 308 VP_REG_FLD_MOD(priv, hw_videoport, DSS_VP_CONTROL, v, 10, 8); 309} 310 311static void dss_enable_oldi(struct tidss_drv_priv *priv, u32 hw_videoport) 312{ 313 u32 oldi_cfg = 0; 314 u32 oldi_reset_bit = BIT(5 + hw_videoport); 315 int count = 0; 316 317 /* 318 * For the moment MASTERSLAVE, and SRC bits of DSS_VP_DSS_OLDI_CFG are 319 * set statically to 0. 320 */ 321 322 if (priv->bus_format->data_width == 24) 323 oldi_cfg |= BIT(8); /* MSB */ 324 else if (priv->bus_format->data_width != 18) 325 dev_warn(priv->dev, "%s: %d port width not supported\n", 326 __func__, priv->bus_format->data_width); 327 328 oldi_cfg |= BIT(7); /* DEPOL */ 329 330 oldi_cfg = FLD_MOD(oldi_cfg, priv->bus_format->oldi_mode_reg_val, 3, 1); 331 332 oldi_cfg |= BIT(12); /* SOFTRST */ 333 334 oldi_cfg |= BIT(0); /* ENABLE */ 335 336 switch (priv->oldi_mode) { 337 case OLDI_MODE_OFF: 338 oldi_cfg &= ~BIT(0); /* DISABLE */ 339 break; 340 341 case OLDI_SINGLE_LINK_SINGLE_MODE: 342 /* All configuration is done for this mode. */ 343 break; 344 345 case OLDI_SINGLE_LINK_DUPLICATE_MODE: 346 oldi_cfg |= BIT(5); /* DUPLICATE MODE */ 347 break; 348 349 case OLDI_DUAL_LINK: 350 oldi_cfg |= BIT(11); /* DUALMODESYNC */ 351 oldi_cfg |= BIT(3); /* data-mapping field also indicates dual-link mode */ 352 break; 353 354 default: 355 dev_warn(priv->dev, "%s: Incorrect oldi mode. Returning.\n", 356 __func__); 357 return; 358 } 359 360 dss_vp_write(priv, hw_videoport, DSS_VP_DSS_OLDI_CFG, oldi_cfg); 361 362 while (!(oldi_reset_bit & dss_read(priv, DSS_SYSSTATUS)) && 363 count < 10000) 364 count++; 365 366 if (!(oldi_reset_bit & dss_read(priv, DSS_SYSSTATUS))) 367 dev_warn(priv->dev, "%s: timeout waiting OLDI reset done\n", 368 __func__); 369} 370 371static const struct dss_color_lut dss_vp_gamma_default_lut[] = { 372 { .red = 0, .green = 0, .blue = 0, }, 373 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, 374}; 375 376static void dss_vp_write_gamma_table(struct tidss_drv_priv *priv, 377 u32 hw_videoport) 378{ 379 u32 *table = priv->vp_data[hw_videoport].gamma_table; 380 u32 hwlen = priv->feat->vp_feat.color.gamma_size; 381 unsigned int i; 382 383 dev_dbg(priv->dev, "%s: hw_videoport %d\n", __func__, hw_videoport); 384 385 for (i = 0; i < hwlen; ++i) { 386 u32 v = table[i]; 387 388 v |= i << 24; 389 390 dss_vp_write(priv, hw_videoport, DSS_VP_GAMMA_TABLE, v); 391 } 392} 393 394static void dss_vp_set_gamma(struct tidss_drv_priv *priv, 395 u32 hw_videoport, const struct dss_color_lut *lut, 396 unsigned int length) 397{ 398 u32 *table = priv->vp_data[hw_videoport].gamma_table; 399 u32 hwlen = priv->feat->vp_feat.color.gamma_size; 400 u32 hwbits; 401 unsigned int i; 402 403 dev_dbg(priv->dev, "%s: hw_videoport %d, lut len %u, hw len %u\n", 404 __func__, hw_videoport, length, hwlen); 405 406 if (priv->feat->vp_feat.color.gamma_type == TIDSS_GAMMA_10BIT) 407 hwbits = 10; 408 else 409 hwbits = 8; 410 411 lut = dss_vp_gamma_default_lut; 412 length = ARRAY_SIZE(dss_vp_gamma_default_lut); 413 414 for (i = 0; i < length - 1; ++i) { 415 unsigned int first = i * (hwlen - 1) / (length - 1); 416 unsigned int last = (i + 1) * (hwlen - 1) / (length - 1); 417 unsigned int w = last - first; 418 u16 r, g, b; 419 unsigned int j; 420 421 if (w == 0) 422 continue; 423 424 for (j = 0; j <= w; j++) { 425 r = (lut[i].red * (w - j) + lut[i + 1].red * j) / w; 426 g = (lut[i].green * (w - j) + lut[i + 1].green * j) / w; 427 b = (lut[i].blue * (w - j) + lut[i + 1].blue * j) / w; 428 429 r >>= 16 - hwbits; 430 g >>= 16 - hwbits; 431 b >>= 16 - hwbits; 432 433 table[first + j] = (r << (hwbits * 2)) | 434 (g << hwbits) | b; 435 } 436 } 437 438 dss_vp_write_gamma_table(priv, hw_videoport); 439} 440 441void dss_vp_enable(struct tidss_drv_priv *priv, u32 hw_videoport, struct display_timing *timing) 442{ 443 bool align, onoff, rf, ieo, ipc, ihs, ivs; 444 u32 hsw, hfp, hbp, vsw, vfp, vbp; 445 446 dss_set_num_datalines(priv, hw_videoport); 447 448 /* panel parameters to set clocks for video port*/ 449 hfp = timing->hfront_porch.typ; 450 hsw = timing->hsync_len.typ; 451 hbp = timing->hback_porch.typ; 452 vfp = timing->vfront_porch.typ; 453 vsw = timing->vsync_len.typ; 454 vbp = timing->vback_porch.typ; 455 456 dss_vp_write(priv, hw_videoport, DSS_VP_TIMING_H, 457 FLD_VAL(hsw - 1, 7, 0) | 458 FLD_VAL(hfp - 1, 19, 8) | FLD_VAL(hbp - 1, 31, 20)); 459 460 dss_vp_write(priv, hw_videoport, DSS_VP_TIMING_V, 461 FLD_VAL(vsw - 1, 7, 0) | 462 FLD_VAL(vfp, 19, 8) | FLD_VAL(vbp, 31, 20)); 463 464 ivs = !!(timing->flags & (1 << 3)); 465 466 ihs = !!(timing->flags & (1 << 1)); 467 468 ieo = 0; 469 470 ipc = 0; 471 472 /* always use the 'rf' setting */ 473 onoff = true; 474 475 rf = true; 476 477 /* always use aligned syncs */ 478 align = true; 479 480 /* always use DE_HIGH for OLDI */ 481 if (priv->feat->vp_bus_type[hw_videoport] == DSS_VP_OLDI) 482 ieo = false; 483 484 dss_vp_write(priv, hw_videoport, DSS_VP_POL_FREQ, 485 FLD_VAL(align, 18, 18) | 486 FLD_VAL(onoff, 17, 17) | 487 FLD_VAL(rf, 16, 16) | 488 FLD_VAL(ieo, 15, 15) | 489 FLD_VAL(ipc, 14, 14) | 490 FLD_VAL(ihs, 13, 13) | 491 FLD_VAL(ivs, 12, 12)); 492 493 dss_vp_write(priv, hw_videoport, DSS_VP_SIZE_SCREEN, 494 FLD_VAL(timing->hactive.typ - 1, 11, 0) | 495 FLD_VAL(timing->vactive.typ - 1, 27, 16)); 496 497 VP_REG_FLD_MOD(priv, hw_videoport, DSS_VP_CONTROL, 1, 0, 0); 498} 499 500enum c8_to_c12_mode { C8_TO_C12_REPLICATE, C8_TO_C12_MAX, C8_TO_C12_MIN }; 501 502static u16 c8_to_c12(u8 c8, enum c8_to_c12_mode mode) 503{ 504 u16 c12; 505 506 c12 = c8 << 4; 507 508 switch (mode) { 509 case C8_TO_C12_REPLICATE: 510 /* Copy c8 4 MSB to 4 LSB for full scale c12 */ 511 c12 |= c8 >> 4; 512 break; 513 case C8_TO_C12_MAX: 514 c12 |= 0xF; 515 break; 516 default: 517 case C8_TO_C12_MIN: 518 break; 519 } 520 521 return c12; 522} 523 524static u64 argb8888_to_argb12121212(u32 argb8888, enum c8_to_c12_mode m) 525{ 526 u8 a, r, g, b; 527 u64 v; 528 529 a = (argb8888 >> 24) & 0xff; 530 r = (argb8888 >> 16) & 0xff; 531 g = (argb8888 >> 8) & 0xff; 532 b = (argb8888 >> 0) & 0xff; 533 534 v = ((u64)c8_to_c12(a, m) << 36) | ((u64)c8_to_c12(r, m) << 24) | 535 ((u64)c8_to_c12(g, m) << 12) | (u64)c8_to_c12(b, m); 536 537 return v; 538} 539 540static void dss_vp_set_default_color(struct tidss_drv_priv *priv, 541 u32 hw_videoport, u32 default_color) 542{ 543 u64 v; 544 545 v = argb8888_to_argb12121212(default_color, C8_TO_C12_REPLICATE); 546 dss_ovr_write(priv, hw_videoport, 547 DSS_OVR_DEFAULT_COLOR, v & 0xffffffff); 548 dss_ovr_write(priv, hw_videoport, 549 DSS_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff); 550} 551 552int dss_vp_enable_clk(struct tidss_drv_priv *priv, u32 hw_videoport) 553{ 554 int ret = clk_prepare_enable(&priv->vp_clk[hw_videoport]); 555 556 if (ret) 557 dev_dbg(priv->dev, "%s: enabling clk failed: %d\n", __func__, 558 ret); 559 560 return ret; 561} 562 563void dss_vp_prepare(struct tidss_drv_priv *priv, u32 hw_videoport) 564{ 565 dss_vp_set_gamma(priv, hw_videoport, NULL, 0); 566 dss_vp_set_default_color(priv, 0, 0); 567 568 if (priv->feat->vp_bus_type[hw_videoport] == DSS_VP_OLDI) { 569 dss_oldi_tx_power(priv, true); 570 dss_enable_oldi(priv, hw_videoport); 571 } 572} 573 574static 575unsigned int dss_pclk_diff(unsigned long rate, unsigned long real_rate) 576{ 577 int r = rate / 100, rr = real_rate / 100; 578 579 return (unsigned int)(abs(((rr - r) * 100) / r)); 580} 581 582int dss_vp_set_clk_rate(struct tidss_drv_priv *priv, u32 hw_videoport, 583 unsigned long rate) 584{ 585 int r; 586 unsigned long new_rate; 587 588 /* 589 * For AM625 OLDI video ports, the requested pixel clock needs to take into account the 590 * serial clock required for the serialization of DPI signals into LVDS signals. The 591 * incoming pixel clock on the OLDI video port gets divided by 7 whenever OLDI enable bit 592 * gets set. 593 */ 594 if (priv->feat->vp_bus_type[hw_videoport] == DSS_VP_OLDI && 595 priv->feat->subrev == DSS_AM625) 596 rate *= 7; 597 598 r = clk_set_rate(&priv->vp_clk[hw_videoport], rate); 599 600 new_rate = clk_get_rate(&priv->vp_clk[hw_videoport]); 601 602 if (dss_pclk_diff(rate, new_rate) > 5) 603 dev_warn(priv->dev, 604 "vp%d: Clock rate %lu differs over 5%% from requested %lu\n", 605 hw_videoport, new_rate, rate); 606 607 dev_dbg(priv->dev, "vp%d: new rate %lu Hz (requested %lu Hz)\n", 608 hw_videoport, clk_get_rate(&priv->vp_clk[hw_videoport]), rate); 609 return 0; 610} 611 612static void dss_ovr_set_plane(struct tidss_drv_priv *priv, 613 u32 hw_plane, u32 hw_ovr, 614 u32 x, u32 y, u32 layer) 615{ 616 OVR_REG_FLD_MOD(priv, hw_ovr, DSS_OVR_ATTRIBUTES(layer), 617 0x1, 4, 1); 618 OVR_REG_FLD_MOD(priv, hw_ovr, DSS_OVR_ATTRIBUTES(layer), 619 x, 17, 6); 620 OVR_REG_FLD_MOD(priv, hw_ovr, DSS_OVR_ATTRIBUTES(layer), 621 y, 30, 19); 622} 623 624void dss_ovr_enable_layer(struct tidss_drv_priv *priv, 625 u32 hw_ovr, u32 layer, bool enable) 626{ 627 OVR_REG_FLD_MOD(priv, hw_ovr, DSS_OVR_ATTRIBUTES(layer), 628 !!enable, 0, 0); 629} 630 631static void dss_vid_csc_enable(struct tidss_drv_priv *priv, u32 hw_plane, 632 bool enable) 633{ 634 VID_REG_FLD_MOD(priv, hw_plane, DSS_VID_ATTRIBUTES, !!enable, 9, 9); 635} 636 637int dss_plane_setup(struct tidss_drv_priv *priv, u32 hw_plane, u32 hw_videoport) 638{ 639 VID_REG_FLD_MOD(priv, hw_plane, DSS_VID_ATTRIBUTES, 640 priv->pixel_format, 6, 1); 641 642 dss_vid_write(priv, hw_plane, DSS_VID_PICTURE_SIZE, 643 ((LCD_MAX_WIDTH - 1) | ((LCD_MAX_HEIGHT - 1) << 16))); 644 645 dss_vid_csc_enable(priv, hw_plane, false); 646 647 dss_vid_write(priv, hw_plane, DSS_VID_GLOBAL_ALPHA, 0xFF); 648 649 VID_REG_FLD_MOD(priv, hw_plane, DSS_VID_ATTRIBUTES, 1, 28, 28); 650 return 0; 651} 652 653int dss_plane_enable(struct tidss_drv_priv *priv, u32 hw_plane, bool enable) 654{ 655 VID_REG_FLD_MOD(priv, hw_plane, DSS_VID_ATTRIBUTES, !!enable, 0, 0); 656 657 return 0; 658} 659 660static u32 dss_vid_get_fifo_size(struct tidss_drv_priv *priv, u32 hw_plane) 661{ 662 return VID_REG_GET(priv, hw_plane, DSS_VID_BUF_SIZE_STATUS, 15, 0); 663} 664 665static void dss_vid_set_mflag_threshold(struct tidss_drv_priv *priv, 666 u32 hw_plane, u32 low, u32 high) 667{ 668 dss_vid_write(priv, hw_plane, DSS_VID_MFLAG_THRESHOLD, 669 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 670} 671 672static 673void dss_vid_set_buf_threshold(struct tidss_drv_priv *priv, 674 u32 hw_plane, u32 low, u32 high) 675{ 676 dss_vid_write(priv, hw_plane, DSS_VID_BUF_THRESHOLD, 677 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 678} 679 680static void dss_plane_init(struct tidss_drv_priv *priv) 681{ 682 unsigned int hw_plane; 683 u32 cba_lo_pri = 1; 684 u32 cba_hi_pri = 0; 685 686 REG_FLD_MOD(priv, DSS_CBA_CFG, cba_lo_pri, 2, 0); 687 REG_FLD_MOD(priv, DSS_CBA_CFG, cba_hi_pri, 5, 3); 688 689 /* MFLAG_CTRL = ENABLED */ 690 REG_FLD_MOD(priv, DSS_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0); 691 /* MFLAG_START = MFLAGNORMALSTARTMODE */ 692 REG_FLD_MOD(priv, DSS_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6); 693 694 for (hw_plane = 0; hw_plane < priv->feat->num_planes; hw_plane++) { 695 u32 size = dss_vid_get_fifo_size(priv, hw_plane); 696 u32 thr_low, thr_high; 697 u32 mflag_low, mflag_high; 698 u32 preload; 699 700 thr_high = size - 1; 701 thr_low = size / 2; 702 703 mflag_high = size * 2 / 3; 704 mflag_low = size / 3; 705 706 preload = thr_low; 707 708 dev_dbg(priv->dev, 709 "%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n", 710 priv->feat->vid_name[hw_plane], 711 size, 712 thr_high, thr_low, 713 mflag_high, mflag_low, 714 preload); 715 716 dss_vid_set_buf_threshold(priv, hw_plane, 717 thr_low, thr_high); 718 dss_vid_set_mflag_threshold(priv, hw_plane, 719 mflag_low, mflag_high); 720 721 dss_vid_write(priv, hw_plane, DSS_VID_PRELOAD, preload); 722 723 /* Prefech up to PRELOAD value */ 724 VID_REG_FLD_MOD(priv, hw_plane, DSS_VID_ATTRIBUTES, 0, 725 19, 19); 726 } 727} 728 729static void dss_vp_init(struct tidss_drv_priv *priv) 730{ 731 unsigned int i; 732 733 /* Enable the gamma Shadow bit-field for all VPs*/ 734 for (i = 0; i < priv->feat->num_vps; i++) 735 VP_REG_FLD_MOD(priv, i, DSS_VP_CONFIG, 1, 2, 2); 736} 737 738static int dss_init_am65x_oldi_io_ctrl(struct udevice *dev, 739 struct tidss_drv_priv *priv) 740{ 741 struct udevice *syscon; 742 struct regmap *regmap; 743 int ret = 0; 744 745 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "ti,am65x-oldi-io-ctrl", 746 &syscon); 747 if (ret) { 748 debug("unable to find ti,am65x-oldi-io-ctrl syscon device (%d)\n", ret); 749 return ret; 750 } 751 752 /* get grf-reg base address */ 753 regmap = syscon_get_regmap(syscon); 754 if (!regmap) { 755 debug("unable to find rockchip grf regmap\n"); 756 return -ENODEV; 757 } 758 priv->oldi_io_ctrl = regmap; 759 return 0; 760} 761 762static int tidss_drv_probe(struct udevice *dev) 763{ 764 struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev); 765 struct video_priv *uc_priv = dev_get_uclass_priv(dev); 766 struct tidss_drv_priv *priv = dev_get_priv(dev); 767 struct udevice *panel = NULL; 768 struct display_timing timings; 769 unsigned int i; 770 int ret = 0; 771 const char *mode; 772 773 priv->dev = dev; 774 775 priv->feat = &dss_am625_feats; 776 777 /* 778 * set your plane format based on your bmp image 779 * Supported 24bpp and 32bpp bmpimages 780 */ 781 782 priv->pixel_format = DSS_FORMAT_XRGB8888; 783 784 dss_common_regmap = priv->feat->common_regs; 785 786 ret = uclass_first_device_err(UCLASS_PANEL, &panel); 787 if (ret) { 788 if (ret != -ENODEV) 789 dev_err(dev, "panel device error %d\n", ret); 790 return ret; 791 } 792 793 ret = panel_get_display_timing(panel, &timings); 794 if (ret) { 795 ret = ofnode_decode_panel_timing(dev_ofnode(panel), 796 &timings); 797 if (ret) { 798 dev_err(dev, "decode display timing error %d\n", ret); 799 return ret; 800 } 801 } 802 803 mode = ofnode_read_string(dev_ofnode(panel), "data-mapping"); 804 if (!mode) { 805 debug("%s: Could not read mode property\n", dev->name); 806 return -EINVAL; 807 } 808 809 uc_priv->bpix = VIDEO_BPP32; 810 811 if (!strcmp(mode, "vesa-24")) 812 priv->bus_format = &dss_bus_formats[7]; 813 else 814 priv->bus_format = &dss_bus_formats[8]; 815 816 /* Common address */ 817 priv->base_common = dev_remap_addr_name(dev, priv->feat->common); 818 if (!priv->base_common) 819 return -EINVAL; 820 821 /* plane address setup and enable */ 822 for (i = 0; i < priv->feat->num_planes; i++) { 823 priv->base_vid[i] = dev_remap_addr_name(dev, priv->feat->vid_name[i]); 824 if (!priv->base_vid[i]) 825 return -EINVAL; 826 } 827 828 dss_vid_write(priv, 0, DSS_VID_BA_0, uc_plat->base & 0xffffffff); 829 dss_vid_write(priv, 0, DSS_VID_BA_EXT_0, (u64)uc_plat->base >> 32); 830 dss_vid_write(priv, 0, DSS_VID_BA_1, uc_plat->base & 0xffffffff); 831 dss_vid_write(priv, 0, DSS_VID_BA_EXT_1, (u64)uc_plat->base >> 32); 832 833 ret = dss_plane_setup(priv, 0, 0); 834 if (ret) { 835 dss_plane_enable(priv, 0, false); 836 return ret; 837 } 838 839 dss_plane_enable(priv, 0, true); 840 dss_plane_init(priv); 841 842 /* video port address clocks and enable */ 843 for (i = 0; i < priv->feat->num_vps; i++) { 844 priv->base_ovr[i] = dev_remap_addr_name(dev, priv->feat->ovr_name[i]); 845 priv->base_vp[i] = dev_remap_addr_name(dev, priv->feat->vp_name[i]); 846 } 847 848 ret = clk_get_by_name(dev, "vp1", &priv->vp_clk[0]); 849 if (ret) { 850 dev_err(dev, "video port %d clock enable error %d\n", i, ret); 851 return ret; 852 } 853 854 dss_ovr_set_plane(priv, 1, 0, 0, 0, 0); 855 dss_ovr_enable_layer(priv, 0, 0, true); 856 857 /* Video Port cloks */ 858 dss_vp_enable_clk(priv, 0); 859 860 dss_vp_set_clk_rate(priv, 0, timings.pixelclock.typ * 1000); 861 862 priv->oldi_mode = OLDI_MODE_OFF; 863 uc_priv->xsize = timings.hactive.typ; 864 uc_priv->ysize = timings.vactive.typ; 865 if (priv->feat->subrev == DSS_AM65X || priv->feat->subrev == DSS_AM625) { 866 priv->oldi_mode = OLDI_DUAL_LINK; 867 if (priv->oldi_mode) { 868 ret = dss_init_am65x_oldi_io_ctrl(dev, priv); 869 if (ret) 870 return ret; 871 } 872 } 873 874 dss_vp_prepare(priv, 0); 875 dss_vp_enable(priv, 0, &timings); 876 dss_vp_init(priv); 877 878 ret = clk_get_by_name(dev, "fck", &priv->fclk); 879 if (ret) { 880 dev_err(dev, "peripheral clock get error %d\n", ret); 881 return ret; 882 } 883 884 ret = clk_enable(&priv->fclk); 885 if (ret) { 886 dev_err(dev, "peripheral clock enable error %d\n", ret); 887 return ret; 888 } 889 890 if (IS_ERR(&priv->fclk)) { 891 dev_err(dev, "%s: Failed to get fclk: %ld\n", 892 __func__, PTR_ERR(&priv->fclk)); 893 return PTR_ERR(&priv->fclk); 894 } 895 896 dev_dbg(dev, "DSS fclk %lu Hz\n", clk_get_rate(&priv->fclk)); 897 898 video_set_flush_dcache(dev, true); 899 return 0; 900} 901 902static int tidss_drv_remove(struct udevice *dev) 903{ 904 if (CONFIG_IS_ENABLED(VIDEO_REMOVE)) { 905 struct tidss_drv_priv *priv = dev_get_priv(dev); 906 907 VP_REG_FLD_MOD(priv, 0, DSS_VP_CONTROL, 0, 0, 0); 908 } 909 return 0; 910} 911 912static int tidss_drv_bind(struct udevice *dev) 913{ 914 struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev); 915 916 uc_plat->size = ((LCD_MAX_WIDTH * LCD_MAX_HEIGHT * 917 (1 << LCD_MAX_LOG2_BPP)) >> 3) + 0x20; 918 return 0; 919} 920 921static const struct udevice_id tidss_drv_ids[] = { 922 { .compatible = "ti,am625-dss" }, 923 { } 924}; 925 926U_BOOT_DRIVER(tidss_drv) = { 927 .name = "tidss_drv", 928 .id = UCLASS_VIDEO, 929 .of_match = tidss_drv_ids, 930 .bind = tidss_drv_bind, 931 .probe = tidss_drv_probe, 932 .remove = tidss_drv_remove, 933 .priv_auto = sizeof(struct tidss_drv_priv), 934#if CONFIG_IS_ENABLED(VIDEO_REMOVE) 935 .flags = DM_FLAG_OS_PREPARE, 936#else 937 .flags = DM_FLAG_OS_PREPARE | DM_FLAG_LEAVE_PD_ON, 938#endif 939}; 940