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

Merge tag 'drm/tegra/for-4.18-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/tegra: Changes for v4.18-rc1

This set enables IOMMU support in the gr2d and gr3d drivers and adds
support for the zpos property on older Tegra generations. It also
enables scaling filters and incorporates some rework to eliminate a
private wrapper around struct drm_framebuffer.

The remainder is mostly a random assortment of fixes and cleanups, as
well as some preparatory work for destaging the userspace ABI, which
is almost ready and is targetted for v4.19-rc1.

Signed-off-by: Dave Airlie <airlied@redhat.com>

# gpg: Signature made Sat 19 May 2018 08:31:00 AEST
# gpg: using RSA key DD23ACD77F3EB3A1
# gpg: Can't check signature: public key not found
Link: https://patchwork.freedesktop.org/patch/msgid/20180518224523.30982-1-thierry.reding@gmail.com

+1151 -551
+222 -84
drivers/gpu/drm/tegra/dc.c
··· 163 163 BLEND_COLOR_KEY_NONE; 164 164 u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255); 165 165 struct tegra_plane_state *state; 166 + u32 blending[2]; 166 167 unsigned int i; 167 168 168 - state = to_tegra_plane_state(plane->base.state); 169 - 170 - /* alpha contribution is 1 minus sum of overlapping windows */ 171 - for (i = 0; i < 3; i++) { 172 - if (state->dependent[i]) 173 - background[i] |= BLEND_CONTROL_DEPENDENT; 174 - } 175 - 176 - /* enable alpha blending if pixel format has an alpha component */ 177 - if (!state->opaque) 178 - foreground |= BLEND_CONTROL_ALPHA; 179 - 180 - /* 181 - * Disable blending and assume Window A is the bottom-most window, 182 - * Window C is the top-most window and Window B is in the middle. 183 - */ 169 + /* disable blending for non-overlapping case */ 184 170 tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY); 185 171 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN); 186 172 187 - switch (plane->index) { 173 + state = to_tegra_plane_state(plane->base.state); 174 + 175 + if (state->opaque) { 176 + /* 177 + * Since custom fix-weight blending isn't utilized and weight 178 + * of top window is set to max, we can enforce dependent 179 + * blending which in this case results in transparent bottom 180 + * window if top window is opaque and if top window enables 181 + * alpha blending, then bottom window is getting alpha value 182 + * of 1 minus the sum of alpha components of the overlapping 183 + * plane. 184 + */ 185 + background[0] |= BLEND_CONTROL_DEPENDENT; 186 + background[1] |= BLEND_CONTROL_DEPENDENT; 187 + 188 + /* 189 + * The region where three windows overlap is the intersection 190 + * of the two regions where two windows overlap. It contributes 191 + * to the area if all of the windows on top of it have an alpha 192 + * component. 193 + */ 194 + switch (state->base.normalized_zpos) { 195 + case 0: 196 + if (state->blending[0].alpha && 197 + state->blending[1].alpha) 198 + background[2] |= BLEND_CONTROL_DEPENDENT; 199 + break; 200 + 201 + case 1: 202 + background[2] |= BLEND_CONTROL_DEPENDENT; 203 + break; 204 + } 205 + } else { 206 + /* 207 + * Enable alpha blending if pixel format has an alpha 208 + * component. 209 + */ 210 + foreground |= BLEND_CONTROL_ALPHA; 211 + 212 + /* 213 + * If any of the windows on top of this window is opaque, it 214 + * will completely conceal this window within that area. If 215 + * top window has an alpha component, it is blended over the 216 + * bottom window. 217 + */ 218 + for (i = 0; i < 2; i++) { 219 + if (state->blending[i].alpha && 220 + state->blending[i].top) 221 + background[i] |= BLEND_CONTROL_DEPENDENT; 222 + } 223 + 224 + switch (state->base.normalized_zpos) { 225 + case 0: 226 + if (state->blending[0].alpha && 227 + state->blending[1].alpha) 228 + background[2] |= BLEND_CONTROL_DEPENDENT; 229 + break; 230 + 231 + case 1: 232 + /* 233 + * When both middle and topmost windows have an alpha, 234 + * these windows a mixed together and then the result 235 + * is blended over the bottom window. 236 + */ 237 + if (state->blending[0].alpha && 238 + state->blending[0].top) 239 + background[2] |= BLEND_CONTROL_ALPHA; 240 + 241 + if (state->blending[1].alpha && 242 + state->blending[1].top) 243 + background[2] |= BLEND_CONTROL_ALPHA; 244 + break; 245 + } 246 + } 247 + 248 + switch (state->base.normalized_zpos) { 188 249 case 0: 189 250 tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X); 190 251 tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y); ··· 253 192 break; 254 193 255 194 case 1: 256 - tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X); 257 - tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y); 195 + /* 196 + * If window B / C is topmost, then X / Y registers are 197 + * matching the order of blending[...] state indices, 198 + * otherwise a swap is required. 199 + */ 200 + if (!state->blending[0].top && state->blending[1].top) { 201 + blending[0] = foreground; 202 + blending[1] = background[1]; 203 + } else { 204 + blending[0] = background[0]; 205 + blending[1] = foreground; 206 + } 207 + 208 + tegra_plane_writel(plane, blending[0], DC_WIN_BLEND_2WIN_X); 209 + tegra_plane_writel(plane, blending[1], DC_WIN_BLEND_2WIN_Y); 258 210 tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY); 259 211 break; 260 212 ··· 296 222 297 223 value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - window->zpos); 298 224 tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL); 225 + } 226 + 227 + static bool 228 + tegra_plane_use_horizontal_filtering(struct tegra_plane *plane, 229 + const struct tegra_dc_window *window) 230 + { 231 + struct tegra_dc *dc = plane->dc; 232 + 233 + if (window->src.w == window->dst.w) 234 + return false; 235 + 236 + if (plane->index == 0 && dc->soc->has_win_a_without_filters) 237 + return false; 238 + 239 + return true; 240 + } 241 + 242 + static bool 243 + tegra_plane_use_vertical_filtering(struct tegra_plane *plane, 244 + const struct tegra_dc_window *window) 245 + { 246 + struct tegra_dc *dc = plane->dc; 247 + 248 + if (window->src.h == window->dst.h) 249 + return false; 250 + 251 + if (plane->index == 0 && dc->soc->has_win_a_without_filters) 252 + return false; 253 + 254 + if (plane->index == 2 && dc->soc->has_win_c_without_vert_filter) 255 + return false; 256 + 257 + return true; 299 258 } 300 259 301 260 static void tegra_dc_setup_window(struct tegra_plane *plane, ··· 468 361 if (window->bottom_up) 469 362 value |= V_DIRECTION; 470 363 364 + if (tegra_plane_use_horizontal_filtering(plane, window)) { 365 + /* 366 + * Enable horizontal 6-tap filter and set filtering 367 + * coefficients to the default values defined in TRM. 368 + */ 369 + tegra_plane_writel(plane, 0x00008000, DC_WIN_H_FILTER_P(0)); 370 + tegra_plane_writel(plane, 0x3e087ce1, DC_WIN_H_FILTER_P(1)); 371 + tegra_plane_writel(plane, 0x3b117ac1, DC_WIN_H_FILTER_P(2)); 372 + tegra_plane_writel(plane, 0x591b73aa, DC_WIN_H_FILTER_P(3)); 373 + tegra_plane_writel(plane, 0x57256d9a, DC_WIN_H_FILTER_P(4)); 374 + tegra_plane_writel(plane, 0x552f668b, DC_WIN_H_FILTER_P(5)); 375 + tegra_plane_writel(plane, 0x73385e8b, DC_WIN_H_FILTER_P(6)); 376 + tegra_plane_writel(plane, 0x72435583, DC_WIN_H_FILTER_P(7)); 377 + tegra_plane_writel(plane, 0x714c4c8b, DC_WIN_H_FILTER_P(8)); 378 + tegra_plane_writel(plane, 0x70554393, DC_WIN_H_FILTER_P(9)); 379 + tegra_plane_writel(plane, 0x715e389b, DC_WIN_H_FILTER_P(10)); 380 + tegra_plane_writel(plane, 0x71662faa, DC_WIN_H_FILTER_P(11)); 381 + tegra_plane_writel(plane, 0x536d25ba, DC_WIN_H_FILTER_P(12)); 382 + tegra_plane_writel(plane, 0x55731bca, DC_WIN_H_FILTER_P(13)); 383 + tegra_plane_writel(plane, 0x387a11d9, DC_WIN_H_FILTER_P(14)); 384 + tegra_plane_writel(plane, 0x3c7c08f1, DC_WIN_H_FILTER_P(15)); 385 + 386 + value |= H_FILTER; 387 + } 388 + 389 + if (tegra_plane_use_vertical_filtering(plane, window)) { 390 + unsigned int i, k; 391 + 392 + /* 393 + * Enable vertical 2-tap filter and set filtering 394 + * coefficients to the default values defined in TRM. 395 + */ 396 + for (i = 0, k = 128; i < 16; i++, k -= 8) 397 + tegra_plane_writel(plane, k, DC_WIN_V_FILTER_P(i)); 398 + 399 + value |= V_FILTER; 400 + } 401 + 471 402 tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS); 472 403 473 - if (dc->soc->supports_blending) 474 - tegra_plane_setup_blending(plane, window); 475 - else 404 + if (dc->soc->has_legacy_blending) 476 405 tegra_plane_setup_blending_legacy(plane); 406 + else 407 + tegra_plane_setup_blending(plane, window); 477 408 } 478 409 479 410 static const u32 tegra20_primary_formats[] = { ··· 596 451 struct drm_plane_state *state) 597 452 { 598 453 struct tegra_plane_state *plane_state = to_tegra_plane_state(state); 454 + unsigned int rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y; 599 455 struct tegra_bo_tiling *tiling = &plane_state->tiling; 600 456 struct tegra_plane *tegra = to_tegra_plane(plane); 601 457 struct tegra_dc *dc = to_tegra_dc(state->crtc); 602 - unsigned int format; 603 458 int err; 604 459 605 460 /* no need for further checks if the plane is being disabled */ 606 461 if (!state->crtc) 607 462 return 0; 608 463 609 - err = tegra_plane_format(state->fb->format->format, &format, 464 + err = tegra_plane_format(state->fb->format->format, 465 + &plane_state->format, 610 466 &plane_state->swap); 611 467 if (err < 0) 612 468 return err; ··· 618 472 * the corresponding opaque formats. However, the opaque formats can 619 473 * be emulated by disabling alpha blending for the plane. 620 474 */ 621 - if (!dc->soc->supports_blending) { 622 - if (!tegra_plane_format_has_alpha(format)) { 623 - err = tegra_plane_format_get_alpha(format, &format); 624 - if (err < 0) 625 - return err; 626 - 627 - plane_state->opaque = true; 628 - } else { 629 - plane_state->opaque = false; 630 - } 631 - 632 - tegra_plane_check_dependent(tegra, plane_state); 475 + if (dc->soc->has_legacy_blending) { 476 + err = tegra_plane_setup_legacy_state(tegra, plane_state); 477 + if (err < 0) 478 + return err; 633 479 } 634 - 635 - plane_state->format = format; 636 480 637 481 err = tegra_fb_get_tiling(state->fb, tiling); 638 482 if (err < 0) ··· 633 497 DRM_ERROR("hardware doesn't support block linear mode\n"); 634 498 return -EINVAL; 635 499 } 500 + 501 + rotation = drm_rotation_simplify(state->rotation, rotation); 502 + 503 + if (rotation & DRM_MODE_REFLECT_Y) 504 + plane_state->bottom_up = true; 505 + else 506 + plane_state->bottom_up = false; 636 507 637 508 /* 638 509 * Tegra doesn't support different strides for U and V planes so we ··· 701 558 window.dst.w = drm_rect_width(&plane->state->dst); 702 559 window.dst.h = drm_rect_height(&plane->state->dst); 703 560 window.bits_per_pixel = fb->format->cpp[0] * 8; 704 - window.bottom_up = tegra_fb_is_bottom_up(fb); 561 + window.bottom_up = tegra_fb_is_bottom_up(fb) || state->bottom_up; 705 562 706 563 /* copy from state */ 707 564 window.zpos = plane->state->normalized_zpos; ··· 782 639 } 783 640 784 641 drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); 642 + drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255); 785 643 786 - if (dc->soc->supports_blending) 787 - drm_plane_create_zpos_property(&plane->base, 0, 0, 255); 644 + err = drm_plane_create_rotation_property(&plane->base, 645 + DRM_MODE_ROTATE_0, 646 + DRM_MODE_ROTATE_0 | 647 + DRM_MODE_REFLECT_Y); 648 + if (err < 0) 649 + dev_err(dc->dev, "failed to create rotation property: %d\n", 650 + err); 788 651 789 652 return &plane->base; 790 653 } ··· 1067 918 } 1068 919 1069 920 drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs); 921 + drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255); 1070 922 1071 - if (dc->soc->supports_blending) 1072 - drm_plane_create_zpos_property(&plane->base, 0, 0, 255); 923 + err = drm_plane_create_rotation_property(&plane->base, 924 + DRM_MODE_ROTATE_0, 925 + DRM_MODE_ROTATE_0 | 926 + DRM_MODE_REFLECT_Y); 927 + if (err < 0) 928 + dev_err(dc->dev, "failed to create rotation property: %d\n", 929 + err); 1073 930 1074 931 return &plane->base; 1075 932 } ··· 1981 1826 static int tegra_dc_init(struct host1x_client *client) 1982 1827 { 1983 1828 struct drm_device *drm = dev_get_drvdata(client->parent); 1984 - struct iommu_group *group = iommu_group_get(client->dev); 1985 1829 unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; 1986 1830 struct tegra_dc *dc = host1x_client_to_dc(client); 1987 1831 struct tegra_drm *tegra = drm->dev_private; ··· 1992 1838 if (!dc->syncpt) 1993 1839 dev_warn(dc->dev, "failed to allocate syncpoint\n"); 1994 1840 1995 - if (group && tegra->domain) { 1996 - if (group != tegra->group) { 1997 - err = iommu_attach_group(tegra->domain, group); 1998 - if (err < 0) { 1999 - dev_err(dc->dev, 2000 - "failed to attach to domain: %d\n", 2001 - err); 2002 - return err; 2003 - } 2004 - 2005 - tegra->group = group; 2006 - } 2007 - 2008 - dc->domain = tegra->domain; 1841 + dc->group = host1x_client_iommu_attach(client, true); 1842 + if (IS_ERR(dc->group)) { 1843 + err = PTR_ERR(dc->group); 1844 + dev_err(client->dev, "failed to attach to domain: %d\n", err); 1845 + return err; 2009 1846 } 2010 1847 2011 1848 if (dc->soc->wgrps) ··· 2061 1916 if (!IS_ERR(primary)) 2062 1917 drm_plane_cleanup(primary); 2063 1918 2064 - if (group && dc->domain) { 2065 - if (group == tegra->group) { 2066 - iommu_detach_group(dc->domain, group); 2067 - tegra->group = NULL; 2068 - } 2069 - 2070 - dc->domain = NULL; 2071 - } 1919 + host1x_client_iommu_detach(client, dc->group); 1920 + host1x_syncpt_free(dc->syncpt); 2072 1921 2073 1922 return err; 2074 1923 } 2075 1924 2076 1925 static int tegra_dc_exit(struct host1x_client *client) 2077 1926 { 2078 - struct drm_device *drm = dev_get_drvdata(client->parent); 2079 - struct iommu_group *group = iommu_group_get(client->dev); 2080 1927 struct tegra_dc *dc = host1x_client_to_dc(client); 2081 - struct tegra_drm *tegra = drm->dev_private; 2082 1928 int err; 2083 1929 2084 1930 devm_free_irq(dc->dev, dc->irq, dc); ··· 2080 1944 return err; 2081 1945 } 2082 1946 2083 - if (group && dc->domain) { 2084 - if (group == tegra->group) { 2085 - iommu_detach_group(dc->domain, group); 2086 - tegra->group = NULL; 2087 - } 2088 - 2089 - dc->domain = NULL; 2090 - } 2091 - 1947 + host1x_client_iommu_detach(client, dc->group); 2092 1948 host1x_syncpt_free(dc->syncpt); 2093 1949 2094 1950 return 0; ··· 2096 1968 .supports_interlacing = false, 2097 1969 .supports_cursor = false, 2098 1970 .supports_block_linear = false, 2099 - .supports_blending = false, 1971 + .has_legacy_blending = true, 2100 1972 .pitch_align = 8, 2101 1973 .has_powergate = false, 2102 1974 .coupled_pm = true, ··· 2106 1978 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), 2107 1979 .overlay_formats = tegra20_overlay_formats, 2108 1980 .modifiers = tegra20_modifiers, 1981 + .has_win_a_without_filters = true, 1982 + .has_win_c_without_vert_filter = true, 2109 1983 }; 2110 1984 2111 1985 static const struct tegra_dc_soc_info tegra30_dc_soc_info = { ··· 2115 1985 .supports_interlacing = false, 2116 1986 .supports_cursor = false, 2117 1987 .supports_block_linear = false, 2118 - .supports_blending = false, 1988 + .has_legacy_blending = true, 2119 1989 .pitch_align = 8, 2120 1990 .has_powergate = false, 2121 1991 .coupled_pm = false, ··· 2125 1995 .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), 2126 1996 .overlay_formats = tegra20_overlay_formats, 2127 1997 .modifiers = tegra20_modifiers, 1998 + .has_win_a_without_filters = false, 1999 + .has_win_c_without_vert_filter = false, 2128 2000 }; 2129 2001 2130 2002 static const struct tegra_dc_soc_info tegra114_dc_soc_info = { ··· 2134 2002 .supports_interlacing = false, 2135 2003 .supports_cursor = false, 2136 2004 .supports_block_linear = false, 2137 - .supports_blending = false, 2005 + .has_legacy_blending = true, 2138 2006 .pitch_align = 64, 2139 2007 .has_powergate = true, 2140 2008 .coupled_pm = false, ··· 2144 2012 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), 2145 2013 .overlay_formats = tegra114_overlay_formats, 2146 2014 .modifiers = tegra20_modifiers, 2015 + .has_win_a_without_filters = false, 2016 + .has_win_c_without_vert_filter = false, 2147 2017 }; 2148 2018 2149 2019 static const struct tegra_dc_soc_info tegra124_dc_soc_info = { ··· 2153 2019 .supports_interlacing = true, 2154 2020 .supports_cursor = true, 2155 2021 .supports_block_linear = true, 2156 - .supports_blending = true, 2022 + .has_legacy_blending = false, 2157 2023 .pitch_align = 64, 2158 2024 .has_powergate = true, 2159 2025 .coupled_pm = false, ··· 2163 2029 .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats), 2164 2030 .overlay_formats = tegra124_overlay_formats, 2165 2031 .modifiers = tegra124_modifiers, 2032 + .has_win_a_without_filters = false, 2033 + .has_win_c_without_vert_filter = false, 2166 2034 }; 2167 2035 2168 2036 static const struct tegra_dc_soc_info tegra210_dc_soc_info = { ··· 2172 2036 .supports_interlacing = true, 2173 2037 .supports_cursor = true, 2174 2038 .supports_block_linear = true, 2175 - .supports_blending = true, 2039 + .has_legacy_blending = false, 2176 2040 .pitch_align = 64, 2177 2041 .has_powergate = true, 2178 2042 .coupled_pm = false, ··· 2182 2046 .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), 2183 2047 .overlay_formats = tegra114_overlay_formats, 2184 2048 .modifiers = tegra124_modifiers, 2049 + .has_win_a_without_filters = false, 2050 + .has_win_c_without_vert_filter = false, 2185 2051 }; 2186 2052 2187 2053 static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { ··· 2225 2087 .supports_interlacing = true, 2226 2088 .supports_cursor = true, 2227 2089 .supports_block_linear = true, 2228 - .supports_blending = true, 2090 + .has_legacy_blending = false, 2229 2091 .pitch_align = 64, 2230 2092 .has_powergate = false, 2231 2093 .coupled_pm = false,
+9 -2
drivers/gpu/drm/tegra/dc.h
··· 55 55 bool supports_interlacing; 56 56 bool supports_cursor; 57 57 bool supports_block_linear; 58 - bool supports_blending; 58 + bool has_legacy_blending; 59 59 unsigned int pitch_align; 60 60 bool has_powergate; 61 61 bool coupled_pm; ··· 67 67 const u32 *overlay_formats; 68 68 unsigned int num_overlay_formats; 69 69 const u64 *modifiers; 70 + bool has_win_a_without_filters; 71 + bool has_win_c_without_vert_filter; 70 72 }; 71 73 72 74 struct tegra_dc { ··· 94 92 95 93 const struct tegra_dc_soc_info *soc; 96 94 97 - struct iommu_domain *domain; 95 + struct iommu_group *group; 98 96 }; 99 97 100 98 static inline struct tegra_dc * ··· 555 553 #define THREAD_NUM(x) (((x) & 0x1f) << 1) 556 554 #define THREAD_GROUP_ENABLE (1 << 0) 557 555 556 + #define DC_WIN_H_FILTER_P(p) (0x601 + (p)) 557 + #define DC_WIN_V_FILTER_P(p) (0x619 + (p)) 558 + 558 559 #define DC_WIN_CSC_YOF 0x611 559 560 #define DC_WIN_CSC_KYRGB 0x612 560 561 #define DC_WIN_CSC_KUR 0x613 ··· 571 566 #define H_DIRECTION (1 << 0) 572 567 #define V_DIRECTION (1 << 2) 573 568 #define COLOR_EXPAND (1 << 6) 569 + #define H_FILTER (1 << 8) 570 + #define V_FILTER (1 << 10) 574 571 #define CSC_ENABLE (1 << 18) 575 572 #define WIN_ENABLE (1 << 30) 576 573
+65 -68
drivers/gpu/drm/tegra/drm.c
··· 98 98 goto free; 99 99 } 100 100 101 + err = iova_cache_get(); 102 + if (err < 0) 103 + goto domain; 104 + 101 105 geometry = &tegra->domain->geometry; 102 106 gem_start = geometry->aperture_start; 103 107 gem_end = geometry->aperture_end - CARVEOUT_SZ; ··· 195 191 drm_mode_config_cleanup(drm); 196 192 197 193 if (tegra->domain) { 198 - iommu_domain_free(tegra->domain); 199 - drm_mm_takedown(&tegra->mm); 200 194 mutex_destroy(&tegra->mm_lock); 195 + drm_mm_takedown(&tegra->mm); 201 196 put_iova_domain(&tegra->carveout.domain); 197 + iova_cache_put(); 202 198 } 199 + domain: 200 + if (tegra->domain) 201 + iommu_domain_free(tegra->domain); 203 202 free: 204 203 kfree(tegra); 205 204 return err; ··· 224 217 return; 225 218 226 219 if (tegra->domain) { 227 - iommu_domain_free(tegra->domain); 228 - drm_mm_takedown(&tegra->mm); 229 220 mutex_destroy(&tegra->mm_lock); 221 + drm_mm_takedown(&tegra->mm); 230 222 put_iova_domain(&tegra->carveout.domain); 223 + iova_cache_put(); 224 + iommu_domain_free(tegra->domain); 231 225 } 232 226 233 227 kfree(tegra); ··· 308 300 return 0; 309 301 } 310 302 311 - static int host1x_waitchk_copy_from_user(struct host1x_waitchk *dest, 312 - struct drm_tegra_waitchk __user *src, 313 - struct drm_file *file) 314 - { 315 - u32 cmdbuf; 316 - int err; 317 - 318 - err = get_user(cmdbuf, &src->handle); 319 - if (err < 0) 320 - return err; 321 - 322 - err = get_user(dest->offset, &src->offset); 323 - if (err < 0) 324 - return err; 325 - 326 - err = get_user(dest->syncpt_id, &src->syncpt); 327 - if (err < 0) 328 - return err; 329 - 330 - err = get_user(dest->thresh, &src->thresh); 331 - if (err < 0) 332 - return err; 333 - 334 - dest->bo = host1x_bo_lookup(file, cmdbuf); 335 - if (!dest->bo) 336 - return -ENOENT; 337 - 338 - return 0; 339 - } 340 - 341 303 int tegra_drm_submit(struct tegra_drm_context *context, 342 304 struct drm_tegra_submit *args, struct drm_device *drm, 343 305 struct drm_file *file) 344 306 { 307 + struct host1x_client *client = &context->client->base; 345 308 unsigned int num_cmdbufs = args->num_cmdbufs; 346 309 unsigned int num_relocs = args->num_relocs; 347 - unsigned int num_waitchks = args->num_waitchks; 348 310 struct drm_tegra_cmdbuf __user *user_cmdbufs; 349 311 struct drm_tegra_reloc __user *user_relocs; 350 - struct drm_tegra_waitchk __user *user_waitchks; 351 312 struct drm_tegra_syncpt __user *user_syncpt; 352 313 struct drm_tegra_syncpt syncpt; 353 314 struct host1x *host1x = dev_get_drvdata(drm->dev->parent); ··· 328 351 329 352 user_cmdbufs = u64_to_user_ptr(args->cmdbufs); 330 353 user_relocs = u64_to_user_ptr(args->relocs); 331 - user_waitchks = u64_to_user_ptr(args->waitchks); 332 354 user_syncpt = u64_to_user_ptr(args->syncpts); 333 355 334 356 /* We don't yet support other than one syncpt_incr struct per submit */ ··· 339 363 return -EINVAL; 340 364 341 365 job = host1x_job_alloc(context->channel, args->num_cmdbufs, 342 - args->num_relocs, args->num_waitchks); 366 + args->num_relocs); 343 367 if (!job) 344 368 return -ENOMEM; 345 369 346 370 job->num_relocs = args->num_relocs; 347 - job->num_waitchk = args->num_waitchks; 348 - job->client = (u32)args->context; 349 - job->class = context->client->base.class; 371 + job->client = client; 372 + job->class = client->class; 350 373 job->serialize = true; 351 374 352 375 /* 353 376 * Track referenced BOs so that they can be unreferenced after the 354 377 * submission is complete. 355 378 */ 356 - num_refs = num_cmdbufs + num_relocs * 2 + num_waitchks; 379 + num_refs = num_cmdbufs + num_relocs * 2; 357 380 358 381 refs = kmalloc_array(num_refs, sizeof(*refs), GFP_KERNEL); 359 382 if (!refs) { ··· 413 438 struct host1x_reloc *reloc; 414 439 struct tegra_bo *obj; 415 440 416 - err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs], 441 + err = host1x_reloc_copy_from_user(&job->relocs[num_relocs], 417 442 &user_relocs[num_relocs], drm, 418 443 file); 419 444 if (err < 0) 420 445 goto fail; 421 446 422 - reloc = &job->relocarray[num_relocs]; 447 + reloc = &job->relocs[num_relocs]; 423 448 obj = host1x_to_tegra_bo(reloc->cmdbuf.bo); 424 449 refs[num_refs++] = &obj->gem; 425 450 ··· 438 463 refs[num_refs++] = &obj->gem; 439 464 440 465 if (reloc->target.offset >= obj->gem.size) { 441 - err = -EINVAL; 442 - goto fail; 443 - } 444 - } 445 - 446 - /* copy and resolve waitchks from submit */ 447 - while (num_waitchks--) { 448 - struct host1x_waitchk *wait = &job->waitchk[num_waitchks]; 449 - struct tegra_bo *obj; 450 - 451 - err = host1x_waitchk_copy_from_user( 452 - wait, &user_waitchks[num_waitchks], file); 453 - if (err < 0) 454 - goto fail; 455 - 456 - obj = host1x_to_tegra_bo(wait->bo); 457 - refs[num_refs++] = &obj->gem; 458 - 459 - /* 460 - * The unaligned offset will cause an unaligned write during 461 - * of the waitchks patching, corrupting the commands stream. 462 - */ 463 - if (wait->offset & 3 || 464 - wait->offset >= obj->gem.size) { 465 466 err = -EINVAL; 466 467 goto fail; 467 468 } ··· 1050 1099 mutex_unlock(&tegra->clients_lock); 1051 1100 1052 1101 return 0; 1102 + } 1103 + 1104 + struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, 1105 + bool shared) 1106 + { 1107 + struct drm_device *drm = dev_get_drvdata(client->parent); 1108 + struct tegra_drm *tegra = drm->dev_private; 1109 + struct iommu_group *group = NULL; 1110 + int err; 1111 + 1112 + if (tegra->domain) { 1113 + group = iommu_group_get(client->dev); 1114 + if (!group) { 1115 + dev_err(client->dev, "failed to get IOMMU group\n"); 1116 + return ERR_PTR(-ENODEV); 1117 + } 1118 + 1119 + if (!shared || (shared && (group != tegra->group))) { 1120 + err = iommu_attach_group(tegra->domain, group); 1121 + if (err < 0) { 1122 + iommu_group_put(group); 1123 + return ERR_PTR(err); 1124 + } 1125 + 1126 + if (shared && !tegra->group) 1127 + tegra->group = group; 1128 + } 1129 + } 1130 + 1131 + return group; 1132 + } 1133 + 1134 + void host1x_client_iommu_detach(struct host1x_client *client, 1135 + struct iommu_group *group) 1136 + { 1137 + struct drm_device *drm = dev_get_drvdata(client->parent); 1138 + struct tegra_drm *tegra = drm->dev_private; 1139 + 1140 + if (group) { 1141 + if (group == tegra->group) { 1142 + iommu_detach_group(tegra->domain, group); 1143 + tegra->group = NULL; 1144 + } 1145 + 1146 + iommu_group_put(group); 1147 + } 1053 1148 } 1054 1149 1055 1150 void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *dma)
+6 -7
drivers/gpu/drm/tegra/drm.h
··· 29 29 30 30 struct reset_control; 31 31 32 - struct tegra_fb { 33 - struct drm_framebuffer base; 34 - struct tegra_bo **planes; 35 - unsigned int num_planes; 36 - }; 37 - 38 32 #ifdef CONFIG_DRM_FBDEV_EMULATION 39 33 struct tegra_fbdev { 40 34 struct drm_fb_helper base; 41 - struct tegra_fb *fb; 35 + struct drm_framebuffer *fb; 42 36 }; 43 37 #endif 44 38 ··· 91 97 struct host1x_client base; 92 98 struct list_head list; 93 99 100 + unsigned int version; 94 101 const struct tegra_drm_client_ops *ops; 95 102 }; 96 103 ··· 105 110 struct tegra_drm_client *client); 106 111 int tegra_drm_unregister_client(struct tegra_drm *tegra, 107 112 struct tegra_drm_client *client); 113 + struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, 114 + bool shared); 115 + void host1x_client_iommu_detach(struct host1x_client *client, 116 + struct iommu_group *group); 108 117 109 118 int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); 110 119 int tegra_drm_exit(struct tegra_drm *tegra);
+30 -69
drivers/gpu/drm/tegra/fb.c
··· 14 14 15 15 #include "drm.h" 16 16 #include "gem.h" 17 - 18 - static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb) 19 - { 20 - return container_of(fb, struct tegra_fb, base); 21 - } 17 + #include <drm/drm_gem_framebuffer_helper.h> 22 18 23 19 #ifdef CONFIG_DRM_FBDEV_EMULATION 24 20 static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) ··· 26 30 struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, 27 31 unsigned int index) 28 32 { 29 - struct tegra_fb *fb = to_tegra_fb(framebuffer); 30 - 31 - if (index >= framebuffer->format->num_planes) 32 - return NULL; 33 - 34 - return fb->planes[index]; 33 + return to_tegra_bo(drm_gem_fb_get_obj(framebuffer, index)); 35 34 } 36 35 37 36 bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer) 38 37 { 39 - struct tegra_fb *fb = to_tegra_fb(framebuffer); 38 + struct tegra_bo *bo = tegra_fb_get_plane(framebuffer, 0); 40 39 41 - if (fb->planes[0]->flags & TEGRA_BO_BOTTOM_UP) 40 + if (bo->flags & TEGRA_BO_BOTTOM_UP) 42 41 return true; 43 42 44 43 return false; ··· 42 51 int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, 43 52 struct tegra_bo_tiling *tiling) 44 53 { 45 - struct tegra_fb *fb = to_tegra_fb(framebuffer); 46 - uint64_t modifier = fb->base.modifier; 54 + uint64_t modifier = framebuffer->modifier; 47 55 48 56 switch (modifier) { 49 57 case DRM_FORMAT_MOD_LINEAR: ··· 92 102 return 0; 93 103 } 94 104 95 - static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) 96 - { 97 - struct tegra_fb *fb = to_tegra_fb(framebuffer); 98 - unsigned int i; 99 - 100 - for (i = 0; i < fb->num_planes; i++) { 101 - struct tegra_bo *bo = fb->planes[i]; 102 - 103 - if (bo) { 104 - if (bo->pages) 105 - vunmap(bo->vaddr); 106 - 107 - drm_gem_object_put_unlocked(&bo->gem); 108 - } 109 - } 110 - 111 - drm_framebuffer_cleanup(framebuffer); 112 - kfree(fb->planes); 113 - kfree(fb); 114 - } 115 - 116 - static int tegra_fb_create_handle(struct drm_framebuffer *framebuffer, 117 - struct drm_file *file, unsigned int *handle) 118 - { 119 - struct tegra_fb *fb = to_tegra_fb(framebuffer); 120 - 121 - return drm_gem_handle_create(file, &fb->planes[0]->gem, handle); 122 - } 123 - 124 105 static const struct drm_framebuffer_funcs tegra_fb_funcs = { 125 - .destroy = tegra_fb_destroy, 126 - .create_handle = tegra_fb_create_handle, 106 + .destroy = drm_gem_fb_destroy, 107 + .create_handle = drm_gem_fb_create_handle, 127 108 }; 128 109 129 - static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, 130 - const struct drm_mode_fb_cmd2 *mode_cmd, 131 - struct tegra_bo **planes, 132 - unsigned int num_planes) 110 + static struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm, 111 + const struct drm_mode_fb_cmd2 *mode_cmd, 112 + struct tegra_bo **planes, 113 + unsigned int num_planes) 133 114 { 134 - struct tegra_fb *fb; 115 + struct drm_framebuffer *fb; 135 116 unsigned int i; 136 117 int err; 137 118 ··· 110 149 if (!fb) 111 150 return ERR_PTR(-ENOMEM); 112 151 113 - fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL); 114 - if (!fb->planes) { 115 - kfree(fb); 116 - return ERR_PTR(-ENOMEM); 117 - } 152 + drm_helper_mode_fill_fb_struct(drm, fb, mode_cmd); 118 153 119 - fb->num_planes = num_planes; 154 + for (i = 0; i < fb->format->num_planes; i++) 155 + fb->obj[i] = &planes[i]->gem; 120 156 121 - drm_helper_mode_fill_fb_struct(drm, &fb->base, mode_cmd); 122 - 123 - for (i = 0; i < fb->num_planes; i++) 124 - fb->planes[i] = planes[i]; 125 - 126 - err = drm_framebuffer_init(drm, &fb->base, &tegra_fb_funcs); 157 + err = drm_framebuffer_init(drm, fb, &tegra_fb_funcs); 127 158 if (err < 0) { 128 159 dev_err(drm->dev, "failed to initialize framebuffer: %d\n", 129 160 err); 130 - kfree(fb->planes); 131 161 kfree(fb); 132 162 return ERR_PTR(err); 133 163 } ··· 133 181 unsigned int hsub, vsub, i; 134 182 struct tegra_bo *planes[4]; 135 183 struct drm_gem_object *gem; 136 - struct tegra_fb *fb; 184 + struct drm_framebuffer *fb; 137 185 int err; 138 186 139 187 hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); ··· 169 217 goto unreference; 170 218 } 171 219 172 - return &fb->base; 220 + return fb; 173 221 174 222 unreference: 175 223 while (i--) ··· 250 298 return PTR_ERR(fbdev->fb); 251 299 } 252 300 253 - fb = &fbdev->fb->base; 301 + fb = fbdev->fb; 254 302 helper->fb = fb; 255 303 helper->fbdev = info; 256 304 ··· 350 398 { 351 399 drm_fb_helper_unregister_fbi(&fbdev->base); 352 400 353 - if (fbdev->fb) 354 - drm_framebuffer_remove(&fbdev->fb->base); 401 + if (fbdev->fb) { 402 + struct tegra_bo *bo = tegra_fb_get_plane(fbdev->fb, 0); 403 + 404 + /* Undo the special mapping we made in fbdev probe. */ 405 + if (bo && bo->pages) { 406 + vunmap(bo->vaddr); 407 + bo->vaddr = 0; 408 + } 409 + 410 + drm_framebuffer_remove(fbdev->fb); 411 + } 355 412 356 413 drm_fb_helper_fini(&fbdev->base); 357 414 tegra_fbdev_free(fbdev);
+4 -16
drivers/gpu/drm/tegra/gem.c
··· 422 422 return 0; 423 423 } 424 424 425 - static int tegra_bo_fault(struct vm_fault *vmf) 425 + static vm_fault_t tegra_bo_fault(struct vm_fault *vmf) 426 426 { 427 427 struct vm_area_struct *vma = vmf->vma; 428 428 struct drm_gem_object *gem = vma->vm_private_data; 429 429 struct tegra_bo *bo = to_tegra_bo(gem); 430 430 struct page *page; 431 431 pgoff_t offset; 432 - int err; 433 432 434 433 if (!bo->pages) 435 434 return VM_FAULT_SIGBUS; ··· 436 437 offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; 437 438 page = bo->pages[offset]; 438 439 439 - err = vm_insert_page(vma, vmf->address, page); 440 - switch (err) { 441 - case -EAGAIN: 442 - case 0: 443 - case -ERESTARTSYS: 444 - case -EINTR: 445 - case -EBUSY: 446 - return VM_FAULT_NOPAGE; 447 - 448 - case -ENOMEM: 449 - return VM_FAULT_OOM; 450 - } 451 - 452 - return VM_FAULT_SIGBUS; 440 + return vmf_insert_page(vma, vmf->address, page); 453 441 } 454 442 455 443 const struct vm_operations_struct tegra_bo_vm_ops = { ··· 649 663 { 650 664 DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 651 665 666 + exp_info.exp_name = KBUILD_MODNAME; 667 + exp_info.owner = drm->driver->fops->owner; 652 668 exp_info.ops = &tegra_gem_prime_dmabuf_ops; 653 669 exp_info.size = gem->size; 654 670 exp_info.flags = flags;
+51 -6
drivers/gpu/drm/tegra/gr2d.c
··· 7 7 */ 8 8 9 9 #include <linux/clk.h> 10 + #include <linux/iommu.h> 11 + #include <linux/of_device.h> 10 12 11 13 #include "drm.h" 12 14 #include "gem.h" 13 15 #include "gr2d.h" 14 16 17 + struct gr2d_soc { 18 + unsigned int version; 19 + }; 20 + 15 21 struct gr2d { 22 + struct iommu_group *group; 16 23 struct tegra_drm_client client; 17 24 struct host1x_channel *channel; 18 25 struct clk *clk; 26 + 27 + const struct gr2d_soc *soc; 19 28 20 29 DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS); 21 30 }; ··· 40 31 struct drm_device *dev = dev_get_drvdata(client->parent); 41 32 unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 42 33 struct gr2d *gr2d = to_gr2d(drm); 34 + int err; 43 35 44 36 gr2d->channel = host1x_channel_request(client->dev); 45 37 if (!gr2d->channel) ··· 48 38 49 39 client->syncpts[0] = host1x_syncpt_request(client, flags); 50 40 if (!client->syncpts[0]) { 51 - host1x_channel_put(gr2d->channel); 52 - return -ENOMEM; 41 + err = -ENOMEM; 42 + dev_err(client->dev, "failed to request syncpoint: %d\n", err); 43 + goto put; 53 44 } 54 45 55 - return tegra_drm_register_client(dev->dev_private, drm); 46 + gr2d->group = host1x_client_iommu_attach(client, false); 47 + if (IS_ERR(gr2d->group)) { 48 + err = PTR_ERR(gr2d->group); 49 + dev_err(client->dev, "failed to attach to domain: %d\n", err); 50 + goto free; 51 + } 52 + 53 + err = tegra_drm_register_client(dev->dev_private, drm); 54 + if (err < 0) { 55 + dev_err(client->dev, "failed to register client: %d\n", err); 56 + goto detach; 57 + } 58 + 59 + return 0; 60 + 61 + detach: 62 + host1x_client_iommu_detach(client, gr2d->group); 63 + free: 64 + host1x_syncpt_free(client->syncpts[0]); 65 + put: 66 + host1x_channel_put(gr2d->channel); 67 + return err; 56 68 } 57 69 58 70 static int gr2d_exit(struct host1x_client *client) 59 71 { 60 72 struct tegra_drm_client *drm = host1x_to_drm_client(client); 61 73 struct drm_device *dev = dev_get_drvdata(client->parent); 74 + struct tegra_drm *tegra = dev->dev_private; 62 75 struct gr2d *gr2d = to_gr2d(drm); 63 76 int err; 64 77 65 - err = tegra_drm_unregister_client(dev->dev_private, drm); 78 + err = tegra_drm_unregister_client(tegra, drm); 66 79 if (err < 0) 67 80 return err; 68 81 82 + host1x_client_iommu_detach(client, gr2d->group); 69 83 host1x_syncpt_free(client->syncpts[0]); 70 84 host1x_channel_put(gr2d->channel); 71 85 ··· 157 123 .submit = tegra_drm_submit, 158 124 }; 159 125 126 + static const struct gr2d_soc tegra20_gr2d_soc = { 127 + .version = 0x20, 128 + }; 129 + 130 + static const struct gr2d_soc tegra30_gr2d_soc = { 131 + .version = 0x30, 132 + }; 133 + 160 134 static const struct of_device_id gr2d_match[] = { 161 - { .compatible = "nvidia,tegra30-gr2d" }, 162 - { .compatible = "nvidia,tegra20-gr2d" }, 135 + { .compatible = "nvidia,tegra30-gr2d", .data = &tegra20_gr2d_soc }, 136 + { .compatible = "nvidia,tegra20-gr2d", .data = &tegra30_gr2d_soc }, 163 137 { }, 164 138 }; 165 139 MODULE_DEVICE_TABLE(of, gr2d_match); ··· 200 158 if (!gr2d) 201 159 return -ENOMEM; 202 160 161 + gr2d->soc = of_device_get_match_data(dev); 162 + 203 163 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 204 164 if (!syncpts) 205 165 return -ENOMEM; ··· 226 182 gr2d->client.base.num_syncpts = 1; 227 183 228 184 INIT_LIST_HEAD(&gr2d->client.list); 185 + gr2d->client.version = gr2d->soc->version; 229 186 gr2d->client.ops = &gr2d_ops; 230 187 231 188 err = host1x_client_register(&gr2d->client.base);
+54 -6
drivers/gpu/drm/tegra/gr3d.c
··· 9 9 10 10 #include <linux/clk.h> 11 11 #include <linux/host1x.h> 12 + #include <linux/iommu.h> 12 13 #include <linux/module.h> 14 + #include <linux/of_device.h> 13 15 #include <linux/platform_device.h> 14 16 #include <linux/reset.h> 15 17 ··· 21 19 #include "gem.h" 22 20 #include "gr3d.h" 23 21 22 + struct gr3d_soc { 23 + unsigned int version; 24 + }; 25 + 24 26 struct gr3d { 27 + struct iommu_group *group; 25 28 struct tegra_drm_client client; 26 29 struct host1x_channel *channel; 27 30 struct clk *clk_secondary; 28 31 struct clk *clk; 29 32 struct reset_control *rst_secondary; 30 33 struct reset_control *rst; 34 + 35 + const struct gr3d_soc *soc; 31 36 32 37 DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); 33 38 }; ··· 50 41 struct drm_device *dev = dev_get_drvdata(client->parent); 51 42 unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 52 43 struct gr3d *gr3d = to_gr3d(drm); 44 + int err; 53 45 54 46 gr3d->channel = host1x_channel_request(client->dev); 55 47 if (!gr3d->channel) ··· 58 48 59 49 client->syncpts[0] = host1x_syncpt_request(client, flags); 60 50 if (!client->syncpts[0]) { 61 - host1x_channel_put(gr3d->channel); 62 - return -ENOMEM; 51 + err = -ENOMEM; 52 + dev_err(client->dev, "failed to request syncpoint: %d\n", err); 53 + goto put; 63 54 } 64 55 65 - return tegra_drm_register_client(dev->dev_private, drm); 56 + gr3d->group = host1x_client_iommu_attach(client, false); 57 + if (IS_ERR(gr3d->group)) { 58 + err = PTR_ERR(gr3d->group); 59 + dev_err(client->dev, "failed to attach to domain: %d\n", err); 60 + goto free; 61 + } 62 + 63 + err = tegra_drm_register_client(dev->dev_private, drm); 64 + if (err < 0) { 65 + dev_err(client->dev, "failed to register client: %d\n", err); 66 + goto detach; 67 + } 68 + 69 + return 0; 70 + 71 + detach: 72 + host1x_client_iommu_detach(client, gr3d->group); 73 + free: 74 + host1x_syncpt_free(client->syncpts[0]); 75 + put: 76 + host1x_channel_put(gr3d->channel); 77 + return err; 66 78 } 67 79 68 80 static int gr3d_exit(struct host1x_client *client) ··· 98 66 if (err < 0) 99 67 return err; 100 68 69 + host1x_client_iommu_detach(client, gr3d->group); 101 70 host1x_syncpt_free(client->syncpts[0]); 102 71 host1x_channel_put(gr3d->channel); 103 72 ··· 158 125 .submit = tegra_drm_submit, 159 126 }; 160 127 128 + static const struct gr3d_soc tegra20_gr3d_soc = { 129 + .version = 0x20, 130 + }; 131 + 132 + static const struct gr3d_soc tegra30_gr3d_soc = { 133 + .version = 0x30, 134 + }; 135 + 136 + static const struct gr3d_soc tegra114_gr3d_soc = { 137 + .version = 0x35, 138 + }; 139 + 161 140 static const struct of_device_id tegra_gr3d_match[] = { 162 - { .compatible = "nvidia,tegra114-gr3d" }, 163 - { .compatible = "nvidia,tegra30-gr3d" }, 164 - { .compatible = "nvidia,tegra20-gr3d" }, 141 + { .compatible = "nvidia,tegra114-gr3d", .data = &tegra114_gr3d_soc }, 142 + { .compatible = "nvidia,tegra30-gr3d", .data = &tegra30_gr3d_soc }, 143 + { .compatible = "nvidia,tegra20-gr3d", .data = &tegra20_gr3d_soc }, 165 144 { } 166 145 }; 167 146 MODULE_DEVICE_TABLE(of, tegra_gr3d_match); ··· 295 250 if (!gr3d) 296 251 return -ENOMEM; 297 252 253 + gr3d->soc = of_device_get_match_data(&pdev->dev); 254 + 298 255 syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL); 299 256 if (!syncpts) 300 257 return -ENOMEM; ··· 354 307 gr3d->client.base.num_syncpts = 1; 355 308 356 309 INIT_LIST_HEAD(&gr3d->client.list); 310 + gr3d->client.version = gr3d->soc->version; 357 311 gr3d->client.ops = &gr3d_ops; 358 312 359 313 err = host1x_client_register(&gr3d->client.base);
+1 -1
drivers/gpu/drm/tegra/hub.c
··· 687 687 struct device *dev = hub->client.dev; 688 688 int err; 689 689 690 - hub_state = tegra_display_hub_get_state(hub, state); 690 + hub_state = to_tegra_display_hub_state(hub->base.state); 691 691 692 692 if (hub_state->clk) { 693 693 err = clk_set_rate(hub_state->clk, hub_state->rate);
+140 -54
drivers/gpu/drm/tegra/plane.c
··· 23 23 24 24 static void tegra_plane_reset(struct drm_plane *plane) 25 25 { 26 + struct tegra_plane *p = to_tegra_plane(plane); 26 27 struct tegra_plane_state *state; 27 28 28 29 if (plane->state) ··· 36 35 if (state) { 37 36 plane->state = &state->base; 38 37 plane->state->plane = plane; 38 + plane->state->zpos = p->index; 39 + plane->state->normalized_zpos = p->index; 39 40 } 40 41 } 41 42 ··· 56 53 copy->tiling = state->tiling; 57 54 copy->format = state->format; 58 55 copy->swap = state->swap; 56 + copy->bottom_up = state->bottom_up; 59 57 copy->opaque = state->opaque; 60 58 61 - for (i = 0; i < 3; i++) 62 - copy->dependent[i] = state->dependent[i]; 59 + for (i = 0; i < 2; i++) 60 + copy->blending[i] = state->blending[i]; 63 61 64 62 return &copy->base; 65 63 } ··· 271 267 return false; 272 268 } 273 269 274 - /* 275 - * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 276 - * be emulated using the alpha formats and alpha blending disabled. 277 - */ 278 - bool tegra_plane_format_has_alpha(unsigned int format) 279 - { 280 - switch (format) { 281 - case WIN_COLOR_DEPTH_B5G5R5A1: 282 - case WIN_COLOR_DEPTH_A1B5G5R5: 283 - case WIN_COLOR_DEPTH_R8G8B8A8: 284 - case WIN_COLOR_DEPTH_B8G8R8A8: 285 - return true; 286 - } 287 - 288 - return false; 289 - } 290 - 291 - int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha) 270 + static int tegra_plane_format_get_alpha(unsigned int opaque, 271 + unsigned int *alpha) 292 272 { 293 273 if (tegra_plane_format_is_yuv(opaque, NULL)) { 294 274 *alpha = opaque; ··· 304 316 return -EINVAL; 305 317 } 306 318 319 + /* 320 + * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 321 + * be emulated using the alpha formats and alpha blending disabled. 322 + */ 323 + static int tegra_plane_setup_opacity(struct tegra_plane *tegra, 324 + struct tegra_plane_state *state) 325 + { 326 + unsigned int format; 327 + int err; 328 + 329 + switch (state->format) { 330 + case WIN_COLOR_DEPTH_B5G5R5A1: 331 + case WIN_COLOR_DEPTH_A1B5G5R5: 332 + case WIN_COLOR_DEPTH_R8G8B8A8: 333 + case WIN_COLOR_DEPTH_B8G8R8A8: 334 + state->opaque = false; 335 + break; 336 + 337 + default: 338 + err = tegra_plane_format_get_alpha(state->format, &format); 339 + if (err < 0) 340 + return err; 341 + 342 + state->format = format; 343 + state->opaque = true; 344 + break; 345 + } 346 + 347 + return 0; 348 + } 349 + 350 + static int tegra_plane_check_transparency(struct tegra_plane *tegra, 351 + struct tegra_plane_state *state) 352 + { 353 + struct drm_plane_state *old, *plane_state; 354 + struct drm_plane *plane; 355 + 356 + old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base); 357 + 358 + /* check if zpos / transparency changed */ 359 + if (old->normalized_zpos == state->base.normalized_zpos && 360 + to_tegra_plane_state(old)->opaque == state->opaque) 361 + return 0; 362 + 363 + /* include all sibling planes into this commit */ 364 + drm_for_each_plane(plane, tegra->base.dev) { 365 + struct tegra_plane *p = to_tegra_plane(plane); 366 + 367 + /* skip this plane and planes on different CRTCs */ 368 + if (p == tegra || p->dc != tegra->dc) 369 + continue; 370 + 371 + plane_state = drm_atomic_get_plane_state(state->base.state, 372 + plane); 373 + if (IS_ERR(plane_state)) 374 + return PTR_ERR(plane_state); 375 + } 376 + 377 + return 1; 378 + } 379 + 307 380 static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 308 381 struct tegra_plane *other) 309 382 { ··· 385 336 return index; 386 337 } 387 338 388 - void tegra_plane_check_dependent(struct tegra_plane *tegra, 389 - struct tegra_plane_state *state) 339 + static void tegra_plane_update_transparency(struct tegra_plane *tegra, 340 + struct tegra_plane_state *state) 390 341 { 391 - struct drm_plane_state *old, *new; 342 + struct drm_plane_state *new; 392 343 struct drm_plane *plane; 393 - unsigned int zpos[2]; 394 344 unsigned int i; 395 345 396 - for (i = 0; i < 2; i++) 397 - zpos[i] = 0; 398 - 399 - for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) { 346 + for_each_new_plane_in_state(state->base.state, plane, new, i) { 400 347 struct tegra_plane *p = to_tegra_plane(plane); 401 348 unsigned index; 402 349 403 350 /* skip this plane and planes on different CRTCs */ 404 - if (p == tegra || new->crtc != state->base.crtc) 351 + if (p == tegra || p->dc != tegra->dc) 405 352 continue; 406 353 407 354 index = tegra_plane_get_overlap_index(tegra, p); 408 355 409 - state->dependent[index] = false; 356 + if (new->fb && __drm_format_has_alpha(new->fb->format->format)) 357 + state->blending[index].alpha = true; 358 + else 359 + state->blending[index].alpha = false; 360 + 361 + if (new->normalized_zpos > state->base.normalized_zpos) 362 + state->blending[index].top = true; 363 + else 364 + state->blending[index].top = false; 410 365 411 366 /* 412 - * If any of the other planes is on top of this plane and uses 413 - * a format with an alpha component, mark this plane as being 414 - * dependent, meaning it's alpha value will be 1 minus the sum 415 - * of alpha components of the overlapping planes. 367 + * Missing framebuffer means that plane is disabled, in this 368 + * case mark B / C window as top to be able to differentiate 369 + * windows indices order in regards to zPos for the middle 370 + * window X / Y registers programming. 416 371 */ 417 - if (p->index > tegra->index) { 418 - if (__drm_format_has_alpha(new->fb->format->format)) 419 - state->dependent[index] = true; 420 - 421 - /* keep track of the Z position */ 422 - zpos[index] = p->index; 423 - } 372 + if (!new->fb) 373 + state->blending[index].top = (index == 1); 424 374 } 375 + } 376 + 377 + static int tegra_plane_setup_transparency(struct tegra_plane *tegra, 378 + struct tegra_plane_state *state) 379 + { 380 + struct tegra_plane_state *tegra_state; 381 + struct drm_plane_state *new; 382 + struct drm_plane *plane; 383 + int err; 425 384 426 385 /* 427 - * The region where three windows overlap is the intersection of the 428 - * two regions where two windows overlap. It contributes to the area 429 - * if any of the windows on top of it have an alpha component. 386 + * If planes zpos / transparency changed, sibling planes blending 387 + * state may require adjustment and in this case they will be included 388 + * into this atom commit, otherwise blending state is unchanged. 430 389 */ 431 - for (i = 0; i < 2; i++) 432 - state->dependent[2] = state->dependent[2] || 433 - state->dependent[i]; 390 + err = tegra_plane_check_transparency(tegra, state); 391 + if (err <= 0) 392 + return err; 434 393 435 394 /* 436 - * However, if any of the windows on top of this window is opaque, it 437 - * will completely conceal this window within that area, so avoid the 438 - * window from contributing to the area. 395 + * All planes are now in the atomic state, walk them up and update 396 + * transparency state for each plane. 439 397 */ 440 - for (i = 0; i < 2; i++) { 441 - if (zpos[i] > tegra->index) 442 - state->dependent[2] = state->dependent[2] && 443 - state->dependent[i]; 398 + drm_for_each_plane(plane, tegra->base.dev) { 399 + struct tegra_plane *p = to_tegra_plane(plane); 400 + 401 + /* skip planes on different CRTCs */ 402 + if (p->dc != tegra->dc) 403 + continue; 404 + 405 + new = drm_atomic_get_new_plane_state(state->base.state, plane); 406 + tegra_state = to_tegra_plane_state(new); 407 + 408 + /* 409 + * There is no need to update blending state for the disabled 410 + * plane. 411 + */ 412 + if (new->fb) 413 + tegra_plane_update_transparency(p, tegra_state); 444 414 } 415 + 416 + return 0; 417 + } 418 + 419 + int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 420 + struct tegra_plane_state *state) 421 + { 422 + int err; 423 + 424 + err = tegra_plane_setup_opacity(tegra, state); 425 + if (err < 0) 426 + return err; 427 + 428 + err = tegra_plane_setup_transparency(tegra, state); 429 + if (err < 0) 430 + return err; 431 + 432 + return 0; 445 433 }
+10 -5
drivers/gpu/drm/tegra/plane.h
··· 34 34 return container_of(plane, struct tegra_plane, base); 35 35 } 36 36 37 + struct tegra_plane_legacy_blending_state { 38 + bool alpha; 39 + bool top; 40 + }; 41 + 37 42 struct tegra_plane_state { 38 43 struct drm_plane_state base; 39 44 ··· 46 41 u32 format; 47 42 u32 swap; 48 43 44 + bool bottom_up; 45 + 49 46 /* used for legacy blending support only */ 47 + struct tegra_plane_legacy_blending_state blending[2]; 50 48 bool opaque; 51 - bool dependent[3]; 52 49 }; 53 50 54 51 static inline struct tegra_plane_state * ··· 69 62 70 63 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap); 71 64 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar); 72 - bool tegra_plane_format_has_alpha(unsigned int format); 73 - int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha); 74 - void tegra_plane_check_dependent(struct tegra_plane *tegra, 75 - struct tegra_plane_state *state); 65 + int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 66 + struct tegra_plane_state *state); 76 67 77 68 #endif /* TEGRA_PLANE_H */
+5
drivers/gpu/drm/tegra/vic.c
··· 25 25 26 26 struct vic_config { 27 27 const char *firmware; 28 + unsigned int version; 28 29 }; 29 30 30 31 struct vic { ··· 265 264 266 265 static const struct vic_config vic_t124_config = { 267 266 .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE, 267 + .version = 0x40, 268 268 }; 269 269 270 270 #define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin" 271 271 272 272 static const struct vic_config vic_t210_config = { 273 273 .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE, 274 + .version = 0x21, 274 275 }; 275 276 276 277 #define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin" 277 278 278 279 static const struct vic_config vic_t186_config = { 279 280 .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE, 281 + .version = 0x18, 280 282 }; 281 283 282 284 static const struct of_device_id vic_match[] = { ··· 346 342 vic->dev = dev; 347 343 348 344 INIT_LIST_HEAD(&vic->client.list); 345 + vic->client.version = vic->config->version; 349 346 vic->client.ops = &vic_ops; 350 347 351 348 err = host1x_client_register(&vic->client.base);
+3 -3
drivers/gpu/host1x/cdma.c
··· 51 51 struct host1x_cdma *cdma = pb_to_cdma(pb); 52 52 struct host1x *host1x = cdma_to_host1x(cdma); 53 53 54 - if (!pb->phys) 54 + if (!pb->mapped) 55 55 return; 56 56 57 57 if (host1x->domain) { ··· 127 127 iommu_free_iova: 128 128 __free_iova(&host1x->iova, alloc); 129 129 iommu_free_mem: 130 - dma_free_wc(host1x->dev, pb->alloc_size, pb->mapped, pb->phys); 130 + dma_free_wc(host1x->dev, size, pb->mapped, pb->phys); 131 131 132 132 return err; 133 133 } ··· 247 247 static void stop_cdma_timer_locked(struct host1x_cdma *cdma) 248 248 { 249 249 cancel_delayed_work(&cdma->timeout.wq); 250 - cdma->timeout.client = 0; 250 + cdma->timeout.client = NULL; 251 251 } 252 252 253 253 /*
+2 -2
drivers/gpu/host1x/cdma.h
··· 44 44 struct push_buffer { 45 45 void *mapped; /* mapped pushbuffer memory */ 46 46 dma_addr_t dma; /* device address of pushbuffer */ 47 - phys_addr_t phys; /* physical address of pushbuffer */ 47 + dma_addr_t phys; /* physical address of pushbuffer */ 48 48 u32 fence; /* index we've written */ 49 49 u32 pos; /* index to write to */ 50 50 u32 size; ··· 58 58 u32 syncpt_val; /* syncpt value when completed */ 59 59 ktime_t start_ktime; /* starting time */ 60 60 /* context timeout information */ 61 - int client; 61 + struct host1x_client *client; 62 62 }; 63 63 64 64 enum cdma_event {
+1 -1
drivers/gpu/host1x/debug.c
··· 103 103 104 104 static void show_all(struct host1x *m, struct output *o, bool show_fifo) 105 105 { 106 - int i; 106 + unsigned int i; 107 107 108 108 host1x_hw_show_mlocks(m, o); 109 109 show_syncpts(m, o);
+10 -1
drivers/gpu/host1x/dev.c
··· 223 223 struct iommu_domain_geometry *geometry; 224 224 unsigned long order; 225 225 226 + err = iova_cache_get(); 227 + if (err < 0) 228 + goto put_group; 229 + 226 230 host->domain = iommu_domain_alloc(&platform_bus_type); 227 231 if (!host->domain) { 228 232 err = -ENOMEM; 229 - goto put_group; 233 + goto put_cache; 230 234 } 231 235 232 236 err = iommu_attach_group(host->domain, host->group); ··· 238 234 if (err == -ENODEV) { 239 235 iommu_domain_free(host->domain); 240 236 host->domain = NULL; 237 + iova_cache_put(); 241 238 iommu_group_put(host->group); 242 239 host->group = NULL; 243 240 goto skip_iommu; ··· 313 308 fail_free_domain: 314 309 if (host->domain) 315 310 iommu_domain_free(host->domain); 311 + put_cache: 312 + if (host->group) 313 + iova_cache_put(); 316 314 put_group: 317 315 iommu_group_put(host->group); 318 316 ··· 336 328 put_iova_domain(&host->iova); 337 329 iommu_detach_group(host->domain, host->group); 338 330 iommu_domain_free(host->domain); 331 + iova_cache_put(); 339 332 iommu_group_put(host->group); 340 333 } 341 334
-8
drivers/gpu/host1x/dev.h
··· 78 78 void (*load_wait_base)(struct host1x_syncpt *syncpt); 79 79 u32 (*load)(struct host1x_syncpt *syncpt); 80 80 int (*cpu_incr)(struct host1x_syncpt *syncpt); 81 - int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr); 82 81 void (*assign_to_channel)(struct host1x_syncpt *syncpt, 83 82 struct host1x_channel *channel); 84 83 void (*enable_protection)(struct host1x *host); ··· 180 181 struct host1x_syncpt *sp) 181 182 { 182 183 return host->syncpt_op->cpu_incr(sp); 183 - } 184 - 185 - static inline int host1x_hw_syncpt_patch_wait(struct host1x *host, 186 - struct host1x_syncpt *sp, 187 - void *patch_addr) 188 - { 189 - return host->syncpt_op->patch_wait(sp, patch_addr); 190 184 } 191 185 192 186 static inline void host1x_hw_syncpt_assign_to_channel(
+2 -3
drivers/gpu/host1x/hw/channel_hw.c
··· 104 104 sp = host->syncpt + job->syncpt_id; 105 105 trace_host1x_channel_submit(dev_name(ch->dev), 106 106 job->num_gathers, job->num_relocs, 107 - job->num_waitchk, job->syncpt_id, 108 - job->syncpt_incrs); 107 + job->syncpt_id, job->syncpt_incrs); 109 108 110 109 /* before error checks, return current max */ 111 110 prev_max = job->syncpt_end = host1x_syncpt_read_max(sp); ··· 164 165 trace_host1x_channel_submitted(dev_name(ch->dev), prev_max, syncval); 165 166 166 167 /* schedule a submit complete interrupt */ 167 - err = host1x_intr_add_action(host, job->syncpt_id, syncval, 168 + err = host1x_intr_add_action(host, sp, syncval, 168 169 HOST1X_INTR_ACTION_SUBMIT_COMPLETE, ch, 169 170 completed_waiter, NULL); 170 171 completed_waiter = NULL;
-11
drivers/gpu/host1x/hw/syncpt_hw.c
··· 96 96 return 0; 97 97 } 98 98 99 - /* remove a wait pointed to by patch_addr */ 100 - static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) 101 - { 102 - u32 override = host1x_class_host_wait_syncpt(HOST1X_SYNCPT_RESERVED, 0); 103 - 104 - *((u32 *)patch_addr) = override; 105 - 106 - return 0; 107 - } 108 - 109 99 /** 110 100 * syncpt_assign_to_channel() - Assign syncpoint to channel 111 101 * @sp: syncpoint ··· 146 156 .load_wait_base = syncpt_read_wait_base, 147 157 .load = syncpt_load, 148 158 .cpu_incr = syncpt_cpu_incr, 149 - .patch_wait = syncpt_patch_wait, 150 159 .assign_to_channel = syncpt_assign_to_channel, 151 160 .enable_protection = syncpt_enable_protection, 152 161 };
+7 -9
drivers/gpu/host1x/intr.c
··· 144 144 static void run_handlers(struct list_head completed[HOST1X_INTR_ACTION_COUNT]) 145 145 { 146 146 struct list_head *head = completed; 147 - int i; 147 + unsigned int i; 148 148 149 149 for (i = 0; i < HOST1X_INTR_ACTION_COUNT; ++i, ++head) { 150 150 action_handler handler = action_handlers[i]; ··· 211 211 host1x_syncpt_load(host->syncpt + id)); 212 212 } 213 213 214 - int host1x_intr_add_action(struct host1x *host, unsigned int id, u32 thresh, 215 - enum host1x_intr_action action, void *data, 216 - struct host1x_waitlist *waiter, void **ref) 214 + int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt, 215 + u32 thresh, enum host1x_intr_action action, 216 + void *data, struct host1x_waitlist *waiter, 217 + void **ref) 217 218 { 218 - struct host1x_syncpt *syncpt; 219 219 int queue_was_empty; 220 220 221 221 if (waiter == NULL) { ··· 234 234 waiter->data = data; 235 235 waiter->count = 1; 236 236 237 - syncpt = host->syncpt + id; 238 - 239 237 spin_lock(&syncpt->intr.lock); 240 238 241 239 queue_was_empty = list_empty(&syncpt->intr.wait_head); 242 240 243 241 if (add_waiter_to_queue(waiter, &syncpt->intr.wait_head)) { 244 242 /* added at head of list - new threshold value */ 245 - host1x_hw_intr_set_syncpt_threshold(host, id, thresh); 243 + host1x_hw_intr_set_syncpt_threshold(host, syncpt->id, thresh); 246 244 247 245 /* added as first waiter - enable interrupt */ 248 246 if (queue_was_empty) 249 - host1x_hw_intr_enable_syncpt_intr(host, id); 247 + host1x_hw_intr_enable_syncpt_intr(host, syncpt->id); 250 248 } 251 249 252 250 spin_unlock(&syncpt->intr.lock);
+5 -3
drivers/gpu/host1x/intr.h
··· 22 22 #include <linux/interrupt.h> 23 23 #include <linux/workqueue.h> 24 24 25 + struct host1x_syncpt; 25 26 struct host1x; 26 27 27 28 enum host1x_intr_action { ··· 76 75 * 77 76 * This is a non-blocking api. 78 77 */ 79 - int host1x_intr_add_action(struct host1x *host, unsigned int id, u32 thresh, 80 - enum host1x_intr_action action, void *data, 81 - struct host1x_waitlist *waiter, void **ref); 78 + int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt, 79 + u32 thresh, enum host1x_intr_action action, 80 + void *data, struct host1x_waitlist *waiter, 81 + void **ref); 82 82 83 83 /* 84 84 * Unreference an action submitted to host1x_intr_add_action().
+15 -132
drivers/gpu/host1x/job.c
··· 34 34 #define HOST1X_WAIT_SYNCPT_OFFSET 0x8 35 35 36 36 struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, 37 - u32 num_cmdbufs, u32 num_relocs, 38 - u32 num_waitchks) 37 + u32 num_cmdbufs, u32 num_relocs) 39 38 { 40 39 struct host1x_job *job = NULL; 41 40 unsigned int num_unpins = num_cmdbufs + num_relocs; ··· 45 46 total = sizeof(struct host1x_job) + 46 47 (u64)num_relocs * sizeof(struct host1x_reloc) + 47 48 (u64)num_unpins * sizeof(struct host1x_job_unpin_data) + 48 - (u64)num_waitchks * sizeof(struct host1x_waitchk) + 49 49 (u64)num_cmdbufs * sizeof(struct host1x_job_gather) + 50 50 (u64)num_unpins * sizeof(dma_addr_t) + 51 51 (u64)num_unpins * sizeof(u32 *); ··· 60 62 61 63 /* Redistribute memory to the structs */ 62 64 mem += sizeof(struct host1x_job); 63 - job->relocarray = num_relocs ? mem : NULL; 65 + job->relocs = num_relocs ? mem : NULL; 64 66 mem += num_relocs * sizeof(struct host1x_reloc); 65 67 job->unpins = num_unpins ? mem : NULL; 66 68 mem += num_unpins * sizeof(struct host1x_job_unpin_data); 67 - job->waitchk = num_waitchks ? mem : NULL; 68 - mem += num_waitchks * sizeof(struct host1x_waitchk); 69 69 job->gathers = num_cmdbufs ? mem : NULL; 70 70 mem += num_cmdbufs * sizeof(struct host1x_job_gather); 71 71 job->addr_phys = num_unpins ? mem : NULL; ··· 96 100 EXPORT_SYMBOL(host1x_job_put); 97 101 98 102 void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, 99 - u32 words, u32 offset) 103 + unsigned int words, unsigned int offset) 100 104 { 101 - struct host1x_job_gather *cur_gather = &job->gathers[job->num_gathers]; 105 + struct host1x_job_gather *gather = &job->gathers[job->num_gathers]; 102 106 103 - cur_gather->words = words; 104 - cur_gather->bo = bo; 105 - cur_gather->offset = offset; 107 + gather->words = words; 108 + gather->bo = bo; 109 + gather->offset = offset; 110 + 106 111 job->num_gathers++; 107 112 } 108 113 EXPORT_SYMBOL(host1x_job_add_gather); 109 - 110 - /* 111 - * NULL an already satisfied WAIT_SYNCPT host method, by patching its 112 - * args in the command stream. The method data is changed to reference 113 - * a reserved (never given out or incr) HOST1X_SYNCPT_RESERVED syncpt 114 - * with a matching threshold value of 0, so is guaranteed to be popped 115 - * by the host HW. 116 - */ 117 - static void host1x_syncpt_patch_offset(struct host1x_syncpt *sp, 118 - struct host1x_bo *h, u32 offset) 119 - { 120 - void *patch_addr = NULL; 121 - 122 - /* patch the wait */ 123 - patch_addr = host1x_bo_kmap(h, offset >> PAGE_SHIFT); 124 - if (patch_addr) { 125 - host1x_syncpt_patch_wait(sp, 126 - patch_addr + (offset & ~PAGE_MASK)); 127 - host1x_bo_kunmap(h, offset >> PAGE_SHIFT, patch_addr); 128 - } else 129 - pr_err("Could not map cmdbuf for wait check\n"); 130 - } 131 - 132 - /* 133 - * Check driver supplied waitchk structs for syncpt thresholds 134 - * that have already been satisfied and NULL the comparison (to 135 - * avoid a wrap condition in the HW). 136 - */ 137 - static int do_waitchks(struct host1x_job *job, struct host1x *host, 138 - struct host1x_job_gather *g) 139 - { 140 - struct host1x_bo *patch = g->bo; 141 - int i; 142 - 143 - /* compare syncpt vs wait threshold */ 144 - for (i = 0; i < job->num_waitchk; i++) { 145 - struct host1x_waitchk *wait = &job->waitchk[i]; 146 - struct host1x_syncpt *sp = 147 - host1x_syncpt_get(host, wait->syncpt_id); 148 - 149 - /* validate syncpt id */ 150 - if (wait->syncpt_id > host1x_syncpt_nb_pts(host)) 151 - continue; 152 - 153 - /* skip all other gathers */ 154 - if (patch != wait->bo) 155 - continue; 156 - 157 - trace_host1x_syncpt_wait_check(wait->bo, wait->offset, 158 - wait->syncpt_id, wait->thresh, 159 - host1x_syncpt_read_min(sp)); 160 - 161 - if (host1x_syncpt_is_expired(sp, wait->thresh)) { 162 - dev_dbg(host->dev, 163 - "drop WAIT id %u (%s) thresh 0x%x, min 0x%x\n", 164 - wait->syncpt_id, sp->name, wait->thresh, 165 - host1x_syncpt_read_min(sp)); 166 - 167 - host1x_syncpt_patch_offset(sp, patch, 168 - g->offset + wait->offset); 169 - } 170 - 171 - wait->bo = NULL; 172 - } 173 - 174 - return 0; 175 - } 176 114 177 115 static unsigned int pin_job(struct host1x *host, struct host1x_job *job) 178 116 { ··· 116 186 job->num_unpins = 0; 117 187 118 188 for (i = 0; i < job->num_relocs; i++) { 119 - struct host1x_reloc *reloc = &job->relocarray[i]; 189 + struct host1x_reloc *reloc = &job->relocs[i]; 120 190 struct sg_table *sgt; 121 191 dma_addr_t phys_addr; 122 192 ··· 197 267 198 268 static int do_relocs(struct host1x_job *job, struct host1x_job_gather *g) 199 269 { 200 - int i = 0; 201 270 u32 last_page = ~0; 202 271 void *cmdbuf_page_addr = NULL; 203 272 struct host1x_bo *cmdbuf = g->bo; 273 + unsigned int i; 204 274 205 275 /* pin & patch the relocs for one gather */ 206 276 for (i = 0; i < job->num_relocs; i++) { 207 - struct host1x_reloc *reloc = &job->relocarray[i]; 277 + struct host1x_reloc *reloc = &job->relocs[i]; 208 278 u32 reloc_addr = (job->reloc_addr_phys[i] + 209 279 reloc->target.offset) >> reloc->shift; 210 280 u32 *target; ··· 261 331 return true; 262 332 } 263 333 264 - static bool check_wait(struct host1x_waitchk *wait, struct host1x_bo *cmdbuf, 265 - unsigned int offset) 266 - { 267 - offset *= sizeof(u32); 268 - 269 - if (wait->bo != cmdbuf || wait->offset != offset) 270 - return false; 271 - 272 - return true; 273 - } 274 - 275 334 struct host1x_firewall { 276 335 struct host1x_job *job; 277 336 struct device *dev; 278 337 279 338 unsigned int num_relocs; 280 339 struct host1x_reloc *reloc; 281 - 282 - unsigned int num_waitchks; 283 - struct host1x_waitchk *waitchk; 284 340 285 341 struct host1x_bo *cmdbuf; 286 342 unsigned int offset; ··· 292 376 293 377 fw->num_relocs--; 294 378 fw->reloc++; 295 - } 296 - 297 - if (offset == HOST1X_WAIT_SYNCPT_OFFSET) { 298 - if (fw->class != HOST1X_CLASS_HOST1X) 299 - return -EINVAL; 300 - 301 - if (!fw->num_waitchks) 302 - return -EINVAL; 303 - 304 - if (!check_wait(fw->waitchk, fw->cmdbuf, fw->offset)) 305 - return -EINVAL; 306 - 307 - fw->num_waitchks--; 308 - fw->waitchk++; 309 379 } 310 380 311 381 return 0; ··· 452 550 struct host1x_firewall fw; 453 551 size_t size = 0; 454 552 size_t offset = 0; 455 - int i; 553 + unsigned int i; 456 554 457 555 fw.job = job; 458 556 fw.dev = dev; 459 - fw.reloc = job->relocarray; 557 + fw.reloc = job->relocs; 460 558 fw.num_relocs = job->num_relocs; 461 - fw.waitchk = job->waitchk; 462 - fw.num_waitchks = job->num_waitchk; 463 559 fw.class = job->class; 464 560 465 561 for (i = 0; i < job->num_gathers; i++) { ··· 504 604 offset += g->words * sizeof(u32); 505 605 } 506 606 507 - /* No relocs and waitchks should remain at this point */ 508 - if (fw.num_relocs || fw.num_waitchks) 607 + /* No relocs should remain at this point */ 608 + if (fw.num_relocs) 509 609 return -EINVAL; 510 610 511 611 return 0; ··· 516 616 int err; 517 617 unsigned int i, j; 518 618 struct host1x *host = dev_get_drvdata(dev->parent); 519 - DECLARE_BITMAP(waitchk_mask, host1x_syncpt_nb_pts(host)); 520 - 521 - bitmap_zero(waitchk_mask, host1x_syncpt_nb_pts(host)); 522 - for (i = 0; i < job->num_waitchk; i++) { 523 - u32 syncpt_id = job->waitchk[i].syncpt_id; 524 - 525 - if (syncpt_id < host1x_syncpt_nb_pts(host)) 526 - set_bit(syncpt_id, waitchk_mask); 527 - } 528 - 529 - /* get current syncpt values for waitchk */ 530 - for_each_set_bit(i, waitchk_mask, host1x_syncpt_nb_pts(host)) 531 - host1x_syncpt_load(host->syncpt + i); 532 619 533 620 /* pin memory */ 534 621 err = pin_job(host, job); ··· 548 661 } 549 662 550 663 err = do_relocs(job, g); 551 - if (err) 552 - break; 553 - 554 - err = do_waitchks(job, host, g); 555 664 if (err) 556 665 break; 557 666 }
+2 -2
drivers/gpu/host1x/job.h
··· 20 20 #define __HOST1X_JOB_H 21 21 22 22 struct host1x_job_gather { 23 - u32 words; 23 + unsigned int words; 24 24 dma_addr_t base; 25 25 struct host1x_bo *bo; 26 - u32 offset; 26 + unsigned int offset; 27 27 bool handled; 28 28 }; 29 29
+2 -8
drivers/gpu/host1x/syncpt.c
··· 57 57 struct host1x_client *client, 58 58 unsigned long flags) 59 59 { 60 - int i; 61 60 struct host1x_syncpt *sp = host->syncpt; 61 + unsigned int i; 62 62 char *name; 63 63 64 64 mutex_lock(&host->syncpt_mutex); ··· 255 255 } 256 256 257 257 /* schedule a wakeup when the syncpoint value is reached */ 258 - err = host1x_intr_add_action(sp->host, sp->id, thresh, 258 + err = host1x_intr_add_action(sp->host, sp, thresh, 259 259 HOST1X_INTR_ACTION_WAKEUP_INTERRUPTIBLE, 260 260 &wq, waiter, &ref); 261 261 if (err) ··· 371 371 return future_val - thresh >= current_val - thresh; 372 372 else 373 373 return (s32)(current_val - thresh) >= 0; 374 - } 375 - 376 - /* remove a wait pointed to by patch_addr */ 377 - int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) 378 - { 379 - return host1x_hw_syncpt_patch_wait(sp->host, sp, patch_addr); 380 374 } 381 375 382 376 int host1x_syncpt_init(struct host1x *host)
-3
drivers/gpu/host1x/syncpt.h
··· 124 124 return sp->id < host1x_syncpt_nb_pts(sp->host); 125 125 } 126 126 127 - /* Patch a wait by replacing it with a wait for syncpt 0 value 0 */ 128 - int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr); 129 - 130 127 #endif
+6 -18
include/linux/host1x.h
··· 192 192 unsigned long shift; 193 193 }; 194 194 195 - struct host1x_waitchk { 196 - struct host1x_bo *bo; 197 - u32 offset; 198 - u32 syncpt_id; 199 - u32 thresh; 200 - }; 201 - 202 195 struct host1x_job { 203 196 /* When refcount goes to zero, job can be freed */ 204 197 struct kref ref; ··· 202 209 /* Channel where job is submitted to */ 203 210 struct host1x_channel *channel; 204 211 205 - u32 client; 212 + /* client where the job originated */ 213 + struct host1x_client *client; 206 214 207 215 /* Gathers and their memory */ 208 216 struct host1x_job_gather *gathers; 209 217 unsigned int num_gathers; 210 218 211 - /* Wait checks to be processed at submit time */ 212 - struct host1x_waitchk *waitchk; 213 - unsigned int num_waitchk; 214 - u32 waitchk_mask; 215 - 216 219 /* Array of handles to be pinned & unpinned */ 217 - struct host1x_reloc *relocarray; 220 + struct host1x_reloc *relocs; 218 221 unsigned int num_relocs; 219 222 struct host1x_job_unpin_data *unpins; 220 223 unsigned int num_unpins; ··· 250 261 }; 251 262 252 263 struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, 253 - u32 num_cmdbufs, u32 num_relocs, 254 - u32 num_waitchks); 255 - void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *mem_id, 256 - u32 words, u32 offset); 264 + u32 num_cmdbufs, u32 num_relocs); 265 + void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, 266 + unsigned int words, unsigned int offset); 257 267 struct host1x_job *host1x_job_get(struct host1x_job *job); 258 268 void host1x_job_put(struct host1x_job *job); 259 269 int host1x_job_pin(struct host1x_job *job, struct device *dev);
+7 -9
include/trace/events/host1x.h
··· 115 115 ); 116 116 117 117 TRACE_EVENT(host1x_channel_submit, 118 - TP_PROTO(const char *name, u32 cmdbufs, u32 relocs, u32 waitchks, 119 - u32 syncpt_id, u32 syncpt_incrs), 118 + TP_PROTO(const char *name, u32 cmdbufs, u32 relocs, u32 syncpt_id, 119 + u32 syncpt_incrs), 120 120 121 - TP_ARGS(name, cmdbufs, relocs, waitchks, syncpt_id, syncpt_incrs), 121 + TP_ARGS(name, cmdbufs, relocs, syncpt_id, syncpt_incrs), 122 122 123 123 TP_STRUCT__entry( 124 124 __field(const char *, name) 125 125 __field(u32, cmdbufs) 126 126 __field(u32, relocs) 127 - __field(u32, waitchks) 128 127 __field(u32, syncpt_id) 129 128 __field(u32, syncpt_incrs) 130 129 ), ··· 132 133 __entry->name = name; 133 134 __entry->cmdbufs = cmdbufs; 134 135 __entry->relocs = relocs; 135 - __entry->waitchks = waitchks; 136 136 __entry->syncpt_id = syncpt_id; 137 137 __entry->syncpt_incrs = syncpt_incrs; 138 138 ), 139 139 140 - TP_printk("name=%s, cmdbufs=%u, relocs=%u, waitchks=%d," 141 - "syncpt_id=%u, syncpt_incrs=%u", 142 - __entry->name, __entry->cmdbufs, __entry->relocs, __entry->waitchks, 143 - __entry->syncpt_id, __entry->syncpt_incrs) 140 + TP_printk("name=%s, cmdbufs=%u, relocs=%u, syncpt_id=%u, " 141 + "syncpt_incrs=%u", 142 + __entry->name, __entry->cmdbufs, __entry->relocs, 143 + __entry->syncpt_id, __entry->syncpt_incrs) 144 144 ); 145 145 146 146 TRACE_EVENT(host1x_channel_submitted,
+492 -20
include/uapi/drm/tegra_drm.h
··· 32 32 #define DRM_TEGRA_GEM_CREATE_TILED (1 << 0) 33 33 #define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1) 34 34 35 + /** 36 + * struct drm_tegra_gem_create - parameters for the GEM object creation IOCTL 37 + */ 35 38 struct drm_tegra_gem_create { 39 + /** 40 + * @size: 41 + * 42 + * The size, in bytes, of the buffer object to be created. 43 + */ 36 44 __u64 size; 45 + 46 + /** 47 + * @flags: 48 + * 49 + * A bitmask of flags that influence the creation of GEM objects: 50 + * 51 + * DRM_TEGRA_GEM_CREATE_TILED 52 + * Use the 16x16 tiling format for this buffer. 53 + * 54 + * DRM_TEGRA_GEM_CREATE_BOTTOM_UP 55 + * The buffer has a bottom-up layout. 56 + */ 37 57 __u32 flags; 58 + 59 + /** 60 + * @handle: 61 + * 62 + * The handle of the created GEM object. Set by the kernel upon 63 + * successful completion of the IOCTL. 64 + */ 38 65 __u32 handle; 39 66 }; 40 67 68 + /** 69 + * struct drm_tegra_gem_mmap - parameters for the GEM mmap IOCTL 70 + */ 41 71 struct drm_tegra_gem_mmap { 72 + /** 73 + * @handle: 74 + * 75 + * Handle of the GEM object to obtain an mmap offset for. 76 + */ 42 77 __u32 handle; 78 + 79 + /** 80 + * @pad: 81 + * 82 + * Structure padding that may be used in the future. Must be 0. 83 + */ 43 84 __u32 pad; 85 + 86 + /** 87 + * @offset: 88 + * 89 + * The mmap offset for the given GEM object. Set by the kernel upon 90 + * successful completion of the IOCTL. 91 + */ 44 92 __u64 offset; 45 93 }; 46 94 95 + /** 96 + * struct drm_tegra_syncpt_read - parameters for the read syncpoint IOCTL 97 + */ 47 98 struct drm_tegra_syncpt_read { 99 + /** 100 + * @id: 101 + * 102 + * ID of the syncpoint to read the current value from. 103 + */ 48 104 __u32 id; 105 + 106 + /** 107 + * @value: 108 + * 109 + * The current syncpoint value. Set by the kernel upon successful 110 + * completion of the IOCTL. 111 + */ 49 112 __u32 value; 50 113 }; 51 114 115 + /** 116 + * struct drm_tegra_syncpt_incr - parameters for the increment syncpoint IOCTL 117 + */ 52 118 struct drm_tegra_syncpt_incr { 119 + /** 120 + * @id: 121 + * 122 + * ID of the syncpoint to increment. 123 + */ 53 124 __u32 id; 125 + 126 + /** 127 + * @pad: 128 + * 129 + * Structure padding that may be used in the future. Must be 0. 130 + */ 54 131 __u32 pad; 55 132 }; 56 133 134 + /** 135 + * struct drm_tegra_syncpt_wait - parameters for the wait syncpoint IOCTL 136 + */ 57 137 struct drm_tegra_syncpt_wait { 138 + /** 139 + * @id: 140 + * 141 + * ID of the syncpoint to wait on. 142 + */ 58 143 __u32 id; 144 + 145 + /** 146 + * @thresh: 147 + * 148 + * Threshold value for which to wait. 149 + */ 59 150 __u32 thresh; 151 + 152 + /** 153 + * @timeout: 154 + * 155 + * Timeout, in milliseconds, to wait. 156 + */ 60 157 __u32 timeout; 158 + 159 + /** 160 + * @value: 161 + * 162 + * The new syncpoint value after the wait. Set by the kernel upon 163 + * successful completion of the IOCTL. 164 + */ 61 165 __u32 value; 62 166 }; 63 167 64 168 #define DRM_TEGRA_NO_TIMEOUT (0xffffffff) 65 169 170 + /** 171 + * struct drm_tegra_open_channel - parameters for the open channel IOCTL 172 + */ 66 173 struct drm_tegra_open_channel { 174 + /** 175 + * @client: 176 + * 177 + * The client ID for this channel. 178 + */ 67 179 __u32 client; 180 + 181 + /** 182 + * @pad: 183 + * 184 + * Structure padding that may be used in the future. Must be 0. 185 + */ 68 186 __u32 pad; 187 + 188 + /** 189 + * @context: 190 + * 191 + * The application context of this channel. Set by the kernel upon 192 + * successful completion of the IOCTL. This context needs to be passed 193 + * to the DRM_TEGRA_CHANNEL_CLOSE or the DRM_TEGRA_SUBMIT IOCTLs. 194 + */ 69 195 __u64 context; 70 196 }; 71 197 198 + /** 199 + * struct drm_tegra_close_channel - parameters for the close channel IOCTL 200 + */ 72 201 struct drm_tegra_close_channel { 202 + /** 203 + * @context: 204 + * 205 + * The application context of this channel. This is obtained from the 206 + * DRM_TEGRA_OPEN_CHANNEL IOCTL. 207 + */ 73 208 __u64 context; 74 209 }; 75 210 211 + /** 212 + * struct drm_tegra_get_syncpt - parameters for the get syncpoint IOCTL 213 + */ 76 214 struct drm_tegra_get_syncpt { 215 + /** 216 + * @context: 217 + * 218 + * The application context identifying the channel for which to obtain 219 + * the syncpoint ID. 220 + */ 77 221 __u64 context; 222 + 223 + /** 224 + * @index: 225 + * 226 + * Index of the client syncpoint for which to obtain the ID. 227 + */ 78 228 __u32 index; 229 + 230 + /** 231 + * @id: 232 + * 233 + * The ID of the given syncpoint. Set by the kernel upon successful 234 + * completion of the IOCTL. 235 + */ 79 236 __u32 id; 80 237 }; 81 238 239 + /** 240 + * struct drm_tegra_get_syncpt_base - parameters for the get wait base IOCTL 241 + */ 82 242 struct drm_tegra_get_syncpt_base { 243 + /** 244 + * @context: 245 + * 246 + * The application context identifying for which channel to obtain the 247 + * wait base. 248 + */ 83 249 __u64 context; 250 + 251 + /** 252 + * @syncpt: 253 + * 254 + * ID of the syncpoint for which to obtain the wait base. 255 + */ 84 256 __u32 syncpt; 257 + 258 + /** 259 + * @id: 260 + * 261 + * The ID of the wait base corresponding to the client syncpoint. Set 262 + * by the kernel upon successful completion of the IOCTL. 263 + */ 85 264 __u32 id; 86 265 }; 87 266 267 + /** 268 + * struct drm_tegra_syncpt - syncpoint increment operation 269 + */ 88 270 struct drm_tegra_syncpt { 271 + /** 272 + * @id: 273 + * 274 + * ID of the syncpoint to operate on. 275 + */ 89 276 __u32 id; 277 + 278 + /** 279 + * @incrs: 280 + * 281 + * Number of increments to perform for the syncpoint. 282 + */ 90 283 __u32 incrs; 91 284 }; 92 285 286 + /** 287 + * struct drm_tegra_cmdbuf - structure describing a command buffer 288 + */ 93 289 struct drm_tegra_cmdbuf { 290 + /** 291 + * @handle: 292 + * 293 + * Handle to a GEM object containing the command buffer. 294 + */ 94 295 __u32 handle; 296 + 297 + /** 298 + * @offset: 299 + * 300 + * Offset, in bytes, into the GEM object identified by @handle at 301 + * which the command buffer starts. 302 + */ 95 303 __u32 offset; 304 + 305 + /** 306 + * @words: 307 + * 308 + * Number of 32-bit words in this command buffer. 309 + */ 96 310 __u32 words; 311 + 312 + /** 313 + * @pad: 314 + * 315 + * Structure padding that may be used in the future. Must be 0. 316 + */ 97 317 __u32 pad; 98 318 }; 99 319 320 + /** 321 + * struct drm_tegra_reloc - GEM object relocation structure 322 + */ 100 323 struct drm_tegra_reloc { 101 324 struct { 325 + /** 326 + * @cmdbuf.handle: 327 + * 328 + * Handle to the GEM object containing the command buffer for 329 + * which to perform this GEM object relocation. 330 + */ 102 331 __u32 handle; 332 + 333 + /** 334 + * @cmdbuf.offset: 335 + * 336 + * Offset, in bytes, into the command buffer at which to 337 + * insert the relocated address. 338 + */ 103 339 __u32 offset; 104 340 } cmdbuf; 105 341 struct { 342 + /** 343 + * @target.handle: 344 + * 345 + * Handle to the GEM object to be relocated. 346 + */ 106 347 __u32 handle; 348 + 349 + /** 350 + * @target.offset: 351 + * 352 + * Offset, in bytes, into the target GEM object at which the 353 + * relocated data starts. 354 + */ 107 355 __u32 offset; 108 356 } target; 357 + 358 + /** 359 + * @shift: 360 + * 361 + * The number of bits by which to shift relocated addresses. 362 + */ 109 363 __u32 shift; 364 + 365 + /** 366 + * @pad: 367 + * 368 + * Structure padding that may be used in the future. Must be 0. 369 + */ 110 370 __u32 pad; 111 371 }; 112 372 373 + /** 374 + * struct drm_tegra_waitchk - wait check structure 375 + */ 113 376 struct drm_tegra_waitchk { 377 + /** 378 + * @handle: 379 + * 380 + * Handle to the GEM object containing a command stream on which to 381 + * perform the wait check. 382 + */ 114 383 __u32 handle; 384 + 385 + /** 386 + * @offset: 387 + * 388 + * Offset, in bytes, of the location in the command stream to perform 389 + * the wait check on. 390 + */ 115 391 __u32 offset; 392 + 393 + /** 394 + * @syncpt: 395 + * 396 + * ID of the syncpoint to wait check. 397 + */ 116 398 __u32 syncpt; 399 + 400 + /** 401 + * @thresh: 402 + * 403 + * Threshold value for which to check. 404 + */ 117 405 __u32 thresh; 118 406 }; 119 407 408 + /** 409 + * struct drm_tegra_submit - job submission structure 410 + */ 120 411 struct drm_tegra_submit { 412 + /** 413 + * @context: 414 + * 415 + * The application context identifying the channel to use for the 416 + * execution of this job. 417 + */ 121 418 __u64 context; 122 - __u32 num_syncpts; 123 - __u32 num_cmdbufs; 124 - __u32 num_relocs; 125 - __u32 num_waitchks; 126 - __u32 waitchk_mask; 127 - __u32 timeout; 128 - __u64 syncpts; 129 - __u64 cmdbufs; 130 - __u64 relocs; 131 - __u64 waitchks; 132 - __u32 fence; /* Return value */ 133 419 134 - __u32 reserved[5]; /* future expansion */ 420 + /** 421 + * @num_syncpts: 422 + * 423 + * The number of syncpoints operated on by this job. This defines the 424 + * length of the array pointed to by @syncpts. 425 + */ 426 + __u32 num_syncpts; 427 + 428 + /** 429 + * @num_cmdbufs: 430 + * 431 + * The number of command buffers to execute as part of this job. This 432 + * defines the length of the array pointed to by @cmdbufs. 433 + */ 434 + __u32 num_cmdbufs; 435 + 436 + /** 437 + * @num_relocs: 438 + * 439 + * The number of relocations to perform before executing this job. 440 + * This defines the length of the array pointed to by @relocs. 441 + */ 442 + __u32 num_relocs; 443 + 444 + /** 445 + * @num_waitchks: 446 + * 447 + * The number of wait checks to perform as part of this job. This 448 + * defines the length of the array pointed to by @waitchks. 449 + */ 450 + __u32 num_waitchks; 451 + 452 + /** 453 + * @waitchk_mask: 454 + * 455 + * Bitmask of valid wait checks. 456 + */ 457 + __u32 waitchk_mask; 458 + 459 + /** 460 + * @timeout: 461 + * 462 + * Timeout, in milliseconds, before this job is cancelled. 463 + */ 464 + __u32 timeout; 465 + 466 + /** 467 + * @syncpts: 468 + * 469 + * A pointer to an array of &struct drm_tegra_syncpt structures that 470 + * specify the syncpoint operations performed as part of this job. 471 + * The number of elements in the array must be equal to the value 472 + * given by @num_syncpts. 473 + */ 474 + __u64 syncpts; 475 + 476 + /** 477 + * @cmdbufs: 478 + * 479 + * A pointer to an array of &struct drm_tegra_cmdbuf structures that 480 + * define the command buffers to execute as part of this job. The 481 + * number of elements in the array must be equal to the value given 482 + * by @num_syncpts. 483 + */ 484 + __u64 cmdbufs; 485 + 486 + /** 487 + * @relocs: 488 + * 489 + * A pointer to an array of &struct drm_tegra_reloc structures that 490 + * specify the relocations that need to be performed before executing 491 + * this job. The number of elements in the array must be equal to the 492 + * value given by @num_relocs. 493 + */ 494 + __u64 relocs; 495 + 496 + /** 497 + * @waitchks: 498 + * 499 + * A pointer to an array of &struct drm_tegra_waitchk structures that 500 + * specify the wait checks to be performed while executing this job. 501 + * The number of elements in the array must be equal to the value 502 + * given by @num_waitchks. 503 + */ 504 + __u64 waitchks; 505 + 506 + /** 507 + * @fence: 508 + * 509 + * The threshold of the syncpoint associated with this job after it 510 + * has been completed. Set by the kernel upon successful completion of 511 + * the IOCTL. This can be used with the DRM_TEGRA_SYNCPT_WAIT IOCTL to 512 + * wait for this job to be finished. 513 + */ 514 + __u32 fence; 515 + 516 + /** 517 + * @reserved: 518 + * 519 + * This field is reserved for future use. Must be 0. 520 + */ 521 + __u32 reserved[5]; 135 522 }; 136 523 137 524 #define DRM_TEGRA_GEM_TILING_MODE_PITCH 0 138 525 #define DRM_TEGRA_GEM_TILING_MODE_TILED 1 139 526 #define DRM_TEGRA_GEM_TILING_MODE_BLOCK 2 140 527 528 + /** 529 + * struct drm_tegra_gem_set_tiling - parameters for the set tiling IOCTL 530 + */ 141 531 struct drm_tegra_gem_set_tiling { 142 - /* input */ 532 + /** 533 + * @handle: 534 + * 535 + * Handle to the GEM object for which to set the tiling parameters. 536 + */ 143 537 __u32 handle; 538 + 539 + /** 540 + * @mode: 541 + * 542 + * The tiling mode to set. Must be one of: 543 + * 544 + * DRM_TEGRA_GEM_TILING_MODE_PITCH 545 + * pitch linear format 546 + * 547 + * DRM_TEGRA_GEM_TILING_MODE_TILED 548 + * 16x16 tiling format 549 + * 550 + * DRM_TEGRA_GEM_TILING_MODE_BLOCK 551 + * 16Bx2 tiling format 552 + */ 144 553 __u32 mode; 554 + 555 + /** 556 + * @value: 557 + * 558 + * The value to set for the tiling mode parameter. 559 + */ 145 560 __u32 value; 561 + 562 + /** 563 + * @pad: 564 + * 565 + * Structure padding that may be used in the future. Must be 0. 566 + */ 146 567 __u32 pad; 147 568 }; 148 569 570 + /** 571 + * struct drm_tegra_gem_get_tiling - parameters for the get tiling IOCTL 572 + */ 149 573 struct drm_tegra_gem_get_tiling { 150 - /* input */ 574 + /** 575 + * @handle: 576 + * 577 + * Handle to the GEM object for which to query the tiling parameters. 578 + */ 151 579 __u32 handle; 152 - /* output */ 580 + 581 + /** 582 + * @mode: 583 + * 584 + * The tiling mode currently associated with the GEM object. Set by 585 + * the kernel upon successful completion of the IOCTL. 586 + */ 153 587 __u32 mode; 588 + 589 + /** 590 + * @value: 591 + * 592 + * The tiling mode parameter currently associated with the GEM object. 593 + * Set by the kernel upon successful completion of the IOCTL. 594 + */ 154 595 __u32 value; 596 + 597 + /** 598 + * @pad: 599 + * 600 + * Structure padding that may be used in the future. Must be 0. 601 + */ 155 602 __u32 pad; 156 603 }; 157 604 158 605 #define DRM_TEGRA_GEM_BOTTOM_UP (1 << 0) 159 606 #define DRM_TEGRA_GEM_FLAGS (DRM_TEGRA_GEM_BOTTOM_UP) 160 607 608 + /** 609 + * struct drm_tegra_gem_set_flags - parameters for the set flags IOCTL 610 + */ 161 611 struct drm_tegra_gem_set_flags { 162 - /* input */ 612 + /** 613 + * @handle: 614 + * 615 + * Handle to the GEM object for which to set the flags. 616 + */ 163 617 __u32 handle; 164 - /* output */ 618 + 619 + /** 620 + * @flags: 621 + * 622 + * The flags to set for the GEM object. 623 + */ 165 624 __u32 flags; 166 625 }; 167 626 627 + /** 628 + * struct drm_tegra_gem_get_flags - parameters for the get flags IOCTL 629 + */ 168 630 struct drm_tegra_gem_get_flags { 169 - /* input */ 631 + /** 632 + * @handle: 633 + * 634 + * Handle to the GEM object for which to query the flags. 635 + */ 170 636 __u32 handle; 171 - /* output */ 637 + 638 + /** 639 + * @flags: 640 + * 641 + * The flags currently associated with the GEM object. Set by the 642 + * kernel upon successful completion of the IOCTL. 643 + */ 172 644 __u32 flags; 173 645 }; 174 646 ··· 665 193 #define DRM_IOCTL_TEGRA_SYNCPT_INCR DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_INCR, struct drm_tegra_syncpt_incr) 666 194 #define DRM_IOCTL_TEGRA_SYNCPT_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_WAIT, struct drm_tegra_syncpt_wait) 667 195 #define DRM_IOCTL_TEGRA_OPEN_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_OPEN_CHANNEL, struct drm_tegra_open_channel) 668 - #define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_open_channel) 196 + #define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_close_channel) 669 197 #define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt) 670 198 #define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit) 671 199 #define DRM_IOCTL_TEGRA_GET_SYNCPT_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT_BASE, struct drm_tegra_get_syncpt_base)