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