18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Avionic Design GmbH 48c2ecf20Sopenharmony_ci * Copyright (C) 2013 NVIDIA Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/host1x.h> 98c2ecf20Sopenharmony_ci#include <linux/iommu.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/of_device.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/reset.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <soc/tegra/pmc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "drm.h" 188c2ecf20Sopenharmony_ci#include "gem.h" 198c2ecf20Sopenharmony_ci#include "gr3d.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct gr3d_soc { 228c2ecf20Sopenharmony_ci unsigned int version; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct gr3d { 268c2ecf20Sopenharmony_ci struct tegra_drm_client client; 278c2ecf20Sopenharmony_ci struct host1x_channel *channel; 288c2ecf20Sopenharmony_ci struct clk *clk_secondary; 298c2ecf20Sopenharmony_ci struct clk *clk; 308c2ecf20Sopenharmony_ci struct reset_control *rst_secondary; 318c2ecf20Sopenharmony_ci struct reset_control *rst; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci const struct gr3d_soc *soc; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline struct gr3d *to_gr3d(struct tegra_drm_client *client) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return container_of(client, struct gr3d, client); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int gr3d_init(struct host1x_client *client) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct tegra_drm_client *drm = host1x_to_drm_client(client); 468c2ecf20Sopenharmony_ci struct drm_device *dev = dev_get_drvdata(client->host); 478c2ecf20Sopenharmony_ci unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 488c2ecf20Sopenharmony_ci struct gr3d *gr3d = to_gr3d(drm); 498c2ecf20Sopenharmony_ci int err; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci gr3d->channel = host1x_channel_request(client); 528c2ecf20Sopenharmony_ci if (!gr3d->channel) 538c2ecf20Sopenharmony_ci return -ENOMEM; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci client->syncpts[0] = host1x_syncpt_request(client, flags); 568c2ecf20Sopenharmony_ci if (!client->syncpts[0]) { 578c2ecf20Sopenharmony_ci err = -ENOMEM; 588c2ecf20Sopenharmony_ci dev_err(client->dev, "failed to request syncpoint: %d\n", err); 598c2ecf20Sopenharmony_ci goto put; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci err = host1x_client_iommu_attach(client); 638c2ecf20Sopenharmony_ci if (err < 0) { 648c2ecf20Sopenharmony_ci dev_err(client->dev, "failed to attach to domain: %d\n", err); 658c2ecf20Sopenharmony_ci goto free; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci err = tegra_drm_register_client(dev->dev_private, drm); 698c2ecf20Sopenharmony_ci if (err < 0) { 708c2ecf20Sopenharmony_ci dev_err(client->dev, "failed to register client: %d\n", err); 718c2ecf20Sopenharmony_ci goto detach; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cidetach: 778c2ecf20Sopenharmony_ci host1x_client_iommu_detach(client); 788c2ecf20Sopenharmony_cifree: 798c2ecf20Sopenharmony_ci host1x_syncpt_free(client->syncpts[0]); 808c2ecf20Sopenharmony_ciput: 818c2ecf20Sopenharmony_ci host1x_channel_put(gr3d->channel); 828c2ecf20Sopenharmony_ci return err; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int gr3d_exit(struct host1x_client *client) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct tegra_drm_client *drm = host1x_to_drm_client(client); 888c2ecf20Sopenharmony_ci struct drm_device *dev = dev_get_drvdata(client->host); 898c2ecf20Sopenharmony_ci struct gr3d *gr3d = to_gr3d(drm); 908c2ecf20Sopenharmony_ci int err; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci err = tegra_drm_unregister_client(dev->dev_private, drm); 938c2ecf20Sopenharmony_ci if (err < 0) 948c2ecf20Sopenharmony_ci return err; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci host1x_client_iommu_detach(client); 978c2ecf20Sopenharmony_ci host1x_syncpt_free(client->syncpts[0]); 988c2ecf20Sopenharmony_ci host1x_channel_put(gr3d->channel); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const struct host1x_client_ops gr3d_client_ops = { 1048c2ecf20Sopenharmony_ci .init = gr3d_init, 1058c2ecf20Sopenharmony_ci .exit = gr3d_exit, 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int gr3d_open_channel(struct tegra_drm_client *client, 1098c2ecf20Sopenharmony_ci struct tegra_drm_context *context) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct gr3d *gr3d = to_gr3d(client); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci context->channel = host1x_channel_get(gr3d->channel); 1148c2ecf20Sopenharmony_ci if (!context->channel) 1158c2ecf20Sopenharmony_ci return -ENOMEM; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void gr3d_close_channel(struct tegra_drm_context *context) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci host1x_channel_put(context->channel); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct gr3d *gr3d = dev_get_drvdata(dev); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci switch (class) { 1308c2ecf20Sopenharmony_ci case HOST1X_CLASS_HOST1X: 1318c2ecf20Sopenharmony_ci if (offset == 0x2b) 1328c2ecf20Sopenharmony_ci return 1; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci case HOST1X_CLASS_GR3D: 1378c2ecf20Sopenharmony_ci if (offset >= GR3D_NUM_REGS) 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (test_bit(offset, gr3d->addr_regs)) 1418c2ecf20Sopenharmony_ci return 1; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct tegra_drm_client_ops gr3d_ops = { 1508c2ecf20Sopenharmony_ci .open_channel = gr3d_open_channel, 1518c2ecf20Sopenharmony_ci .close_channel = gr3d_close_channel, 1528c2ecf20Sopenharmony_ci .is_addr_reg = gr3d_is_addr_reg, 1538c2ecf20Sopenharmony_ci .submit = tegra_drm_submit, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct gr3d_soc tegra20_gr3d_soc = { 1578c2ecf20Sopenharmony_ci .version = 0x20, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct gr3d_soc tegra30_gr3d_soc = { 1618c2ecf20Sopenharmony_ci .version = 0x30, 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic const struct gr3d_soc tegra114_gr3d_soc = { 1658c2ecf20Sopenharmony_ci .version = 0x35, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_gr3d_match[] = { 1698c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra114-gr3d", .data = &tegra114_gr3d_soc }, 1708c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra30-gr3d", .data = &tegra30_gr3d_soc }, 1718c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra20-gr3d", .data = &tegra20_gr3d_soc }, 1728c2ecf20Sopenharmony_ci { } 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_gr3d_match); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic const u32 gr3d_addr_regs[] = { 1778c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 0), 1788c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 1), 1798c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 2), 1808c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 3), 1818c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 4), 1828c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 5), 1838c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 6), 1848c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 7), 1858c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 8), 1868c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE( 9), 1878c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE(10), 1888c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE(11), 1898c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE(12), 1908c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE(13), 1918c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE(14), 1928c2ecf20Sopenharmony_ci GR3D_IDX_ATTRIBUTE(15), 1938c2ecf20Sopenharmony_ci GR3D_IDX_INDEX_BASE, 1948c2ecf20Sopenharmony_ci GR3D_QR_ZTAG_ADDR, 1958c2ecf20Sopenharmony_ci GR3D_QR_CTAG_ADDR, 1968c2ecf20Sopenharmony_ci GR3D_QR_CZ_ADDR, 1978c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 0), 1988c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 1), 1998c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 2), 2008c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 3), 2018c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 4), 2028c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 5), 2038c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 6), 2048c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 7), 2058c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 8), 2068c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR( 9), 2078c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR(10), 2088c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR(11), 2098c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR(12), 2108c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR(13), 2118c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR(14), 2128c2ecf20Sopenharmony_ci GR3D_TEX_TEX_ADDR(15), 2138c2ecf20Sopenharmony_ci GR3D_DW_MEMORY_OUTPUT_ADDRESS, 2148c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 0), 2158c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 1), 2168c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 2), 2178c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 3), 2188c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 4), 2198c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 5), 2208c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 6), 2218c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 7), 2228c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 8), 2238c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR( 9), 2248c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR(10), 2258c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR(11), 2268c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR(12), 2278c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR(13), 2288c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR(14), 2298c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFADDR(15), 2308c2ecf20Sopenharmony_ci GR3D_GLOBAL_SPILLSURFADDR, 2318c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 0), 2328c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 1), 2338c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 2), 2348c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 3), 2358c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 4), 2368c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 5), 2378c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 6), 2388c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 7), 2398c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 8), 2408c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR( 9), 2418c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR(10), 2428c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR(11), 2438c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR(12), 2448c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR(13), 2458c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR(14), 2468c2ecf20Sopenharmony_ci GR3D_GLOBAL_SURFOVERADDR(15), 2478c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 0), 2488c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 1), 2498c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 2), 2508c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 3), 2518c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 4), 2528c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 5), 2538c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 6), 2548c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 7), 2558c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 8), 2568c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR( 9), 2578c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR(10), 2588c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR(11), 2598c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR(12), 2608c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR(13), 2618c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR(14), 2628c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP01SURFADDR(15), 2638c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 0), 2648c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 1), 2658c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 2), 2668c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 3), 2678c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 4), 2688c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 5), 2698c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 6), 2708c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 7), 2718c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 8), 2728c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR( 9), 2738c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR(10), 2748c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR(11), 2758c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR(12), 2768c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR(13), 2778c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR(14), 2788c2ecf20Sopenharmony_ci GR3D_GLOBAL_SAMP23SURFADDR(15), 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int gr3d_probe(struct platform_device *pdev) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 2848c2ecf20Sopenharmony_ci struct host1x_syncpt **syncpts; 2858c2ecf20Sopenharmony_ci struct gr3d *gr3d; 2868c2ecf20Sopenharmony_ci unsigned int i; 2878c2ecf20Sopenharmony_ci int err; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci gr3d = devm_kzalloc(&pdev->dev, sizeof(*gr3d), GFP_KERNEL); 2908c2ecf20Sopenharmony_ci if (!gr3d) 2918c2ecf20Sopenharmony_ci return -ENOMEM; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci gr3d->soc = of_device_get_match_data(&pdev->dev); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL); 2968c2ecf20Sopenharmony_ci if (!syncpts) 2978c2ecf20Sopenharmony_ci return -ENOMEM; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci gr3d->clk = devm_clk_get(&pdev->dev, NULL); 3008c2ecf20Sopenharmony_ci if (IS_ERR(gr3d->clk)) { 3018c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get clock\n"); 3028c2ecf20Sopenharmony_ci return PTR_ERR(gr3d->clk); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci gr3d->rst = devm_reset_control_get(&pdev->dev, "3d"); 3068c2ecf20Sopenharmony_ci if (IS_ERR(gr3d->rst)) { 3078c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get reset\n"); 3088c2ecf20Sopenharmony_ci return PTR_ERR(gr3d->rst); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) { 3128c2ecf20Sopenharmony_ci gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2"); 3138c2ecf20Sopenharmony_ci if (IS_ERR(gr3d->clk_secondary)) { 3148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get secondary clock\n"); 3158c2ecf20Sopenharmony_ci return PTR_ERR(gr3d->clk_secondary); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci gr3d->rst_secondary = devm_reset_control_get(&pdev->dev, 3198c2ecf20Sopenharmony_ci "3d2"); 3208c2ecf20Sopenharmony_ci if (IS_ERR(gr3d->rst_secondary)) { 3218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get secondary reset\n"); 3228c2ecf20Sopenharmony_ci return PTR_ERR(gr3d->rst_secondary); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk, 3278c2ecf20Sopenharmony_ci gr3d->rst); 3288c2ecf20Sopenharmony_ci if (err < 0) { 3298c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to power up 3D unit\n"); 3308c2ecf20Sopenharmony_ci return err; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (gr3d->clk_secondary) { 3348c2ecf20Sopenharmony_ci err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1, 3358c2ecf20Sopenharmony_ci gr3d->clk_secondary, 3368c2ecf20Sopenharmony_ci gr3d->rst_secondary); 3378c2ecf20Sopenharmony_ci if (err < 0) { 3388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 3398c2ecf20Sopenharmony_ci "failed to power up secondary 3D unit\n"); 3408c2ecf20Sopenharmony_ci return err; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&gr3d->client.base.list); 3458c2ecf20Sopenharmony_ci gr3d->client.base.ops = &gr3d_client_ops; 3468c2ecf20Sopenharmony_ci gr3d->client.base.dev = &pdev->dev; 3478c2ecf20Sopenharmony_ci gr3d->client.base.class = HOST1X_CLASS_GR3D; 3488c2ecf20Sopenharmony_ci gr3d->client.base.syncpts = syncpts; 3498c2ecf20Sopenharmony_ci gr3d->client.base.num_syncpts = 1; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&gr3d->client.list); 3528c2ecf20Sopenharmony_ci gr3d->client.version = gr3d->soc->version; 3538c2ecf20Sopenharmony_ci gr3d->client.ops = &gr3d_ops; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci err = host1x_client_register(&gr3d->client.base); 3568c2ecf20Sopenharmony_ci if (err < 0) { 3578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register host1x client: %d\n", 3588c2ecf20Sopenharmony_ci err); 3598c2ecf20Sopenharmony_ci return err; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* initialize address register map */ 3638c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++) 3648c2ecf20Sopenharmony_ci set_bit(gr3d_addr_regs[i], gr3d->addr_regs); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, gr3d); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int gr3d_remove(struct platform_device *pdev) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct gr3d *gr3d = platform_get_drvdata(pdev); 3748c2ecf20Sopenharmony_ci int err; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci err = host1x_client_unregister(&gr3d->client.base); 3778c2ecf20Sopenharmony_ci if (err < 0) { 3788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 3798c2ecf20Sopenharmony_ci err); 3808c2ecf20Sopenharmony_ci return err; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (gr3d->clk_secondary) { 3848c2ecf20Sopenharmony_ci reset_control_assert(gr3d->rst_secondary); 3858c2ecf20Sopenharmony_ci tegra_powergate_power_off(TEGRA_POWERGATE_3D1); 3868c2ecf20Sopenharmony_ci clk_disable_unprepare(gr3d->clk_secondary); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci reset_control_assert(gr3d->rst); 3908c2ecf20Sopenharmony_ci tegra_powergate_power_off(TEGRA_POWERGATE_3D); 3918c2ecf20Sopenharmony_ci clk_disable_unprepare(gr3d->clk); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistruct platform_driver tegra_gr3d_driver = { 3978c2ecf20Sopenharmony_ci .driver = { 3988c2ecf20Sopenharmony_ci .name = "tegra-gr3d", 3998c2ecf20Sopenharmony_ci .of_match_table = tegra_gr3d_match, 4008c2ecf20Sopenharmony_ci }, 4018c2ecf20Sopenharmony_ci .probe = gr3d_probe, 4028c2ecf20Sopenharmony_ci .remove = gr3d_remove, 4038c2ecf20Sopenharmony_ci}; 404