1 /* 2 * Copyright (c) 2015, NVIDIA Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/host1x.h> 11 #include <linux/iommu.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_device.h> 15 #include <linux/of_platform.h> 16 #include <linux/platform_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/reset.h> 19 20 #include <soc/tegra/pmc.h> 21 22 #include "drm.h" 23 #include "falcon.h" 24 #include "vic.h" 25 26 struct vic_config { 27 const char *firmware; 28 unsigned int version; 29 bool supports_sid; 30 }; 31 32 struct vic { 33 struct falcon falcon; 34 bool booted; 35 36 void __iomem *regs; 37 struct tegra_drm_client client; 38 struct host1x_channel *channel; 39 struct iommu_domain *domain; 40 struct device *dev; 41 struct clk *clk; 42 struct reset_control *rst; 43 44 /* Platform configuration */ 45 const struct vic_config *config; 46 }; 47 48 static inline struct vic *to_vic(struct tegra_drm_client *client) 49 { 50 return container_of(client, struct vic, client); 51 } 52 53 static void vic_writel(struct vic *vic, u32 value, unsigned int offset) 54 { 55 writel(value, vic->regs + offset); 56 } 57 58 static int vic_runtime_resume(struct device *dev) 59 { 60 struct vic *vic = dev_get_drvdata(dev); 61 int err; 62 63 err = clk_prepare_enable(vic->clk); 64 if (err < 0) 65 return err; 66 67 usleep_range(10, 20); 68 69 err = reset_control_deassert(vic->rst); 70 if (err < 0) 71 goto disable; 72 73 usleep_range(10, 20); 74 75 return 0; 76 77 disable: 78 clk_disable_unprepare(vic->clk); 79 return err; 80 } 81 82 static int vic_runtime_suspend(struct device *dev) 83 { 84 struct vic *vic = dev_get_drvdata(dev); 85 int err; 86 87 err = reset_control_assert(vic->rst); 88 if (err < 0) 89 return err; 90 91 usleep_range(2000, 4000); 92 93 clk_disable_unprepare(vic->clk); 94 95 vic->booted = false; 96 97 return 0; 98 } 99 100 static int vic_boot(struct vic *vic) 101 { 102 u32 fce_ucode_size, fce_bin_data_offset; 103 void *hdr; 104 int err = 0; 105 106 if (vic->booted) 107 return 0; 108 109 #ifdef CONFIG_IOMMU_API 110 if (vic->config->supports_sid) { 111 struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev); 112 u32 value; 113 114 value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | 115 TRANSCFG_ATT(0, TRANSCFG_SID_HW); 116 vic_writel(vic, value, VIC_TFBIF_TRANSCFG); 117 118 if (spec && spec->num_ids > 0) { 119 value = spec->ids[0] & 0xffff; 120 121 vic_writel(vic, value, VIC_THI_STREAMID0); 122 vic_writel(vic, value, VIC_THI_STREAMID1); 123 } 124 } 125 #endif 126 127 /* setup clockgating registers */ 128 vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) | 129 CG_IDLE_CG_EN | 130 CG_WAKEUP_DLY_CNT(4), 131 NV_PVIC_MISC_PRI_VIC_CG); 132 133 err = falcon_boot(&vic->falcon); 134 if (err < 0) 135 return err; 136 137 hdr = vic->falcon.firmware.vaddr; 138 fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET); 139 hdr = vic->falcon.firmware.vaddr + 140 *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET); 141 fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET); 142 143 falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1); 144 falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE, 145 fce_ucode_size); 146 falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_OFFSET, 147 (vic->falcon.firmware.paddr + fce_bin_data_offset) 148 >> 8); 149 150 err = falcon_wait_idle(&vic->falcon); 151 if (err < 0) { 152 dev_err(vic->dev, 153 "failed to set application ID and FCE base\n"); 154 return err; 155 } 156 157 vic->booted = true; 158 159 return 0; 160 } 161 162 static void *vic_falcon_alloc(struct falcon *falcon, size_t size, 163 dma_addr_t *iova) 164 { 165 struct tegra_drm *tegra = falcon->data; 166 167 return tegra_drm_alloc(tegra, size, iova); 168 } 169 170 static void vic_falcon_free(struct falcon *falcon, size_t size, 171 dma_addr_t iova, void *va) 172 { 173 struct tegra_drm *tegra = falcon->data; 174 175 return tegra_drm_free(tegra, size, va, iova); 176 } 177 178 static const struct falcon_ops vic_falcon_ops = { 179 .alloc = vic_falcon_alloc, 180 .free = vic_falcon_free 181 }; 182 183 static int vic_init(struct host1x_client *client) 184 { 185 struct tegra_drm_client *drm = host1x_to_drm_client(client); 186 struct iommu_group *group = iommu_group_get(client->dev); 187 struct drm_device *dev = dev_get_drvdata(client->parent); 188 struct tegra_drm *tegra = dev->dev_private; 189 struct vic *vic = to_vic(drm); 190 int err; 191 192 if (group && tegra->domain) { 193 err = iommu_attach_group(tegra->domain, group); 194 if (err < 0) { 195 dev_err(vic->dev, "failed to attach to domain: %d\n", 196 err); 197 return err; 198 } 199 200 vic->domain = tegra->domain; 201 } 202 203 vic->channel = host1x_channel_request(client->dev); 204 if (!vic->channel) { 205 err = -ENOMEM; 206 goto detach; 207 } 208 209 client->syncpts[0] = host1x_syncpt_request(client, 0); 210 if (!client->syncpts[0]) { 211 err = -ENOMEM; 212 goto free_channel; 213 } 214 215 err = tegra_drm_register_client(tegra, drm); 216 if (err < 0) 217 goto free_syncpt; 218 219 return 0; 220 221 free_syncpt: 222 host1x_syncpt_free(client->syncpts[0]); 223 free_channel: 224 host1x_channel_put(vic->channel); 225 detach: 226 if (group && tegra->domain) 227 iommu_detach_group(tegra->domain, group); 228 229 return err; 230 } 231 232 static int vic_exit(struct host1x_client *client) 233 { 234 struct tegra_drm_client *drm = host1x_to_drm_client(client); 235 struct iommu_group *group = iommu_group_get(client->dev); 236 struct drm_device *dev = dev_get_drvdata(client->parent); 237 struct tegra_drm *tegra = dev->dev_private; 238 struct vic *vic = to_vic(drm); 239 int err; 240 241 err = tegra_drm_unregister_client(tegra, drm); 242 if (err < 0) 243 return err; 244 245 host1x_syncpt_free(client->syncpts[0]); 246 host1x_channel_put(vic->channel); 247 248 if (vic->domain) { 249 iommu_detach_group(vic->domain, group); 250 vic->domain = NULL; 251 } 252 253 return 0; 254 } 255 256 static const struct host1x_client_ops vic_client_ops = { 257 .init = vic_init, 258 .exit = vic_exit, 259 }; 260 261 static int vic_load_firmware(struct vic *vic) 262 { 263 int err; 264 265 if (vic->falcon.data) 266 return 0; 267 268 vic->falcon.data = vic->client.drm; 269 270 err = falcon_read_firmware(&vic->falcon, vic->config->firmware); 271 if (err < 0) 272 goto cleanup; 273 274 err = falcon_load_firmware(&vic->falcon); 275 if (err < 0) 276 goto cleanup; 277 278 return 0; 279 280 cleanup: 281 vic->falcon.data = NULL; 282 return err; 283 } 284 285 static int vic_open_channel(struct tegra_drm_client *client, 286 struct tegra_drm_context *context) 287 { 288 struct vic *vic = to_vic(client); 289 int err; 290 291 err = pm_runtime_get_sync(vic->dev); 292 if (err < 0) 293 return err; 294 295 err = vic_load_firmware(vic); 296 if (err < 0) 297 goto rpm_put; 298 299 err = vic_boot(vic); 300 if (err < 0) 301 goto rpm_put; 302 303 context->channel = host1x_channel_get(vic->channel); 304 if (!context->channel) { 305 err = -ENOMEM; 306 goto rpm_put; 307 } 308 309 return 0; 310 311 rpm_put: 312 pm_runtime_put(vic->dev); 313 return err; 314 } 315 316 static void vic_close_channel(struct tegra_drm_context *context) 317 { 318 struct vic *vic = to_vic(context->client); 319 320 host1x_channel_put(context->channel); 321 322 pm_runtime_put(vic->dev); 323 } 324 325 static const struct tegra_drm_client_ops vic_ops = { 326 .open_channel = vic_open_channel, 327 .close_channel = vic_close_channel, 328 .submit = tegra_drm_submit, 329 }; 330 331 #define NVIDIA_TEGRA_124_VIC_FIRMWARE "nvidia/tegra124/vic03_ucode.bin" 332 333 static const struct vic_config vic_t124_config = { 334 .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE, 335 .version = 0x40, 336 .supports_sid = false, 337 }; 338 339 #define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin" 340 341 static const struct vic_config vic_t210_config = { 342 .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE, 343 .version = 0x21, 344 .supports_sid = false, 345 }; 346 347 #define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin" 348 349 static const struct vic_config vic_t186_config = { 350 .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE, 351 .version = 0x18, 352 .supports_sid = true, 353 }; 354 355 #define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin" 356 357 static const struct vic_config vic_t194_config = { 358 .firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE, 359 .version = 0x19, 360 .supports_sid = true, 361 }; 362 363 static const struct of_device_id vic_match[] = { 364 { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config }, 365 { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config }, 366 { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config }, 367 { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config }, 368 { }, 369 }; 370 371 static int vic_probe(struct platform_device *pdev) 372 { 373 struct device *dev = &pdev->dev; 374 struct host1x_syncpt **syncpts; 375 struct resource *regs; 376 struct vic *vic; 377 int err; 378 379 vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL); 380 if (!vic) 381 return -ENOMEM; 382 383 vic->config = of_device_get_match_data(dev); 384 385 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 386 if (!syncpts) 387 return -ENOMEM; 388 389 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 390 if (!regs) { 391 dev_err(&pdev->dev, "failed to get registers\n"); 392 return -ENXIO; 393 } 394 395 vic->regs = devm_ioremap_resource(dev, regs); 396 if (IS_ERR(vic->regs)) 397 return PTR_ERR(vic->regs); 398 399 vic->clk = devm_clk_get(dev, NULL); 400 if (IS_ERR(vic->clk)) { 401 dev_err(&pdev->dev, "failed to get clock\n"); 402 return PTR_ERR(vic->clk); 403 } 404 405 if (!dev->pm_domain) { 406 vic->rst = devm_reset_control_get(dev, "vic"); 407 if (IS_ERR(vic->rst)) { 408 dev_err(&pdev->dev, "failed to get reset\n"); 409 return PTR_ERR(vic->rst); 410 } 411 } 412 413 vic->falcon.dev = dev; 414 vic->falcon.regs = vic->regs; 415 vic->falcon.ops = &vic_falcon_ops; 416 417 err = falcon_init(&vic->falcon); 418 if (err < 0) 419 return err; 420 421 platform_set_drvdata(pdev, vic); 422 423 INIT_LIST_HEAD(&vic->client.base.list); 424 vic->client.base.ops = &vic_client_ops; 425 vic->client.base.dev = dev; 426 vic->client.base.class = HOST1X_CLASS_VIC; 427 vic->client.base.syncpts = syncpts; 428 vic->client.base.num_syncpts = 1; 429 vic->dev = dev; 430 431 INIT_LIST_HEAD(&vic->client.list); 432 vic->client.version = vic->config->version; 433 vic->client.ops = &vic_ops; 434 435 err = host1x_client_register(&vic->client.base); 436 if (err < 0) { 437 dev_err(dev, "failed to register host1x client: %d\n", err); 438 goto exit_falcon; 439 } 440 441 pm_runtime_enable(&pdev->dev); 442 if (!pm_runtime_enabled(&pdev->dev)) { 443 err = vic_runtime_resume(&pdev->dev); 444 if (err < 0) 445 goto unregister_client; 446 } 447 448 return 0; 449 450 unregister_client: 451 host1x_client_unregister(&vic->client.base); 452 exit_falcon: 453 falcon_exit(&vic->falcon); 454 455 return err; 456 } 457 458 static int vic_remove(struct platform_device *pdev) 459 { 460 struct vic *vic = platform_get_drvdata(pdev); 461 int err; 462 463 err = host1x_client_unregister(&vic->client.base); 464 if (err < 0) { 465 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 466 err); 467 return err; 468 } 469 470 if (pm_runtime_enabled(&pdev->dev)) 471 pm_runtime_disable(&pdev->dev); 472 else 473 vic_runtime_suspend(&pdev->dev); 474 475 falcon_exit(&vic->falcon); 476 477 return 0; 478 } 479 480 static const struct dev_pm_ops vic_pm_ops = { 481 SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL) 482 }; 483 484 struct platform_driver tegra_vic_driver = { 485 .driver = { 486 .name = "tegra-vic", 487 .of_match_table = vic_match, 488 .pm = &vic_pm_ops 489 }, 490 .probe = vic_probe, 491 .remove = vic_remove, 492 }; 493 494 #if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) 495 MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE); 496 #endif 497 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) 498 MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE); 499 #endif 500 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) 501 MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE); 502 #endif 503 #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) 504 MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE); 505 #endif 506