15f60ed0dSThierry Reding /* 25f60ed0dSThierry Reding * Copyright (C) 2013 Avionic Design GmbH 35f60ed0dSThierry Reding * Copyright (C) 2013 NVIDIA Corporation 45f60ed0dSThierry Reding * 55f60ed0dSThierry Reding * This program is free software; you can redistribute it and/or modify 65f60ed0dSThierry Reding * it under the terms of the GNU General Public License version 2 as 75f60ed0dSThierry Reding * published by the Free Software Foundation. 85f60ed0dSThierry Reding */ 95f60ed0dSThierry Reding 105f60ed0dSThierry Reding #include <linux/clk.h> 115f60ed0dSThierry Reding #include <linux/host1x.h> 125f60ed0dSThierry Reding #include <linux/module.h> 135f60ed0dSThierry Reding #include <linux/platform_device.h> 14ca48080aSStephen Warren #include <linux/reset.h> 155f60ed0dSThierry Reding #include <linux/tegra-powergate.h> 165f60ed0dSThierry Reding 175f60ed0dSThierry Reding #include "drm.h" 185f60ed0dSThierry Reding #include "gem.h" 195f60ed0dSThierry Reding #include "gr3d.h" 205f60ed0dSThierry Reding 215f60ed0dSThierry Reding struct gr3d { 225f60ed0dSThierry Reding struct tegra_drm_client client; 235f60ed0dSThierry Reding struct host1x_channel *channel; 245f60ed0dSThierry Reding struct clk *clk_secondary; 255f60ed0dSThierry Reding struct clk *clk; 26ca48080aSStephen Warren struct reset_control *rst_secondary; 27ca48080aSStephen Warren struct reset_control *rst; 285f60ed0dSThierry Reding 295f60ed0dSThierry Reding DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); 305f60ed0dSThierry Reding }; 315f60ed0dSThierry Reding 325f60ed0dSThierry Reding static inline struct gr3d *to_gr3d(struct tegra_drm_client *client) 335f60ed0dSThierry Reding { 345f60ed0dSThierry Reding return container_of(client, struct gr3d, client); 355f60ed0dSThierry Reding } 365f60ed0dSThierry Reding 375f60ed0dSThierry Reding static int gr3d_init(struct host1x_client *client) 385f60ed0dSThierry Reding { 395f60ed0dSThierry Reding struct tegra_drm_client *drm = host1x_to_drm_client(client); 405f60ed0dSThierry Reding struct tegra_drm *tegra = dev_get_drvdata(client->parent); 41977386a0SThierry Reding unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 425f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(drm); 435f60ed0dSThierry Reding 445f60ed0dSThierry Reding gr3d->channel = host1x_channel_request(client->dev); 455f60ed0dSThierry Reding if (!gr3d->channel) 465f60ed0dSThierry Reding return -ENOMEM; 475f60ed0dSThierry Reding 48977386a0SThierry Reding client->syncpts[0] = host1x_syncpt_request(client->dev, flags); 495f60ed0dSThierry Reding if (!client->syncpts[0]) { 505f60ed0dSThierry Reding host1x_channel_free(gr3d->channel); 515f60ed0dSThierry Reding return -ENOMEM; 525f60ed0dSThierry Reding } 535f60ed0dSThierry Reding 545f60ed0dSThierry Reding return tegra_drm_register_client(tegra, drm); 555f60ed0dSThierry Reding } 565f60ed0dSThierry Reding 575f60ed0dSThierry Reding static int gr3d_exit(struct host1x_client *client) 585f60ed0dSThierry Reding { 595f60ed0dSThierry Reding struct tegra_drm_client *drm = host1x_to_drm_client(client); 605f60ed0dSThierry Reding struct tegra_drm *tegra = dev_get_drvdata(client->parent); 615f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(drm); 625f60ed0dSThierry Reding int err; 635f60ed0dSThierry Reding 645f60ed0dSThierry Reding err = tegra_drm_unregister_client(tegra, drm); 655f60ed0dSThierry Reding if (err < 0) 665f60ed0dSThierry Reding return err; 675f60ed0dSThierry Reding 685f60ed0dSThierry Reding host1x_syncpt_free(client->syncpts[0]); 695f60ed0dSThierry Reding host1x_channel_free(gr3d->channel); 705f60ed0dSThierry Reding 715f60ed0dSThierry Reding return 0; 725f60ed0dSThierry Reding } 735f60ed0dSThierry Reding 745f60ed0dSThierry Reding static const struct host1x_client_ops gr3d_client_ops = { 755f60ed0dSThierry Reding .init = gr3d_init, 765f60ed0dSThierry Reding .exit = gr3d_exit, 775f60ed0dSThierry Reding }; 785f60ed0dSThierry Reding 795f60ed0dSThierry Reding static int gr3d_open_channel(struct tegra_drm_client *client, 805f60ed0dSThierry Reding struct tegra_drm_context *context) 815f60ed0dSThierry Reding { 825f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(client); 835f60ed0dSThierry Reding 845f60ed0dSThierry Reding context->channel = host1x_channel_get(gr3d->channel); 855f60ed0dSThierry Reding if (!context->channel) 865f60ed0dSThierry Reding return -ENOMEM; 875f60ed0dSThierry Reding 885f60ed0dSThierry Reding return 0; 895f60ed0dSThierry Reding } 905f60ed0dSThierry Reding 915f60ed0dSThierry Reding static void gr3d_close_channel(struct tegra_drm_context *context) 925f60ed0dSThierry Reding { 935f60ed0dSThierry Reding host1x_channel_put(context->channel); 945f60ed0dSThierry Reding } 955f60ed0dSThierry Reding 965f60ed0dSThierry Reding static int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset) 975f60ed0dSThierry Reding { 985f60ed0dSThierry Reding struct gr3d *gr3d = dev_get_drvdata(dev); 995f60ed0dSThierry Reding 1005f60ed0dSThierry Reding switch (class) { 1015f60ed0dSThierry Reding case HOST1X_CLASS_HOST1X: 1025f60ed0dSThierry Reding if (offset == 0x2b) 1035f60ed0dSThierry Reding return 1; 1045f60ed0dSThierry Reding 1055f60ed0dSThierry Reding break; 1065f60ed0dSThierry Reding 1075f60ed0dSThierry Reding case HOST1X_CLASS_GR3D: 1085f60ed0dSThierry Reding if (offset >= GR3D_NUM_REGS) 1095f60ed0dSThierry Reding break; 1105f60ed0dSThierry Reding 1115f60ed0dSThierry Reding if (test_bit(offset, gr3d->addr_regs)) 1125f60ed0dSThierry Reding return 1; 1135f60ed0dSThierry Reding 1145f60ed0dSThierry Reding break; 1155f60ed0dSThierry Reding } 1165f60ed0dSThierry Reding 1175f60ed0dSThierry Reding return 0; 1185f60ed0dSThierry Reding } 1195f60ed0dSThierry Reding 1205f60ed0dSThierry Reding static const struct tegra_drm_client_ops gr3d_ops = { 1215f60ed0dSThierry Reding .open_channel = gr3d_open_channel, 1225f60ed0dSThierry Reding .close_channel = gr3d_close_channel, 1235f60ed0dSThierry Reding .is_addr_reg = gr3d_is_addr_reg, 1245f60ed0dSThierry Reding .submit = tegra_drm_submit, 1255f60ed0dSThierry Reding }; 1265f60ed0dSThierry Reding 1275f60ed0dSThierry Reding static const struct of_device_id tegra_gr3d_match[] = { 1285f60ed0dSThierry Reding { .compatible = "nvidia,tegra114-gr3d" }, 1295f60ed0dSThierry Reding { .compatible = "nvidia,tegra30-gr3d" }, 1305f60ed0dSThierry Reding { .compatible = "nvidia,tegra20-gr3d" }, 1315f60ed0dSThierry Reding { } 1325f60ed0dSThierry Reding }; 1335f60ed0dSThierry Reding 1345f60ed0dSThierry Reding static const u32 gr3d_addr_regs[] = { 1355f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 0), 1365f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 1), 1375f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 2), 1385f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 3), 1395f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 4), 1405f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 5), 1415f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 6), 1425f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 7), 1435f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 8), 1445f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 9), 1455f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(10), 1465f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(11), 1475f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(12), 1485f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(13), 1495f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(14), 1505f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(15), 1515f60ed0dSThierry Reding GR3D_IDX_INDEX_BASE, 1525f60ed0dSThierry Reding GR3D_QR_ZTAG_ADDR, 1535f60ed0dSThierry Reding GR3D_QR_CTAG_ADDR, 1545f60ed0dSThierry Reding GR3D_QR_CZ_ADDR, 1555f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 0), 1565f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 1), 1575f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 2), 1585f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 3), 1595f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 4), 1605f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 5), 1615f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 6), 1625f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 7), 1635f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 8), 1645f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 9), 1655f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(10), 1665f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(11), 1675f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(12), 1685f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(13), 1695f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(14), 1705f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(15), 1715f60ed0dSThierry Reding GR3D_DW_MEMORY_OUTPUT_ADDRESS, 1725f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 0), 1735f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 1), 1745f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 2), 1755f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 3), 1765f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 4), 1775f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 5), 1785f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 6), 1795f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 7), 1805f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 8), 1815f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 9), 1825f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(10), 1835f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(11), 1845f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(12), 1855f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(13), 1865f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(14), 1875f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(15), 1885f60ed0dSThierry Reding GR3D_GLOBAL_SPILLSURFADDR, 1895f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 0), 1905f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 1), 1915f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 2), 1925f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 3), 1935f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 4), 1945f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 5), 1955f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 6), 1965f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 7), 1975f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 8), 1985f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 9), 1995f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(10), 2005f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(11), 2015f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(12), 2025f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(13), 2035f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(14), 2045f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(15), 2055f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 0), 2065f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 1), 2075f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 2), 2085f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 3), 2095f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 4), 2105f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 5), 2115f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 6), 2125f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 7), 2135f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 8), 2145f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 9), 2155f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(10), 2165f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(11), 2175f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(12), 2185f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(13), 2195f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(14), 2205f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(15), 2215f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 0), 2225f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 1), 2235f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 2), 2245f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 3), 2255f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 4), 2265f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 5), 2275f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 6), 2285f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 7), 2295f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 8), 2305f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 9), 2315f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(10), 2325f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(11), 2335f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(12), 2345f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(13), 2355f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(14), 2365f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(15), 2375f60ed0dSThierry Reding }; 2385f60ed0dSThierry Reding 2395f60ed0dSThierry Reding static int gr3d_probe(struct platform_device *pdev) 2405f60ed0dSThierry Reding { 2415f60ed0dSThierry Reding struct device_node *np = pdev->dev.of_node; 2425f60ed0dSThierry Reding struct host1x_syncpt **syncpts; 2435f60ed0dSThierry Reding struct gr3d *gr3d; 2445f60ed0dSThierry Reding unsigned int i; 2455f60ed0dSThierry Reding int err; 2465f60ed0dSThierry Reding 2475f60ed0dSThierry Reding gr3d = devm_kzalloc(&pdev->dev, sizeof(*gr3d), GFP_KERNEL); 2485f60ed0dSThierry Reding if (!gr3d) 2495f60ed0dSThierry Reding return -ENOMEM; 2505f60ed0dSThierry Reding 2515f60ed0dSThierry Reding syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL); 2525f60ed0dSThierry Reding if (!syncpts) 2535f60ed0dSThierry Reding return -ENOMEM; 2545f60ed0dSThierry Reding 2555f60ed0dSThierry Reding gr3d->clk = devm_clk_get(&pdev->dev, NULL); 2565f60ed0dSThierry Reding if (IS_ERR(gr3d->clk)) { 2575f60ed0dSThierry Reding dev_err(&pdev->dev, "cannot get clock\n"); 2585f60ed0dSThierry Reding return PTR_ERR(gr3d->clk); 2595f60ed0dSThierry Reding } 2605f60ed0dSThierry Reding 261ca48080aSStephen Warren gr3d->rst = devm_reset_control_get(&pdev->dev, "3d"); 262ca48080aSStephen Warren if (IS_ERR(gr3d->rst)) { 263ca48080aSStephen Warren dev_err(&pdev->dev, "cannot get reset\n"); 264ca48080aSStephen Warren return PTR_ERR(gr3d->rst); 265ca48080aSStephen Warren } 266ca48080aSStephen Warren 2675f60ed0dSThierry Reding if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) { 2685f60ed0dSThierry Reding gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2"); 2695f60ed0dSThierry Reding if (IS_ERR(gr3d->clk)) { 2705f60ed0dSThierry Reding dev_err(&pdev->dev, "cannot get secondary clock\n"); 2715f60ed0dSThierry Reding return PTR_ERR(gr3d->clk); 2725f60ed0dSThierry Reding } 273ca48080aSStephen Warren 274ca48080aSStephen Warren gr3d->rst_secondary = devm_reset_control_get(&pdev->dev, 275ca48080aSStephen Warren "3d2"); 276ca48080aSStephen Warren if (IS_ERR(gr3d->rst_secondary)) { 277ca48080aSStephen Warren dev_err(&pdev->dev, "cannot get secondary reset\n"); 278ca48080aSStephen Warren return PTR_ERR(gr3d->rst_secondary); 279ca48080aSStephen Warren } 2805f60ed0dSThierry Reding } 2815f60ed0dSThierry Reding 28280b28791SStephen Warren err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk, 28380b28791SStephen Warren gr3d->rst); 2845f60ed0dSThierry Reding if (err < 0) { 2855f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to power up 3D unit\n"); 2865f60ed0dSThierry Reding return err; 2875f60ed0dSThierry Reding } 2885f60ed0dSThierry Reding 2895f60ed0dSThierry Reding if (gr3d->clk_secondary) { 2905f60ed0dSThierry Reding err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1, 29180b28791SStephen Warren gr3d->clk_secondary, 29280b28791SStephen Warren gr3d->rst_secondary); 2935f60ed0dSThierry Reding if (err < 0) { 2945f60ed0dSThierry Reding dev_err(&pdev->dev, 2955f60ed0dSThierry Reding "failed to power up secondary 3D unit\n"); 2965f60ed0dSThierry Reding return err; 2975f60ed0dSThierry Reding } 2985f60ed0dSThierry Reding } 2995f60ed0dSThierry Reding 3005f60ed0dSThierry Reding INIT_LIST_HEAD(&gr3d->client.base.list); 3015f60ed0dSThierry Reding gr3d->client.base.ops = &gr3d_client_ops; 3025f60ed0dSThierry Reding gr3d->client.base.dev = &pdev->dev; 3035f60ed0dSThierry Reding gr3d->client.base.class = HOST1X_CLASS_GR3D; 3045f60ed0dSThierry Reding gr3d->client.base.syncpts = syncpts; 3055f60ed0dSThierry Reding gr3d->client.base.num_syncpts = 1; 3065f60ed0dSThierry Reding 3075f60ed0dSThierry Reding INIT_LIST_HEAD(&gr3d->client.list); 3085f60ed0dSThierry Reding gr3d->client.ops = &gr3d_ops; 3095f60ed0dSThierry Reding 3105f60ed0dSThierry Reding err = host1x_client_register(&gr3d->client.base); 3115f60ed0dSThierry Reding if (err < 0) { 3125f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 3135f60ed0dSThierry Reding err); 3145f60ed0dSThierry Reding return err; 3155f60ed0dSThierry Reding } 3165f60ed0dSThierry Reding 3175f60ed0dSThierry Reding /* initialize address register map */ 3185f60ed0dSThierry Reding for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++) 3195f60ed0dSThierry Reding set_bit(gr3d_addr_regs[i], gr3d->addr_regs); 3205f60ed0dSThierry Reding 3215f60ed0dSThierry Reding platform_set_drvdata(pdev, gr3d); 3225f60ed0dSThierry Reding 3235f60ed0dSThierry Reding return 0; 3245f60ed0dSThierry Reding } 3255f60ed0dSThierry Reding 3265f60ed0dSThierry Reding static int gr3d_remove(struct platform_device *pdev) 3275f60ed0dSThierry Reding { 3285f60ed0dSThierry Reding struct gr3d *gr3d = platform_get_drvdata(pdev); 3295f60ed0dSThierry Reding int err; 3305f60ed0dSThierry Reding 3315f60ed0dSThierry Reding err = host1x_client_unregister(&gr3d->client.base); 3325f60ed0dSThierry Reding if (err < 0) { 3335f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 3345f60ed0dSThierry Reding err); 3355f60ed0dSThierry Reding return err; 3365f60ed0dSThierry Reding } 3375f60ed0dSThierry Reding 3385f60ed0dSThierry Reding if (gr3d->clk_secondary) { 3395f60ed0dSThierry Reding tegra_powergate_power_off(TEGRA_POWERGATE_3D1); 3405f60ed0dSThierry Reding clk_disable_unprepare(gr3d->clk_secondary); 3415f60ed0dSThierry Reding } 3425f60ed0dSThierry Reding 3435f60ed0dSThierry Reding tegra_powergate_power_off(TEGRA_POWERGATE_3D); 3445f60ed0dSThierry Reding clk_disable_unprepare(gr3d->clk); 3455f60ed0dSThierry Reding 3465f60ed0dSThierry Reding return 0; 3475f60ed0dSThierry Reding } 3485f60ed0dSThierry Reding 3495f60ed0dSThierry Reding struct platform_driver tegra_gr3d_driver = { 3505f60ed0dSThierry Reding .driver = { 3515f60ed0dSThierry Reding .name = "tegra-gr3d", 3525f60ed0dSThierry Reding .of_match_table = tegra_gr3d_match, 3535f60ed0dSThierry Reding }, 3545f60ed0dSThierry Reding .probe = gr3d_probe, 3555f60ed0dSThierry Reding .remove = gr3d_remove, 3565f60ed0dSThierry Reding }; 357