1 /* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * for STMicroelectronics. 6 * License terms: GNU General Public License (GPL), version 2 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/dma-mapping.h> 11 12 #include "sti_compositor.h" 13 #include "sti_gdp.h" 14 #include "sti_plane.h" 15 #include "sti_vtg.h" 16 17 #define ALPHASWITCH BIT(6) 18 #define ENA_COLOR_FILL BIT(8) 19 #define BIGNOTLITTLE BIT(23) 20 #define WAIT_NEXT_VSYNC BIT(31) 21 22 /* GDP color formats */ 23 #define GDP_RGB565 0x00 24 #define GDP_RGB888 0x01 25 #define GDP_RGB888_32 0x02 26 #define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) 27 #define GDP_ARGB8565 0x04 28 #define GDP_ARGB8888 0x05 29 #define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) 30 #define GDP_ARGB1555 0x06 31 #define GDP_ARGB4444 0x07 32 #define GDP_CLUT8 0x0B 33 #define GDP_YCBR888 0x10 34 #define GDP_YCBR422R 0x12 35 #define GDP_AYCBR8888 0x15 36 37 #define GAM_GDP_CTL_OFFSET 0x00 38 #define GAM_GDP_AGC_OFFSET 0x04 39 #define GAM_GDP_VPO_OFFSET 0x0C 40 #define GAM_GDP_VPS_OFFSET 0x10 41 #define GAM_GDP_PML_OFFSET 0x14 42 #define GAM_GDP_PMP_OFFSET 0x18 43 #define GAM_GDP_SIZE_OFFSET 0x1C 44 #define GAM_GDP_NVN_OFFSET 0x24 45 #define GAM_GDP_KEY1_OFFSET 0x28 46 #define GAM_GDP_KEY2_OFFSET 0x2C 47 #define GAM_GDP_PPT_OFFSET 0x34 48 #define GAM_GDP_CML_OFFSET 0x3C 49 #define GAM_GDP_MST_OFFSET 0x68 50 51 #define GAM_GDP_ALPHARANGE_255 BIT(5) 52 #define GAM_GDP_AGC_FULL_RANGE 0x00808080 53 #define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0)) 54 #define GAM_GDP_SIZE_MAX 0x7FF 55 56 #define GDP_NODE_NB_BANK 2 57 #define GDP_NODE_PER_FIELD 2 58 59 struct sti_gdp_node { 60 u32 gam_gdp_ctl; 61 u32 gam_gdp_agc; 62 u32 reserved1; 63 u32 gam_gdp_vpo; 64 u32 gam_gdp_vps; 65 u32 gam_gdp_pml; 66 u32 gam_gdp_pmp; 67 u32 gam_gdp_size; 68 u32 reserved2; 69 u32 gam_gdp_nvn; 70 u32 gam_gdp_key1; 71 u32 gam_gdp_key2; 72 u32 reserved3; 73 u32 gam_gdp_ppt; 74 u32 reserved4; 75 u32 gam_gdp_cml; 76 }; 77 78 struct sti_gdp_node_list { 79 struct sti_gdp_node *top_field; 80 dma_addr_t top_field_paddr; 81 struct sti_gdp_node *btm_field; 82 dma_addr_t btm_field_paddr; 83 }; 84 85 /** 86 * STI GDP structure 87 * 88 * @sti_plane: sti_plane structure 89 * @dev: driver device 90 * @regs: gdp registers 91 * @clk_pix: pixel clock for the current gdp 92 * @clk_main_parent: gdp parent clock if main path used 93 * @clk_aux_parent: gdp parent clock if aux path used 94 * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification 95 * @is_curr_top: true if the current node processed is the top field 96 * @node_list: array of node list 97 */ 98 struct sti_gdp { 99 struct sti_plane plane; 100 struct device *dev; 101 void __iomem *regs; 102 struct clk *clk_pix; 103 struct clk *clk_main_parent; 104 struct clk *clk_aux_parent; 105 struct notifier_block vtg_field_nb; 106 bool is_curr_top; 107 struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK]; 108 }; 109 110 #define to_sti_gdp(x) container_of(x, struct sti_gdp, plane) 111 112 static const uint32_t gdp_supported_formats[] = { 113 DRM_FORMAT_XRGB8888, 114 DRM_FORMAT_XBGR8888, 115 DRM_FORMAT_ARGB8888, 116 DRM_FORMAT_ABGR8888, 117 DRM_FORMAT_ARGB4444, 118 DRM_FORMAT_ARGB1555, 119 DRM_FORMAT_RGB565, 120 DRM_FORMAT_RGB888, 121 DRM_FORMAT_AYUV, 122 DRM_FORMAT_YUV444, 123 DRM_FORMAT_VYUY, 124 DRM_FORMAT_C8, 125 }; 126 127 static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane) 128 { 129 return gdp_supported_formats; 130 } 131 132 static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane) 133 { 134 return ARRAY_SIZE(gdp_supported_formats); 135 } 136 137 static int sti_gdp_fourcc2format(int fourcc) 138 { 139 switch (fourcc) { 140 case DRM_FORMAT_XRGB8888: 141 return GDP_RGB888_32; 142 case DRM_FORMAT_XBGR8888: 143 return GDP_XBGR8888; 144 case DRM_FORMAT_ARGB8888: 145 return GDP_ARGB8888; 146 case DRM_FORMAT_ABGR8888: 147 return GDP_ABGR8888; 148 case DRM_FORMAT_ARGB4444: 149 return GDP_ARGB4444; 150 case DRM_FORMAT_ARGB1555: 151 return GDP_ARGB1555; 152 case DRM_FORMAT_RGB565: 153 return GDP_RGB565; 154 case DRM_FORMAT_RGB888: 155 return GDP_RGB888; 156 case DRM_FORMAT_AYUV: 157 return GDP_AYCBR8888; 158 case DRM_FORMAT_YUV444: 159 return GDP_YCBR888; 160 case DRM_FORMAT_VYUY: 161 return GDP_YCBR422R; 162 case DRM_FORMAT_C8: 163 return GDP_CLUT8; 164 } 165 return -1; 166 } 167 168 static int sti_gdp_get_alpharange(int format) 169 { 170 switch (format) { 171 case GDP_ARGB8565: 172 case GDP_ARGB8888: 173 case GDP_AYCBR8888: 174 case GDP_ABGR8888: 175 return GAM_GDP_ALPHARANGE_255; 176 } 177 return 0; 178 } 179 180 /** 181 * sti_gdp_get_free_nodes 182 * @plane: gdp plane 183 * 184 * Look for a GDP node list that is not currently read by the HW. 185 * 186 * RETURNS: 187 * Pointer to the free GDP node list 188 */ 189 static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) 190 { 191 int hw_nvn; 192 struct sti_gdp *gdp = to_sti_gdp(plane); 193 unsigned int i; 194 195 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); 196 if (!hw_nvn) 197 goto end; 198 199 for (i = 0; i < GDP_NODE_NB_BANK; i++) 200 if ((hw_nvn != gdp->node_list[i].btm_field_paddr) && 201 (hw_nvn != gdp->node_list[i].top_field_paddr)) 202 return &gdp->node_list[i]; 203 204 /* in hazardious cases restart with the first node */ 205 DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", 206 sti_plane_to_str(plane), hw_nvn); 207 208 end: 209 return &gdp->node_list[0]; 210 } 211 212 /** 213 * sti_gdp_get_current_nodes 214 * @plane: GDP plane 215 * 216 * Look for GDP nodes that are currently read by the HW. 217 * 218 * RETURNS: 219 * Pointer to the current GDP node list 220 */ 221 static 222 struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) 223 { 224 int hw_nvn; 225 struct sti_gdp *gdp = to_sti_gdp(plane); 226 unsigned int i; 227 228 hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); 229 if (!hw_nvn) 230 goto end; 231 232 for (i = 0; i < GDP_NODE_NB_BANK; i++) 233 if ((hw_nvn == gdp->node_list[i].btm_field_paddr) || 234 (hw_nvn == gdp->node_list[i].top_field_paddr)) 235 return &gdp->node_list[i]; 236 237 end: 238 DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", 239 hw_nvn, sti_plane_to_str(plane)); 240 241 return NULL; 242 } 243 244 /** 245 * sti_gdp_prepare 246 * @plane: gdp plane 247 * @first_prepare: true if it is the first time this function is called 248 * 249 * Update the free GDP node list according to the plane properties. 250 * 251 * RETURNS: 252 * 0 on success. 253 */ 254 static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare) 255 { 256 struct sti_gdp_node_list *list; 257 struct sti_gdp_node *top_field, *btm_field; 258 struct drm_display_mode *mode = plane->mode; 259 struct sti_gdp *gdp = to_sti_gdp(plane); 260 struct device *dev = gdp->dev; 261 struct sti_compositor *compo = dev_get_drvdata(dev); 262 int format; 263 unsigned int depth, bpp; 264 int rate = mode->clock * 1000; 265 int res; 266 u32 ydo, xdo, yds, xds; 267 268 list = sti_gdp_get_free_nodes(plane); 269 top_field = list->top_field; 270 btm_field = list->btm_field; 271 272 dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, 273 sti_plane_to_str(plane), top_field, btm_field); 274 275 /* Build the top field from plane params */ 276 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; 277 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; 278 format = sti_gdp_fourcc2format(plane->format); 279 if (format == -1) { 280 DRM_ERROR("Format not supported by GDP %.4s\n", 281 (char *)&plane->format); 282 return 1; 283 } 284 top_field->gam_gdp_ctl |= format; 285 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); 286 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; 287 288 /* pixel memory location */ 289 drm_fb_get_bpp_depth(plane->format, &depth, &bpp); 290 top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0]; 291 top_field->gam_gdp_pml += plane->src_x * (bpp >> 3); 292 top_field->gam_gdp_pml += plane->src_y * plane->pitches[0]; 293 294 /* input parameters */ 295 top_field->gam_gdp_pmp = plane->pitches[0]; 296 top_field->gam_gdp_size = 297 clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 | 298 clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX); 299 300 /* output parameters */ 301 ydo = sti_vtg_get_line_number(*mode, plane->dst_y); 302 yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); 303 xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); 304 xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); 305 top_field->gam_gdp_vpo = (ydo << 16) | xdo; 306 top_field->gam_gdp_vps = (yds << 16) | xds; 307 308 /* Same content and chained together */ 309 memcpy(btm_field, top_field, sizeof(*btm_field)); 310 top_field->gam_gdp_nvn = list->btm_field_paddr; 311 btm_field->gam_gdp_nvn = list->top_field_paddr; 312 313 /* Interlaced mode */ 314 if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) 315 btm_field->gam_gdp_pml = top_field->gam_gdp_pml + 316 plane->pitches[0]; 317 318 if (first_prepare) { 319 /* Register gdp callback */ 320 if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ? 321 compo->vtg_main : compo->vtg_aux, 322 &gdp->vtg_field_nb, plane->mixer_id)) { 323 DRM_ERROR("Cannot register VTG notifier\n"); 324 return 1; 325 } 326 327 /* Set and enable gdp clock */ 328 if (gdp->clk_pix) { 329 struct clk *clkp; 330 /* According to the mixer used, the gdp pixel clock 331 * should have a different parent clock. */ 332 if (plane->mixer_id == STI_MIXER_MAIN) 333 clkp = gdp->clk_main_parent; 334 else 335 clkp = gdp->clk_aux_parent; 336 337 if (clkp) 338 clk_set_parent(gdp->clk_pix, clkp); 339 340 res = clk_set_rate(gdp->clk_pix, rate); 341 if (res < 0) { 342 DRM_ERROR("Cannot set rate (%dHz) for gdp\n", 343 rate); 344 return 1; 345 } 346 347 if (clk_prepare_enable(gdp->clk_pix)) { 348 DRM_ERROR("Failed to prepare/enable gdp\n"); 349 return 1; 350 } 351 } 352 } 353 354 return 0; 355 } 356 357 /** 358 * sti_gdp_commit 359 * @plane: gdp plane 360 * 361 * Update the NVN field of the 'right' field of the current GDP node (being 362 * used by the HW) with the address of the updated ('free') top field GDP node. 363 * - In interlaced mode the 'right' field is the bottom field as we update 364 * frames starting from their top field 365 * - In progressive mode, we update both bottom and top fields which are 366 * equal nodes. 367 * At the next VSYNC, the updated node list will be used by the HW. 368 * 369 * RETURNS: 370 * 0 on success. 371 */ 372 static int sti_gdp_commit(struct sti_plane *plane) 373 { 374 struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane); 375 struct sti_gdp_node *updated_top_node = updated_list->top_field; 376 struct sti_gdp_node *updated_btm_node = updated_list->btm_field; 377 struct sti_gdp *gdp = to_sti_gdp(plane); 378 u32 dma_updated_top = updated_list->top_field_paddr; 379 u32 dma_updated_btm = updated_list->btm_field_paddr; 380 struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane); 381 382 dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__, 383 sti_plane_to_str(plane), 384 updated_top_node, updated_btm_node); 385 dev_dbg(gdp->dev, "Current NVN:0x%X\n", 386 readl(gdp->regs + GAM_GDP_NVN_OFFSET)); 387 dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", 388 (unsigned long)plane->paddr, 389 readl(gdp->regs + GAM_GDP_PML_OFFSET)); 390 391 if (curr_list == NULL) { 392 /* First update or invalid node should directly write in the 393 * hw register */ 394 DRM_DEBUG_DRIVER("%s first update (or invalid node)", 395 sti_plane_to_str(plane)); 396 397 writel(gdp->is_curr_top == true ? 398 dma_updated_btm : dma_updated_top, 399 gdp->regs + GAM_GDP_NVN_OFFSET); 400 return 0; 401 } 402 403 if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) { 404 if (gdp->is_curr_top == true) { 405 /* Do not update in the middle of the frame, but 406 * postpone the update after the bottom field has 407 * been displayed */ 408 curr_list->btm_field->gam_gdp_nvn = dma_updated_top; 409 } else { 410 /* Direct update to avoid one frame delay */ 411 writel(dma_updated_top, 412 gdp->regs + GAM_GDP_NVN_OFFSET); 413 } 414 } else { 415 /* Direct update for progressive to avoid one frame delay */ 416 writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); 417 } 418 419 return 0; 420 } 421 422 /** 423 * sti_gdp_disable 424 * @plane: gdp plane 425 * 426 * Disable a GDP. 427 * 428 * RETURNS: 429 * 0 on success. 430 */ 431 static int sti_gdp_disable(struct sti_plane *plane) 432 { 433 unsigned int i; 434 struct sti_gdp *gdp = to_sti_gdp(plane); 435 struct sti_compositor *compo = dev_get_drvdata(gdp->dev); 436 437 DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); 438 439 /* Set the nodes as 'to be ignored on mixer' */ 440 for (i = 0; i < GDP_NODE_NB_BANK; i++) { 441 gdp->node_list[i].top_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; 442 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; 443 } 444 445 if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ? 446 compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) 447 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); 448 449 if (gdp->clk_pix) 450 clk_disable_unprepare(gdp->clk_pix); 451 452 return 0; 453 } 454 455 /** 456 * sti_gdp_field_cb 457 * @nb: notifier block 458 * @event: event message 459 * @data: private data 460 * 461 * Handle VTG top field and bottom field event. 462 * 463 * RETURNS: 464 * 0 on success. 465 */ 466 int sti_gdp_field_cb(struct notifier_block *nb, 467 unsigned long event, void *data) 468 { 469 struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb); 470 471 switch (event) { 472 case VTG_TOP_FIELD_EVENT: 473 gdp->is_curr_top = true; 474 break; 475 case VTG_BOTTOM_FIELD_EVENT: 476 gdp->is_curr_top = false; 477 break; 478 default: 479 DRM_ERROR("unsupported event: %lu\n", event); 480 break; 481 } 482 483 return 0; 484 } 485 486 static void sti_gdp_init(struct sti_gdp *gdp) 487 { 488 struct device_node *np = gdp->dev->of_node; 489 dma_addr_t dma_addr; 490 void *base; 491 unsigned int i, size; 492 493 /* Allocate all the nodes within a single memory page */ 494 size = sizeof(struct sti_gdp_node) * 495 GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK; 496 base = dma_alloc_writecombine(gdp->dev, 497 size, &dma_addr, GFP_KERNEL | GFP_DMA); 498 499 if (!base) { 500 DRM_ERROR("Failed to allocate memory for GDP node\n"); 501 return; 502 } 503 memset(base, 0, size); 504 505 for (i = 0; i < GDP_NODE_NB_BANK; i++) { 506 if (dma_addr & 0xF) { 507 DRM_ERROR("Mem alignment failed\n"); 508 return; 509 } 510 gdp->node_list[i].top_field = base; 511 gdp->node_list[i].top_field_paddr = dma_addr; 512 513 DRM_DEBUG_DRIVER("node[%d].top_field=%p\n", i, base); 514 base += sizeof(struct sti_gdp_node); 515 dma_addr += sizeof(struct sti_gdp_node); 516 517 if (dma_addr & 0xF) { 518 DRM_ERROR("Mem alignment failed\n"); 519 return; 520 } 521 gdp->node_list[i].btm_field = base; 522 gdp->node_list[i].btm_field_paddr = dma_addr; 523 DRM_DEBUG_DRIVER("node[%d].btm_field=%p\n", i, base); 524 base += sizeof(struct sti_gdp_node); 525 dma_addr += sizeof(struct sti_gdp_node); 526 } 527 528 if (of_device_is_compatible(np, "st,stih407-compositor")) { 529 /* GDP of STiH407 chip have its own pixel clock */ 530 char *clk_name; 531 532 switch (gdp->plane.desc) { 533 case STI_GDP_0: 534 clk_name = "pix_gdp1"; 535 break; 536 case STI_GDP_1: 537 clk_name = "pix_gdp2"; 538 break; 539 case STI_GDP_2: 540 clk_name = "pix_gdp3"; 541 break; 542 case STI_GDP_3: 543 clk_name = "pix_gdp4"; 544 break; 545 default: 546 DRM_ERROR("GDP id not recognized\n"); 547 return; 548 } 549 550 gdp->clk_pix = devm_clk_get(gdp->dev, clk_name); 551 if (IS_ERR(gdp->clk_pix)) 552 DRM_ERROR("Cannot get %s clock\n", clk_name); 553 554 gdp->clk_main_parent = devm_clk_get(gdp->dev, "main_parent"); 555 if (IS_ERR(gdp->clk_main_parent)) 556 DRM_ERROR("Cannot get main_parent clock\n"); 557 558 gdp->clk_aux_parent = devm_clk_get(gdp->dev, "aux_parent"); 559 if (IS_ERR(gdp->clk_aux_parent)) 560 DRM_ERROR("Cannot get aux_parent clock\n"); 561 } 562 } 563 564 static const struct sti_plane_funcs gdp_plane_ops = { 565 .get_formats = sti_gdp_get_formats, 566 .get_nb_formats = sti_gdp_get_nb_formats, 567 .prepare = sti_gdp_prepare, 568 .commit = sti_gdp_commit, 569 .disable = sti_gdp_disable, 570 }; 571 572 struct sti_plane *sti_gdp_create(struct device *dev, int desc, 573 void __iomem *baseaddr) 574 { 575 struct sti_gdp *gdp; 576 577 gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL); 578 if (!gdp) { 579 DRM_ERROR("Failed to allocate memory for GDP\n"); 580 return NULL; 581 } 582 583 gdp->dev = dev; 584 gdp->regs = baseaddr; 585 gdp->plane.desc = desc; 586 gdp->plane.ops = &gdp_plane_ops; 587 588 gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; 589 590 sti_gdp_init(gdp); 591 592 return &gdp->plane; 593 } 594