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