1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2012-2013, NVIDIA Corporation. 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/delay.h> 8 #include <linux/iommu.h> 9 #include <linux/module.h> 10 #include <linux/of_device.h> 11 #include <linux/reset.h> 12 13 #include "drm.h" 14 #include "gem.h" 15 #include "gr2d.h" 16 17 struct gr2d_soc { 18 unsigned int version; 19 }; 20 21 struct gr2d { 22 struct tegra_drm_client client; 23 struct host1x_channel *channel; 24 struct reset_control *rst; 25 struct clk *clk; 26 27 const struct gr2d_soc *soc; 28 29 DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS); 30 }; 31 32 static inline struct gr2d *to_gr2d(struct tegra_drm_client *client) 33 { 34 return container_of(client, struct gr2d, client); 35 } 36 37 static int gr2d_init(struct host1x_client *client) 38 { 39 struct tegra_drm_client *drm = host1x_to_drm_client(client); 40 struct drm_device *dev = dev_get_drvdata(client->host); 41 unsigned long flags = HOST1X_SYNCPT_HAS_BASE; 42 struct gr2d *gr2d = to_gr2d(drm); 43 int err; 44 45 gr2d->channel = host1x_channel_request(client); 46 if (!gr2d->channel) 47 return -ENOMEM; 48 49 client->syncpts[0] = host1x_syncpt_request(client, flags); 50 if (!client->syncpts[0]) { 51 err = -ENOMEM; 52 dev_err(client->dev, "failed to request syncpoint: %d\n", err); 53 goto put; 54 } 55 56 err = host1x_client_iommu_attach(client); 57 if (err < 0) { 58 dev_err(client->dev, "failed to attach to domain: %d\n", err); 59 goto free; 60 } 61 62 err = tegra_drm_register_client(dev->dev_private, drm); 63 if (err < 0) { 64 dev_err(client->dev, "failed to register client: %d\n", err); 65 goto detach; 66 } 67 68 return 0; 69 70 detach: 71 host1x_client_iommu_detach(client); 72 free: 73 host1x_syncpt_put(client->syncpts[0]); 74 put: 75 host1x_channel_put(gr2d->channel); 76 return err; 77 } 78 79 static int gr2d_exit(struct host1x_client *client) 80 { 81 struct tegra_drm_client *drm = host1x_to_drm_client(client); 82 struct drm_device *dev = dev_get_drvdata(client->host); 83 struct tegra_drm *tegra = dev->dev_private; 84 struct gr2d *gr2d = to_gr2d(drm); 85 int err; 86 87 err = tegra_drm_unregister_client(tegra, drm); 88 if (err < 0) 89 return err; 90 91 host1x_client_iommu_detach(client); 92 host1x_syncpt_put(client->syncpts[0]); 93 host1x_channel_put(gr2d->channel); 94 95 return 0; 96 } 97 98 static const struct host1x_client_ops gr2d_client_ops = { 99 .init = gr2d_init, 100 .exit = gr2d_exit, 101 }; 102 103 static int gr2d_open_channel(struct tegra_drm_client *client, 104 struct tegra_drm_context *context) 105 { 106 struct gr2d *gr2d = to_gr2d(client); 107 108 context->channel = host1x_channel_get(gr2d->channel); 109 if (!context->channel) 110 return -ENOMEM; 111 112 return 0; 113 } 114 115 static void gr2d_close_channel(struct tegra_drm_context *context) 116 { 117 host1x_channel_put(context->channel); 118 } 119 120 static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) 121 { 122 struct gr2d *gr2d = dev_get_drvdata(dev); 123 124 switch (class) { 125 case HOST1X_CLASS_HOST1X: 126 if (offset == 0x2b) 127 return 1; 128 129 break; 130 131 case HOST1X_CLASS_GR2D: 132 case HOST1X_CLASS_GR2D_SB: 133 if (offset >= GR2D_NUM_REGS) 134 break; 135 136 if (test_bit(offset, gr2d->addr_regs)) 137 return 1; 138 139 break; 140 } 141 142 return 0; 143 } 144 145 static int gr2d_is_valid_class(u32 class) 146 { 147 return (class == HOST1X_CLASS_GR2D || 148 class == HOST1X_CLASS_GR2D_SB); 149 } 150 151 static const struct tegra_drm_client_ops gr2d_ops = { 152 .open_channel = gr2d_open_channel, 153 .close_channel = gr2d_close_channel, 154 .is_addr_reg = gr2d_is_addr_reg, 155 .is_valid_class = gr2d_is_valid_class, 156 .submit = tegra_drm_submit, 157 }; 158 159 static const struct gr2d_soc tegra20_gr2d_soc = { 160 .version = 0x20, 161 }; 162 163 static const struct gr2d_soc tegra30_gr2d_soc = { 164 .version = 0x30, 165 }; 166 167 static const struct gr2d_soc tegra114_gr2d_soc = { 168 .version = 0x35, 169 }; 170 171 static const struct of_device_id gr2d_match[] = { 172 { .compatible = "nvidia,tegra114-gr2d", .data = &tegra114_gr2d_soc }, 173 { .compatible = "nvidia,tegra30-gr2d", .data = &tegra30_gr2d_soc }, 174 { .compatible = "nvidia,tegra20-gr2d", .data = &tegra20_gr2d_soc }, 175 { }, 176 }; 177 MODULE_DEVICE_TABLE(of, gr2d_match); 178 179 static const u32 gr2d_addr_regs[] = { 180 GR2D_UA_BASE_ADDR, 181 GR2D_VA_BASE_ADDR, 182 GR2D_PAT_BASE_ADDR, 183 GR2D_DSTA_BASE_ADDR, 184 GR2D_DSTB_BASE_ADDR, 185 GR2D_DSTC_BASE_ADDR, 186 GR2D_SRCA_BASE_ADDR, 187 GR2D_SRCB_BASE_ADDR, 188 GR2D_PATBASE_ADDR, 189 GR2D_SRC_BASE_ADDR_SB, 190 GR2D_DSTA_BASE_ADDR_SB, 191 GR2D_DSTB_BASE_ADDR_SB, 192 GR2D_UA_BASE_ADDR_SB, 193 GR2D_VA_BASE_ADDR_SB, 194 }; 195 196 static int gr2d_probe(struct platform_device *pdev) 197 { 198 struct device *dev = &pdev->dev; 199 struct host1x_syncpt **syncpts; 200 struct gr2d *gr2d; 201 unsigned int i; 202 int err; 203 204 gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL); 205 if (!gr2d) 206 return -ENOMEM; 207 208 gr2d->soc = of_device_get_match_data(dev); 209 210 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 211 if (!syncpts) 212 return -ENOMEM; 213 214 gr2d->rst = devm_reset_control_get(dev, NULL); 215 if (IS_ERR(gr2d->rst)) { 216 dev_err(dev, "cannot get reset\n"); 217 return PTR_ERR(gr2d->rst); 218 } 219 220 gr2d->clk = devm_clk_get(dev, NULL); 221 if (IS_ERR(gr2d->clk)) { 222 dev_err(dev, "cannot get clock\n"); 223 return PTR_ERR(gr2d->clk); 224 } 225 226 err = clk_prepare_enable(gr2d->clk); 227 if (err) { 228 dev_err(dev, "cannot turn on clock\n"); 229 return err; 230 } 231 232 usleep_range(2000, 4000); 233 234 err = reset_control_deassert(gr2d->rst); 235 if (err < 0) { 236 dev_err(dev, "failed to deassert reset: %d\n", err); 237 goto disable_clk; 238 } 239 240 INIT_LIST_HEAD(&gr2d->client.base.list); 241 gr2d->client.base.ops = &gr2d_client_ops; 242 gr2d->client.base.dev = dev; 243 gr2d->client.base.class = HOST1X_CLASS_GR2D; 244 gr2d->client.base.syncpts = syncpts; 245 gr2d->client.base.num_syncpts = 1; 246 247 INIT_LIST_HEAD(&gr2d->client.list); 248 gr2d->client.version = gr2d->soc->version; 249 gr2d->client.ops = &gr2d_ops; 250 251 err = host1x_client_register(&gr2d->client.base); 252 if (err < 0) { 253 dev_err(dev, "failed to register host1x client: %d\n", err); 254 goto assert_rst; 255 } 256 257 /* initialize address register map */ 258 for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++) 259 set_bit(gr2d_addr_regs[i], gr2d->addr_regs); 260 261 platform_set_drvdata(pdev, gr2d); 262 263 return 0; 264 265 assert_rst: 266 (void)reset_control_assert(gr2d->rst); 267 disable_clk: 268 clk_disable_unprepare(gr2d->clk); 269 270 return err; 271 } 272 273 static int gr2d_remove(struct platform_device *pdev) 274 { 275 struct gr2d *gr2d = platform_get_drvdata(pdev); 276 int err; 277 278 err = host1x_client_unregister(&gr2d->client.base); 279 if (err < 0) { 280 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 281 err); 282 return err; 283 } 284 285 err = reset_control_assert(gr2d->rst); 286 if (err < 0) 287 dev_err(&pdev->dev, "failed to assert reset: %d\n", err); 288 289 usleep_range(2000, 4000); 290 291 clk_disable_unprepare(gr2d->clk); 292 293 return 0; 294 } 295 296 struct platform_driver tegra_gr2d_driver = { 297 .driver = { 298 .name = "tegra-gr2d", 299 .of_match_table = gr2d_match, 300 }, 301 .probe = gr2d_probe, 302 .remove = gr2d_remove, 303 }; 304