1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25f60ed0dSThierry Reding /* 35f60ed0dSThierry Reding * Copyright (C) 2013 Avionic Design GmbH 45f60ed0dSThierry Reding * Copyright (C) 2013 NVIDIA Corporation 55f60ed0dSThierry Reding */ 65f60ed0dSThierry Reding 75f60ed0dSThierry Reding #include <linux/clk.h> 85f60ed0dSThierry Reding #include <linux/host1x.h> 9c9ac5217SDmitry Osipenko #include <linux/iommu.h> 105f60ed0dSThierry Reding #include <linux/module.h> 1133f150eaSThierry Reding #include <linux/of_device.h> 125f60ed0dSThierry Reding #include <linux/platform_device.h> 13ca48080aSStephen Warren #include <linux/reset.h> 14306a7f91SThierry Reding 157232398aSThierry Reding #include <soc/tegra/pmc.h> 165f60ed0dSThierry Reding 175f60ed0dSThierry Reding #include "drm.h" 185f60ed0dSThierry Reding #include "gem.h" 195f60ed0dSThierry Reding #include "gr3d.h" 205f60ed0dSThierry Reding 2133f150eaSThierry Reding struct gr3d_soc { 2233f150eaSThierry Reding unsigned int version; 2333f150eaSThierry Reding }; 2433f150eaSThierry Reding 255f60ed0dSThierry Reding struct gr3d { 265f60ed0dSThierry Reding struct tegra_drm_client client; 275f60ed0dSThierry Reding struct host1x_channel *channel; 285f60ed0dSThierry Reding struct clk *clk_secondary; 295f60ed0dSThierry Reding struct clk *clk; 30ca48080aSStephen Warren struct reset_control *rst_secondary; 31ca48080aSStephen Warren struct reset_control *rst; 325f60ed0dSThierry Reding 3333f150eaSThierry Reding const struct gr3d_soc *soc; 3433f150eaSThierry Reding 355f60ed0dSThierry Reding DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); 365f60ed0dSThierry Reding }; 375f60ed0dSThierry Reding 385f60ed0dSThierry Reding static inline struct gr3d *to_gr3d(struct tegra_drm_client *client) 395f60ed0dSThierry Reding { 405f60ed0dSThierry Reding return container_of(client, struct gr3d, client); 415f60ed0dSThierry Reding } 425f60ed0dSThierry Reding 435f60ed0dSThierry Reding static int gr3d_init(struct host1x_client *client) 445f60ed0dSThierry Reding { 455f60ed0dSThierry Reding struct tegra_drm_client *drm = host1x_to_drm_client(client); 46608f43adSThierry Reding struct drm_device *dev = dev_get_drvdata(client->host); 47977386a0SThierry Reding unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 485f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(drm); 49c9ac5217SDmitry Osipenko int err; 505f60ed0dSThierry Reding 51caccddcfSThierry Reding gr3d->channel = host1x_channel_request(client); 525f60ed0dSThierry Reding if (!gr3d->channel) 535f60ed0dSThierry Reding return -ENOMEM; 545f60ed0dSThierry Reding 55617dd7ccSThierry Reding client->syncpts[0] = host1x_syncpt_request(client, flags); 565f60ed0dSThierry Reding if (!client->syncpts[0]) { 57230630bdSThierry Reding err = -ENOMEM; 58230630bdSThierry Reding dev_err(client->dev, "failed to request syncpoint: %d\n", err); 59230630bdSThierry Reding goto put; 605f60ed0dSThierry Reding } 615f60ed0dSThierry Reding 627edd7961SThierry Reding err = host1x_client_iommu_attach(client); 63aacdf198SThierry Reding if (err < 0) { 640c407de5SThierry Reding dev_err(client->dev, "failed to attach to domain: %d\n", err); 65230630bdSThierry Reding goto free; 66c9ac5217SDmitry Osipenko } 67c9ac5217SDmitry Osipenko 68230630bdSThierry Reding err = tegra_drm_register_client(dev->dev_private, drm); 69230630bdSThierry Reding if (err < 0) { 70230630bdSThierry Reding dev_err(client->dev, "failed to register client: %d\n", err); 71230630bdSThierry Reding goto detach; 72230630bdSThierry Reding } 73230630bdSThierry Reding 74230630bdSThierry Reding return 0; 75230630bdSThierry Reding 76230630bdSThierry Reding detach: 77aacdf198SThierry Reding host1x_client_iommu_detach(client); 78230630bdSThierry Reding free: 79230630bdSThierry Reding host1x_syncpt_free(client->syncpts[0]); 80230630bdSThierry Reding put: 81230630bdSThierry Reding host1x_channel_put(gr3d->channel); 82230630bdSThierry Reding return err; 835f60ed0dSThierry Reding } 845f60ed0dSThierry Reding 855f60ed0dSThierry Reding static int gr3d_exit(struct host1x_client *client) 865f60ed0dSThierry Reding { 875f60ed0dSThierry Reding struct tegra_drm_client *drm = host1x_to_drm_client(client); 88608f43adSThierry Reding struct drm_device *dev = dev_get_drvdata(client->host); 895f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(drm); 905f60ed0dSThierry Reding int err; 915f60ed0dSThierry Reding 929910f5c4SThierry Reding err = tegra_drm_unregister_client(dev->dev_private, drm); 935f60ed0dSThierry Reding if (err < 0) 945f60ed0dSThierry Reding return err; 955f60ed0dSThierry Reding 96aacdf198SThierry Reding host1x_client_iommu_detach(client); 975f60ed0dSThierry Reding host1x_syncpt_free(client->syncpts[0]); 988474b025SMikko Perttunen host1x_channel_put(gr3d->channel); 995f60ed0dSThierry Reding 1005f60ed0dSThierry Reding return 0; 1015f60ed0dSThierry Reding } 1025f60ed0dSThierry Reding 1035f60ed0dSThierry Reding static const struct host1x_client_ops gr3d_client_ops = { 1045f60ed0dSThierry Reding .init = gr3d_init, 1055f60ed0dSThierry Reding .exit = gr3d_exit, 1065f60ed0dSThierry Reding }; 1075f60ed0dSThierry Reding 1085f60ed0dSThierry Reding static int gr3d_open_channel(struct tegra_drm_client *client, 1095f60ed0dSThierry Reding struct tegra_drm_context *context) 1105f60ed0dSThierry Reding { 1115f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(client); 1125f60ed0dSThierry Reding 1135f60ed0dSThierry Reding context->channel = host1x_channel_get(gr3d->channel); 1145f60ed0dSThierry Reding if (!context->channel) 1155f60ed0dSThierry Reding return -ENOMEM; 1165f60ed0dSThierry Reding 1175f60ed0dSThierry Reding return 0; 1185f60ed0dSThierry Reding } 1195f60ed0dSThierry Reding 1205f60ed0dSThierry Reding static void gr3d_close_channel(struct tegra_drm_context *context) 1215f60ed0dSThierry Reding { 1225f60ed0dSThierry Reding host1x_channel_put(context->channel); 1235f60ed0dSThierry Reding } 1245f60ed0dSThierry Reding 1255f60ed0dSThierry Reding static int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset) 1265f60ed0dSThierry Reding { 1275f60ed0dSThierry Reding struct gr3d *gr3d = dev_get_drvdata(dev); 1285f60ed0dSThierry Reding 1295f60ed0dSThierry Reding switch (class) { 1305f60ed0dSThierry Reding case HOST1X_CLASS_HOST1X: 1315f60ed0dSThierry Reding if (offset == 0x2b) 1325f60ed0dSThierry Reding return 1; 1335f60ed0dSThierry Reding 1345f60ed0dSThierry Reding break; 1355f60ed0dSThierry Reding 1365f60ed0dSThierry Reding case HOST1X_CLASS_GR3D: 1375f60ed0dSThierry Reding if (offset >= GR3D_NUM_REGS) 1385f60ed0dSThierry Reding break; 1395f60ed0dSThierry Reding 1405f60ed0dSThierry Reding if (test_bit(offset, gr3d->addr_regs)) 1415f60ed0dSThierry Reding return 1; 1425f60ed0dSThierry Reding 1435f60ed0dSThierry Reding break; 1445f60ed0dSThierry Reding } 1455f60ed0dSThierry Reding 1465f60ed0dSThierry Reding return 0; 1475f60ed0dSThierry Reding } 1485f60ed0dSThierry Reding 1495f60ed0dSThierry Reding static const struct tegra_drm_client_ops gr3d_ops = { 1505f60ed0dSThierry Reding .open_channel = gr3d_open_channel, 1515f60ed0dSThierry Reding .close_channel = gr3d_close_channel, 1525f60ed0dSThierry Reding .is_addr_reg = gr3d_is_addr_reg, 1535f60ed0dSThierry Reding .submit = tegra_drm_submit, 1545f60ed0dSThierry Reding }; 1555f60ed0dSThierry Reding 15633f150eaSThierry Reding static const struct gr3d_soc tegra20_gr3d_soc = { 15733f150eaSThierry Reding .version = 0x20, 15833f150eaSThierry Reding }; 15933f150eaSThierry Reding 16033f150eaSThierry Reding static const struct gr3d_soc tegra30_gr3d_soc = { 16133f150eaSThierry Reding .version = 0x30, 16233f150eaSThierry Reding }; 16333f150eaSThierry Reding 16433f150eaSThierry Reding static const struct gr3d_soc tegra114_gr3d_soc = { 16533f150eaSThierry Reding .version = 0x35, 16633f150eaSThierry Reding }; 16733f150eaSThierry Reding 1685f60ed0dSThierry Reding static const struct of_device_id tegra_gr3d_match[] = { 16933f150eaSThierry Reding { .compatible = "nvidia,tegra114-gr3d", .data = &tegra114_gr3d_soc }, 17033f150eaSThierry Reding { .compatible = "nvidia,tegra30-gr3d", .data = &tegra30_gr3d_soc }, 17133f150eaSThierry Reding { .compatible = "nvidia,tegra20-gr3d", .data = &tegra20_gr3d_soc }, 1725f60ed0dSThierry Reding { } 1735f60ed0dSThierry Reding }; 174ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_gr3d_match); 1755f60ed0dSThierry Reding 1765f60ed0dSThierry Reding static const u32 gr3d_addr_regs[] = { 1775f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 0), 1785f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 1), 1795f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 2), 1805f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 3), 1815f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 4), 1825f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 5), 1835f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 6), 1845f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 7), 1855f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 8), 1865f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 9), 1875f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(10), 1885f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(11), 1895f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(12), 1905f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(13), 1915f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(14), 1925f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(15), 1935f60ed0dSThierry Reding GR3D_IDX_INDEX_BASE, 1945f60ed0dSThierry Reding GR3D_QR_ZTAG_ADDR, 1955f60ed0dSThierry Reding GR3D_QR_CTAG_ADDR, 1965f60ed0dSThierry Reding GR3D_QR_CZ_ADDR, 1975f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 0), 1985f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 1), 1995f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 2), 2005f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 3), 2015f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 4), 2025f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 5), 2035f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 6), 2045f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 7), 2055f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 8), 2065f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 9), 2075f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(10), 2085f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(11), 2095f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(12), 2105f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(13), 2115f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(14), 2125f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(15), 2135f60ed0dSThierry Reding GR3D_DW_MEMORY_OUTPUT_ADDRESS, 2145f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 0), 2155f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 1), 2165f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 2), 2175f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 3), 2185f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 4), 2195f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 5), 2205f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 6), 2215f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 7), 2225f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 8), 2235f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 9), 2245f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(10), 2255f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(11), 2265f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(12), 2275f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(13), 2285f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(14), 2295f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(15), 2305f60ed0dSThierry Reding GR3D_GLOBAL_SPILLSURFADDR, 2315f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 0), 2325f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 1), 2335f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 2), 2345f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 3), 2355f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 4), 2365f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 5), 2375f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 6), 2385f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 7), 2395f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 8), 2405f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 9), 2415f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(10), 2425f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(11), 2435f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(12), 2445f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(13), 2455f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(14), 2465f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(15), 2475f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 0), 2485f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 1), 2495f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 2), 2505f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 3), 2515f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 4), 2525f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 5), 2535f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 6), 2545f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 7), 2555f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 8), 2565f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 9), 2575f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(10), 2585f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(11), 2595f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(12), 2605f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(13), 2615f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(14), 2625f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(15), 2635f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 0), 2645f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 1), 2655f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 2), 2665f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 3), 2675f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 4), 2685f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 5), 2695f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 6), 2705f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 7), 2715f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 8), 2725f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 9), 2735f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(10), 2745f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(11), 2755f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(12), 2765f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(13), 2775f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(14), 2785f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(15), 2795f60ed0dSThierry Reding }; 2805f60ed0dSThierry Reding 2815f60ed0dSThierry Reding static int gr3d_probe(struct platform_device *pdev) 2825f60ed0dSThierry Reding { 2835f60ed0dSThierry Reding struct device_node *np = pdev->dev.of_node; 2845f60ed0dSThierry Reding struct host1x_syncpt **syncpts; 2855f60ed0dSThierry Reding struct gr3d *gr3d; 2865f60ed0dSThierry Reding unsigned int i; 2875f60ed0dSThierry Reding int err; 2885f60ed0dSThierry Reding 2895f60ed0dSThierry Reding gr3d = devm_kzalloc(&pdev->dev, sizeof(*gr3d), GFP_KERNEL); 2905f60ed0dSThierry Reding if (!gr3d) 2915f60ed0dSThierry Reding return -ENOMEM; 2925f60ed0dSThierry Reding 29333f150eaSThierry Reding gr3d->soc = of_device_get_match_data(&pdev->dev); 29433f150eaSThierry Reding 2955f60ed0dSThierry Reding syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL); 2965f60ed0dSThierry Reding if (!syncpts) 2975f60ed0dSThierry Reding return -ENOMEM; 2985f60ed0dSThierry Reding 2995f60ed0dSThierry Reding gr3d->clk = devm_clk_get(&pdev->dev, NULL); 3005f60ed0dSThierry Reding if (IS_ERR(gr3d->clk)) { 3015f60ed0dSThierry Reding dev_err(&pdev->dev, "cannot get clock\n"); 3025f60ed0dSThierry Reding return PTR_ERR(gr3d->clk); 3035f60ed0dSThierry Reding } 3045f60ed0dSThierry Reding 305ca48080aSStephen Warren gr3d->rst = devm_reset_control_get(&pdev->dev, "3d"); 306ca48080aSStephen Warren if (IS_ERR(gr3d->rst)) { 307ca48080aSStephen Warren dev_err(&pdev->dev, "cannot get reset\n"); 308ca48080aSStephen Warren return PTR_ERR(gr3d->rst); 309ca48080aSStephen Warren } 310ca48080aSStephen Warren 3115f60ed0dSThierry Reding if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) { 3125f60ed0dSThierry Reding gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2"); 31387ba3e15SChristophe Jaillet if (IS_ERR(gr3d->clk_secondary)) { 3145f60ed0dSThierry Reding dev_err(&pdev->dev, "cannot get secondary clock\n"); 31587ba3e15SChristophe Jaillet return PTR_ERR(gr3d->clk_secondary); 3165f60ed0dSThierry Reding } 317ca48080aSStephen Warren 318ca48080aSStephen Warren gr3d->rst_secondary = devm_reset_control_get(&pdev->dev, 319ca48080aSStephen Warren "3d2"); 320ca48080aSStephen Warren if (IS_ERR(gr3d->rst_secondary)) { 321ca48080aSStephen Warren dev_err(&pdev->dev, "cannot get secondary reset\n"); 322ca48080aSStephen Warren return PTR_ERR(gr3d->rst_secondary); 323ca48080aSStephen Warren } 3245f60ed0dSThierry Reding } 3255f60ed0dSThierry Reding 32680b28791SStephen Warren err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk, 32780b28791SStephen Warren gr3d->rst); 3285f60ed0dSThierry Reding if (err < 0) { 3295f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to power up 3D unit\n"); 3305f60ed0dSThierry Reding return err; 3315f60ed0dSThierry Reding } 3325f60ed0dSThierry Reding 3335f60ed0dSThierry Reding if (gr3d->clk_secondary) { 3345f60ed0dSThierry Reding err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1, 33580b28791SStephen Warren gr3d->clk_secondary, 33680b28791SStephen Warren gr3d->rst_secondary); 3375f60ed0dSThierry Reding if (err < 0) { 3385f60ed0dSThierry Reding dev_err(&pdev->dev, 3395f60ed0dSThierry Reding "failed to power up secondary 3D unit\n"); 3405f60ed0dSThierry Reding return err; 3415f60ed0dSThierry Reding } 3425f60ed0dSThierry Reding } 3435f60ed0dSThierry Reding 3445f60ed0dSThierry Reding INIT_LIST_HEAD(&gr3d->client.base.list); 3455f60ed0dSThierry Reding gr3d->client.base.ops = &gr3d_client_ops; 3465f60ed0dSThierry Reding gr3d->client.base.dev = &pdev->dev; 3475f60ed0dSThierry Reding gr3d->client.base.class = HOST1X_CLASS_GR3D; 3485f60ed0dSThierry Reding gr3d->client.base.syncpts = syncpts; 3495f60ed0dSThierry Reding gr3d->client.base.num_syncpts = 1; 3505f60ed0dSThierry Reding 3515f60ed0dSThierry Reding INIT_LIST_HEAD(&gr3d->client.list); 35233f150eaSThierry Reding gr3d->client.version = gr3d->soc->version; 3535f60ed0dSThierry Reding gr3d->client.ops = &gr3d_ops; 3545f60ed0dSThierry Reding 3555f60ed0dSThierry Reding err = host1x_client_register(&gr3d->client.base); 3565f60ed0dSThierry Reding if (err < 0) { 3575f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 3585f60ed0dSThierry Reding err); 3595f60ed0dSThierry Reding return err; 3605f60ed0dSThierry Reding } 3615f60ed0dSThierry Reding 3625f60ed0dSThierry Reding /* initialize address register map */ 3635f60ed0dSThierry Reding for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++) 3645f60ed0dSThierry Reding set_bit(gr3d_addr_regs[i], gr3d->addr_regs); 3655f60ed0dSThierry Reding 3665f60ed0dSThierry Reding platform_set_drvdata(pdev, gr3d); 3675f60ed0dSThierry Reding 3685f60ed0dSThierry Reding return 0; 3695f60ed0dSThierry Reding } 3705f60ed0dSThierry Reding 3715f60ed0dSThierry Reding static int gr3d_remove(struct platform_device *pdev) 3725f60ed0dSThierry Reding { 3735f60ed0dSThierry Reding struct gr3d *gr3d = platform_get_drvdata(pdev); 3745f60ed0dSThierry Reding int err; 3755f60ed0dSThierry Reding 3765f60ed0dSThierry Reding err = host1x_client_unregister(&gr3d->client.base); 3775f60ed0dSThierry Reding if (err < 0) { 3785f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 3795f60ed0dSThierry Reding err); 3805f60ed0dSThierry Reding return err; 3815f60ed0dSThierry Reding } 3825f60ed0dSThierry Reding 3835f60ed0dSThierry Reding if (gr3d->clk_secondary) { 3845f60ed0dSThierry Reding tegra_powergate_power_off(TEGRA_POWERGATE_3D1); 3855f60ed0dSThierry Reding clk_disable_unprepare(gr3d->clk_secondary); 3865f60ed0dSThierry Reding } 3875f60ed0dSThierry Reding 3885f60ed0dSThierry Reding tegra_powergate_power_off(TEGRA_POWERGATE_3D); 3895f60ed0dSThierry Reding clk_disable_unprepare(gr3d->clk); 3905f60ed0dSThierry Reding 3915f60ed0dSThierry Reding return 0; 3925f60ed0dSThierry Reding } 3935f60ed0dSThierry Reding 3945f60ed0dSThierry Reding struct platform_driver tegra_gr3d_driver = { 3955f60ed0dSThierry Reding .driver = { 3965f60ed0dSThierry Reding .name = "tegra-gr3d", 3975f60ed0dSThierry Reding .of_match_table = tegra_gr3d_match, 3985f60ed0dSThierry Reding }, 3995f60ed0dSThierry Reding .probe = gr3d_probe, 4005f60ed0dSThierry Reding .remove = gr3d_remove, 4015f60ed0dSThierry Reding }; 402