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 { 26c9ac5217SDmitry Osipenko struct iommu_group *group; 275f60ed0dSThierry Reding struct tegra_drm_client client; 285f60ed0dSThierry Reding struct host1x_channel *channel; 295f60ed0dSThierry Reding struct clk *clk_secondary; 305f60ed0dSThierry Reding struct clk *clk; 31ca48080aSStephen Warren struct reset_control *rst_secondary; 32ca48080aSStephen Warren struct reset_control *rst; 335f60ed0dSThierry Reding 3433f150eaSThierry Reding const struct gr3d_soc *soc; 3533f150eaSThierry Reding 365f60ed0dSThierry Reding DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); 375f60ed0dSThierry Reding }; 385f60ed0dSThierry Reding 395f60ed0dSThierry Reding static inline struct gr3d *to_gr3d(struct tegra_drm_client *client) 405f60ed0dSThierry Reding { 415f60ed0dSThierry Reding return container_of(client, struct gr3d, client); 425f60ed0dSThierry Reding } 435f60ed0dSThierry Reding 445f60ed0dSThierry Reding static int gr3d_init(struct host1x_client *client) 455f60ed0dSThierry Reding { 465f60ed0dSThierry Reding struct tegra_drm_client *drm = host1x_to_drm_client(client); 479910f5c4SThierry Reding struct drm_device *dev = dev_get_drvdata(client->parent); 48977386a0SThierry Reding unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 495f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(drm); 50c9ac5217SDmitry Osipenko int err; 515f60ed0dSThierry Reding 52caccddcfSThierry Reding gr3d->channel = host1x_channel_request(client); 535f60ed0dSThierry Reding if (!gr3d->channel) 545f60ed0dSThierry Reding return -ENOMEM; 555f60ed0dSThierry Reding 56617dd7ccSThierry Reding client->syncpts[0] = host1x_syncpt_request(client, flags); 575f60ed0dSThierry Reding if (!client->syncpts[0]) { 58230630bdSThierry Reding err = -ENOMEM; 59230630bdSThierry Reding dev_err(client->dev, "failed to request syncpoint: %d\n", err); 60230630bdSThierry Reding goto put; 615f60ed0dSThierry Reding } 625f60ed0dSThierry Reding 630c407de5SThierry Reding gr3d->group = host1x_client_iommu_attach(client, false); 640c407de5SThierry Reding if (IS_ERR(gr3d->group)) { 650c407de5SThierry Reding err = PTR_ERR(gr3d->group); 660c407de5SThierry Reding dev_err(client->dev, "failed to attach to domain: %d\n", err); 67230630bdSThierry Reding goto free; 68c9ac5217SDmitry Osipenko } 69c9ac5217SDmitry Osipenko 70230630bdSThierry Reding err = tegra_drm_register_client(dev->dev_private, drm); 71230630bdSThierry Reding if (err < 0) { 72230630bdSThierry Reding dev_err(client->dev, "failed to register client: %d\n", err); 73230630bdSThierry Reding goto detach; 74230630bdSThierry Reding } 75230630bdSThierry Reding 76230630bdSThierry Reding return 0; 77230630bdSThierry Reding 78230630bdSThierry Reding detach: 790c407de5SThierry Reding host1x_client_iommu_detach(client, gr3d->group); 80230630bdSThierry Reding free: 81230630bdSThierry Reding host1x_syncpt_free(client->syncpts[0]); 82230630bdSThierry Reding put: 83230630bdSThierry Reding host1x_channel_put(gr3d->channel); 84230630bdSThierry Reding return err; 855f60ed0dSThierry Reding } 865f60ed0dSThierry Reding 875f60ed0dSThierry Reding static int gr3d_exit(struct host1x_client *client) 885f60ed0dSThierry Reding { 895f60ed0dSThierry Reding struct tegra_drm_client *drm = host1x_to_drm_client(client); 909910f5c4SThierry Reding struct drm_device *dev = dev_get_drvdata(client->parent); 915f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(drm); 925f60ed0dSThierry Reding int err; 935f60ed0dSThierry Reding 949910f5c4SThierry Reding err = tegra_drm_unregister_client(dev->dev_private, drm); 955f60ed0dSThierry Reding if (err < 0) 965f60ed0dSThierry Reding return err; 975f60ed0dSThierry Reding 980c407de5SThierry Reding host1x_client_iommu_detach(client, gr3d->group); 995f60ed0dSThierry Reding host1x_syncpt_free(client->syncpts[0]); 1008474b025SMikko Perttunen host1x_channel_put(gr3d->channel); 1015f60ed0dSThierry Reding 1025f60ed0dSThierry Reding return 0; 1035f60ed0dSThierry Reding } 1045f60ed0dSThierry Reding 1055f60ed0dSThierry Reding static const struct host1x_client_ops gr3d_client_ops = { 1065f60ed0dSThierry Reding .init = gr3d_init, 1075f60ed0dSThierry Reding .exit = gr3d_exit, 1085f60ed0dSThierry Reding }; 1095f60ed0dSThierry Reding 1105f60ed0dSThierry Reding static int gr3d_open_channel(struct tegra_drm_client *client, 1115f60ed0dSThierry Reding struct tegra_drm_context *context) 1125f60ed0dSThierry Reding { 1135f60ed0dSThierry Reding struct gr3d *gr3d = to_gr3d(client); 1145f60ed0dSThierry Reding 1155f60ed0dSThierry Reding context->channel = host1x_channel_get(gr3d->channel); 1165f60ed0dSThierry Reding if (!context->channel) 1175f60ed0dSThierry Reding return -ENOMEM; 1185f60ed0dSThierry Reding 1195f60ed0dSThierry Reding return 0; 1205f60ed0dSThierry Reding } 1215f60ed0dSThierry Reding 1225f60ed0dSThierry Reding static void gr3d_close_channel(struct tegra_drm_context *context) 1235f60ed0dSThierry Reding { 1245f60ed0dSThierry Reding host1x_channel_put(context->channel); 1255f60ed0dSThierry Reding } 1265f60ed0dSThierry Reding 1275f60ed0dSThierry Reding static int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset) 1285f60ed0dSThierry Reding { 1295f60ed0dSThierry Reding struct gr3d *gr3d = dev_get_drvdata(dev); 1305f60ed0dSThierry Reding 1315f60ed0dSThierry Reding switch (class) { 1325f60ed0dSThierry Reding case HOST1X_CLASS_HOST1X: 1335f60ed0dSThierry Reding if (offset == 0x2b) 1345f60ed0dSThierry Reding return 1; 1355f60ed0dSThierry Reding 1365f60ed0dSThierry Reding break; 1375f60ed0dSThierry Reding 1385f60ed0dSThierry Reding case HOST1X_CLASS_GR3D: 1395f60ed0dSThierry Reding if (offset >= GR3D_NUM_REGS) 1405f60ed0dSThierry Reding break; 1415f60ed0dSThierry Reding 1425f60ed0dSThierry Reding if (test_bit(offset, gr3d->addr_regs)) 1435f60ed0dSThierry Reding return 1; 1445f60ed0dSThierry Reding 1455f60ed0dSThierry Reding break; 1465f60ed0dSThierry Reding } 1475f60ed0dSThierry Reding 1485f60ed0dSThierry Reding return 0; 1495f60ed0dSThierry Reding } 1505f60ed0dSThierry Reding 1515f60ed0dSThierry Reding static const struct tegra_drm_client_ops gr3d_ops = { 1525f60ed0dSThierry Reding .open_channel = gr3d_open_channel, 1535f60ed0dSThierry Reding .close_channel = gr3d_close_channel, 1545f60ed0dSThierry Reding .is_addr_reg = gr3d_is_addr_reg, 1555f60ed0dSThierry Reding .submit = tegra_drm_submit, 1565f60ed0dSThierry Reding }; 1575f60ed0dSThierry Reding 15833f150eaSThierry Reding static const struct gr3d_soc tegra20_gr3d_soc = { 15933f150eaSThierry Reding .version = 0x20, 16033f150eaSThierry Reding }; 16133f150eaSThierry Reding 16233f150eaSThierry Reding static const struct gr3d_soc tegra30_gr3d_soc = { 16333f150eaSThierry Reding .version = 0x30, 16433f150eaSThierry Reding }; 16533f150eaSThierry Reding 16633f150eaSThierry Reding static const struct gr3d_soc tegra114_gr3d_soc = { 16733f150eaSThierry Reding .version = 0x35, 16833f150eaSThierry Reding }; 16933f150eaSThierry Reding 1705f60ed0dSThierry Reding static const struct of_device_id tegra_gr3d_match[] = { 17133f150eaSThierry Reding { .compatible = "nvidia,tegra114-gr3d", .data = &tegra114_gr3d_soc }, 17233f150eaSThierry Reding { .compatible = "nvidia,tegra30-gr3d", .data = &tegra30_gr3d_soc }, 17333f150eaSThierry Reding { .compatible = "nvidia,tegra20-gr3d", .data = &tegra20_gr3d_soc }, 1745f60ed0dSThierry Reding { } 1755f60ed0dSThierry Reding }; 176ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_gr3d_match); 1775f60ed0dSThierry Reding 1785f60ed0dSThierry Reding static const u32 gr3d_addr_regs[] = { 1795f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 0), 1805f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 1), 1815f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 2), 1825f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 3), 1835f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 4), 1845f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 5), 1855f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 6), 1865f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 7), 1875f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 8), 1885f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE( 9), 1895f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(10), 1905f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(11), 1915f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(12), 1925f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(13), 1935f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(14), 1945f60ed0dSThierry Reding GR3D_IDX_ATTRIBUTE(15), 1955f60ed0dSThierry Reding GR3D_IDX_INDEX_BASE, 1965f60ed0dSThierry Reding GR3D_QR_ZTAG_ADDR, 1975f60ed0dSThierry Reding GR3D_QR_CTAG_ADDR, 1985f60ed0dSThierry Reding GR3D_QR_CZ_ADDR, 1995f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 0), 2005f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 1), 2015f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 2), 2025f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 3), 2035f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 4), 2045f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 5), 2055f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 6), 2065f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 7), 2075f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 8), 2085f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR( 9), 2095f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(10), 2105f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(11), 2115f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(12), 2125f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(13), 2135f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(14), 2145f60ed0dSThierry Reding GR3D_TEX_TEX_ADDR(15), 2155f60ed0dSThierry Reding GR3D_DW_MEMORY_OUTPUT_ADDRESS, 2165f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 0), 2175f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 1), 2185f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 2), 2195f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 3), 2205f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 4), 2215f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 5), 2225f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 6), 2235f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 7), 2245f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 8), 2255f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR( 9), 2265f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(10), 2275f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(11), 2285f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(12), 2295f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(13), 2305f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(14), 2315f60ed0dSThierry Reding GR3D_GLOBAL_SURFADDR(15), 2325f60ed0dSThierry Reding GR3D_GLOBAL_SPILLSURFADDR, 2335f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 0), 2345f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 1), 2355f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 2), 2365f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 3), 2375f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 4), 2385f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 5), 2395f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 6), 2405f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 7), 2415f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 8), 2425f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR( 9), 2435f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(10), 2445f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(11), 2455f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(12), 2465f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(13), 2475f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(14), 2485f60ed0dSThierry Reding GR3D_GLOBAL_SURFOVERADDR(15), 2495f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 0), 2505f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 1), 2515f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 2), 2525f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 3), 2535f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 4), 2545f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 5), 2555f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 6), 2565f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 7), 2575f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 8), 2585f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR( 9), 2595f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(10), 2605f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(11), 2615f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(12), 2625f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(13), 2635f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(14), 2645f60ed0dSThierry Reding GR3D_GLOBAL_SAMP01SURFADDR(15), 2655f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 0), 2665f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 1), 2675f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 2), 2685f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 3), 2695f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 4), 2705f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 5), 2715f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 6), 2725f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 7), 2735f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 8), 2745f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR( 9), 2755f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(10), 2765f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(11), 2775f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(12), 2785f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(13), 2795f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(14), 2805f60ed0dSThierry Reding GR3D_GLOBAL_SAMP23SURFADDR(15), 2815f60ed0dSThierry Reding }; 2825f60ed0dSThierry Reding 2835f60ed0dSThierry Reding static int gr3d_probe(struct platform_device *pdev) 2845f60ed0dSThierry Reding { 2855f60ed0dSThierry Reding struct device_node *np = pdev->dev.of_node; 2865f60ed0dSThierry Reding struct host1x_syncpt **syncpts; 2875f60ed0dSThierry Reding struct gr3d *gr3d; 2885f60ed0dSThierry Reding unsigned int i; 2895f60ed0dSThierry Reding int err; 2905f60ed0dSThierry Reding 2915f60ed0dSThierry Reding gr3d = devm_kzalloc(&pdev->dev, sizeof(*gr3d), GFP_KERNEL); 2925f60ed0dSThierry Reding if (!gr3d) 2935f60ed0dSThierry Reding return -ENOMEM; 2945f60ed0dSThierry Reding 29533f150eaSThierry Reding gr3d->soc = of_device_get_match_data(&pdev->dev); 29633f150eaSThierry Reding 2975f60ed0dSThierry Reding syncpts = devm_kzalloc(&pdev->dev, sizeof(*syncpts), GFP_KERNEL); 2985f60ed0dSThierry Reding if (!syncpts) 2995f60ed0dSThierry Reding return -ENOMEM; 3005f60ed0dSThierry Reding 3015f60ed0dSThierry Reding gr3d->clk = devm_clk_get(&pdev->dev, NULL); 3025f60ed0dSThierry Reding if (IS_ERR(gr3d->clk)) { 3035f60ed0dSThierry Reding dev_err(&pdev->dev, "cannot get clock\n"); 3045f60ed0dSThierry Reding return PTR_ERR(gr3d->clk); 3055f60ed0dSThierry Reding } 3065f60ed0dSThierry Reding 307ca48080aSStephen Warren gr3d->rst = devm_reset_control_get(&pdev->dev, "3d"); 308ca48080aSStephen Warren if (IS_ERR(gr3d->rst)) { 309ca48080aSStephen Warren dev_err(&pdev->dev, "cannot get reset\n"); 310ca48080aSStephen Warren return PTR_ERR(gr3d->rst); 311ca48080aSStephen Warren } 312ca48080aSStephen Warren 3135f60ed0dSThierry Reding if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) { 3145f60ed0dSThierry Reding gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2"); 31587ba3e15SChristophe Jaillet if (IS_ERR(gr3d->clk_secondary)) { 3165f60ed0dSThierry Reding dev_err(&pdev->dev, "cannot get secondary clock\n"); 31787ba3e15SChristophe Jaillet return PTR_ERR(gr3d->clk_secondary); 3185f60ed0dSThierry Reding } 319ca48080aSStephen Warren 320ca48080aSStephen Warren gr3d->rst_secondary = devm_reset_control_get(&pdev->dev, 321ca48080aSStephen Warren "3d2"); 322ca48080aSStephen Warren if (IS_ERR(gr3d->rst_secondary)) { 323ca48080aSStephen Warren dev_err(&pdev->dev, "cannot get secondary reset\n"); 324ca48080aSStephen Warren return PTR_ERR(gr3d->rst_secondary); 325ca48080aSStephen Warren } 3265f60ed0dSThierry Reding } 3275f60ed0dSThierry Reding 32880b28791SStephen Warren err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk, 32980b28791SStephen Warren gr3d->rst); 3305f60ed0dSThierry Reding if (err < 0) { 3315f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to power up 3D unit\n"); 3325f60ed0dSThierry Reding return err; 3335f60ed0dSThierry Reding } 3345f60ed0dSThierry Reding 3355f60ed0dSThierry Reding if (gr3d->clk_secondary) { 3365f60ed0dSThierry Reding err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1, 33780b28791SStephen Warren gr3d->clk_secondary, 33880b28791SStephen Warren gr3d->rst_secondary); 3395f60ed0dSThierry Reding if (err < 0) { 3405f60ed0dSThierry Reding dev_err(&pdev->dev, 3415f60ed0dSThierry Reding "failed to power up secondary 3D unit\n"); 3425f60ed0dSThierry Reding return err; 3435f60ed0dSThierry Reding } 3445f60ed0dSThierry Reding } 3455f60ed0dSThierry Reding 3465f60ed0dSThierry Reding INIT_LIST_HEAD(&gr3d->client.base.list); 3475f60ed0dSThierry Reding gr3d->client.base.ops = &gr3d_client_ops; 3485f60ed0dSThierry Reding gr3d->client.base.dev = &pdev->dev; 3495f60ed0dSThierry Reding gr3d->client.base.class = HOST1X_CLASS_GR3D; 3505f60ed0dSThierry Reding gr3d->client.base.syncpts = syncpts; 3515f60ed0dSThierry Reding gr3d->client.base.num_syncpts = 1; 3525f60ed0dSThierry Reding 3535f60ed0dSThierry Reding INIT_LIST_HEAD(&gr3d->client.list); 35433f150eaSThierry Reding gr3d->client.version = gr3d->soc->version; 3555f60ed0dSThierry Reding gr3d->client.ops = &gr3d_ops; 3565f60ed0dSThierry Reding 3575f60ed0dSThierry Reding err = host1x_client_register(&gr3d->client.base); 3585f60ed0dSThierry Reding if (err < 0) { 3595f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 3605f60ed0dSThierry Reding err); 3615f60ed0dSThierry Reding return err; 3625f60ed0dSThierry Reding } 3635f60ed0dSThierry Reding 3645f60ed0dSThierry Reding /* initialize address register map */ 3655f60ed0dSThierry Reding for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++) 3665f60ed0dSThierry Reding set_bit(gr3d_addr_regs[i], gr3d->addr_regs); 3675f60ed0dSThierry Reding 3685f60ed0dSThierry Reding platform_set_drvdata(pdev, gr3d); 3695f60ed0dSThierry Reding 3705f60ed0dSThierry Reding return 0; 3715f60ed0dSThierry Reding } 3725f60ed0dSThierry Reding 3735f60ed0dSThierry Reding static int gr3d_remove(struct platform_device *pdev) 3745f60ed0dSThierry Reding { 3755f60ed0dSThierry Reding struct gr3d *gr3d = platform_get_drvdata(pdev); 3765f60ed0dSThierry Reding int err; 3775f60ed0dSThierry Reding 3785f60ed0dSThierry Reding err = host1x_client_unregister(&gr3d->client.base); 3795f60ed0dSThierry Reding if (err < 0) { 3805f60ed0dSThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 3815f60ed0dSThierry Reding err); 3825f60ed0dSThierry Reding return err; 3835f60ed0dSThierry Reding } 3845f60ed0dSThierry Reding 3855f60ed0dSThierry Reding if (gr3d->clk_secondary) { 3865f60ed0dSThierry Reding tegra_powergate_power_off(TEGRA_POWERGATE_3D1); 3875f60ed0dSThierry Reding clk_disable_unprepare(gr3d->clk_secondary); 3885f60ed0dSThierry Reding } 3895f60ed0dSThierry Reding 3905f60ed0dSThierry Reding tegra_powergate_power_off(TEGRA_POWERGATE_3D); 3915f60ed0dSThierry Reding clk_disable_unprepare(gr3d->clk); 3925f60ed0dSThierry Reding 3935f60ed0dSThierry Reding return 0; 3945f60ed0dSThierry Reding } 3955f60ed0dSThierry Reding 3965f60ed0dSThierry Reding struct platform_driver tegra_gr3d_driver = { 3975f60ed0dSThierry Reding .driver = { 3985f60ed0dSThierry Reding .name = "tegra-gr3d", 3995f60ed0dSThierry Reding .of_match_table = tegra_gr3d_match, 4005f60ed0dSThierry Reding }, 4015f60ed0dSThierry Reding .probe = gr3d_probe, 4025f60ed0dSThierry Reding .remove = gr3d_remove, 4035f60ed0dSThierry Reding }; 404